spring 生命周期最详解
目的
在大三开始学习spring时,老师就说spring bean周期非常重要,当时也有仔细看,但是说实话搞不大懂,后面工作面试也问过,还是有点模糊,就是没有掌握好,进行深入理解,这次“老大”又问到了。不允许再回避了,所以这次坚决搞明白,理解生命周期作用,为啥要这样设计,我们能在生命周期做哪些更高层次的编程。
生命周期流程图
先总体看下spring的生命周期流程图,实现(继承)这些接口(抽象类)并在容器里注册,就可以看到bean的生命周期会按下面流程进行,后面会给出测试代码。
可以看出设计策略是“先顾大局”-类似的操作BeanFactory一般出现在Bean之前,操作完Bean之后,BeanFactory会进行“管理”;Bean操作的前提是应用了BeanPostProcessor。
测试代码
要被注册的Person类
package springBeanTest;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
public class Person implements BeanFactoryAware, BeanNameAware, InitializingBean, DisposableBean {
private String name;
private String address;
private int phone;
private BeanFactory beanFactory;
private String beanName;
public Person() {
System.out.println("【构造器】调用Person的构造器实例化");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("【注入属性】name");
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
System.out.println("【注入属性】address");
this.address = address;
}
public int getPhone() {
return phone;
}
public void setPhone(int phone) {
System.out.println("【注入属性】phone");
this.phone = phone;
}
// 这是BeanFactoryAware接口方法
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("【BeanFactoryAware接口】调用setBeanFactory方法");
this.beanFactory = beanFactory;
}
// 这是BeanNameAware接口方法
public void setBeanName(String s) {
System.out.println("【BeanNameAware接口】调用setBeanName方法");
this.beanName = s;
}
// 这是DiposibleBean接口方法
public void destroy() throws Exception {
System.out.println("【DiposibleBean接口】调用destroy方法");
}
// 这是InitializingBean接口方法
public void afterPropertiesSet() throws Exception {
System.out.println("【InitializingBean接口】调用afterPropertiesSet方法");
}
// 通过<bean>的init-method属性指定的初始化方法
public void myInit() {
System.out.println("【init-method】调用<bean>的init-method属性指定的初始化方法");
}
// 通过<bean>的destroy-method属性指定的初始化方法
public void myDestory() {
System.out.println("【destroy-method】调用<bean>的destroy-method属性指定的初始化方法");
}
}
实现BeanFactoryPostProcessor的类
package springBeanTest;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor{
public MyBeanFactoryPostProcessor() {
super();
System.out.println("这是BeanFactoryPostProcessor实现类构造器!!");
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
System.out
.println("BeanFactoryPostProcessor调用postProcessBeanFactory方法");
BeanDefinition bd = configurableListableBeanFactory.getBeanDefinition("person");
bd.getPropertyValues().addPropertyValue("phone", "110");
}
}
继承InstantiationAwareBeanPostProcessorAdapter的类
package springBeanTest;
import java.beans.PropertyDescriptor;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
public class MyInstantiationAwareBeanPostProcessor extends
InstantiationAwareBeanPostProcessorAdapter {
public MyInstantiationAwareBeanPostProcessor() {
super();
System.out
.println("这是InstantiationAwareBeanPostProcessorAdapter实现类构造器!!");
}
// 接口方法、实例化Bean之前调用
@Override
public Object postProcessBeforeInstantiation(Class beanClass,
String beanName) throws BeansException {
System.out
.println("InstantiationAwareBeanPostProcessor调用postProcessBeforeInstantiation方法");
return null;
}
// 接口方法、实例化Bean之后调用
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
System.out
.println("InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization方法");
return bean;
}
// 接口方法、设置某个属性时调用
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs,
PropertyDescriptor[] pds, Object bean, String beanName)
throws BeansException {
System.out
.println("InstantiationAwareBeanPostProcessor调用postProcessPropertyValues方法");
return pvs;
}
}
实现BeanPostProcessor的类
package springBeanTest;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor{
public MyBeanPostProcessor(){
System.out.println("这是BeanPostProcessor实现类构造器!!");
}
public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
System.out.println("BeanPostProcessor接口方法postProcessBeforeInitialization对属性进行更改");
return o;
}
public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
System.out.println("BeanPostProcessor接口方法postProcessAfterInitialization对属性进行更改");
return o;
}
}
测试类BeanLifeCycle
package springBeanTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanLifeCycle {
public static void main(String[] args) {
System.out.println("现在开始初始化容器");
ApplicationContext factory = new ClassPathXmlApplicationContext("beans.xml");
System.out.println("容器初始化成功");
//得到Preson,并使用
Person person = factory.getBean("person",Person.class);
System.out.println(person);
System.out.println("现在开始关闭容器!");
((ClassPathXmlApplicationContext)factory).registerShutdownHook();
}
}
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
<bean id="beanPostProcessor" class="springBeanTest.MyBeanPostProcessor">
</bean>
<bean id="instantiationAwareBeanPostProcessor" class="springBeanTest.MyInstantiationAwareBeanPostProcessor">
</bean>
<bean id="beanFactoryPostProcessor" class="springBeanTest.MyBeanFactoryPostProcessor">
</bean>
<bean id="person" class="springBeanTest.Person" init-method="myInit"
destroy-method="myDestory" scope="singleton" p:name="张三" p:address="广州"
p:phone="123567889"/>
</beans>
运行结果如下:
"C:\Program Files\Java\jdk1.8.0_171\bin\java.exe" -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:57343,suspend=y,server=n -javaagent:C:\Users\shoshana\.IntelliJIdea2019.1\system\captureAgent\debugger-agent.jar -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_171\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\rt.jar;D:\project\myself\demo\springbeanlifedemo\target\classes;D:\dev_env\maven\local_repository\org\springframework\spring-context\4.3.9.RELEASE\spring-context-4.3.9.RELEASE.jar;D:\dev_env\maven\local_repository\org\springframework\spring-aop\4.3.9.RELEASE\spring-aop-4.3.9.RELEASE.jar;D:\dev_env\maven\local_repository\org\springframework\spring-beans\4.3.9.RELEASE\spring-beans-4.3.9.RELEASE.jar;D:\dev_env\maven\local_repository\org\springframework\spring-core\4.3.9.RELEASE\spring-core-4.3.9.RELEASE.jar;D:\dev_env\maven\local_repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;D:\dev_env\maven\local_repository\org\springframework\spring-expression\4.3.9.RELEASE\spring-expression-4.3.9.RELEASE.jar;D:\dev_env\idea\JetBrains\IntelliJ IDEA 2019.1\lib\idea_rt.jar" com.shoshana.service.BeanLifeCycle
Connected to the target VM, address: '127.0.0.1:57343', transport: 'socket'
现在开始初始化容器
四月 13, 2019 5:08:17 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@17550481: startup date [Sat Apr 13 17:08:17 CST 2019]; root of context hierarchy
四月 13, 2019 5:08:17 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [spring.xml]
这是BeanFactoryPostProcessor实现类构造器!!
BeanFactoryPostProcessor调 用postProcessBeanFactory方法
这是BeanPostProcessor实现类构造器!!
这是InstantiationAwareBeanPostProcessorAdapter实现类构造器!!
InstantiationAwareBeanPostProcessor调用postProcessBeforeInstantiation方法
InstantiationAwareBeanPostProcessor调用postProcessPropertyValues方法
BeanPostProcessor接口方法postProcessBeforeInitialization对属性进行更改
BeanPostProcessor接口方法postProcessAfterInitialization对属性进行更改
InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization方法
InstantiationAwareBeanPostProcessor调用postProcessBeforeInstantiation方法
【构造器】调用Person的构造器实例化
InstantiationAwareBeanPostProcessor调用postProcessPropertyValues方法
【注入属性】phone
【BeanNameAware接口】调用setBeanName方法
【BeanFactoryAware接口】调用setBeanFactory方法
BeanPostProcessor接口方法postProcessBeforeInitialization对属性进行更改
【InitializingBean接口】调用afterPropertiesSet方法
【init-method】调用<bean>的init-method属性指定的初始化方法
BeanPostProcessor接口方法postProcessAfterInitialization对属性进行更改
InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization方法
容器初始化成功
com.shoshana.service.Person@38425407
现在开始关闭容器!
四月 13, 2019 5:08:18 下午 org.springframework.context.support.ClassPathXmlApplicationContext doClose
信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@17550481: startup date [Sat Apr 13 17:08:17 CST 2019]; root of context hierarchy
【DiposibleBean接口】调用destroy方法
【destroy-method】调用<bean>的destroy-method属性指定的初始化方法
Disconnected from the target VM, address: '127.0.0.1:57343', transport: 'socket' Process finished with exit code 0
生命周期的接口和抽象类
大概了解了生命周期的流程和运用到哪些接口和抽象类之后,下面开始进一步深入了解他们的具体作用,按照流程往下一一介绍。
这里spring版本是4.1.8.RELEASE。
BeanFactoryPostProcessor接口
package org.springframework.beans.factory.config;
import org.springframework.beans.BeansException;
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory var1) throws BeansException;
}
该接口只有一个postProcessBeanFactory方法,BeanFactoryPostProcessor:在bean factory标准初始化之后可以进行修改。将加载所有bean定义,但是还没有实例化bean。这个方法允许重新覆盖或者添加属性甚至快速的初始化bean。
初次看不知干嘛,关键在于参数,可以利用参数做一些操作。
下面了解一下这个参数。
ConfigurableListableBeanFactory 提供分析、修改bean定义和预先实例化单例。这个BeanFactory的子接口不应该是被使用于普通应用程序中:BeanFactory和ListableBeanFactory铁铮铮作为最经典的用例;这个接口是仅应该允许内部框架使用,即使在访问bean factory配置方法时也如此。
ConfigurableListableBeanFactory 的方法
- freezeConfiguration():冻结全部bean定义,给被注册的bean定义发信号告诉它们今后不再被修改和进一步后续处理。它允许factory去积极缓存bean定义元数据。
- getBeanDefinition(String beanName):根据指定的bean name返回被注册的bean定义,允许访问其属性值和构造函数参数值(可以在bean工厂后期处理期间被修改)。这个被返回的bean definition对象不应该是副本而是原始在工厂被注册的。这意味着如果需要它可以被转换为更具体的实现类型。注意这个方法只能获得本地工厂bean definition。
- Iterator getBeanNamesIterator():返回由这个bean factory管理的所有bean name统一视图。
void ignoreDependencyType(Class<?> type)
:忽略被给定注入依赖类型 ,例如String。void ignoreDependencyInterface(Class<?> ifc)
:忽略被给定注入依赖接口 。这个通常被使用由application contexts去注册依赖,可以以多种方式实现。例如BeanFactory通过BeanFactoryAware,ApplicationContext 通过ApplicationContextAware。默认情况下,仅BeanFactoryAware接口是被忽略,需要忽略其他接口,调用此方法。boolean isAutowireCandidate(String beanName,DependencyDescriptor descriptor)throws NoSuchBeanDefinitionException
:确认这个被指定的bean是否是一个autowire候选,将被注入到其他声明匹配类型的依赖的bean中。- isConfigurationFrozen():返回该工厂的bean definnitions是否被冻结。
- preInstantiateSingletons():确保所有非懒加载的单例bean被实例化,包括factoryBeans。
void registerResolvableDependency(Class<?> dependencyType,Object autowiredValue)
:注册一个特定类型依赖伴随着相应的autowired值。这个是准备被用于应该可以autowire而不是在这个工厂被定义的bean的工厂/上下文引用。例如 将ApplicationContext类型的依赖项解析为Bean所在的ApplicationContext实例。注意~在普通的BeanFactory中没有注册这样的默认类型,甚至连BeanFactory接口本身都没有。
postProcessBeanFactory使用示例
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
// TODO: 2018/6/7 覆盖属性值
System.out.println("BeanFactoryPostProcessor调用postProcessBeanFactory方法");
BeanDefinition bd = configurableListableBeanFactory.getBeanDefinition("person");
bd.getPropertyValues().addPropertyValue("phone", "110");
// TODO: 2018/6/7 快速初始化bean
configurableListableBeanFactory.preInstantiateSingletons();
}
BeanPostProcessor接口
允许自定义修改新bean实例的Factory hook,例如检查标记接口或者把bean包装成代理。
ApplicationContext 可以在它们的beans definitions自动检测BeanPostProcessor bean并且把这些bean应用于随后的bean创建。普通的bean factory允许对后处理器进行程序化注册,通过工厂应用于所有bean创建。
BeanPostProcessor 的方法
postProcessBeforeInitialization(Object bean, String beanName):在一些bean实例化回调(例如InitializingBean的afterPropertiesSet 或者一个定制的init-method)之前应用这个BeanPostProcessor
postProcessAfterInitialization(Object bean, String beanName):在一些bean实例化回调(例如InitializingBean的afterPropertiesSet 或者一个定制的init-method)之后应用这个BeanPostProcessor
BeanPostProcessor用法示例
postProcessBeforeInitialization一
class BeanValidationPostProcessor...
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (!this.afterInitialization) {
doValidate(bean);
}
return bean;
}
/**
* Perform validation of the given bean.
* @param bean the bean instance to validate
* @see javax.validation.Validator#validate
*/
protected void doValidate(Object bean) {
Set<ConstraintViolation<Object>> result = this.validator.validate(bean);
if (!result.isEmpty()) {
StringBuilder sb = new StringBuilder("Bean state is invalid: ");
for (Iterator<ConstraintViolation<Object>> it = result.iterator(); it.hasNext();) {
ConstraintViolation<Object> violation = it.next();
sb.append(violation.getPropertyPath()).append(" - ").append(violation.getMessage());
if (it.hasNext()) {
sb.append("; ");
}
}
throw new BeanInitializationException(sb.toString());
}
}
检验bean状态是否有效。
postProcessBeforeInitialization二
class ApplicationContextAwareProcessor...
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
AccessControlContext acc = null;
if (System.getSecurityManager() != null &&
(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareInterfaces(bean);
return null;
}
}, acc);
}
else {
invokeAwareInterfaces(bean);
}
return bean;
}
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(
new EmbeddedValueResolver(this.applicationContext.getBeanFactory()));
}
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);
}
}
}
判断bean是什么接口,然后进行set属性。应该就是api里面说的检查标记接口。
大概意识是bean已经实例成功,你可以做一些校验或者补充些内容或者把bean包装代理注入。包装代理直接把代理实例返回就行。
postProcessAfterInitialization和postProcessBeforeInitialization类似。
InstantiationAwareBeanPostProcessorAdapter
实现SmartInstantiationAwareBeanPostProcessor全部方法的适配器,这将不改变由容器正常处理每一个实例化的bean。子类仅覆盖自己想要的方法。
注意,只有在实际需要 InstantiationAwareBeanPostProcessor 功能时,才推荐这个基类。如果您所需要的只是简单的BeanPostProcessor功能,那么您应该选择直接实现那个(更简单的)接口。
postProcessBeforeInstantiation(Class<?> beanClass, String beanName)
:在实例化目标bean之前应用此BeanPostProcessor。这个返回的bean也许是一个代理代替目标bean,有效地抑制目标bean的默认实例化。如果此方法返回一个非空对象,则bean的创建过程将被短路。唯一的进一步处理被应用是BeanPostProcessor.postProcessAfterInitialization(java.lang.Object, java.lang.String)方法(可以自己试下,改变了bean的生命周期实例化之后直接进入BeanPostProcessor.postProcessAfterInitialization)回调来自于配置好的BeanPostProcessors。这个回调将仅被应用于有bean class的bean defintions。特别是,它不会应用于采用”factory-method“的beans。后处理器可以实现扩展的SmartInstantiationAwareBeanPostProcessor接口,以便预测它们将返回的bean对象的类型。postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
:在工厂将给定的属性值应用到给定的bean之前,对给定的属性值进行后处理。允许检查全部依赖是否已经全部满足,例如基于一个@Required在bean属性的setter上。还允许替换要应用的属性值,通常通过基于原始的PropertyValues创建一个新的MutablePropertyValues实例,添加或删除特定的值。postProcessAfterInitialization(Object bean, String beanName)
:在bean初始化回调(例如:InitializingBean的afterPropertiesSet或者定制的init-method)之后,应用这个BeanPostProcessor去给一个新的bean实例。bean已经配置了属性值,返回的bean实例可能已经被包装。
如果是FactoryBean,这个回调将为FactoryBean实例和其他被FactoryBean创建的对象所调用。这个post-processor可以通过相应的FactoryBean实例去检查决定是否应用FactoryBean或者被创建的对象或者两个都有。
这个回调在一个由InstantiationAwareBeanPostProcessor短路的触发之后将被调用。
看到这里我也没看懂是啥意思,下面我们看看源代码。
postProcessBeforeInstantiation使用示例
class AbstractAutoProxyCreator...
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
Object cacheKey = this.getCacheKey(beanClass, beanName);
if(beanName == null || !this.targetSourcedBeans.contains(beanName)) {
if(this.advisedBeans.containsKey(cacheKey)) {
return null;
}
if(this.isInfrastructureClass(beanClass) || this.shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
if(beanName != null) {
TargetSource targetSource = this.getCustomTargetSource(beanClass, beanName);
if(targetSource != null) {
this.targetSourcedBeans.add(beanName);
Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = this.createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
}
return null;
}
这个可以返回代理。
postProcessPropertyValues使用示例
示例一
class RequiredAnnotationBeanPostProcessor ...
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
throws BeansException {
if (!this.validatedBeanNames.contains(beanName)) {
if (!shouldSkip(this.beanFactory, beanName)) {
List<String> invalidProperties = new ArrayList<String>();
for (PropertyDescriptor pd : pds) {
if (isRequiredProperty(pd) && !pvs.contains(pd.getName())) {
invalidProperties.add(pd.getName());
}
}
if (!invalidProperties.isEmpty()) {
throw new BeanInitializationException(buildExceptionMessage(invalidProperties, beanName));
}
}
this.validatedBeanNames.add(beanName);
}
return pvs;
}
这个方法很明显校验需要注入的属性是否有属性值。
示例二
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {
if (bean instanceof EnhancedConfiguration) {
((EnhancedConfiguration) bean).setBeanFactory(this.beanFactory);
}
return pvs;
}
在AutowiredAnnotationBeanPostProcessor的postProcessPropertyValues方法试图自auto-wire其他配置bean之前注入BeanFactory。
postProcessAfterInitialization使用示例
public Object postProcessAfterInitialization(Object bean, String beanName) {
if(bean instanceof AopInfrastructureBean) {
return bean;
} else {
if(bean instanceof Advised) {
Advised advised = (Advised)bean;
if(!advised.isFrozen() && this.isEligible(AopUtils.getTargetClass(bean))) {
if(this.beforeExistingAdvisors) {
advised.addAdvisor(0, this.advisor);
} else {
advised.addAdvisor(this.advisor);
}
return bean;
}
}
if(this.isEligible(bean, beanName)) {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
proxyFactory.setTarget(bean);
if(!proxyFactory.isProxyTargetClass()) {
this.evaluateProxyInterfaces(bean.getClass(), proxyFactory);
}
proxyFactory.addAdvisor(this.advisor);
return proxyFactory.getProxy(this.getProxyClassLoader());
} else {
return bean;
}
}
}
如果bean是一个基础的aop bean那么就直接返回,如果不是基础的aop bean并且实现了Advise接口那么就对这个bean进行一些操作,如果不是基础的aop bean没实现Advise接口并且是合格的bean就用代理工厂进行代理,如果不是基础的aop bean没实现Advise接口并且不是合格的bean那么也直接返回。
总之对已经实例化的bean进行一些处理,可能这个bean在早期已经实例化了又是单例,那么就销毁这个bean用原来的bean。
BeanNameAware接口
接口是被实现由那些想知道其在bean factory中的名称的bean实现。请注意,通常不建议对象依赖于它的bean名称,因为这表示对外部配置的潜在脆弱依赖性,以及对Spring API可能不必要的依赖。
- setBeanName(String name):在创建这个bean的bean factory里设置名字。在填充正常bean属性之后调用但是在初始化回调之前例如InitializingBean的afterPropertiesSet方法或者一个定制的init-method.
示例
class SchedulerFactoryBean ...
public void setBeanName(String name) {
if(this.schedulerName == null) {
this.schedulerName = name;
}
}
对工厂bean进行set name
BeanFactoryAware接口
接口由希望知道其拥有的BeanFactory的bean实现。
例如beans可以通过这个工厂去查阅和它合作的beans(查阅依赖)。注意大部分beans将选择通过协作相应bean属性或者构造函数参数(依赖注入)去接收协作beans的引用。
- setBeanFactory(BeanFactory beanFactory) :为bean实例提供所属工厂的回调。在普通的bean属性值填充之后但是在初始化回调之前(例如InitializingBean的afterPropertiesSet方法或者一个定制的init-method方法)被调用
setBeanFactory示例
public void setBeanFactory(BeanFactory beanFactory) {
super.setBeanFactory(beanFactory);
if(!(beanFactory instanceof ConfigurableListableBeanFactory)) {
throw new IllegalStateException("Cannot use AdvisorAutoProxyCreator without a ConfigurableListableBeanFactory");
} else {
this.initBeanFactory((ConfigurableListableBeanFactory)beanFactory);
}
}
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
this.advisorRetrievalHelper = new AbstractAdvisorAutoProxyCreator.BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
}
获得所属的beanFactory并拷贝到本对象中。可以通过这个bean所属的beanFactory检查bean依赖的bean、beanClassLoader、互斥的单例等。
InitializingBean接口
接口被实现由那些需要响应所有已经被BeanFactory set的属性:例如执行自定义初始化或者仅检查是否已经set所有必要属性。
实现InitializingBean的另一种方法是指定一个自定义的init-method,例如在一个XML配置文件中指定bean的init-method。
- afterPropertiesSet():在设置完所有提供的bean属性(并满足BeanFactoryAware和ApplicationContextAware)之后由beanFactory调用。这个方法允许bean实例只有在所有的bean属性都被设置并且在错误配置的情况下抛出异常的情况下才能执行初始化。
afterPropertiesSet示例
public void afterPropertiesSet() {
if(this.getDataSource() == null) {
throw new IllegalArgumentException("Property 'dataSource' is required");
}
}
检查是否已经set所有必要属性。
/**
* Eagerly create the singleton instance, if necessary.
*/
@Override
public void afterPropertiesSet() throws Exception {
if (isSingleton()) {
this.initialized = true;
this.singletonInstance = createInstance();
this.earlySingletonInstance = null;
}
}
- 这里没做什么自定义初始化和检查是否已经set所有必要属性,而是提前初始化单例bean,说明你可以做一些其他操作。
DisposableBean接口
接口已经被实现由那些想在销毁释放资源的bean。如果BeanFactory处理缓存的单例对象,那么它应该调用destroy方法。
应用程序上下文在关闭的时候应该处理它的所有单例。
实现InitializingBean的另一种方法是指定一个自定义的destroy-method,例如在一个XML配置文件中指定bean的destroy-method。
destroy示例
@Override
public void destroy() {
close();
}
/**
* Close this application context, destroying all beans in its bean factory.
* <p>Delegates to {@code doClose()} for the actual closing procedure.
* Also removes a JVM shutdown hook, if registered, as it's not needed anymore.
* @see #doClose()
* @see #registerShutdownHook()
*/
@Override
public void close() {
synchronized (this.startupShutdownMonitor) {
doClose();
// If we registered a JVM shutdown hook, we don't need it anymore now:
// We've already explicitly closed the context.
if (this.shutdownHook != null) {
try {
Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
}
catch (IllegalStateException ex) {
// ignore - VM is already shutting down
}
}
}
}
/**
* Actually performs context closing: publishes a ContextClosedEvent and
* destroys the singletons in the bean factory of this application context.
* <p>Called by both {@code close()} and a JVM shutdown hook, if any.
* @see org.springframework.context.event.ContextClosedEvent
* @see #destroyBeans()
* @see #close()
* @see #registerShutdownHook()
*/
protected void doClose() {
if (this.active.get() && this.closed.compareAndSet(false, true)) {
if (logger.isInfoEnabled()) {
logger.info("Closing " + this);
}
LiveBeansView.unregisterApplicationContext(this);
try {
// Publish shutdown event.
publishEvent(new ContextClosedEvent(this));
}
catch (Throwable ex) {
logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
}
// Stop all Lifecycle beans, to avoid delays during individual destruction.
try {
getLifecycleProcessor().onClose();
}
catch (Throwable ex) {
logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
}
// Destroy all cached singletons in the context's BeanFactory.
destroyBeans();
// Close the state of this context itself.
closeBeanFactory();
// Let subclasses do some final clean-up if they wish...
onClose();
this.active.set(false);
}
}
执行上下文关闭:发布一个ContextClosedEvent和破坏了这个应用上下文的bean工厂中的单例。
spring 生命周期最详解的更多相关文章
- 大厂高频面试题Spring Bean生命周期最详解
Spring作为当前Java最流行.最强大的轻量级框架.Spring Bean的生命周期也是面试高频题,了解Spring Bean周期也能更好地帮助我们解决日常开发中的问题.程序员应该都知道Sprin ...
- Vue钩子函数生命周期实例详解
vue生命周期简介 Vue实例有一个完整的生命周期,也就是从开始创建.初始化数据.编译模板.挂载Dom.渲染→更新→渲染.卸载等一系列过程,我们称这是Vue的生命周期.通俗说就是Vue实例从创建到销毁 ...
- 【vue生命周期】- 详解
这篇文章通俗易懂,写的不错,本文转载至:https://www.cnblogs.com/happ0/p/8075562.html 详解Vue Lifecycle 先来看看vue官网对vue生命周期的介 ...
- <JVM中篇:字节码与类的加载篇>03-类的加载过程(类的生命周期)详解
笔记来源:尚硅谷JVM全套教程,百万播放,全网巅峰(宋红康详解java虚拟机) 同步更新:https://gitee.com/vectorx/NOTE_JVM https://codechina.cs ...
- vue 生命周期的详解
一.vue生命周期的解析 > 1>什么是vue生命周期 每个vue实例在被创建之前都要经过一系列的初始化过程,这个过程就是vue的生命周期.详细来说,就是Vue实例从开始创建,初始化数据, ...
- SpringBoot内置生命周期事件详解 SpringBoot源码(十)
SpringBoot中文注释项目Github地址: https://github.com/yuanmabiji/spring-boot-2.1.0.RELEASE 本篇接 SpringBoot事件监听 ...
- Asp.Net生命周期的详解
一.Asp.Net页面生命周期的概念 当我们在浏览器地址栏中输入网址,回车查看页面时,这时会向服务器端IIS)发送一个request请求,服务器就会判断发送过来的请求页面,当完全识别 TTP页面处理程 ...
- Asp.Net WebForm生命周期的详解
一.Asp.Net页面生命周期的概念 当我们在浏览器地址栏中输入网址,回车查看页面时,这时会向服务器端IIS)发送一个request请求,服务器就会判断发送过来的请求页面,当完全识别 TTP页面处理程 ...
- 微信小程序~生命周期方法详解
生命周期是指一个小程序从创建到销毁的一系列过程 在小程序中 ,通过App()来注册一个小程序 ,通过Page()来注册一个页面 先来看一张小程序项目结构 从上图可以看出,根目录下面有包含了app.js ...
随机推荐
- Linux防火墙iptables的基础
一.网络访问控制 1.Linux一般都是作为服务器系统使用,对外提供一些基于网络的服务 2.通常我们都需要对服务器进行一些网络访问控制,类似防火墙的功能 3.常见的访问控制包括:哪些IP可以访问服务器 ...
- 将SD卡的音频设置为手机铃声后删除,手机铃声没有恢复到默认的问题
1. Android7.0,将存储卡中MP3设置为铃声,删除该MP3后,settings中的铃声没有变化,来电铃声也没有变化. 原因:android7.0的新特性 google 默认如此设计,在选择铃 ...
- ef core code frist
https://docs.microsoft.com/zh-cn/ef/core/get-started/aspnetcore/new-db?view=aspnetcore-2.1 1.先创建对应的实 ...
- 不得不补:PHP的JSON, SQL
不管怎么说,还是得感谢慕课网,提供了很多免费的视频教学. 学习自: https://www.imooc.com/view/68 前端页面: <!DOCTYPE html> <html ...
- activity select problem(greedy algorithms)
many activities will use the same place, every activity ai has its' start time si and finish time f ...
- 使用CSMA/CD协议一个计算题
题干: 首先计算一下A这个以太网所容许的最短的帧它的发送帧的长度时间为: (8(前同步码为8)+64(最短帧长))*8(单位转换b到B)=576比特 有关于单位转换: B是Byte的缩写,B就是Byt ...
- pycharm 设置参数,快捷键
pycharm 设置参数 当编写代码的时候出现红色下划线提示,表示有异常,此时需要导入此模块 参数设置 设置完参数之后执行一下看看效果 这里面0为脚本本身,1为刚才设置的参数hello 快捷键设置 常 ...
- Couldn't find preset "es2015" relative to directory问题解决
由于是菜鸟没使用ES标准,而引入的vue-ueditor使用了ES标准,所以编译会报错,解决办法如下: npm install babel-preset-es2015 --save-dev 然后需要在 ...
- vue.js--遇到的一些错误
1. <sapn> - did you register the component correctly? For recursive components, make sure to p ...
- c# 如何 使用共用体
用起来真的方便 转摘如下: C#借助FieldOffset属性实现共用体与强制类型转换 这两天被C#的强制类型转换弄得有点不习惯.事出如此. 在C#中,我打算读二进制文.文件的结构很简单,一连串的紧密 ...