Solon v3.0.3

五、LifecycleBean 和 @Init、@Destroy

</> markdown

LifecycleBean 接口,是绑定应用上下文(AppContext)的启动与停止的。

  • 启动时,Bean 扫描已经结束,可以做一些初始化动作(@Init 函数,与此相当)
  • 启动之后,一般开始网络监听与注册
  • 停止之前,一般注销网络登记
  • 停止时,可以做一些释放动作(@Destroy 函数,与此相当)

它,只对单例有效。非单例时,仅扫描时产生的第一实例会被纳管,其它实例的生命周期会失效(或者自己处理)。当有多个 LifecycleBean 相互依赖时,会自动排序。

接口对应注解执行时机说明
LifecycleBean::start@InitAppContext::start()启动
LifecycleBean::postStart 同上启动之后
LifecycleBean::preStop AppContext::preStop()停止之前
LifecycleBean::stop@DestroyAppContext::stop()停止

1、使用 @Init@Destroy 替代轻量

如果不需要 LifecycleBean::stop,使用注解 @Init 更简洁。一般只做初始化处理。

@Component
public class Demo {
    @Init
    public void init(){ //一个无参的函数,名字随便取
    }
}

如果不需要 LifecycleBean::start,使用注解 @Destroy 更简洁。一般只做注销处理。

@Component
public class Demo {
    @Destroy
    public void destroy(){ //一个无参的函数,名字随便取
    }
}

2、LifecycleBean 的自动排序(v2.2.8 后支持)

自动排序。当 Bean2 依赖 Bean1 注入时。Bean1::start() 会先执行,再执行 Bean2::start()。例:

@Component
public class Bean1 implements LifecycleBean{
    @Override
    public void start(){
        //db1 init ...
    }
    
    public void func1(){
        //db1 call
    }
}

@Component
public class Bean2 implements LifecycleBean{
    @Inject 
    Bean1 bean1;
    
    @Override
    public void start(){
        bean1.func1();
    }
}

有时候 Bean1 和 Bean2 可能并没有直接的依赖关系。也是可以通过注入,形成依赖关系,让执行自动排序(这个可称为"小技巧")

3、LifecycleBean 自动排序引起的循环依赖问题

因为自动排序是基于注入的依赖关系来确定的。当相互依赖时就会傻掉(异常提示)。像这样:

@Component
public class Bean1 implements LifecycleBean{
    @Inject 
    Bean2 bean2;
    
    @Override
    public void start(){
    }
}

@Component
public class Bean2 implements LifecycleBean{
    @Inject 
    Bean1 bean1;
    
    @Override
    public void start(){
    }
}

要么取消相互依赖。要么手工指定顺序位:

@Component(index = 1)
public class Bean1 implements LifecycleBean{
    @Inject 
    Bean2 bean2;
    
    @Override
    public void start(){
    }
}

@Component(index = 2)
public class Bean2 implements LifecycleBean{
    @Inject 
    Bean1 bean1;
    
    @Override
    public void start(){
    }
}

附:AppLoadEndEvent (即,应用启动完成)

如果初始化时,有些依赖的 Bean 未准备就绪(比如,有些 bean 是在初始化时,才产生的)。可以使用 AppLoadEndEvent 事件:

//注解模式
@Component
public class AppLoadEndListener implements EventListener<AppLoadEndEvent>{
    @Override
    public void onEvent(AppLoadEndEvent event) throws Throwable {
        //db1 init ...
    }
}