Spring 系列——Bean生命周期

    技术2023-06-23  87

    上篇文章《Spring 系列——IOC容器初始化》中我们介绍了Spring IOC容器初始化的过程,主要过程分为三个步骤:

    解析配置文件,组装成BeanDefinition对象将BeanDefinition注册到容器中对单例非懒加载Bean进行实例化

    容器初始化完毕后,我们就能通过getBean()方法从容器中获取Bean实例。 对于单例非懒加载的Bean,容器在第三步中已经进行了实例化,getBean直接能取到实例对象 对于其他Bean,容器还未进行实例化,getBean()方法会先实例化Bean,然后再返回实例对象。本篇文章就对Bean在容器中的生命周期进行介绍。

    注意:Spring容器只负责管理单例Bean(scope=singleton)的生命周期;对于多例Bean(scope=prototype),只负责创建,交给使用者之后就不会管理其生命周期

    如果文章中有描述错误或者不合理的地方,欢迎指正!

    开门见山

    废话不多说,直接上图,让我们从宏观的视角去感受一下Bean在容器里发生了什么 从上图中,我们看到Spring 容器中 Bean从创建到销毁,有5个主干流程:

    构造 Bean 对象设置 Bean 属性初始化回调Bean 调用销毁 Bean

    左侧图例标识了关键源码的位置,方便大家自己去看源码,下面是对源码关键代码的说明

    createBeanInstance:通过反射API创建Bean对象populateBean:如果Bean有依赖属性,则会设置属性;如果是依赖对象,则会先实例化依赖的对象initializeBean:Bean初始化回调 invokeAwareMethods:调用实现了*Aware接口中的方法 如果Bean实现了BeanNameAware接口,调用setBeanName设置Bean的名称如果Bean实现了BeanClassLoaderAware,调用setBeanClassLoader设置Bean的类加载器如果Bean实现了BeanFactoryAware,调用setBeanFactory设置Bean的容器 applyBeanPostProcessorsBeforeInitialization:初始化前置增强,如果注册了BeanPostProcessor,调用postProcessBeforeInitialization,在Bean初始化前执行invokeInitMethods:调用初始化方法 如果Bean实现了InitializingBean接口,调用afterPropertiesSet,执行初始化如果配置文件中Bean定义包含了init-method属性,则调用相应的方法 applyBeanPostProcessorsAfterInitialization:初始化后置增强,如果注册了BeanPostProcessor,调用postProcessAfterInitialization,在Bean初始化后执行 Bean初始化完成,可以被调用销毁Bean 如果Bean实现了DisposableBean接口,当容器不再需要Bean引用时,执行destory销毁Bean如果配置文件中Bean定义包含了destory-method属性,则调用相应的方法

    小试牛刀

    下面我们通过一个Demo来演示一下Bean完整的生命周期,加深大家的印象

    我们定义一个LifeService类,实现下面6个接口:BeanNameAware、BeanClassLoaderAware、BeanFactoryAware、InitializingBean、DisposableBean、ApplicationContextAware接口;同时自定义init-method和destory-method方法。如果不了解这几个接口,大家可以去阅读源码了解一下,这里就不展开了 public class LifeService implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean, ApplicationContextAware { private String name; public void setName(String name) { System.out.println("设置属性"); this.name = name; } public LifeService() { System.out.println("构造方法"); } public void myInit(){ System.out.println("init-method自定义初始化方法"); } public void myDestory(){ System.out.println("destroy-method自定义销毁方法"); } public void printMessage(){ System.out.println("======执行业务逻辑 printMessage====="); } @Override public void setBeanClassLoader(ClassLoader classLoader) { System.out.println("setBeanClassLoader"); } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { System.out.println("setBeanFactory"); } @Override public void setBeanName(String name) { System.out.println("setBeanName"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("初始化init afterPropertiesSet"); } @Override public void destroy() throws Exception { System.out.println("destroy"); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("setApplicationContext"); } } 定义一个MyBeanPostProcessor实现BeanPostProcessor public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("Before postProcessBeforeInitialization"); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("After postProcessAfterInitialization"); return bean; } } 配置xml配置文件,指定init-method和destroy-method属性 <bean id="lifeService" class="com.dev.domain.LifeService" init-method="myInit" destroy-method="myDestory"> <property name="name" value="muskmelon"/> </bean> <!--自定义后置处理器--> <bean id="postProcessor" class="com.dev.domain.MyBeanPostProcessor"/> 启动容器,执行业务逻辑,销毁容器 public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); LifeService lifeService = (LifeService) context.getBean("lifeService"); lifeService.printMessage(); ((ClassPathXmlApplicationContext) context).close(); } =======执行结果======= 构造方法 设置属性,name=muskmelon setBeanName setBeanClassLoader setBeanFactory setApplicationContext Before postProcessBeforeInitialization 初始化init afterPropertiesSet init-method自定义初始化方法 After postProcessAfterInitialization ======执行业务逻辑 printMessage===== destroy destroy-method自定义销毁方法

    可以看到执行结果和我们描述的基本一致,我们前面说了BeanPostProcessor是在Bean生命周期中的调用执行,但是它是什么时候注册到容器中的呢?我们就得翻出讲IOC容器初始化的这篇文章了,详细请看《Spring 系列——IOC容器初始化》

    庖丁解牛

    我们直接看refresh方法的源码吧

    public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { prepareRefresh(); ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); prepareBeanFactory(beanFactory); try { postProcessBeanFactory(beanFactory); invokeBeanFactoryPostProcessors(beanFactory); // 【看这里】注册BeanPostProcessor的实现类 // 接口提供两个方法:postProcessBeforeInitialization 和 postProcessAfterInitialization // 这两个方法分别在初始化前后执行 registerBeanPostProcessors(beanFactory); //下面的省略 ...... } } protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this); } public static void registerBeanPostProcessors( ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) { // 1.获取容器中继承了BeanPostProcessor接口的子类的beanName集合 String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false); // 注册BeanPostProcessorChecker,用于校验一个Bean在实例化的过程中,能成功的执行所有的BeanPostProcessor后置处理,如果有一个失败,则会打印相关日志 int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length; beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount)); // 2.将BeanPostProcessor根据实现的排序接口分类,分为3类:PriorityOrdered,Ordered,nonOrdered List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>(); List<BeanPostProcessor> internalPostProcessors = new ArrayList<>(); List<String> orderedPostProcessorNames = new ArrayList<>(); List<String> nonOrderedPostProcessorNames = new ArrayList<>(); for (String ppName : postProcessorNames) { if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); priorityOrderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } else if (beanFactory.isTypeMatch(ppName, Ordered.class)) { orderedPostProcessorNames.add(ppName); } else { nonOrderedPostProcessorNames.add(ppName); } } // 3. 注册 priorityOrderedPostProcessors sortPostProcessors(priorityOrderedPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors); List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size()); for (String ppName : orderedPostProcessorNames) { BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); orderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } // 4.注册 orderedPostProcessors sortPostProcessors(orderedPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, orderedPostProcessors); List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size()); for (String ppName : nonOrderedPostProcessorNames) { BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); nonOrderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } // 5.注册 nonOrderedPostProcessors registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors); // 6.注册 internalPostProcessors sortPostProcessors(internalPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, internalPostProcessors); // 7.注册ApplicationListenerDetector beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext)); }

    我们看到registerBeanPostProcessors方法的作用就是将BeanPostProcessor注册到容器。细心的读者可能看到我们的示例代码中还实现了一个ApplicationContextAware 接口,其实这是在ApplicationContextAwareProcessor处理器中执行的,这也是BeanPostProcessor的子类,但是上面源码中注册了众多的BeanPostProcessor,并没有对ApplicationContextAwareProcessor进行注册,那它是在哪里注册的呢? 其实也是在容器初始化的过程中进行注册的,我们看refresh方法的prepareBeanFactory方法

    protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // ...省略 // 【看这里】 beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); // ....省略 beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } // ...省略 }

    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)) 注册了容器上下文的增强处理器,除了对实现ApplicationContextAware接口的Bean进行处理,如果Bean还实现了以下接口也会进行调用:EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware,具体的用途就不展开了,有兴趣的读者可以自行查阅资料。

    private void invokeAwareInterfaces(Object bean) { if (bean instanceof EnvironmentAware) { ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment()); } if (bean instanceof EmbeddedValueResolverAware) { ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver); } if (bean instanceof ResourceLoaderAware) { ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext); } if (bean instanceof ApplicationEventPublisherAware) { ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext); } if (bean instanceof MessageSourceAware) { ((MessageSourceAware) bean).setMessageSource(this.applicationContext); } if (bean instanceof ApplicationContextAware) { ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); } }

    抛砖引玉

    上面我们讲述的都是ApplicationContext中Bean的生命周期,那么BeanFactory中Bean的生命周期是否有什么不同呢? 示例代码仍然使用上面的,贴一下使用BeanFactory来注册Bean的代码

    public static void main(String[] args) { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); xmlBeanDefinitionReader.loadBeanDefinitions(new ClassPathResource("spring.xml")); beanFactory.addBeanPostProcessor(new MyBeanPostProcessor()); LifeService lifeService2 = (LifeService)beanFactory.getBean("lifeService"); lifeService2.printMessage(); beanFactory.destroySingletons(); } =======执行结果======= 构造方法 设置属性 setBeanName setBeanClassLoader setBeanFactory Before postProcessBeforeInitialization 初始化init afterPropertiesSet init-method自定义初始化方法 After postProcessAfterInitialization ======执行业务逻辑 printMessage===== destroy destroy-method自定义销毁方法

    对比上面的结果,我们看到执行代码中BeanPostProcessor是通过手动注册,执行结果中没有输出setApplicationContext,这是为什么呢?

    在了解Spring IOC容器初始化的流程后,我们知道ApplicationContext是BeanFactory的子类,它在初始化的过程中(refresh方法),除了读取配置文件,解析成BeanDefinition,并注册到容器中之外,还做了诸多用于扩展Bean的功能,比如:注册BeanPostProcessor,实例化单例非懒加载Bean,注册BeanFactoryPostProcessor等等,不清楚的可以再回过头去看看容器初始化的流程,温故而知新。

    BeanFactory 是Spring容器最顶端的接口类,提供了配置框架和基础功能,ApplicationContext添加了更多企业级功能。所以像BeanPostProcessor诸如此类的功能就需要我们自己手动配置,没有注册过ApplicationContextAwareProcessor,就自然不会打印setApplicationContext。

    综上所述

    至此,Spring Bean生命周期的流程我们讲完了,我们来一起总结以下:

    Spring 容器只管理单例Bean的生命周期,prototype类型的Bean创建完成后,其生命周期就丢给使用者自己处理(一般就是通过GC进行回收了)Bean生命周期关键步骤:创建Bean对象,设置Bean属性,初始化回调,调用Bean,销毁BeanSpring 容器中通过注册BeanPostProcessor,在Bean初始化前后,对Bean实例进行特殊处理;我们也可以通过自定义BeanPostProcessor来实现Bean的扩展功能ApplicationContext中Bean的生命周期和BeanFactory中Bean的生命周期区别 (1)BeanFactory容器中不会调用setApplicationContext方法 (2)BeanFactory容器中BeanPostProcessor需要手动注册 (3)BeanFactory容器启动时不会去实例化所有Bean,包括单例非懒加载的bean,而是在调用的时候去实例化。
    Processed: 0.036, SQL: 9