@PostConstruct 注解导致 Tomcat 的端口号没有启动

导读:本篇文章讲解 @PostConstruct 注解导致 Tomcat 的端口号没有启动,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

@PostConstruct 注解导致 Tomcat 的端口号没有启动

问题背景

在开发一个项目的时候,使用了 @PostConstruct 注解,被注解的方法里面有 GRPC 服务端,所以启动了 GRPC 服务端,然而这个注解又是同步的,所以服务端启动后一直就卡在那里了,不在继续执行其他的初始化,我这里是使 Tomcat 的端口初始化暂停了,其他的程序可能会出现其他的问题,大同小异。问题代码如下:

	@PostConstruct
    public void init() throws IOException, InterruptedException {
        start();
        blockUntilShutdown();
    }
    
	public void start() throws IOException {
        server = ServerBuilder.forPort(port)
                .addService(mapImpl)
                .build()
                .start();
        log.info("server start up...");
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                IdmappingServer.this.stop();
                log.error("Running error, server shutdown");
            }
        });
    }

	public void blockUntilShutdown() throws InterruptedException {
        if (server != null) {
            server.awaitTermination();
        }
    }

在application.yml我设定的端口为server.port=3108,启动程序后:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.6.1)

2021-12-17 10:07:25.325 INFO  [main] c.d.d.a.AuthenticationManagerApplication.logStarting(StartupInfoLogger.java:55): Starting AuthenticationManagerApplication using Java 1.8.0_172 on B-YUAN-G with PID 32708 (D:\code\AuthenticationManager\target\classes started by yuan.g in D:\code\AuthenticationManager)
2021-12-17 10:07:25.328 INFO  [main] c.d.d.a.AuthenticationManagerApplication.logStartupProfileInfo(SpringApplication.java:639): The following profiles are active: dev
2021-12-17 10:07:26.105 INFO  [main] o.s.b.w.e.t.TomcatWebServer.initialize(TomcatWebServer.java:108): Tomcat initialized with port(s): 3108 (http)
2021-12-17 10:07:26.111 INFO  [main] o.a.c.h.Http11NioProtocol.log(DirectJDKLog.java:173): Initializing ProtocolHandler ["http-nio-3108"]
2021-12-17 10:07:26.111 INFO  [main] o.a.c.c.StandardService.log(DirectJDKLog.java:173): Starting service [Tomcat]
2021-12-17 10:07:26.112 INFO  [main] o.a.c.c.StandardEngine.log(DirectJDKLog.java:173): Starting Servlet engine: [Apache Tomcat/9.0.55]
2021-12-17 10:07:26.178 INFO  [main] o.a.c.c.C.[.[.[/].log(DirectJDKLog.java:173): Initializing Spring embedded WebApplicationContext
2021-12-17 10:07:26.178 INFO  [main] o.s.b.w.s.c.ServletWebServerApplicationContext.prepareWebApplicationContext(ServletWebServerApplicationContext.java:290): Root WebApplicationContext: initialization completed in 799 ms
2021-12-17 10:07:27.036 INFO  [main] c.d.d.a.g.s.Server.start(IdmappingServer.java:34):  server start up...

可以看到 Tomcat initialized with port(s): 3108 (http) 这句话,但这句话并没有把端口真正的启动,在端口真正启动前被 Server.start(IdmappingServer.java:34): Idmapping server start up… 阻塞了。

解决方案

只要把 @PostConstruct 注解的方法变为异步就可以解决问题,变为异步的方式也很简单,以我的程序为例,在 start( ) 方法上加上 @Async 注解,在 springboot 的启动程序上,也就是 @SpringBootApplication 上面添加 @EnableAsync 使能异步注解,不能把初始化写在MappingServer中,分开两个类写,否则异步线程无法开启,注意循环依赖,如下所示:
类1

	@Autowired
    MappingServer mappingServer;
	
	//不能把初始化写在MappingServer中,否则异步线程无法开启
	@PostConstruct
    public void init() {
        mappingServer.start();
        mappingServer.blockUntilShutdown();
    }

类2

    
    @Async
	public void start() throws IOException {
        server = ServerBuilder.forPort(port)
                .addService(mapImpl)
                .build()
                .start();
        log.info("server start up...");
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                IdmappingServer.this.stop();
                log.error("Running error, server shutdown");
            }
        });
    }

	public void blockUntilShutdown() throws InterruptedException {
        if (server != null) {
            server.awaitTermination();
        }
    }
    
