當(dāng)我們需要使用BeanPostProcessor時(shí),直接在Spring配置文件中定義這些Bean顯得比較笨拙,例如:使用@Autowired注解酿炸,必須事先在Spring容器中聲明AutowiredAnnotationBeanPostProcessor的Bean:
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor "/>
使用 @Required注解,就必須聲明RequiredAnnotationBeanPostProcessor的Bean:
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>
類似地宾添,使用@Resource、@PostConstruct、@PreDestroy等注解就必須聲明 CommonAnnotationBeanPostProcessor缕陕;使用@PersistenceContext注解粱锐,就必須聲明 PersistenceAnnotationBeanPostProcessor的Bean。
這樣的聲明未免太麻煩了吧扛邑,所以Spring為我們提供了一種極為方便注冊(cè)這些BeanPostProcessor的方式怜浅,即使用<context:annotation- config/>隱式地向 Spring容器注冊(cè)AutowiredAnnotationBeanPostProcessor、RequiredAnnotationBeanPostProcessor蔬崩、CommonAnnotationBeanPostProcessor以及PersistenceAnnotationBeanPostProcessor這4個(gè)BeanPostProcessor恶座。如下:
<context:annotation-config/>
官方文檔的說明:
As always, you can register them as individual bean definitions, but they can also be implicitly registered by including the following tag in an XML-based Spring configuration (notice the inclusion of the context namespace):
<?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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>
那么<context:annotation-config/> 這個(gè)標(biāo)簽時(shí)何時(shí)注入這些BeanPostProcessor的呢?
下面進(jìn)行源碼分析
在Spring容器解析配置文件中時(shí)舱殿,會(huì)加載beans標(biāo)簽中配置的URL,如下圖
<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/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
" >
(1)根據(jù)beans標(biāo)簽中配置的xsi:schemaLocation的URL到spring.handlers文件中奥裸,找到對(duì)應(yīng)的NamespaceHandler
比如我上面的是http://www.springframework.org/schema/context
那么將對(duì)應(yīng)spring.handlers文件中的ContextNamespaceHandler
http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
(2)由上面的可見,根據(jù)這個(gè)http://www.springframework.org/schema/context可以找到ContextNamespaceHandler類沪袭,這個(gè)類是干啥用的呢?
public class ContextNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
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());
}
}
就一個(gè)方法樟氢,在唯一一個(gè)方法中冈绊,可以看到一些很熟悉的單詞。沒錯(cuò)埠啃,它的作用就是創(chuàng)建這些標(biāo)簽所對(duì)應(yīng)的解析類死宣。
何為解析類?也就是所有的自定義命名空間(像mvc碴开,context等)下的標(biāo)簽解析都是由BeanDefinitionParser接口的子類來完成的毅该。
可以看到nnotation-config"的解析類是 AnnotationConfigBeanDefinitionParser
,那么進(jìn)入這個(gè)類中看它是如何解析這個(gè)標(biāo)簽的
(3)
解析的方法是在parse方法中
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
// Obtain bean definitions for all relevant BeanPostProcessors.
Set<BeanDefinitionHolder> processorDefinitions =
//這里將注冊(cè)獲取到所有相關(guān)BeanPostProcessors的bean定義潦牛。 所以解析過程是在這個(gè)方法中
AnnotationConfigUtils.registerAnnotationConfigProcessors(parserContext.getRegistry(), source);
// Register component for the surrounding <context:annotation-config> element.
CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
parserContext.pushContainingComponent(compDefinition);
// Nest the concrete beans in the surrounding component.
for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
parserContext.registerComponent(new BeanComponentDefinition(processorDefinition));
}
// Finally register the composite component.
parserContext.popAndRegisterContainingComponent();
return null;
}
根據(jù)上面代碼可以看出真正的解析是在AnnotationConfigUtils.registerAnnotationConfigProcessors()方法中進(jìn)行的
進(jìn)去這個(gè)方法看看
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, Object source) {
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
//實(shí)例化AutowiredAnnotationBeanPostProcessor
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
//實(shí)例化RequiredAnnotationBeanPostProcessor
if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// 實(shí)例化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));
}
// 實(shí)例化PersistenceAnnotationBeanPostProcessor.
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
}
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
}
return beanDefs;
}
代碼可以看到眶掌,分別注冊(cè)了AutowiredAnnotationBeanPostProcessor、RequiredAnnotationBeanPostProcessor巴碗、CommonAnnotationBeanPostProcessor以及PersistenceAnnotationBeanPostProcessor這4個(gè)BeanPostProcessor朴爬。
后記
這是我自己看源碼總結(jié)的,錯(cuò)誤之處請(qǐng)幫忙指出橡淆,大家一起進(jìn)步召噩。
[朝陽區(qū)尼克楊]
轉(zhuǎn)載請(qǐng)注明原創(chuàng)出處,謝謝啦逸爵!