Spring注解源碼分析
我們知道如果想使用spring注解你需要在
applicationContext.xml
配置文件中設(shè)置context:component-scan base-package='xxx'
這樣spring會幫助我們掃描你所設(shè)置的目錄里面所有的Bean外潜,如果Bean上面有相應(yīng)的@Service,@Controller
注解(當然還有其他的撤防,這里就不一一列出來)弥喉,那么Spring的IOC容器將會幫我實例對象戴涝,設(shè)置屬性洪唐。
分析spring如果實現(xiàn)注解驅(qū)動
還是從spring配置文件的命名空間入手谐鼎,不清楚的可以參考我之前的文章唯咬。找到spring-context包進入文件里面找到src/main/resources/META-INF/spring.handlers
這樣你可以看到一下內(nèi)容:
http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
http\://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler
http\://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler
可以看到context命名空間解析的類org.springframework.context.config.ContextNamespaceHandler
所以可以直接定位到spring掃描的過程席楚。
spring源碼分析-ContextNamespaceHandler
//組件掃描
registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
整個掃描包路徑的過程如下:
取出自定義base-package路徑
-
創(chuàng)建
ClassPathBeanDefinitionScanner
對象并且設(shè)置springIOC容器所關(guān)心的注解@Component
換言之:只要類定義上面有@Component
注解那么我們的掃描器就需要處理這個類咬崔。- 設(shè)置BeanName生成工具(這里是生成類名的工具有默認的beanName,也有自定義@Service("abc"))
開始掃描包烦秩,使用ClassReader掃描所有類可以得到類的信息垮斯,對比是否有
@Component
注解,如果有生成BeanDefinition=ScannedGenericBeanDefinition
-
注冊Spring內(nèi)置的BeanPostProcessor對象只祠。默認有8個
org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)
主要需要注意的有四個-
ConfigurationClassPostProcessor
:處理配置類 -
AutowiredAnnotationBeanPostProcessor
:處理@Autowired幫助類注入屬性 -
RequiredAnnotationBeanPostProcessor
:處理@required -
CommonAnnotationBeanPostProcessor
:處理@Resource幫助類注入屬性 - 入口代碼:
-
if (annotationConfig) {
//這里會注冊很多內(nèi)容BeanPostProcessor類
Set<BeanDefinitionHolder> processorDefinitions =AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));
}
}
上面只是注冊了所有內(nèi)置Annotation工具類兜蠕,還沒有實例化。接下來我們要進入refresh()
方法看看基于注解的類實例化過程
注解類實例過程
在前面基于注解的類已經(jīng)被掃描成為ScannedGenericBeanDefinition
現(xiàn)在就要實例化了抛寝。再refresh()方法中首先需要注冊前面說的內(nèi)置處理Annotation類的工具類熊杨,沒錯就是這幾個:
2 = "org.springframework.context.annotation.internalConfigurationAnnotationProcessor"
3 = "org.springframework.context.annotation.internalAutowiredAnnotationProcessor"
4 = "org.springframework.context.annotation.internalRequiredAnnotationProcessor"
5 = "org.springframework.context.annotation.internalCommonAnnotationProcessor"
6 = "org.springframework.context.event.internalEventListenerProcessor"
7 = "org.springframework.context.event.internalEventListenerFactory"
//最終這些類變?yōu)椋?0 = {ApplicationContextAwareProcessor@1792}
1 = {ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor@1961}
2 = {PostProcessorRegistrationDelegate$BeanPostProcessorChecker@2193}
3 = {CommonAnnotationBeanPostProcessor@2135}
4 = {AutowiredAnnotationBeanPostProcessor@1991}
5 = {RequiredAnnotationBeanPostProcessor@2107}
6 = {ApplicationListenerDetector@2194}
入口在:registerBeanPostProcessors(beanFactory);
這里會將上面的類注冊到IOC容器中,然后根據(jù)Bean的生命周期中的第6步設(shè)置屬性墩剖,依據(jù)Annotation的方式注入屬性:CommonAnnotationBeanPostProcessor來處理屬性的注入猴凹。我們使用了@Resource
來配置屬性。
整個實例的全流程可以參考另一篇文章
07spring源碼分析-從Bean的生命周期分析IOC創(chuàng)建對象過程
//TODO 學習ClassReader對象
classReader