美文网首页
自定义Bean的特性

自定义Bean的特性

作者: macchiato漂浮 | 来源:发表于2019-11-04 04:01 被阅读0次

    Spring 提供了一些接口方便用户自定义bean的特性。比如:

    • Lifecycle Callbacks
    • ApplicationContextAware & BeanNameAware
    • Other Aware Interfaces

    一、生命周期回调

    为了配合容器管理bean,我们可以实现比如InitializingBeanDisposableBean接口,使得容器在初始化和销毁bean时执行指定操作。也可以实现比如LifeCycle接口使bean参与容器的启动和关闭过程。

    1. 初始化回调(Initialization Callbacks)

    定义初始化回调可以使容器在创建完bean后执行自定义的初始化回调动作。

    方式一:

    在代码中实现org.springframework.beans.factory.InitializingBean接口并重写其afterPropertiesSet()方法。这种方式使代码与Spring耦合,不推荐使用。

    public class AnotherExampleBean implements InitializingBean {
    
        @Override
        public void afterPropertiesSet() {
        }
    }
    

    方式二:

    在基于注解的配置中使用@PostConstruct注解

    方式三:

    在基于XML的配置中定义init-method

    public class ExampleBean {
    
        public void init() {
        
        }
    }
    
    <bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
    

    方式四:

    在基于Java的配置中为@Bean设置initMethod属性值

    2. 销毁回调(Destruction Callbacks)

    定义销毁回调可以使bean在容器销毁时执行指定回调操作。

    方式一:

    在代码中实现org.springframework.beans.factory.DisposableBean接口并重写其destroy()方法。

    public class AnotherExampleBean implements DisposableBean {
    
        @Override
        public void destroy() {
            // do some destruction work (like releasing pooled connections)
        }
    }
    

    方式二:

    在基于注解的配置中使用@PreDestroy注解

    方式三:

    在基于XML的配置中定义destroy-method

    public class ExampleBean {
    
        public void cleanup() {
        }
    }
    
    <bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
    

    方式四:

    在基于Java的配置中为@Bean设置destroyMethod属性值

    3. 默认的初始化和销毁回调

    可以通过default-init-method给需要执行回调的bean统一命名回调方法:

    <beans default-init-method="init">
      <bean id=xxx, class=xxx > </bean>
     <bean id=xxx, class=xxx > </bean>
    </beans>
    

    这样需要回调的bean在自己的类定义中实现名称为init()的方法,就会被容器识别并触发此回调方法;
    同理销毁回调使用<beans default-destroy-method="destroy">

    4. 组合使用生命周期回调机制

    如果同时使用多种方式的生命周期机制,会按照以下顺序执行:

    初始化回调的执行顺序:

    • @PostConstruct标注的方法
    • 实现InitializingBean时重写的afterPropertiesSet()方法
    • xml中指定的init()方法

    销毁回调的执行顺序:

    • @PreDestroy标注的方法
    • 实现DisposableBean时重写的destroy()方法
    • xml中指定的destory()方法

    5. 启动&关闭回调(Startup & Shutdown Callbacks)

    Spring提供了LifeCycle接口,使得bean可以实现此接口来启动和停止一些后台处理过程。当ApplicationContext接收到启动和停止信号时,会委托LifecycleProcessor接口去调用这些bean的start()/stop()方法。

    public interface Lifecycle {
        void start();
        void stop();
        boolean isRunning();
    }
    

    LifecycleProcessorLifeCycle接口的基础上扩展了两个方法:

    public interface LifecycleProcessor extends Lifecycle {
        void onRefresh();
        void onClose();
    }
    

    注意:

    • 实现LifeCycle接口并不会实现上下文刷新时自启动。对于想要控制某些特定的bean在自启动(包括启动)阶段的情况,应考虑使用SmartLifeCycle来代替。
    • 容器销毁时并不能保证bean一定能接收到stop信号。在容器正常的关闭情况下,生命周期bean会在销毁回调(destruction callback)执行前收到一个stop信号,但是当上下文热刷新时,或者尝试终止刷新时,仅仅执行destruction()回调。

    起停执行顺序:

    • 对于相互依赖的bean, 依赖先启动后关闭。
    • 对于没有明确约定依赖关系的bean, 可以通过smartLifeCyclegetPhase()(SmartLifeCycle实现了Phase接口)获取bean的启停阶段。phase越小越先执行启动,越后执行关闭。没有实现smartLifecycle的bean的phase默认是0

    SmartLifeCycle

    public interface SmartLifecycle extends Lifecycle, Phased {
        boolean isAutoStartup();
        void stop(Runnable callback);
    }
    

    SmartLifeCyclestop(..)方法需要传入一个回调。实现此接口的bean会在执行完关闭过程后执行此回调。并且实现SmartLifeCycle接口的bean对象的isAutoStartup()若为true,则在LifecycleProcessor执行onRefresh ()时,会调用此对象的start()方法。
    这里在源码中查看DefaultLifecycleProcessoronRefresh()方法:

    DefaultLifecycleProcessor#onRefresh()
    DefaultLifecycleProcessor#startBeans()

    由以上方法可以看出上下文刷新时会调用DefaultLifecycleProcessor#startBeans(true),在startBean()方法中遍历所有实现了LifeCycle接口的bean,如果实现的是SmartLifeCycle接口并且设置了自启动为true,则将其放入map中,通过各个bean定义的起停阶段值分组。再根据顺序依次执行bean的start()

    二、ApplicationContextAware & BeanNameAware

    ApplicationContextAware:

    当容器创建了一个实现ApplicationContextAware接口的对象时,该对象便有了对ApplicationContext的引用。因此bean可以通过编程操作ApplicationContext。比如获取一些容器相关的信息:

    public class Aware implements ApplicationContextAware {
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext)applicationContext;
            configurableApplicationContext.getApplicationName();
            configurableApplicationContext.getEnvironment();
        }
    }
    

    除此之外,还可以通过@Autowired注解注入ApplicationContext来对其进行操作:

    public class AwareAnotation {
            @Autowired
            private ApplicationContext applicationContext;        
        }
    

    BeanNameAware:

    当bean实现BeanNameAware接口时,同理也能获取bean的名称:

    public interface BeanNameAware {
        void setBeanName(String name) throws BeansException;
    }
    

    相关文章

      网友评论

          本文标题:自定义Bean的特性

          本文链接:https://www.haomeiwen.com/subject/zwhrbctx.html