@PostConstruct是由CommonAnnotationBeanPostProcessor類實(shí)現(xiàn)的。
一、CommonAnnotationBeanPostProcessor是什么時(shí)候加載進(jìn)去的呢?
我們首先看到CommonAnnotationBeanPostProcessor是spring context下的包,說明是spring自帶的類。我們就大膽猜想,它是spring的創(chuàng)世紀(jì)類,即internal類。我們?cè)趺打?yàn)證呢?我們知道spring自帶的創(chuàng)世紀(jì)類是在下面的構(gòu)造方法里面:
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
new AnnotatedBeanDefinitionReader的時(shí)候會(huì)調(diào)用:
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
里面有段代碼會(huì)添加CommonAnnotationBeanPostProcessor類:
// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
二、CommonAnnotationBeanPostProcessor怎么和@PostConstruct關(guān)聯(lián)上的?
首先看下該類的無參構(gòu)造方法:
public CommonAnnotationBeanPostProcessor() {
setOrder(Ordered.LOWEST_PRECEDENCE - 3);
setInitAnnotationType(PostConstruct.class);
setDestroyAnnotationType(PreDestroy.class);
ignoreResourceType("javax.xml.ws.WebServiceContext");
}
這個(gè)無參構(gòu)造方法肯定會(huì)在實(shí)例化該類的時(shí)候被調(diào)用。
看到里面有PostConstruct注解了吧。在詳細(xì)看下setInitAnnotationType方法:
public void setInitAnnotationType(Class<? extends Annotation> initAnnotationType) {
this.initAnnotationType = initAnnotationType;
}
會(huì)把PostConstruct.class賦值給initAnnotationType屬性。這個(gè)屬性所屬的類為InitDestroyAnnotationBeanPostProcessor,可以看到它實(shí)現(xiàn)了BeanPostProcessor接口。
我們就很容易猜想了,PostConstruct肯定在BeanPostProcessor的兩個(gè)拓展方法其中一個(gè)被執(zhí)行了。
三、驗(yàn)證BeanPostProcessor中哪個(gè)拓展方法調(diào)用了@PostConstruct注解
大不了我們看下InitDestroyAnnotationBeanPostProcessor類的這兩個(gè)方法的實(shí)現(xiàn):
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
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, "Failed to invoke init method", ex);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
很明顯postProcessAfterInitialization這個(gè)方法的實(shí)現(xiàn)直接返回bean,沒做任何處理,排除。我們看下postProcessBeforeInitialization方法。里面有個(gè)findLifecycleMetadata方法得到metadata,然后調(diào)用invokeInitMethods。我們可以猜想出來,metadata肯定是一個(gè)method反射對(duì)象,然后通過反射調(diào)用該方法。是不是有可能findLifecycleMetadata方法,返回的就是@PostConstruct注解的方法呢?
private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
if (this.lifecycleMetadataCache == null) {
// Happens after deserialization, during destruction...
return buildLifecycleMetadata(clazz);
}
// Quick check on the concurrent map first, with minimal locking.
LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);
if (metadata == null) {
synchronized (this.lifecycleMetadataCache) {
metadata = this.lifecycleMetadataCache.get(clazz);
if (metadata == null) {
metadata = buildLifecycleMetadata(clazz);
this.lifecycleMetadataCache.put(clazz, metadata);
}
return metadata;
}
}
return metadata;
}
核心方法在buildLifecycleMetadata:
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
final boolean debug = logger.isDebugEnabled();
LinkedList<LifecycleElement> initMethods = new LinkedList<LifecycleElement>();
LinkedList<LifecycleElement> destroyMethods = new LinkedList<LifecycleElement>();
Class<?> targetClass = clazz;
do {
final LinkedList<LifecycleElement> currInitMethods = new LinkedList<LifecycleElement>();
final LinkedList<LifecycleElement> currDestroyMethods = new LinkedList<LifecycleElement>();
ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
if (initAnnotationType != null) {
if (method.getAnnotation(initAnnotationType) != null) {
// PostConstruct 賦值給了initAnnotationType,只要用@PostConstruct修飾的方法,必然會(huì)進(jìn)來。
LifecycleElement element = new LifecycleElement(method);
currInitMethods.add(element);
if (debug) {
logger.debug("Found init method on class [" + clazz.getName() + "]: " + method);
}
}
}
if (destroyAnnotationType != null) {
if (method.getAnnotation(destroyAnnotationType) != null) {
currDestroyMethods.add(new LifecycleElement(method));
if (debug) {
logger.debug("Found destroy method on class [" + clazz.getName() + "]: " + method);
}
}
}
}
});
initMethods.addAll(0, currInitMethods);
destroyMethods.addAll(currDestroyMethods);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return new LifecycleMetadata(clazz, initMethods, destroyMethods);
}
看到關(guān)鍵字ReflectionUtils.doWithLocalMethods(class,() -> doWith)了嗎?遍歷class所有的method,執(zhí)行doWith方法。而doWith方法里面出現(xiàn)了最關(guān)鍵的initAnnotationType。是不是關(guān)聯(lián)上了第二節(jié)說的那個(gè)方法了:
public void setInitAnnotationType(Class<? extends Annotation> initAnnotationType) {
// PostConstruct 賦值給了initAnnotationType
this.initAnnotationType = initAnnotationType;
}
最終,bean class所有用@PostConstruct注解修飾的方法,都會(huì)被返回給第三節(jié)中的findLifecycleMetadata方法。如下:
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
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, "Failed to invoke init method", ex);
}
return bean;
}
我們看下metadata.invokeInitMethods方法。
public void invokeInitMethods(Object target, String beanName) throws Throwable {
Collection<LifecycleElement> initMethodsToIterate =
(this.checkedInitMethods != null ? this.checkedInitMethods : this.initMethods);
if (!initMethodsToIterate.isEmpty()) {
boolean debug = logger.isDebugEnabled();
for (LifecycleElement element : initMethodsToIterate) {
if (debug) {
logger.debug("Invoking init method on bean '" + beanName + "': " + element.getMethod());
}
element.invoke(target);
}
}
}
element.invoke(target)不就是method.invoke(object)嘛~
四、知道@PostConstruct怎么被調(diào)用了,那它什么時(shí)候被調(diào)用呢?
上節(jié)我們已經(jīng)知道了@PostConstruct被類CommonAnnotationBeanPostProcessor的構(gòu)造函數(shù)添加進(jìn)去的,該類繼承了InitDestroyAnnotationBeanPostProcessor。而它又實(shí)現(xiàn)了BeanPostProcessor接口,并且實(shí)現(xiàn)在postProcessBeforeInitialization方法里面。
我們都知道postProcessBeforeInitialization方法是在doCreatedBean的initializeBean的applyBeanPostProcessorsBeforeInitialization方法里面。如下:
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
beanProcessor.postProcessBeforeInitialization方法,可不就有CommonAnnotationBeanPostProcessor嘛~因?yàn)樗莝pring的創(chuàng)世紀(jì)類,由第一節(jié)中的spring自動(dòng)加載進(jìn)去。
所以我們這里可以知道初始化bean的時(shí)候(參考initializeBean方法的實(shí)現(xiàn)),那幾個(gè)初始化方法的執(zhí)行順序了。
invokeAwareMethods -> postProcessBeforeInitialization(ApplicationContextAwareProcessor會(huì)執(zhí)行剩下的aware方法) -> afterPropertiesSet -> initMethod -> postProcessAfterInitialization(AOP)
Spring的Aware接口實(shí)現(xiàn)原理
aware其實(shí)就是spring的回調(diào)方法,用來在某一個(gè)生命周期階段,調(diào)用用戶的回調(diào)方法。
比如:我們創(chuàng)建一個(gè)bean實(shí)現(xiàn)ApplicationContextAware接口,該接口只有一個(gè)方法:setApplicationContext。那么我們的bean既然實(shí)現(xiàn)了該接口,必須重寫該方法,這個(gè)時(shí)候我們就可以在這個(gè)bean里面定義一個(gè)容器,來接收spring回調(diào)給我們的ApplicationContext容器。這樣,咱們就可以拿到整個(gè)spring容器了。
再比如:我們創(chuàng)建一個(gè)bean實(shí)現(xiàn)BeanNameAware接口,那么spring會(huì)在特殊生命周期階段回調(diào)咱們的bean的setBeanName。我們同樣也可以定義一個(gè)String成員屬性來接收這個(gè)beanName。
所以,aware接口給了程序員可以讓spring回調(diào)我們業(yè)務(wù)的口子。比如:我們自己實(shí)現(xiàn)一個(gè)demoAware。由于demoAware并沒有被spring預(yù)先硬編碼進(jìn)去,所以想要spring回調(diào)demoAware的實(shí)現(xiàn)類,我們可以看考ApplicationContextAwareProcessor。咱們可以實(shí)現(xiàn)BeanPostProcessor,在postProcessBeforeInitialization或者postProcessAfterInitialization的方法里面,調(diào)用invokeAwareInterfaces方法。是不是很靈活?。?!