专栏首页javathingsSpring 中 Bean 的生命周期

Spring 中 Bean 的生命周期

Spring 中 Bean 的生命周期

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

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

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

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

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

生命周期之方法调用

  • 后置处理器 BeanPostProcessor 接口
  • @PostConstruct 和@PreDestroy
  • InitializingBean.afterPropertiesSet() 和 DisposableBean.destroy()
  • 自定义的 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 容器的对象管理很有好处。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 为什么 spring 中,不支持 autowired 静态变量?

    因为静态变量是属于本身类的信息,当类加载器加载静态变量时,Spring 的上下文环境还没有被加载,所以不可能为静态变量绑定值。

    水货程序员
  • 使用 FactoryBean 接口创建实例

    可以通过实现 FactoryBean<T> 接口,然后创建一个实例到 Spring 容器中。

    水货程序员
  • Spring 中如何控制对象的初始化时间(延迟加载,强制先行加载)

    当标注了@Lazy 注解时候,不会看到 init user… 的输出。只有当首次使用 User 类的时候,才会被初始化。

    水货程序员
  • JavaSE学习总结(五)——封装,继承,多态很简单

    java面向对象的三大特性是:封装、继承与多态,是面向对象编程的核心。 一、封装 简单说封装就是将同一类事物的特性与功能包装在一起,对外暴露调用的接口。 封装:...

    张果
  • 【设计模式】—— 创建者模式Builder

      模式意图   一个对象的创建十分复杂,为了区分构建过程和使用过程,因此分开。使用一个Director类进行对象的创建,Builder规定了这个创建过程。 ...

    用户1154259
  • Java中介者设计模式

    中介者设计模式是一种非常常见的设计模式,其中我们最为熟悉的就是我们的MVC框架,其中的C作为控制器就是一个具体的中介者,它的作用是把业务逻辑(Model),和视...

    用户5166556
  • Java设计模式之模板方法模式

    假设我们现在要造一批悍马汽车,悍马汽车有两个系列H1和H2,首先不考虑任何设计模式,看看设计的类图:

    CoderJed
  • 设计模式-创建型模式-工厂模式(工厂三兄弟)

    mySoul
  • 用一个通俗易懂的例子彻底说清楚单例模式

    实现单例模式有多种写法,这里我们只列举其中最常用的三种实现方式,且考虑到网站登录高并发场景下,将重点关注多线程环境下的安全问题。

    智慧zhuhuix
  • JavaSE学习总结(四)——Java面向对象十分钟入门

    面向对象编程(Object Oriented Programming,OOP)是一种计算机模拟人类的自然思维方式的编程架构技术,解决了传统结构化开发方法中客观...

    张果

扫码关注云+社区

领取腾讯云代金券