Skip to content

启动与停止的扩展点 ​

注册中心、配置中心这类库需要在应用启动的特定时刻做事情。tio-boot 提供三个扩展点,库引入后即可工作,应用代码不需要配合。

EnvLoadedListener:在读取服务配置之前补充配置 ​

tio-boot 启动时先加载命令行参数、app.properties 及其 profile 文件、环境变量,然后才读取 server.port 等服务配置。EnvLoadedListener 在这两步之间执行,适合从配置中心、数据库或加密文件中补充配置,补充的值对整个启动过程生效。

java
package demo.env;

import nexus.io.tio.boot.env.EnvLoadedListener;
import nexus.io.tio.utils.environment.EnvUtils;
import nexus.io.tio.utils.environment.Prop;
import nexus.io.tio.utils.environment.PropUtils;

/**
 * 没有配置 server.port 时,从环境变量 PORT 读取(很多容器平台用它指定端口)
 */
public class PortEnvLoadedListener implements EnvLoadedListener {

  @Override
  public void onEnvLoaded(String[] args) {
    String port = System.getenv("PORT");
    if (port != null && EnvUtils.get("server.port") == null) {
      Prop prop = new Prop();
      prop.getProperties().setProperty("server.port", port);
      PropUtils.append(prop);
    }
  }
}

在 META-INF/services/nexus.io.tio.boot.env.EnvLoadedListener 中登记实现类,tio-boot 通过 ServiceLoader 发现它:

demo.env.PortEnvLoadedListener

写入 PropUtils 的值和配置文件处于同一层,命令行参数和环境变量仍然可以覆盖;如果要强制生效,使用 EnvUtils.set(key, value)。Nacos 配置中心就是这样实现的:tio-boot-cloud-nacos 登记了自己的 EnvLoadedListener,引入后自动加载 nacos.config.data-ids,Nacos 中的配置可以设置端口。

监听器拿到的 args 就是命令行参数;启动后的任何时候也可以用 EnvUtils.getArgs() 获取。

addServerListener:多个服务监听器 ​

TioBootServer.me().setTioBootServerListener(listener) 是应用自己的监听器,只能有一个。库使用 addServerListener 追加监听器,和应用的监听器互不覆盖,按添加顺序在应用监听器之后执行:

java
package demo.listener;

import nexus.io.context.Context;
import nexus.io.context.ServerListener;

public class RegistryListener implements ServerListener {

  @Override
  public void beforeStart(Class<?>[] primarySources, String[] args) {
  }

  @Override
  public void afterStarted(Class<?>[] primarySources, String[] args, Context context) {
    // 端口已经开始监听,可以注册到注册中心
    System.out.println("listening on " + context.getPort());
  }

  @Override
  public void beforeStop() {
    // 停止服务之前,先从注册中心下线
    System.out.println("deregister");
  }

  @Override
  public void afterStopped() {
  }
}
java
package demo;

import demo.listener.RegistryListener;
import nexus.io.tio.boot.TioApplication;
import nexus.io.tio.boot.server.TioBootServer;

public class ListenerApp {
  public static void main(String[] args) {
    TioBootServer.me().addServerListener(new RegistryListener());
    TioApplication.run(ListenerApp.class, () -> {
    }, args);
  }
}

TioBootNacos.start() 就是通过 addServerListener 在 afterStarted 中注册实例、在 beforeStop 中注销实例。

server.shutdown.hook:优雅关闭 ​

properties
server.shutdown.hook=true

开启后 tio-boot 注册 JVM 关闭钩子,进程收到 SIGTERM(kill、docker stop、Kubernetes 停止 Pod)或 Ctrl+C 时执行完整的关闭流程:依次调用监听器的 beforeStop、停止服务、执行 HookCan 中的销毁方法、关闭 Aop 容器,最后调用 afterStopped。关闭流程只执行一次,代码中先调用了 close() 时不会重复执行。

shell
kill -TERM <pid>
Stopping server...
LISTENER beforeStop
LISTENER afterStopped

MIT Licensed