spring源码-value,PostConstruct,PreDestroy,InitializingBean,DisposableBean,init-method,destroy-method顺序
Posted 熊猫小牛牛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring源码-value,PostConstruct,PreDestroy,InitializingBean,DisposableBean,init-method,destroy-method顺序相关的知识,希望对你有一定的参考价值。
项目中用到value注解,再根据value值初始化一些配置,所以就看了下spring源码关于这几个的调用顺序。
demo
application.properties
request.order.service=orderService
request.order.method=queryOrder
beans-auto.xml
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:property-placeholder location="classpath:/conf/application.properties" />
<!-- 可以直接使用这个或配置包扫描、注解驱动就不用手动配置下面2个bean -->
<!--<context:annotation-config/>-->
<!-- 这里手动注册2个bean,后面会有说明why -->
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />
<bean id="orderService" class="com.chris.test.OrderService" init-method="myInit" destroy-method="myDetory"/>
</beans>
OrderService.java
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
/**
* OrderService<br>
*/
public class OrderService implements InitializingBean, DisposableBean
@Value("$request.order.service")
private String requestService;
@Value("$request.order.method")
private String requestOrderMethod;
@Override
public void afterPropertiesSet() throws Exception
System.out.println("call-InitializingBean-afterPropertiesSet");
@Override
public void destroy() throws Exception
System.out.println("call-destroy");
@PostConstruct
private void showPostConstruct()
System.out.println("Value-requestService"+requestService);
System.out.println("Value-requestOrderMethod"+requestOrderMethod);
System.out.println("call-PostConstruct");
@PreDestroy
private void showPreDestroy()
System.out.println("call-PreDestroy");
private void myInit()
System.out.println("call-myInit");
private void myDetory()
System.out.println("call-myDetory");
OrderServiceTest.java
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* OrderServiceTest<br>
*/
public class OrderServiceTest
public static void main(String[] args)
ClassPathXmlApplicationContext ctx=new ClassPathXmlApplicationContext("beans-auto.xml");
ctx.close();
测试结果:
这里我们可以调用顺序:
初始化顺序:
value–>postConstruct–>InitializingBean–>自定义的init-method
销毁时的顺序:
PreDestroy–>DisposableBean–>destroy-method
Value注解
properties配置解析
xml中配置properties:
<context:property-placeholder location="classpath:/conf/application.properties" />
如果你熟悉spring的标签解析,你就会明白必然会有个XXXNamespaceHandler来处理这个。这里使用的是ContextNamespaceHandler来处理。
ContextNamespaceHandler:
public class ContextNamespaceHandler extends NamespaceHandlerSupport
public void init()
// 这里专注properties标签处理
registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
这里不关心标签的解析,大部分的套路基本上都是对标签属性的取值然后设置到bean里面去,我们要关心的是这个bean是谁,通过PropertyPlaceholderBeanDefinitionParser
的方法getBeanClass
根据配置得到这个beanPropertySourcesPlaceholderConfigurer
或PropertyPlaceholderConfigurer
,我们只分析下PropertyPlaceholderConfigurer
。
PropertyPlaceholderConfigurer
看下类继承关系:
我们看到这个类实现了BeanFactoryPostProcessor
接口,而这个接口是spring的beanFactory后置处理器,在获取beanfactory后调用硬编码或配置所有实现这个接口的process(希望你知道我说的是啥),如果对这里不清楚的,可以看下AbstractApplicationContext
的refresh
方法。
我们看下PropertyResourceConfigurer
对这个接口的实现:
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
try
// 加载properties文件
Properties mergedProps = mergeProperties();
// Convert the merged properties, if necessary.
convertProperties(mergedProps);
// Let the subclass process the properties.
// 子类处理properties
processProperties(beanFactory, mergedProps);
catch (IOException ex)
throw new BeanInitializationException("Could not load properties", ex);
PropertyPlaceholderConfigurer:
@Override
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props)
throws BeansException
StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(props);
this.doProcessProperties(beanFactoryToProcess, valueResolver);
记住这里的StringValueResolver,后面对value注解内容替换会使用到这个。
PlaceholderConfigurerSupport:
protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
StringValueResolver valueResolver)
BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);
String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames();
for (String curName : beanNames)
// Check that we're not parsing our own bean definition,
// to avoid failing on unresolvable placeholders in properties file locations.
// 这里使用visitor模式设置bean的一些配置的value替换,对于开发人员来说很少会用这到这里东西,除非你要自定义bean替换,后面有空单独写个访问者模式的短文
if (!(curName.equals(this.beanName) && beanFactoryToProcess.equals(this.beanFactory)))
BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName);
try
visitor.visitBeanDefinition(bd);
catch (Exception ex)
throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage(), ex);
// New in Spring 2.5: resolve placeholders in alias target names and aliases as well.
beanFactoryToProcess.resolveAliases(valueResolver);
// New in Spring 3.0: resolve placeholders in embedded values such as annotation attributes.
// 会将上面说的StringvalueResolver加入
beanFactoryToProcess.addEmbeddedValueResolver(valueResolver);
AbstractBeanFactory:
// 将resolver加入embeddedValueResolvers,后面处理value的时候会for循环使用这个embeddedValueResolvers解析
public void addEmbeddedValueResolver(StringValueResolver valueResolver)
Assert.notNull(valueResolver, "StringValueResolver must not be null");
this.embeddedValueResolvers.add(valueResolver);
value解析
value注解是由xml里面配置的AutowiredAnnotationBeanPostProcessor处理,看下构造方法:
public AutowiredAnnotationBeanPostProcessor()
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
....
发现autowire注解同样由这个类处理。
再来看下这个类继承关系:
红框中这个接口就是处理bean实例化前,实例化后的一个process,后面会讲到在什么地方调用,这里先记得有这个接口,此外这个类还有个方法:
PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
throws BeansException;
这个就是处理bean属性的注入和propreties替换的东东。
AutowiredAnnotationBeanPostProcessor里面有postProcessPropertyValues的实现,跟源码看就行了。
AutowiredAnnotationBeanPostProcessor:
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException
// 查找上面构造里面加入的注解,autowire和value
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass());
try
// 注解注入
metadata.inject(bean, beanName, pvs);
catch (Throwable ex)
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
return pvs;
会跳转到InjectionMetadata过下,再回到AutowiredAnnotationBeanPostProcessor,回来后我们这里只关注字段上面的inject:
@Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable
....
// 解析value的值
value = beanFactory.resolveDependency(descriptor, beanName, autowiredBeanNames, typeConverter);
....
if (value != null)
ReflectionUtils.makeAccessible(field);
// 设置值
field.set(bean, value);
....
我们看下resolveDependency方法。
DefaultListableBeanFactory:
public Object resolveDependency(DependencyDescriptor descriptor, String beanName,
...
return doResolveDependency(descriptor, descriptor.getDependencyType(), beanName, autowiredBeanNames, typeConverter);
...
protected Object doResolveDependency(DependencyDescriptor descriptor, Class<?> type, String beanName,
Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException
// 这里只关注value注解,获取到value的是value注解的内容$"XXX",不是真正的值
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null)
if (value instanceof String)
// 获取到properties注入的值
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
value = evaluateBeanDefinitionString(strVal, bd);
...
AbstractBeanFactory
public String resolveEmbeddedValue(String value)
String result = value;
for (StringValueResolver resolver : this.embeddedValueResolvers)
if (result == null)
return null;
result = resolver.resolveStringValue(result);
return result;
还记得这个StringValueResolver嘛?就是之前properties配置里面解析注入的。
那么到这里这就完成了value的分析,只留下了一疑问:InstantiationAwareBeanPostProcessor这个接口什么时候才会调用?
PostConstruct
xml配置:
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />
看下这个类的构造:
public CommonAnnotationBeanPostProcessor()
setOrder(Ordered.LOWEST_PRECEDENCE - 3);
setInitAnnotationType(PostConstruct.class);
setDestroyAnnotationType(PreDestroy.class);
ignoreResourceType("javax.xml.ws.WebServiceContext");
so,这个类就是专门用来处理PostConstruct和PreDestroy注解的,我们这里只看PostConstruct,另一个没什么区别。其实这个类也处理其他几个注解,比较常见的就是@Resouce
注解,可以按照上面value注解分析的思路,看下这个类,最后重点关注下postProcessPropertyValues
方法。
看下类继承:
看到了BeanPostProcessor接口,这个接口是有2个方法,在bean初始化前\\后添加个process。
在父类InitDestroyAnnotationBeanPostProcessor
中实现了2个接口:
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
// 找到class中带有post和pre2个注解的方法,封装了下
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try
// 调用带有postConstruct注解的方法
metadata.invokeInitMethods(bean, beanName);
catch (InvocationTargetException ex)
throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
catch (Throwable ex)
throw new BeanCreationException(beanName, "Couldn't invoke init method", ex);
return bean;
现在也清除了postConstruct的注解,留下个疑问,BeanPostProcessor这个接口什么时候调用?
bean创建
上面留下2个疑问:
1. InstantiationAwareBeanPostProcessor这个接口什么时候才会调用?
2. BeanPostProcessor这个接口什么时候调用?
要解决这2个问题,需要了解下spring对bean解析创建的整体流程:
1. 加载xml配置文件,解析配置标签,注册bean;
2. 自动创建各种singleton的bean。
是不是有点简单,具体可以看下AbstractApplicationContext
类的refresh
方法,整个spring的bean加载创建流程都在这里,spring的代码写的真牛逼。
我们现在关注下bean创建流程中对这2个接口的处理部分。
AbstractAutowireCapableBeanFactory:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
....
// 处理bean的属性
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null)
// 初始化bean
exposedObject = initializeBean(beanName, exposedObject, mbd);
....
// 注册disposbean
registerDisposableBeanIfNecessary(beanName, bean, mbd);
....
populateBean
方法:
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw)
....
if (hasInstAwareBpps || needsDepCheck)
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps)
for (BeanPostProcessor bp : getBeanPostProcessors())
// 这里解决上面value的问题,调用InstantiationAwareBeanPostProcessor所有实现,处理属性解析
if (bp instanceof InstantiationAwareBeanPostProcessor)
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null)
return;
....
initializeBean
方法:
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd)
if (System.getSecurityManager() != null)
AccessController.doPrivileged(new PrivilegedAction<Object>()
public Object run()
invokeAwareMethods(beanName, bean);
return null;
, getAccessControlContext());
else
invokeAwareMethods(beanName, bean);
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic())
// 调用初始化前方法,进去后,调用所有BeanPostProcessor的postProcessBeforeInitialization方法,解决postConstruct的问题
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
try
// 调用初始化方法
invokeInitMethods(beanName, wrappedBean, mbd);
catch (Throwable ex)
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
if (mbd == null || !mbd.isSynthetic())
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
return wrappedBean;
invokeInitMethods
方法:
protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
throws Throwable
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet")))
if (logger.isDebugEnabled())
logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
if (System.getSecurityManager() != null)
try
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>()
public Object run() throws Exception
((InitializingBean) bean).afterPropertiesSet();
return null;
, getAccessControlContext());
catch (PrivilegedActionException pae)
throw pae.getException();
else
// InitializingBean的接口实现调用
((InitializingBean) bean).afterPropertiesSet();
if (mbd != null)
String initMethodName = mbd.getInitMethodName();
if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName))
// 我们init-method自定义的初始化方法
invokeCustomInitMethod(beanName, bean, mbd);
destroy
还是在上面的doCreateBean
里面:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
....
// 处理bean的属性
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null)
// 初始化bean
exposedObject = initializeBean(beanName, exposedObject, mbd);
....
// 注册disposbean
registerDisposableBeanIfNecessary(beanName, bean, mbd);
....
registerDisposableBeanIfNecessary
:
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd)
AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
if (!mbd.isPrototype() && requiresDestruction(bean, mbd))
if (mbd.isSingleton())
// Register a DisposableBean implementation that performs all destruction
// work for the given bean: DestructionAwareBeanPostProcessors,
// DisposableBean interface, custom destroy method.
// DisposableBean,自定义的destroy方法
registerDisposableBean(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
else
// A bean with a custom scope...
Scope scope = this.scopes.get(mbd.getScope());
if (scope == null)
throw new IllegalStateException("No Scope registered for scope '" + mbd.getScope() + "'");
scope.registerDestructionCallback(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
在这里会注册bean,新建个DisposableBeanAdapter
类用来收集DisposableBean接口实现,自定义的destroy方法,还有实现DestructionAwareBeanPostProcessor
这个接口的processor,而我们处理PostConstruct和preDestroy的类CommonAnnotationBeanPostProcessor
也实现这个接口:
而在CommonAnnotationBeanPostProcessor
父类InitDestroyAnnotationBeanPostProcessor
有这个接口的实现方法:
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try
// 调用preDestroy注解方法
metadata.invokeDestroyMethods(bean, beanName);
catch (InvocationTargetException ex)
String msg = "Invocation of destroy method failed on bean with name '" + beanName + "'";
if (logger.isDebugEnabled())
logger.warn(msg, ex.getTargetException());
else
logger.warn(msg + ": " + ex.getTargetException());
catch (Throwable ex)
logger.error("Couldn't invoke destroy method on bean with name '" + beanName + "'", ex);
我们的context在close的时候会调用销毁所有注册的singletonbean,最终会调用到DisposableBeanAdapter
的destroy
方法:
public void destroy()
if (this.beanPostProcessors != null && !this.beanPostProcessors.isEmpty())
for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors)
// 这里处理preDestroy注解的方法
processor.postProcessBeforeDestruction(this.bean, this.beanName);
if (this.invokeDisposableBean)
if (logger.isDebugEnabled())
logger.debug("Invoking destroy() on bean with name '" + this.beanName + "'");
try
if (System.getSecurityManager() != null)
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>()
public Object run() throws Exception
((DisposableBean) bean).destroy();
return null;
, acc);
else
// 处理DisposableBean的实现处理destroy方法
((DisposableBean) bean).destroy();
catch (Throwable ex)
String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
if (logger.isDebugEnabled())
logger.warn(msg, ex);
else
logger.warn(msg + ": " + ex);
if (this.destroyMethod != null)
// 调用自定义的destroy方法
invokeCustomDestroyMethod(this.destroyMethod);
else if (this.destroyMethodName != null)
Method methodToCall = determineDestroyMethod();
if (methodToCall != null)
// 调用自定义的destroy方法
invokeCustomDestroyMethod(methodToCall);
因此销毁的时候顺序是:
PreDestroy–>DisposableBean–>destroy-method自定义的方法。
总结
- 不明白的地方要多看源码,自己写demo测试,知行合一,不能手高眼低;
- 学习spring的代码编写习惯;
以上是关于spring源码-value,PostConstruct,PreDestroy,InitializingBean,DisposableBean,init-method,destroy-method顺序的主要内容,如果未能解决你的问题,请参考以下文章
【Spring源码配置文件解析】2. xml注入配置信息 & @Value