@EnableAsync
@SpringBootApplication
public class AuthenticationManagerApplication

注意 @Async 没有添加在 init( ) 上,因为启动GRPC服务端的方法是 start( ) 方法,产生的结果如下图所示:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.6.1)

2021-12-17 10:15:17.300 INFO  [main] c.d.d.a.AuthenticationManagerApplication.logStarting(StartupInfoLogger.java:55): Starting AuthenticationManagerApplication using Java 1.8.0_172 on B-YUAN-G with PID 34472 (D:\code\AuthenticationManager\target\classes started by yuan.g in D:\code\AuthenticationManager)
2021-12-17 10:15:17.302 INFO  [main] c.d.d.a.AuthenticationManagerApplication.logStartupProfileInfo(SpringApplication.java:639): The following profiles are active: dev
2021-12-17 10:15:18.077 INFO  [main] o.s.b.w.e.t.TomcatWebServer.initialize(TomcatWebServer.java:108): Tomcat initialized with port(s): 3108 (http)
2021-12-17 10:15:18.084 INFO  [main] o.a.c.h.Http11NioProtocol.log(DirectJDKLog.java:173): Initializing ProtocolHandler ["http-nio-3108"]
2021-12-17 10:15:18.084 INFO  [main] o.a.c.c.StandardService.log(DirectJDKLog.java:173): Starting service [Tomcat]
2021-12-17 10:15:18.084 INFO  [main] o.a.c.c.StandardEngine.log(DirectJDKLog.java:173): Starting Servlet engine: [Apache Tomcat/9.0.55]
2021-12-17 10:15:18.152 INFO  [main] o.a.c.c.C.[.[.[/].log(DirectJDKLog.java:173): Initializing Spring embedded WebApplicationContext
2021-12-17 10:15:18.152 INFO  [main] o.s.b.w.s.c.ServletWebServerApplicationContext.prepareWebApplicationContext(ServletWebServerApplicationContext.java:290): Root WebApplicationContext: initialization completed in 800 ms
2021-12-17 10:15:18.697 INFO  [main] o.a.c.h.Http11NioProtocol.log(DirectJDKLog.java:173): Starting ProtocolHandler ["http-nio-3108"]
2021-12-17 10:15:18.705 INFO  [main] o.s.b.w.e.t.TomcatWebServer.start(TomcatWebServer.java:220): Tomcat started on port(s): 3108 (http) with context path ''
2021-12-17 10:15:18.713 INFO  [main] c.d.d.a.AuthenticationManagerApplication.logStarted(StartupInfoLogger.java:61): Started AuthenticationManagerApplication in 1.892 seconds (JVM running for 2.787)
2021-12-17 10:15:19.089 INFO  [task-1] c.d.d.a.g.s.Server.start(Server.java:34): server start up...

可以看到与之前的对比,多出了三句话,这个时候 Tomcat 的端口才算真正启动了:

2021-12-17 10:15:18.697 INFO  [main] o.a.c.h.Http11NioProtocol.log(DirectJDKLog.java:173): Starting ProtocolHandler ["http-nio-3108"]
2021-12-17 10:15:18.705 INFO  [main] o.s.b.w.e.t.TomcatWebServer.start(TomcatWebServer.java:220): Tomcat started on port(s): 3108 (http) with context path ''
2021-12-17 10:15:18.713 INFO  [main] c.d.d.a.AuthenticationManagerApplication.logStarted(StartupInfoLogger.java:61): Started AuthenticationManagerApplication in 1.892 seconds (JVM running for 2.787)

而且可以看到GRPC服务器已经使用的一个线程进行启动的:
2021-12-17 10:15:19.089 INFO [task-1] c.d.d.a.g.s.Server.start(Server.java:34): server start up…

问题总结

  1. @PostConstruct 注解是同步启动,如果里面的过程时间比较长会影响其他初始化程序,建议改为异步。
  2. 使用 @Async 注解进行方法异步,一定记住添加使能注解 @EnableAsync,否则无效。
  3. 导致 Tomcat 端口不能使用,也有可能是其他原因,比如端口被占用,多排查一下一定会找到问题的。

作为程序员第一篇开源文章,每次写一句歌词记录一下,看看人生有几首歌的时间,wahahaha …
@PostConstruct 注解导致 Tomcat 的端口号没有启动@PostConstruct 注解导致 Tomcat 的端口号没有启动@PostConstruct 注解导致 Tomcat 的端口号没有启动

Lyric: 这蜿蜒的微笑

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/110875.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!