zoukankan      html  css  js  c++  java
  • Spring 中 Bean 的生命周期

     

    所谓 Bean 的生命周期,就是一个 Bean 从创建到销毁,所经历的各种方法调用。大致包含下面几个方法(不是全部)

    1. Bean 的实例化,调用了构造方法。
    2. 使用 setter 方法填充属性。
    3. 一旦依赖注入完成,调用 Spring 感知接口 BeanNameAware.setBeanName()。
    4. BeanFactoryAware.setBeanFactory() 方法
    5. ApplicationContextAware 的 setApplicationContext() 方法
    6. BeanPostProcessor.postProcessBeforeInitialization 方法。
    7. @PostConstruct 标注的方法。
    8. InitializingBean.afterPropertiesSet() 方法
    9. 自定义的 init-method 方法
    10. BeanPostProcessor.postProcessAfterInitialization()

    此时 Bean 可以用了。当容器关闭的时候,则会调用:

    1. @PreDestroy 标注的方法
    2. DisposableBean.destroy()
    3. 自定义的 destroy-method
    4. 对象自定义的 finalize 方法

    其中,有几个方法是容器回调的方法,只要实现了感知接口,就会调用这些方法,比如 BeanNameAware.setBeanName(),BeanFactoryAware.setBeanFactory(),ApplicationContextAware.setApplicationContext()。了解感知接口,可参考 感知接口 。

    生命周期之方法调用

    1. 后置处理器 BeanPostProcessor 接口
    2. @PostConstruct 和@PreDestroy
    3. InitializingBean.afterPropertiesSet() 和 DisposableBean.destroy()
    4. 自定义的 init-method 方法和 destroy-method 方法

    这几组实现方式,都是在容器初始化对象和释放对象的时调用相关方法。它们之间并没有太大的不同,要说不同就是执行顺序的不同。BeanPostProcessor 的 postProcessBeforeInitialization,在初始化之前调用,接着@PostConstruct 标注的方法调用,然后 InitializingBean.afterPropertiesSet(),然后 init-method。通常使用时,根据个人喜好使用,个人比较喜好使用@PostConstruct 和@PreDestroy,因为简单。

    BeanPostProcessor 接口

    BeanPostProcessor 有一个不同于其他 3 个的点,实现 BeanPostProcessor 接口后,容器中的对象,在初始化前和初始化后,都会调用 postProcessBeforeInitialization 方法和 postProcessAfterInitialization 方法。即使这个对象并未实现 BeanPostProcessor 接口。而其他如@PostConstruct 注解等的实现方式中,仅作用在当前的 bean 上。因此 BeanPostProcessor 是全局性的,对容器中所有的对象都有效。

    User类

    @Component
    public class User implements BeanPostProcessor  {	
    	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    		System.out.println("postProcessBeforeInitialization..."+beanName+"=>"+bean);
    		return bean;
    	}
    	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    		System.out.println("postProcessAfterInitialization..."+beanName+"=>"+bean);
    		return bean;
    	}
    }
    @Component
    public class School  {
     
    }

    Main方法

    public static void main(String[] args) {
    	// 使用Config.class这个配置类
    	AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
    	applicationContext.close();
    }

    上述代码中,User 类实现了后置处理器接口,而 School 类并没实现该接口,但是 School 在初始化时,也调用了 User 类中的实现方法。Main 方法运行后的结果如下:

    postProcessBeforeInitialization...org.springframework.context.event.internalEventListenerProcessor=>org.springframework.context.event.EventListenerMethodProcessor@25e20bbb
    postProcessAfterInitialization...org.springframework.context.event.internalEventListenerProcessor=>org.springframework.context.event.EventListenerMethodProcessor@25e20bbb
    postProcessBeforeInitialization...org.springframework.context.event.internalEventListenerFactory=>org.springframework.context.event.DefaultEventListenerFactory@3cbc6f29
    postProcessAfterInitialization...org.springframework.context.event.internalEventListenerFactory=>org.springframework.context.event.DefaultEventListenerFactory@3cbc6f29
    postProcessBeforeInitialization...config=>com.learn.Config$$EnhancerBySpringCGLIB$$5a156ddc@39960641
    postProcessAfterInitialization...config=>com.learn.Config$$EnhancerBySpringCGLIB$$5a156ddc@39960641
    postProcessBeforeInitialization...school=>com.learn.entity.School@c1c6d1b
    postProcessAfterInitialization...school=>com.learn.entity.School@c1c6d1b

    Spring 的底层,大量的使用到了后置处理器这个功能。

    @PostConstruct 和@PreDestroy

    @PostConstruct 和@PreDestroy 是 JSR-250(Java Specification Requests) 中定义的注解,Spring 也支持这些注解。@PostConstruct 和@PreDestroy 必须标注在无参数无返回值的方法上,当容器在加载 bean 时调用@PostConstruct 标注的方法,当容器释放 bean 对象的时候,调用@PreDestroy 标注的方法。

    User类

    @Component
    public class User {
    	@PostConstruct
    	public void postConstruct1()
    	{
    		System.out.println("user postConstruct 1");
    	}
    	
    	@PreDestroy
    	public void preDestroy()
    	{
    		System.out.println("user preDestroy 1");
    	}
    }

    School

    @Component
    public class School {
    	@PostConstruct
    	public void postConstruct1 ()
    	{
    		System.out.println("school postConstruct 1");
    	}
    	
    	@PreDestroy
    	public void preDestroy1 ()
    	{
    		System.out.println("school preDestroy1 1");
    	}
    }

    Main方法

    public static void main(String[] args) {
    		// 使用Config.class这个配置类
    		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
    		applicationContext.close();
    	}

    运行结果:

    school postConstruct 1
    user postConstruct 1
    user preDestroy 1
    school preDestroy1 1

    InitializingBean.afterPropertiesSet() 和 DisposableBean.destroy()

    在 Spring 中,InitializingBean 和 DisposableBean 这两个接口中的方法,在对象的初始化和释放的时候,会被调用。

    当 bean 中所有的属性都被赋值后,会调用 InitializingBean.afterPropertiesSet() 方法。

    当 Spring 释放完 bean 后,会调用 DisposableBean.destroy() 方法。

    User

    @Component
    public class User implements InitializingBean,DisposableBean {
    	public void afterPropertiesSet() throws Exception {
    		System.out.println("User Bean afterPropertiesSet called");
    	}
    	public void destroy() throws Exception {
    		System.out.println("User Bean destroy called");
    	}	
    }

    Main方法

    public static void main(String[] args) {
    	// 使用Config.class这个配置类
    	AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
    	applicationContext.close();
    }

    运行结果

    User Bean afterPropertiesSet called
    User Bean destroy called

    init-method 方法和 destroy-method 方法

    init-method 和 destroy-method 和上面两种方法一样,也是基于 Spring 容器加载对象和释放对象时,调用某些方法。其中指定的方法也需要是无参数,无返回值的。

    User类

    public class User {
    	public void myinit() {
    		System.out.println("myinit运行");
    	}
    	public User() {
    		System.out.println("User创建 ");
    	}
    	public void mydestroy() {
    		System.out.println("mydestroy运行");
    	}
    }
    @Configuration
    @ComponentScan(value = "com.learn")
    public class Config {
    	@Bean(initMethod = "myinit", destroyMethod = "mydestroy")
    	User getUser() {
    		return new User();
    	}
    }

    Main方法

    public static void main(String[] args) {
    	// 使用Config.class这个配置类
    	AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
    	applicationContext.close();
    }

    运行结果

    User创建 
    myinit运行
    mydestroy运行

    总结

    Bean 的生命周期大致包括了这么多点,其实这么多点真正使用的并不多,并且使用场景都属于框架级别的,但是对于了解 Spring 容器的对象管理很有好处。

  • 相关阅读:
    linux时间同步
    阿里云自定义监控tomcat进程数
    Kafka监控
    阿里云ECS主机自定义进程监控
    kafka常用运维命令
    命令--cut
    Linux查看用户及分组
    Bind搭建DNS服务
    使用Bind搭建DNS服务
    DNS开源服务器BIND最小配置详解
  • 原文地址:https://www.cnblogs.com/shoshana-kong/p/10692822.html
Copyright © 2011-2022 走看看