05、IocContainer-5 自定义Bean的性质

自定义Bean的性质

  1. 生命周期回调

    1.1 初始化回调

    如果我们的Bean实现The org.springframework.beans.factory.InitializingBean接口,当容器将所有必要的属性注入该bean之后,我们实现的afterPropertiesSet()方法将会被回调。

    <bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
    
    public class AnotherExampleBean implements InitializingBean {
        @Override
        public void afterPropertiesSet() {
            // do some initialization work
        }
    }
    

    但是这样做就将业务代码与Spring框架耦合了。

    在基于XML的配置中,为<bean>元素的init-method属性指定一个初始化方法,可以起到相同的效果。

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

    在基于注解的配置中,使用@PostConstruct对初始化方法进行注解:

    @Bean
    public class ExampleBean {
        @PostConstruct
        public void init() {
            // do some initialization work
        }
    }
    

    1.2 销毁回调

    如我们的bean实现了org.springframework.beans.factory.DisposableBean接口,当管理该bean的容器被销毁后,我们实现的destroy()方法将会被回调。

    <bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
    
    public class AnotherExampleBean implements DisposableBean {
    
        @Override
        public void destroy() {
            // do some destruction work (like releasing pooled connections)
        }
    }
    

    但是这与Spring框架耦合了。

    在基于XML的配置中,为<bean>元素的destroy-method属性指定一个销毁方法,可以起到相同的效果。

    <bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
    
    public class ExampleBean {
    
        public void cleanup() {
            // do some destruction work (like releasing pooled connections)
        }
    }
    

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

    @Bean
    public class ExampleBean {
        @PreDestroy
        public void init() {
            // do some initialization work
        }
    }
    

    1.3 默认初始化和销毁方法

    如果在整个项目中,都使用相同的名称为bean定义初始化和销毁方法,那么我们就可以配置默认的初始化和销毁回调方法名。

    <beans defualt-init-method="init" defualt-destroy-method="cleanup">
        <bean id="blogService" class="com.something.DefaultBlogService">
            <property name="blogDao" ref="blogDao" />
        </bean>
    </beans>
    
    public class DefaultBlogService implements BlogService {
    
        private BlogDao blogDao;
    
        public void setBlogDao(BlogDao blogDao) {
            this.blogDao = blogDao;
        }
    
        // this is (unsurprisingly) the initialization callback method
        public void init() {
            if (this.blogDao == null) {
                throw new IllegalStateException("The [blogDao] property must be set.");
            }
        }
    }
    

    1.4 联合生命周期机制(多种配置方式混用)

    我们可以同时使用多种方式来定义bean的生命周期回调,如果每种方式对应不同的方法,那么这些方法将按下面的顺序回调。

    初始化方法:

    • @PostConstruct注解的方法
    • 实现InitializingBean接口的afterPropertiesSet方法
    • XML中<bean>元素的init-method指定的方法
      销毁方法:
    • @PreDestroy注解的方法
    • 实现DisposableBean接口的destroy方法
    • XML中<bean>元素的destroy-method指定的方法

    1.5 ·Startup和Shutdown回调

    org.springframework.context.Lifycycle接口为任意有自己生命周期的对象定义了重要的方法:

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

    任何被容器管理的对象都可以继承这个接口,当容器接收到startstop信号后,会将这个调用传递给实现这个接口的对象。

    org.springframework.context.Lifecycle接口只是对start和stop通知的简单定义,它并不会在容器刷新是自动启动,我们应该实现org.springframework.context.SmartLifecycle

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

    当我们实现SmartLifecycle接口的isAutoStartup方法时,如果返回true,那么在容器刷新时,就会自动调用start方法(Lifecycle的实现);如果返回false,那么就只有显示调用这个方法,或者调用容器的start方法时自动回调bean的start方法。

    Phased接口的getPhase方法的返回值将决定哪个bean的start方法先被调用。phase值越小,越先调用start,越后调用stop(Runnable);普通bean(没有继承Lifecycle接口的bean)phase默认为0。

    下面是一个简单的例子:

    public class MyTask implements SmartLifecycle {
        public static final Logger log = Logger.getLogger("com.heisenberg.spring");
        Thread t;
        boolean isRunning = false;
        public void start() {
            MyRunnable runnable = new MyRunnable();
            t = new Thread(runnable);
            t.start();
            if (!t.isInterrupted()){
                log.info(Utils.LOG_TAG + "Task is Running"+Utils.LOG_TAG);
                isRunning = true;
            }
        }
    
        public void stop() {
            t.interrupt();
        }
    
        public boolean isRunning() {
            return isRunning;
        }
    
        public boolean isAutoStartup() {
            return false;
        }
    
        public void stop(Runnable callback) {
            this.stop();
            if (t.isInterrupted()){
                log.info(Utils.LOG_TAG + "Task stopped"+Utils.LOG_TAG);
            }
            callback.run();
        }
    
        public int getPhase() {
            return -1;
        }
    }
    
    class MyRunnable implements Runnable{
        public static final Logger log = Logger.getLogger("com.heisenberg.spring");
        public void run() {
            while (!Thread.currentThread().isInterrupted()){
                log.info(Utils.LOG_TAG + "Tick" + Utils.LOG_TAG);
            }
        }
    }
    

    1.6 在非Web应用中优雅的关闭容器

    public static void main(String[] args){
        //使用AbstractApplicationContext或者ConfigurableApplicationContext都可以
        //AbstractApplicationContext context = new ClassPathXmlApplicationContext("service.xml");
        ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("service.xml");
        //在JVM中注册一个关闭钩子
        context.registerShutdownHook();
    
        //下面是任务
    
        //当任务完成后退出应用,在退出之前退出钩子会被回调,它将关闭容器
        System.exit(0)
    }
    
    
  2. ApplicationContextAwareBeanNameAware

    2.1 ApplicationContextAware

    当一个ApplicationContext容器创建了一个实现了ApplicationContextAware接口的类实例时,这个实例将拥有它所在容器的引用。

    但是并不推荐实现ApplicationContextAware接口,这会使代码跟Spring耦合,这也违背了控制反转的风格。

    我们也可以通过自动装配来获取容器的引用

    2.2 BeanNameAware

    当一个类实现了BeanNameAware接口,容器创建这个类的实例之后,该bean将会得到一个名称的引用。这个名称是其它bean对这个bean的引用的变量名称。

    public interface BeanNameAware {
        //name 便是其它bean对该bean的引用变量名
        void setBeanName(String name) throws BeansException;
    }
    
  3. 其它的Aware接口

     
    5893832-3f63df714dff4b48.png
    其它的Aware接口
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值