1. 前言
最后接触java的接口服务是servlet,最根底要把握的就是servlet的生命周期。当初都是基于springboot开发后盾接口,spring框架的复杂度远远高于原始的servlet,弄清楚spring中bean的生命周期,有利于咱们对其框架的熟练掌握。
2. spring容器加载
springboot的启动类中,都会执行SpringApplication.run
办法。在创立上下文环境之后,最外围的办法就是refreshContext
,对上下文环境进行初始化操作,本段就着重阐明这一过程。
2.1. refreshContext全过程
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { /** * 筹备环境 * 1. 记录容器的启动工夫startupDate,标记容器为激活 * 2. 初始化上下文环境如文件门路信息 * 3. 验证必填属性是否填写 */ prepareRefresh(); /** * 通知子类去刷新beanFactory * 这步实现后配置文件就解析成一个个beanDefination,注册到BeanFactory(然而未被初始化,仅将信息写到了beanDefination的map中) */ ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); /** * 设置beanFactory类加载器,增加多个beanPostProcesser */ prepareBeanFactory(beanFactory); try { /** * 容许子类上下文中对beanFactory做前期解决 */ postProcessBeanFactory(beanFactory); /** * 执行 context 中注册的 BeanFactoryPostProcessor中的postProcessBeanFactory() 办法 * 1. BeanFactoryPostProcessor 是 bean 属性解决容器。即治理 bean工厂中的BeanDefinition * 2. BeanDefinition在 spring mvc中就是xml文件中对应的bean标签(留神,是标签,而不是实在的 java bean) */ invokeBeanFactoryPostProcessors(beanFactory); /** * 注册 BeanPostProcessor 的实现类 * 1. BeanPostProcessor接口蕴含两个办法:postProcessBeforeInitialization 和 postProcessAfterInitialization * 2. 这里只是注册,两个办法理论别离在 Bean初始化之前和初始化之后失去执行 */ registerBeanPostProcessors(beanFactory); /** * 初始化ApplicationContext的MessageSource,MessageSource是国际化相干的接口 */ initMessageSource(); /** * 初始化ApplicationContext事件播送器 */ initApplicationEventMulticaster(); // 初始化子类非凡bean(钩子办法) onRefresh(); /** * 注册事件监听器 */ registerListeners(); /** * 初始化所有的单例java bean(不蕴含懒加载的类) */ finishBeanFactoryInitialization(beanFactory); /** * 播送事件,ApplicationContext初始化实现 */ finishRefresh(); } catch (BeansException ex) { .................... } } }
2.2. BeanDefinition
BeanDefinition 是 spring bean 的建模对象,即把一个bean实例化进去的模型对象。有人会问把一个bean实例化进去有Class就行了啊,Class也就是咱们通常说的类对象,就是一个一般对象的建模对象,那么为什么spring不能用Class来建设bean呢?很简略,因为Class无奈实现bean的形象,比方bean的作用域,bean的注入模型,bean是否是懒加载等等信息,Class是无奈形象进去的,故而须要一个BeanDefinition类来形象这些信息,以便于spring可能完满的实例化一个bean。
spring扫描到某个bean的类时,除了要存储类名、结构器等Class的根底信息以外,还要存储scope,lazy,dependsOn
等spring的属性。BeanDefintion是一个类,专门用来存储上述bean中的各种属性。因而当spring扫描到一个合乎规定的类时,首先是实例化一个BeanDefinition的对象,并且把依据类的类名生成一个bean的名字,继而以beanName为key,BeanDefinition对象为value,寄存在一个map中。
值得注意的是,这里都是讲在扫描bean后,BeanDefinition的实例化,以及放入BeanDefinition的map中。还没有讲到Bean的实例化和装载。
BeanDefinition 的属性办法如下:
- String:
getBeanClassName
: 返回以后bean definition定义的类名 - ConstructorArgumentValues:
getConstructorArgumentValues
:返回bean的结构函数参数 - String[]:
getDependsOn
:返回以后bean所依赖的其余bean的名称 - String:
getFactoryBeanName
: 返回factory bean的名称 - String:
getFactoryMethodName
: 返回工厂办法的名称 - BeanDefinition:
getOriginatingBeanDefinition
: 返回原始的BeanDefinition,如果不存在返回null - String:
getParentName
: 返回以后bean definition的父definition的名字 - MutablePropertyValues:
getPropertyValues
: 返回一个用于新的bean实例上的属性值 - String:
getScope
: 返回以后bean的指标范畴 - boolean:
isAbstract
: 以后bean是否是abstract,意味着不能被实例化 - boolean:
isLazyInit
: bean是否是提早初始化 - boolean:
isPrimary
: bean是否为主动拆卸的次要候选bean - boolean:
isPrototype
: bean是否是多实例 - boolean:
isSingleton
: bean是否是单例 - void:
setAutowiredCandidate
(boolean): 设置bean是否对其余bean是主动拆卸的候选bean - void:
setBeanClassName
(String): 指定bean definition的类名 - void:
setDependsOn
(String ...): 设置以后bean初始化所依赖的beans的名称 - void:
setFactoryBeanName
(String): 如果factory bean的名称 - void:
setFactoryMethodName
(String): 设置工厂的办法名 - void:
setLazyInit
(boolean lazyInit): 设置是否提早初始化 - void:
setParentName
(String): 设置父definition的名称 - void:
setPrimary
(boolean): 设置是否次要的候选bean - void:
setScope
(String): 设置bean的范畴,如:单例,多实例
2.3. BeanFactoryPostProcessor
BeanFactoryPostProcessor是实现spring容器性能扩大的重要接口,例如批改BeanDefinition,实现bean动静代理等。很多框架都是通过此接口实现对spring容器的扩大,例如mybatis与spring集成时,只定义了mapper接口,无实现类,接口也没有增加@Component等注解,但spring却能够实现主动注入,也是基于BeanFactoryPostProcessor接口来实现的。
BeanFactoryPostProcessor.java
@FunctionalInterfacepublic interface BeanFactoryPostProcessor { void postProcessBeanFactory(ConfigurableListableBeanFactory var1) throws BeansException;}
前文说到BeanDefinition在实例化之后,被放入BeanDefinition map中,而BeanFactoryPostProcessor就是在BeanDefinition map初始化实现后,Bean实例构造方法执行之前
执行的。
BeanFactoryPostProcessor的次要作用是,开发者能够批改容器中所有BeanDefinition的信息
,接口办法的入参是ConfigurrableListableBeanFactory,应用该参数,能够获取到相干bean的定义信息。但 相对不容许进行bean实例化相干的操作!
因为中spring加载机制中,BeanFactoryPostProcessor是在Bean构造方法之前执行的,如果这个时候提前实例化bean,很可能会一连串的问题。
如:在接口用通过configurableListableBeanFactory.getBean(“user”),获取User类的bean,实际上即实例化了User的bean。会导致在后续其余节点代码中,无奈注入User的bean实例。
2.4. BeanPostProcessor
如果说BeanFactoryPostProcessor是对BeanDefinition的扩大解决,那么BeanPostProcessor更多的是对Bean的扩大解决。BeanPostProcessor的触发工夫是在 Bean的实例化之后(执行了构造方法,并且对属性进行了赋值),在Bean的init办法执行之前(@PostConstruct注解办法、InitializeBean接口办法、@Bean中initMethod办法)
。
BeanPostProcessor.java
public interface BeanPostProcessor { @Nullable default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } @Nullable default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; }}
BeanPostProcessor接口中定义两个办法,依据名字能够揣测,postProcessBeforeInitialization在Bean的init办法之前执行,postProcessAfterInitialization在Bean的init办法之后执行。这点很好的体现了spring的AOP思维,能够了解为BeanPostProcessor是对Bean的init办法执行前后,做了一层切面拦挡。
有一个实现Spring aop 的BeanPostProcessor 叫 AnnotationAwareAspectJAutoProxyCreator。在postProcessBeforeInitialization或者postProcessAfterInitialization办法中,对对象进行判断,看他需不需要织入切面逻辑,如果须要,那我就依据这个对象,生成一个代理对象,而后返回这个代理对象,那么最终注入容器的,天然就是代理对象了。
2.5. finishBeanFactoryInitialization
该办法会实例化所有残余的非懒加载单例 bean。值得注意的是“所有残余的”
,就是有一些非凡的bean,这该办法之前就曾经加载了,如:
- 一些spring容器外部的bean;
- 实现了 BeanFactoryPostProcessor 接口的bean;
- 实现了 BeanPostProcessor 接口的 bean(然而这些bean会在这个办法中触发)。
其余的非懒加载单例 bean 都会在这个办法中被实例化,并且 BeanPostProcessor 的触发也是在这个办法中。
3. Bean的生命履历
基于spring的refresh过程,咱们把对于bean的局部拎进去,就造成了上面的bean的加载过程:
- spring基于@ComponentScan等注解扫描到bean,并将每个bean实例化成蕴含bean各种属性的
BeanDefinition
的对象,放入beanDefinitionMap中。 - spring 中的 bean 简略分为:非凡bean和一般bean,beanFactory理论会先实例化非凡bean。
- 实现
BeanFactoryPostProcessor
接口的就是一种非凡bean,在beanDefinitionMap加载后触发,能够自定义实现类,对其中的BeanDefinition进行批改。 construct
过程。BeanFactory 执行getBean办法生产其余的一般bean(调用类的构造方法,或FactoryBean的getObject办法,以及@Bean注解的办法)。- 此时bean获取会受三级缓存(singletonFactories、earlySingletonObjects、singletonObjects)影响,如earlySingletonObjects会提前曝光尚未populate属性数据的单例对象,可解决循环依赖问题。
populate
过程。设置bean的依赖关系(基于属性注入)以及属性值。- 对于实现
BeanPostProcessor
接口的类,执行接口中的postProcessBeforeInitialization 办法。 initialze
过程。执行bean的各种初始化办法,initialze办法的优先级如下:(1)@PostConstruct指定的办法 -> (2)InitializingBean接口的afterPropertiesSet()办法 -> (3)@Bean中initMethod指定的办法
。- 对于实现
BeanPostProcessor
接口的类,执行接口中的postProcessAfterInitialization 办法。 destroy
过程,容器销毁,执行bean的各种销毁办法,destroy办法的优先级如下:(1)@PostDestroy指定的办法 -> (2)DisposableBean接口的destroy()办法 -> (3)@Bean中destroyMethod指定的办法
。
在spring bean生命周期中,网上有人用Bean的“初始化”、“实例化”等名字,很容易搞混,所以我应用了下列几个英文单词,感觉更能表白这些过程:
- construct:是对象创立的过程。比方应用构造方法new对象。
- populate:是为对象中的属性赋值的过程,包含@Autowired等依赖注入,@Value的赋值等。
- initialize:执行初始化办法。
其实并非只有在populate
时才会注入依赖,还是要取决于属性的注入形式:基于属性注入、setter注入和结构器注入等。如果是基于结构器注入,在construct
过程中,就会导入依赖。
另外咱们中应用@Value、@ConfigurationProperties等注解赋值,也是属于populate
过程的操作。
4、bean相干办法
对于上述对于bean生命周期的介绍,咱们写个demo,一一实现相干的办法,亲眼看看他们的加载过程。
4.1、BeanFactoryPostProcessor
@Slf4j@Componentpublic class BeanFactoryPostProcessorImpl implements BeanFactoryPostProcessor { /** * getBean 是获取Object对象,getBeanDefinition 是获取Class类 * 能够批改BeanDefinition * 但getBean办法不要用,会导致提前加载bean,bean实例化错乱 * @param beanFactory */ @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { log.warn("实现 BeanFactoryPostProcessor 接口:开始了!"); Arrays.stream(beanFactory.getBeanDefinitionNames()) .filter(beanName -> User.USER_BEAN_NAME.equals(beanName)) .forEach(beanName -> { BeanDefinition beanDefinition=beanFactory.getBeanDefinition(beanName); beanDefinition.getPropertyValues().add("name","Kerry"); log.warn("BeanFactoryPostProcessor:Bean name is " + beanName); }); }}
次要是对 BeanDefinitionName 的批改,这里将对象的属性name的值设置为Kerry。
4.2、BeanPostProcessor
@Slf4j@Componentpublic class BeanPostProcessorImpl implements BeanPostProcessor { /** * Bean 初始化办法 执行前 调用 * @param bean * @param beanName * @return * @throws BeansException */ @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if(User.USER_BEAN_NAME.equals(beanName)) { log.warn("BeanPostProcessor-name:"+((User)bean).getName()); log.warn("实现 BeanPostProcessor 接口:postProcessBeforeInitialization(Object bean, String beanName),beanName=" + beanName); } return bean; } /** * Bean 初始化办法 执行后 调用 * @param bean * @param beanName * @return * @throws BeansException */ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if(User.USER_BEAN_NAME.equals(beanName)) { log.warn("实现 BeanPostProcessor 接口:postProcessAfterInitialization(Object bean, String beanName),beanName=" + beanName); } return bean; }}
4.3、初始化和销毁办法
初始化和销毁两种办法往往是配套的,有上面三种,并且依照下列程序执行:
- @PostConstruct 和 @PreDestroy 注解润饰的办法,别离在初始化和销毁时执行。
- 实现 InitializeBean 接口的 afterPropertiesSet()办法,和实现 DisposableBean 接口的 destroy()办法,别离在初始化和销毁时执行。
- @Bean 中initMethod属性指定的办法,和destroyMethod属性指定的办法,别离在初始化和销毁时执行。
咱们在User类中定义了这些初始化和销毁办法,因为还要测试依赖注入程序,也定义了Type类的办法。
User.java
@Slf4jpublic class User implements InitializingBean, DisposableBean { public final static String USER_BEAN_NAME="user"; //配置文件中,注入的值为 demoName @Value("${params.user.name}") private String name; private Integer age=1; @Autowired private Type type; @Override public String toString(){ return "My name is "+name+",I'm "+age+"years old."; } /** * 构造方法 * 1、默认构造方法 * 2、重载构造方法 */ public User(){ log.warn("构造方法:public User()"); } /** * 初始化 * 1、注解:@PostConstruct 的办法 * 2、实现 InitializeBean 接口:afterPropertiesSet() * 3、@Bean 中指定的 initMethod */ @PostConstruct public void postConstruct(){ log.warn("注解:@PostConstruct 的办法"); } @Override public void afterPropertiesSet(){ log.warn("实现 InitializeBean 接口:afterPropertiesSet()"); } public void initMethod(){ log.warn("@Bean 中指定的 initMethod "); } /** * 销毁 * 1、注解:@PreDestroy 的办法 * 2、实现 DisposableBean 接口:destroy() * 3、@Bean 中指定的 destroyMethod */ @PreDestroy public void preDestroy(){ log.warn("注解:@PreDestroy 的办法"); } @Override public void destroy(){ log.warn("实现 DisposableBean 接口:destroy()"); } public void destroyMethod(){ log.warn("@Bean 中指定的 destroyMethod"); } public void setName(String name) { log.warn("User.setName办法:"+name); this.name = name; }}
Type.java
@Component@Data@Slf4jpublic class Type implements InitializingBean { private String typeCode; public Type(){ log.warn("构造方法:public Type()"); } @Override public void afterPropertiesSet(){ log.warn("Type:实现 InitializeBean 接口:afterPropertiesSet()"); }}
BeanConfig.java
@Configurationpublic class BeanConfig { @Bean(initMethod = "initMethod",destroyMethod = "destroyMethod") public User user(){ return new User(); }}
4.4. 后果验证
还记得咱们在BeanFactoryPostProcessorImpl中批改了name的值吗?咱们先把批改的代码正文掉,执行之后的日志如下,确实依照后面的Bean生命周期加载的:
p.k.e.s.c.BeanFactoryPostProcessorImpl : 实现 BeanFactoryPostProcessor 接口:开始了!p.k.e.s.c.BeanFactoryPostProcessorImpl : BeanFactoryPostProcessor:Bean name is userp.k.exercise.springexercise.pojo.User : 构造方法:public User()p.k.exercise.springexercise.pojo.Type : 构造方法:public Type()p.k.exercise.springexercise.pojo.Type : Type:实现 InitializeBean 接口:afterPropertiesSet()p.k.e.s.config.BeanPostProcessorImpl : BeanPostProcessor-name:demoNamep.k.e.s.config.BeanPostProcessorImpl : 实现 BeanPostProcessor 接口:postProcessBeforeInitialization(Object bean, String beanName),beanName=userp.k.exercise.springexercise.pojo.User : 注解:@PostConstruct 的办法p.k.exercise.springexercise.pojo.User : 实现 InitializeBean 接口:afterPropertiesSet()p.k.exercise.springexercise.pojo.User : @Bean 中指定的 initMethod p.k.e.s.config.BeanPostProcessorImpl : 实现 BeanPostProcessor 接口:postProcessAfterInitialization(Object bean, String beanName),beanName=userp.k.exercise.springexercise.pojo.User : 注解:@PreDestroy 的办法p.k.exercise.springexercise.pojo.User : 实现 DisposableBean 接口:destroy()p.k.exercise.springexercise.pojo.User : @Bean 中指定的 destroyMethod
当初把BeanFactoryPostProcessorImpl中的正文放开,日志变了:
p.k.e.s.c.BeanFactoryPostProcessorImpl : 实现 BeanFactoryPostProcessor 接口:开始了!p.k.e.s.c.BeanFactoryPostProcessorImpl : BeanFactoryPostProcessor:Bean name is userp.k.exercise.springexercise.pojo.User : 构造方法:public User()p.k.exercise.springexercise.pojo.Type : 构造方法:public Type()p.k.exercise.springexercise.pojo.Type : Type:实现 InitializeBean 接口:afterPropertiesSet()p.k.exercise.springexercise.pojo.User : User.setName办法:Kerryp.k.e.s.config.BeanPostProcessorImpl : BeanPostProcessor-name:Kerryp.k.e.s.config.BeanPostProcessorImpl : 实现 BeanPostProcessor 接口:postProcessBeforeInitialization(Object bean, String beanName),beanName=userp.k.exercise.springexercise.pojo.User : 注解:@PostConstruct 的办法p.k.exercise.springexercise.pojo.User : 实现 InitializeBean 接口:afterPropertiesSet()p.k.exercise.springexercise.pojo.User : @Bean 中指定的 initMethod p.k.e.s.config.BeanPostProcessorImpl : 实现 BeanPostProcessor 接口:postProcessAfterInitialization(Object bean, String beanName),beanName=userp.k.exercise.springexercise.pojo.User : 注解:@PreDestroy 的办法p.k.exercise.springexercise.pojo.User : 实现 DisposableBean 接口:destroy()p.k.exercise.springexercise.pojo.User : @Bean 中指定的 destroyMethod
能够看到如果咱们在BeanFactoryPostProcessor接口中通过BeanDefinition 的PropertyValue 设置属性值,其实只是批改了该属性的setter办法,而真正执行该办法,还是在populate
阶段,而非BeanFactoryPostProcessor执行阶段。