Spring容器系列-bean的生命周期
Spring容器系列-bean的生命周期
概要
对于Spring Bean的生命周期来说,可以分为四个阶段,其中初始化完成之后,就代表这个Bean可以使用了,四个阶段如下:
- 实例化 Instantiation : 为Bean分配内存空间
- 属性赋值 Populate :将当前类依赖的Bean属性,进行注入和装配
- 初始化 Initialization
- 销毁 Destruction
一、Spring Bean生命周期
1. Spring Bean 生命周期流程图
先来看看Spring Bean生命周期流程图如下:
下面对Spring Bean生命周期进行详细描述:
1. Bean容器在配置文件中找到Spring Bean的定义。
2. Bean容器使用Java Reflection API创建Bean的实例。
3. 如果声明了任何属性,声明的属性会被设置。如果属性本身是Bean,则将对其进行解析和设置。
4. 如果Bean类实现BeanNameAware接口,则将通过传递Bean的名称来调用setBeanName()方法。
5. 如果Bean类实现BeanClassLoaderAware接口,则将通过传递加载此Bean的ClassLoader对象的实例来调用setBeanClassLoader()方法。
6. 如果Bean类实现BeanFactoryAware接口,则将通过传递BeanFactory对象的实例来调用setBeanFactory()方法。
7. 如果有任何与BeanFactory关联的BeanPostProcessors对象已加载Bean,则将在设置Bean属性之前调用postProcessBeforeInitialization()方法。
8. 如果Bean类实现了InitializingBean接口,则在设置了配置文件中定义的所有Bean属性后,将调用afterPropertiesSet()方法。
9. 如果配置文件中的Bean定义包含init-method属性,则该属性的值将解析为Bean类中的方法名称,并将调用该方法。
10. 如果为Bean Factory对象附加了任何Bean 后置处理器,则将调用postProcessAfterInitialization()方法。
11. 如果Bean类实现DisposableBean接口,则当Application不再需要Bean引用时,将调用destroy()方法。
12. 如果配置文件中的Bean定义包含destroy-method属性,那么将调用Bean类中的相应方法定义。
说明:4、5、6步骤都可以统一看做是第三阶段初始化中的检查aware相关接口并设置相关依赖
2. 举个例子
1)定义一个PersonBean
类,实现了DisposableBean, InitializingBean, BeanFactoryAware, BeanNameAware
这4个接口,同时还有自定义的init-method
和destroy-method
。这里,如果不了解这几个接口的读者,可以先去看看这几个接口的定义。
1 public class PersonBean implements InitializingBean, BeanNameAware,BeanFactoryAware, DisposableBean { 2 /** 3 * 身份证号 4 */ 5 private Integer idNo; 6 7 /** 8 * 姓名 9 */ 10 private String name; 11 12 public PersonBean() { 13 System.out.println("1.调用构造方法:我出生了!"); 14 } 15 16 public Integer getIdNo() { 17 return idNo; 18 } 19 20 public void setIdNo(Integer idNo) { 21 this.idNo = idNo; 22 } 23 24 public String getName() { 25 return name; 26 } 27 28 public void setName(String name) { 29 this.name = name; 30 System.out.println("2.设置属性:我的名字叫"+name); 31 } 32 33 public void setBeanName(String name) { 34 System.out.println("3.调用BeanNameAware#setBeanName方法:我要上学了,起了个学名"); 35 36 } 37 38 public void setBeanFactory(BeanFactory beanFactory) throws BeansException { 39 System.out.println("4.调用BeanFactoryAware#setBeanFactory方法:选好学校了"); 40 } 41 42 public void afterPropertiesSet() throws Exception { 43 System.out.println("6.InitializingBean#afterPropertiesSet方法:入学登记"); 44 } 45 46 public void init() { 47 System.out.println("7.自定义init方法:努力上学ing"); 48 } 49 50 public void destroy() throws Exception { 51 System.out.println("9.DisposableBean#destroy方法:平淡的一生落幕了"); 52 } 53 54 public void destroyMethod() { 55 System.out.println("10.自定义destroy方法:睡了,别想叫醒我"); 56 } 57 58 public void work(){ 59 System.out.println("Bean使用中:工作,只有对社会没有用的人才放假。。"); 60 } 61 62 }
2)定义一个MyBeanPostProcessor
实现BeanPostProcessor
接口。
1 public class MyBeanPostProcessor implements BeanPostProcessor { 2 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { 3 System.out.println("5.BeanPostProcessor.postProcessBeforeInitialization方法:到学校报名啦"); 4 return bean; 5 } 6 7 public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { 8 System.out.println("8.BeanPostProcessor#postProcessAfterInitialization方法:终于毕业,拿到毕业证啦!"); 9 return bean; 10 } 11 }
3)配置文件spring-config.xml,指定init-method
和destroy-method
属性
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> 5 6 <bean name="myBeanPostProcessor" class="ric.study.demo.ioc.life_cycle_demo_set.MyBeanPostProcessor" /> 7 <bean name="personBean" class="ric.study.demo.ioc.life_cycle_demo_set.Person" 8 init-method="init" destroy-method="destroyMethod"> 9 <property name="name" value="Richard Yi" /> 10 </bean> 11 12 </beans>
4)启动类,运行代码
1 public static void main( String[] args ) 2 { 3 ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml"); 4 PersonBean personBean = (PersonBean) context.getBean("personBean"); 5 personBean.work(); 6 ((ClassPathXmlApplicationContext) context).destroy(); 7 8 } 9 10 11 //运行结果如下: 12 1.调用构造方法:我出生了! 13 2.设置属性:我的名字叫张铁钢 14 3.调用BeanNameAware#setBeanName方法:我要上学了,起了个学名 15 4.调用BeanFactoryAware#setBeanFactory方法:选好学校了 16 5.BeanPostProcessor.postProcessBeforeInitialization方法:到学校报名啦 17 6.InitializingBean#afterPropertiesSet方法:入学登记 18 7.自定义init方法:努力上学ing 19 8.BeanPostProcessor#postProcessAfterInitialization方法:终于毕业,拿到毕业证啦! 20 Bean使用中:工作,只有对社会没有用的人才放假。。 21 9.DisposableBean#destroy方法:平淡的一生落幕了 22 10.自定义destroy方法:睡了,别想叫醒我 23
二、 Spring Bean生命周期源码分析
Bean实例化的时机也分为两种,BeanFactory管理的Bean是在使用到Bean的时候才会实例化Bean,ApplicantContext管理的Bean在容器初始化的时候就会完成Bean实例化。
1. getBean()方法
AbstractApplicationContext
类里的refresh
方法,这个方法是 ApplicationContext 容器初始化的关键点。在这个方法里,调用了finishBeanFactoryInitialization
方法,这个方法里调用了getBean
方法,getBean
方法里调用了AbstractBeanFactory
的getBean
方法。
下面我们从源码角度分析:
Bean的创建的入口是 AbstractAutowireCapableBeanFactory#
createBean()
1 /**. 2 * 这个类的核心方法,创建一个bean实例, 填充bean实例,执行后处理等 3 * @see #doCreateBean 详见doCreateBean 4 */ 5 @Override 6 protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) 7 throws BeanCreationException { 8 //..... 9 }
createBean
最终调用的是doCreateBean
方法,AbstractAutowireCapableBeanFactory#doC
reateBean()
源码如下:
1 protected Object doCreateBean(String beanName,RootBeanDefinition mbd,@Nullable Object [args) throws BeanCreationException { 2 3 // 实例化bean. 4 BeanWrapper instanceWrapper = null; 5 if (mbd.isSingleton()) { 6 instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); 7 } 8 if (instanceWrapper == null) { 9 instanceWrapper = createBeanInstance(beanName, mbd, args); 10 } 11 12 ... 13 14 Object exposedObject = bean; 15 try { 16 17 //为bean设置属性值 18 populateBean(beanName,mbd,instanceWrapper); 19 20 //初始化bean 21 exposedObject = initializeBean(beanName,exposedObject,mbd); 22 } 23 ... 24 25 return exposedObject; 26 }
doCreateBean方法中相关的就是populateBean方法和initializeBean方法,populateBean方法主要为bean设置属性值,我们重点关注初始化Bean方法initializeBean。
AbstractAutowireCapableBeanFactory#initializeBean
1 protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) { 2 if (System.getSecurityManager() != null) { 3 AccessController.doPrivileged((PrivilegedAction<Object>) () -> { 4 // 激活 Aware 方法 5 invokeAwareMethods(beanName, bean); 6 return null; 7 }, getAccessControlContext()); 8 } 9 else { 10 // 对特殊的 bean 处理:BeanNameAware、BeanClassLoaderAware、BeanFactoryAware,使得 Bean 可以访问一些容器中特定的资源 11 invokeAwareMethods(beanName, bean); 12 } 13 14 Object wrappedBean = bean; 15 if (mbd == null || !mbd.isSynthetic()) { 16 //执行BeanPostProcessor所有实现类的postProcessBeforeInitialization方法 17 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); 18 } 19 20 try { 21 // 激活用户自定义的 init 方法 22 invokeInitMethods(beanName, wrappedBean, mbd); 23 } 24 catch (Throwable ex) { 25 throw new BeanCreationException( 26 (mbd != null ? mbd.getResourceDescription() : null), 27 beanName, "Invocation of init method failed", ex); 28 } 29 if (mbd == null || !mbd.isSynthetic()) { 30 //执行BeanPostProcessor所有实现类的postProcessAfterInitialization方法 31 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); 32 } 33 return wrappedBean; 34 }
AbstractAutowireCapableBeanFactory#invokeAwareMethods
1 private void invokeAwareMethods(String beanName, Object bean) { 2 // 1. 检查 Bean 是否实现了 Aware 接口 3 if (bean instanceof Aware) { 4 // 2. 如果 Bean 实现了 BeanNameAware 接口 5 if (bean instanceof BeanNameAware) { 6 // 调用 setBeanName 方法,设置 Bean 的名称 7 ((BeanNameAware) bean).setBeanName(beanName); 8 } 9 // 3. 如果 Bean 实现了 BeanClassLoaderAware 接口 10 if (bean instanceof BeanClassLoaderAware) { 11 ClassLoader bcl = getBeanClassLoader(); // 获取 Bean 的类加载器 12 if (bcl != null) { 13 // 调用 setBeanClassLoader 方法,设置类加载器 14 ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl); 15 } 16 } 17 // 4. 如果 Bean 实现了 BeanFactoryAware 接口 18 if (bean instanceof BeanFactoryAware) { 19 // 调用 setBeanFactory 方法,设置 BeanFactory 20 ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); 21 } 22 } 23 }
说明:Spring在创建Bean时进行的一部分初始化工作,确保每个Bean在被使用之前已经具备了必要的依赖和环境信息。
AbstractAutowireCapableBeanFactory#invokeInitMethods
1 protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) 2 throws Throwable { 3 // 判断当前bean是否实现了InitializingBean接口 4 boolean isInitializingBean = (bean instanceof InitializingBean); 5 // 如果当前bean是一个InitializingBean 6 if (isInitializingBean && (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("afterPropertiesSet"))) { 7 if (logger.isTraceEnabled()) { 8 logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); 9 } 10 if (System.getSecurityManager() != null) { 11 try { 12 AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> { 13 ((InitializingBean) bean).afterPropertiesSet(); 14 return null; 15 }, getAccessControlContext()); 16 } 17 catch (PrivilegedActionException pae) { 18 throw pae.getException(); 19 } 20 } 21 else { 22 // 真正调用当前bean的afterPropertiesSet方法 23 ((InitializingBean) bean).afterPropertiesSet(); 24 } 25 } 26 27 if (mbd != null && bean.getClass() != NullBean.class) { 28 String initMethodName = mbd.getInitMethodName(); 29 if (StringUtils.hasLength(initMethodName) && 30 !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && 31 !mbd.hasAnyExternallyManagedInitMethod(initMethodName)) { 32 // 最后通过反射的方式执行init-method属性对应的方法 33 invokeCustomInitMethod(beanName, bean, mbd); 34 } 35 } 36 }
2. afterPropertiesSet()方法
InitializingBean只有一个方法afterPropertiesSet,见名知意,这个方法是在bean的属性值被设置以后执行。 Spring给我们提供了这么一个扩展点,可以用来做很多的事情, 比如可以修改默认设置的属性,添加补充额外的属性值或者针对关键属性做一个校验。
Spring本身也有很多的Bean实现了InitializingBean接口, 比如Spring MVC中的RequestMappingHandlerMapping就实现了InitializingBean接口,在afterPropertiesSet中完成了一些初始化工作,比如url和controller方法的映射。
说明:InitializingBean是Spring中很关键的一个扩展接口,其实它和bean中init-method属性对应的方法功能是一致的,都是初始化bean,我们可以二选一实现即可,当然同时使用也没有问题。init-method是通过反射实现的,性能相对差一点点。另外,如果调用afterPropertiesSet方法时出错,则不会调用init-method指定的方法。
四、容器关闭
1. bean的销毁入口
如下图:
2. Bean的销毁过程触发时机
1)在Spring 中执行显式关闭上下文,关闭时候会执行实现DisposableBean接口类中的destroy() 方法
1 ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"spring.xml"}); 2 // 以下两种显式关闭都会调用实现了DisposableBean接口类中的destroy() 方法 3 // 1、显式关闭上下文 4 context.close(); 5 // 2、显式关闭上下文 6 context.registerShutdownHook();
2)web环境中,Tomcat关闭
在Web环境中,当Tomcat关闭
的时候就会调用到 servlet中的销毁方法
,在这个方法中就会最终也会掉用到Spring中 DisposableBeanAdapter
类的destroy()
方法,该方法就会根据前面的收集进行调用。
1 public class ContextLoaderListener extends ContextLoader implements ServletContextListener { 2 public ContextLoaderListener() { 3 } 4 5 public ContextLoaderListener(WebApplicationContext context) { 6 super(context); 7 } 8 9 public void contextInitialized(ServletContextEvent event) { 10 this.initWebApplicationContext(event.getServletContext()); 11 } 12 // servlet中的销毁方法 13 public void contextDestroyed(ServletContextEvent event) { 14 // 该方法最终会调用Spring的DisposableBeanAdapter类的destroy() 15 this.closeWebApplicationContext(event.getServletContext()); 16 ContextCleanupListener.cleanupAttributes(event.getServletContext()); 17 }
servlet中的closeWebApplicationContext
方法最终也会掉用到Spring中的DisposableBeanAdapter
类的destroy()
方法,该方法就会根据前面的收集进行调用。
3. 销毁过程解析
与Bean初始化类似,当容器关闭时,可以看到对Bean销毁方法的调用。销毁过程是这样的。顺着close()-> doClose() -> destroyBeans() -> destroySingletons() -> destroySingleton() -> destroyBean() -> bean.destroy()
,会看到最终调用Bean的销毁方法。
AbstractApplicationContext#close(),其实实现的是ConfigurableApplicationContext的close()方法
1 @Override 2 public void close() { 3 synchronized (this.startupShutdownMonitor) { 4 doClose(); 5 // If we registered a JVM shutdown hook, we don't need it anymore now: 6 // We've already explicitly closed the context. 7 if (this.shutdownHook != null) { 8 try { 9 Runtime.getRuntime().removeShutdownHook(this.shutdownHook); 10 } 11 catch (IllegalStateException ex) { 12 // ignore - VM is already shutting down 13 } 14 } 15 } 16 }
DefaultSingletonBeanRegistry#destroyBean()源码如下:
1 protected void destroyBean(String beanName, DisposableBean bean) { 2 // 忽略 3 4 // Actually destroy the bean now... 5 if (bean != null) { 6 try { 7 bean.destroy(); 8 } 9 catch (Throwable ex) { 10 logger.error("Destroy method on bean with name '" + beanName + "' threw an exception", ex); 11 } 12 } 13 14 // 忽略 15 }
这里注意哦,这个Bean的类型实际上是DisposableBeanAdapter。
3. DisposableBeanAdapter
DisposableBeanAdapter
是用来管理Spring Bean的销毁的,实际上这里运用了适配器模式。负责将各种销毁方式适配为统一的 destroy() 方法,以便 Spring 容器在关闭时一致地调用。
AbstractAutowireCapableBeanFactory#doCreateBean
1 try { 2 ... 3 4 //注册bean销毁时的类DisposableBeanAdapter:如果实现了 DisposableBean接口或者提供了destroy—method 在这里注册 5 registerDisposableBeanIfNecessary(beanName, bean, mbd); 6 } 7 catch (BeanDefinitionValidationException ex) { 8 throw new BeanCreationException( 9 mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); 10 }
源码位置:AbstractBeanFactory#registerDisposableBeanIfNecessary()
1 protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) { 2 AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null); 3 if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) { 4 if (mbd.isSingleton()) { 5 // 注册一个DisposableBean实现,该实现将执行给定bean的所有销毁工作。 6 // 包括:DestructionAwareBeanPostProcessors,DisposableBean接口,自定义destroy方法。 7 registerDisposableBean(beanName, 8 new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc)); 9 } 10 else { 11 // A bean with a custom scope... 12 Scope scope = this.scopes.get(mbd.getScope()); 13 if (scope == null) { 14 throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'"); 15 } 16 scope.registerDestructionCallback(beanName, 17 new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc)); 18 } 19 } 20 }
再来看看destroy()
的具体方法。
DisposableBeanAdapter#destroy()源码如下:
1 @Override 2 public void destroy() { 3 if (!CollectionUtils.isEmpty(this.beanPostProcessors)) { 4 for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) { 5 processor.postProcessBeforeDestruction(this.bean, this.beanName); 6 } 7 } 8 9 if (this.invokeDisposableBean) { 10 if (logger.isDebugEnabled()) { 11 logger.debug("Invoking destroy() on bean with name '" + this.beanName + "'"); 12 } 13 try { 14 if (System.getSecurityManager() != null) { 15 AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { 16 @Override 17 public Object run() throws Exception { 18 ((DisposableBean) bean).destroy(); 19 return null; 20 } 21 }, acc); 22 } 23 else { 24 // 调用 DisposableBean 的 destroy()方法 25 ((DisposableBean) bean).destroy(); 26 } 27 } 28 catch (Throwable ex) { 29 String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'"; 30 if (logger.isDebugEnabled()) { 31 logger.warn(msg, ex); 32 } 33 else { 34 logger.warn(msg + ": " + ex); 35 } 36 } 37 } 38 39 if (this.destroyMethod != null) { 40 // 调用 设置的destroyMethod 41 invokeCustomDestroyMethod(this.destroyMethod); 42 } 43 else if (this.destroyMethodName != null) { 44 Method methodToCall = determineDestroyMethod(); 45 if (methodToCall != null) { 46 invokeCustomDestroyMethod(methodToCall); 47 } 48 } 49 }
参考链接:
https://segmentfault.com/a/1190000020747302
https://juejin.cn/post/7075168883744718856
https://yangzhiwen911.github.io/