前言
在學習Spring的過程中,自己算是好好體會了一把Spring配置文件的繁瑣。
在學習Spring的時候,過多的標簽我們不容易記住。而且Spring官方也積極的給我們提供了示例項目供我們參考,可見官方也不推薦我們?nèi)ビ涀∧敲幢姸嗟呐渲梦募?,只是記住有這個東西存在就好,我們用到的時候只要去查閱引入配置標簽即可。
今天在搞Spring項目的時候,由于自己最近都在開發(fā)SpringBoot相關的內(nèi)容。所以長期不接觸Spring最明顯的問題就是配置文件不會寫了。過去自己寫的時候也一直都是能自己寫出來的自己寫,寫不出來忘記了的的copy原來項目的配置文件。因為具體到業(yè)務代碼的編寫,很明顯業(yè)務代碼才是我們一個程序員應該關注的事情而不是去花大量的時間去搞配置文件,尤其是對于用過SpringBoot的我來說,真的再也受不了去死記硬背那些眾多的配置文件了。
問題
開啟Spring項目第一件事就是先配置不然你什么都做不了。首先我想要在項目中用我常用的注解@Autowired,我需要在配置文件中聲明AutowiredAnnotationBeanPostProcessor這個bean。我又想要在項目中用到@Required這個注解,那我還需要再配置RequiredAnnotationBeanPostProcesso這個bean。一個功能一個bean搞得自己有點兒頭大。后來查閱到要想支持這兩個注解只需要在配置文件中聲明<context:annotation-config/>該標簽即可。這個標簽自己以前常用,只知道它能為我提供一些注解的支持,但是具體到他能做多少我自己卻沒有深入研究過。今天就來研究一下,也算是為后續(xù)的的Spring標簽的探索先踩踩坑。
深入源碼
這里我只是簡單記錄一下我好奇的地方,并記錄自己解惑的過程。先上一段代碼:
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:annotation-config/>
</beans>
我們來看一下官方對該標簽的說明:
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)
翻譯過來:
與往常一樣,您可以將它們注冊為單獨的bean定義,但也可以通過在基于XML的Spring配置中包含以下標記來隱式注冊它們(注意包含上下文名稱空間)

既然官網(wǎng)這么說,可是那么<context:annotation-config/>這個標簽什么時候起作用的呢?哪兒體現(xiàn)了他實例化了這幾個bean了?
在Spring容器解析配置文件中時,會加載beans標簽中配置的URL,如圖:
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>
我們按住Ctrl點擊該標簽進入到該目錄下:

可以看到代碼提供的注釋這里寫的很清楚,該標簽提供了哪些注解的支持

然后我們再根據(jù)配置文件中beans標簽中配置的xsi:schemaLocation的URL到spring.handlers文件中,找到對應的NamespaceHandler。
比如我上面的是<http://www.springframework.org/schema/context>那么將對應spring.handlers文件中的ContextNamespaceHandler。然后Ctrl B進入


那么這個Handler是做什么的呢?就一個方法,在該方法中,可以看到它的作用就是創(chuàng)建這些標簽所對應的解析類。什么是解析類呢?也就是所有的自定義命名空間(像mvc,context等)下的標簽解析都是由BeanDefinitionParser接口的子類來完成的??梢钥吹?code>annotation-config的解析類是AnnotationConfigBeanDefinitionParser。
我們繼續(xù)Ctrl B進入該類,看一下這個類如何解析這個標簽的。

根據(jù)上面的代碼可以看出真正的解析是在AnnotationConfigUtils.registerAnnotationConfigProcessors()方法中進行的
那就進去這個方法看看
這里代碼篇幅太長,我們貼了代碼:
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);
// ConfigurationClassPostProcessor
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));
}
// 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));
}
// 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));
}
// 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));
}
// PersistenceAnnotationBeanPostProcessor
// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
ClassLoader cl = AnnotationConfigUtils.class.getClassLoader();
def.setBeanClass(cl.loadClass(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME));
}
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));
}
return beanDefs;
}
到這里我們的問題就完美解決了。由代碼可以看出,分別注冊了AutowiredAnnotationBeanPostProcessor、RequiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor以及PersistenceAnnotationBeanPostProcessor、ConfigurationClassPostProcessor這5個BeanPostProcessor。