Spring源码分析之Bean的生命周期
2022/3/18 22:59:24
本文主要是介绍Spring源码分析之Bean的生命周期,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
文章目录
- 前言
- 一、Bean生命周期例子
- 二、执行结果分析
- 说明注意
前言
相信大多数初级程序员在面试的时候都面试过Spring中bean的生命周期,大多数人对其不太了解,认为周期一般都是: 初始化->使用->销毁就行了,Spring对bean的管理增加了很多操作,所以Spring中bean的生命周期上涉及的内容就比较多了,本文写个简单的例子来说明一下。
一、Bean生命周期例子
public class User implements InitializingBean { private String name; private int age; User(){ System.out.println("User Constructor"); } public void init(){ System.out.println("User Init"); } public void destroy(){ System.out.println("Destroy Method"); } public String getName() { return name; } public void setName(String name) { System.out.println("User setName"); this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } @Override public void afterPropertiesSet() throws Exception { System.out.println("User afterPropertiesSet"); } }
public class MyBeanPostProcessor implements BeanPostProcessor { MyBeanPostProcessor(){ System.out.println("MyBeanPostProcessor Constructor"); } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("MyBeanPostProcessor -> BeforeInitialization :"+bean); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("MyBeanPostProcessor -> AfterInitialization :"+bean); return bean; } }
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { MyBeanFactoryPostProcessor(){ System.out.println("MyBeanFactoryPostProcessor Constructor"); } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { BeanDefinition userDefinition = beanFactory.getBeanDefinition("user"); MutablePropertyValues propertyValues = userDefinition.getPropertyValues(); propertyValues.addPropertyValue("age",10); System.out.println("BeanFactoryPostProcessor -> postProcessBeanFactory"); } }
XML中的配置
<bean id="user" class="com.jack.User" init-method="init" destroy-method="destroy"> <property name="name" value="JACK"></property> </bean> <bean class="com.jack.MyBeanPostProcessor"></bean> <bean class="com.jack.MyBeanFactoryPostProcessor"></bean>
测试代码:
public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:beans.xml"); User user = (User) applicationContext.getBean("user"); System.out.println("user=" + user); //这段代码是必须的,当关闭容器的时候会销毁Bean ((ClassPathXmlApplicationContext) applicationContext).close(); }
看一下执行结果:
二、执行结果分析
上面代码中有两个类BeanPostProcessor与BeanFactoryPostProcessor说一下:
这两个类都是后置处理器,其中BeanPostProcessor是Bean对象的后置处理器,主要用来对实例化的bean对象做处理,而BeanFactoryPostProcessor是Bean工厂的后置处理器,Bean工厂内部管理的主要是BeanDefinition,所以它一般用来做对BeanDefinition的处理,在这里可以修改XML中的配置结果,例如给属性设置值,修改对象的单例。正常思考一下BeanFactoryPostProcessor肯定要执行在BeanPostProcessor之前,因为先有工厂再有实例,并且先有模板再有对象,前者操作的是模板,如果先有了对象了改模板就没有意义了。
执行结果从上往下看:
- BeanFactoryPostProcess初始化,这一步其实一般不算在Bean对象的生命周期里面,因为这是对Bean工厂的处理。
- BeanFactory初始化完成之后,需要将XML中的Bean配置转换成BeanDefinition放到工厂的map中,这时候调用后置处理器可以对BeanDefinition做出修改。
- BeanPostProcess后置处理器初始化。
- 到这才算作Bean的生命周期,实体类的构造方法调用。
- 实体类设置属性,其实我认为设置完属性这一步实例类已经创建完成了。
- 调用BeanPostProcess中的postProcessBeforeInitialization()对实例化对象做出处理。
- 执行属性设置完的后置处理操作。
- 这时候bean对象算是完全初始化完成了,调用init()方法标致着初始化完成。
- 调用BeanPostProcess中的postProcessAfterInitialization()对实例化对象做出处理。
- 获取对象进行对象操作。
- 销毁对象。
默认情况下Spring使用的是饿汉式单例设计模式,在容器初始化的时候就做了Bean的初始化操作,如果是懒加载的也就是懒汉式设计模式和非单例的会在getBean()的时候执行Bean的初始化操作。
正常情况下我们认为生命周期也就是Init -> Use -> Destroy,Spring在Bean的生命周期中增加了N多步操作,对我们来讲是没有多大意义的,但是对构建Spring的其他框架来说有着重要的意义,因为其他框架中可能涉及到对Bean的一些处理需要精细到每一步操作,例如看一下BeforeInit和AfterInit是不是比较熟悉,这和我们学的AOP有点相似,没错这里可能创建的类可能在其他框架中需要动态代理,所以加了PostProcess类的操作。
整个Bean初始化操作周期具体执行的源代码在这一步,改天不加班的时候写个生命周期源码解读文章:
// Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory);
而XML中的bean配置转换为BeanDefinition的操作在初始化Bean工厂的时候执行的:
// Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
这两个代码都是在加载配置文件中的refresh()方法中,不管是那种bean注入方式都会调用refresh()方法,这可以说是Spring中比较复杂的代码了,涉及的内容比较多,有耐心的可以自己看一下:
public ClassPathXmlApplicationContext( String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); } }
说明注意
这里面有几个误解的地方需要注意一下:
- 为什么在上面说到调用对象的构造方法才说是真正的开始生命周期了呢?这里可以将bean对象设置成懒加载模式,只有在getBean()的时候才创建对象,在getBean打个断点就可以看到前面三步执行了,说明其不是对象的生命周期。
- 一般情况下我们认为init()的时候对象开始创建了,至少我刚开始工作的时候这么认为的,实际上init()是对象实例化结束的标志。
- postProcessBeforeInitialization()方法执行之前其实bean对象已经实例化完成了,这里可以写个打印对象看到对象的属性已经设置完成,打印出来的对象是完整的对象。而BeforeInitialization的意思不是对象实例化而是init()方法,是这个方法之前。
这篇关于Spring源码分析之Bean的生命周期的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-26消息中间件源码剖析教程
- 2024-11-26JAVA语音识别项目资料的收集与应用
- 2024-11-26Java语音识别项目资料:入门级教程与实战指南
- 2024-11-26SpringAI:Java 开发的智能新利器
- 2024-11-26Java云原生资料:新手入门教程与实战指南
- 2024-11-26JAVA云原生资料入门教程
- 2024-11-26Mybatis官方生成器资料详解与应用教程
- 2024-11-26Mybatis一级缓存资料详解与实战教程
- 2024-11-26Mybatis一级缓存资料详解:新手快速入门
- 2024-11-26SpringBoot3+JDK17搭建后端资料详尽教程