所谓 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 容器的对象管理很有好处。

Spring 中 Bean 的生命周期的更多相关文章

  1. JAVA面试题:Spring中bean的生命周期

    Spring 中bean 的生命周期短暂吗? 在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,也就是预设为每一个Bean的别名只能维持一 ...

  2. 深入理解Spring中bean的生命周期

    [Spring中bean的生命周期] bean的生命周期 1.以ApplocationContext上下文单例模式装配bean为例,深入探讨bean的生命周期: (1).生命周期图: (2).具体事例 ...

  3. Spring中Bean的生命周期及其扩展点

    原创作品,可以转载,但是请标注出处地址http://www.cnblogs.com/V1haoge/p/6106456.html Spring中Bean的管理是其最基本的功能,根据下面的图来了解Spr ...

  4. 简:Spring中Bean的生命周期及代码示例

    (重要:spring bean的生命周期. spring的bean周期,装配.看过spring 源码吗?(把容器启动过程说了一遍,xml解析,bean装载,bean缓存等)) 完整的生命周期概述(牢记 ...

  5. 通过BeanPostProcessor理解Spring中Bean的生命周期

    通过BeanPostProcessor理解Spring中Bean的生命周期及AOP原理 Spring源码解析(十一)Spring扩展接口InstantiationAwareBeanPostProces ...

  6. 一分钟掌握Spring中bean的生命周期!

    Spring 中bean 的生命周期短暂吗? 在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,也就是预设为每一个Bean 的别名只能维持 ...

  7. Spring中bean的生命周期!

    Spring 中bean 的生命周期短暂吗? 在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,也就是预设为每一个Bean的别名只能维持一 ...

  8. Spring中 bean的生命周期

    为什么要了解Spring中 bean的生命周期? 有时候我们需要自定义bean的创建过程,因此了解Spring中 bean的生命周期非常重要. 二话不说先上图: 在谈具体流程之前先看看Spring官方 ...

  9. Spring官网阅读(十)Spring中Bean的生命周期(下)

    文章目录 生命周期概念补充 实例化 createBean流程分析 doCreateBean流程分析 第一步:factoryBeanInstanceCache什么时候不为空? 第二步:创建对象(crea ...

  10. 如果你每次面试前都要去背一篇Spring中Bean的生命周期,请看完这篇文章

    前言 当你准备去复习Spring中Bean的生命周期的时候,这个时候你开始上网找资料,很大概率会看到下面这张图: 先不论这张图上是否全面,但是就说这张图吧,你是不是背了又忘,忘了又背? 究其原因在于, ...

随机推荐

  1. asp.net core mvc HTTP Error 502.5 - Process Failure

    HTTP Error 502.5 - Process Failure Common causes of this issue: The application process failed to st ...

  2. nopi 简洁笔记

    导出excel /// <summary> /// 增加二维码 /// </summary> /// <param name="dt">< ...

  3. python继承和多态

    继承 目标 单继承 多继承 面向对象三大特性 封装 根据 职责 将 属性 和 方法 封装 到一个抽象的 类 中 继承 实现代码的重用,相同的代码不需要重复的编写 多态 不同的对象调用相同的方法,产生不 ...

  4. c++ 生成dll文件并调用-转

    .h(头文件) .lib(库文件) .dll(动态链接库文件) 之间的关系和作用的区分   .h头文件是编译时必须的,lib是链接时需要的,dll是运行时需要的. 附加依赖项的是.lib不是.dll, ...

  5. java学习笔记41(数据库连接池 C3p0连接池)

    在之前的学习中,我们发现,我们需要频繁的创建连接对象,用完之后还需要在关闭资源,因为这些连接对象都是占资源的,但是又不得不创建,比较繁琐,为了解决这种情况,Java出现了数据库连接池: 数据库连接池的 ...

  6. Java多线程入门中几个常用的方法

    一.currentThread()方法 currentThread方法就是返回当前被调用的线程. 该方法为一个本地方法,原码如下: /** * Returns a reference to the c ...

  7. 软件工程 week 05

    关于 石墨文档客户端 的案例分析 作业地址:https://edu.cnblogs.com/campus/nenu/2016CS/homework/2505 一.调研测评 测试平台:Windows 1 ...

  8. Cronolog切割tomcat日志

    Cronolog切割tomcat 安装cronolog 1. 将cronolog-1.6.2.tar.gz 上传至/opt 目录 2. 解压缩 #解压缩 tar -zxvf cronolog-1.6. ...

  9. Python的深copy和浅copy

    浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象. 深拷贝(deepcopy): copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象. 浅copy: a = [1, 2, ...

  10. Netty学习记录

    一.Netty简介 Netty 是一个基于 JAVA NIO 类库的异步通信框架,它的架构特点是:异步非阻塞.基于事件驱动.高性能.高可靠性和高可定制性. Netty 是一个 NIO client-s ...