我們知道如果想使用spring注解你需要在applicationContext.xml配置文件中設置context:component-scan base-package='xxx’這樣spring會幫助我們掃描你所設置的目錄里面所有的Bean,如果Bean上面有相應的@Service,@Controller注解(當然還有其他的,這里就不一一列出來),那么Spring的IOC容器將會幫我實例對象,設置屬性。
分析spring如果實現注解驅動
還是從spring配置文件的命名空間入手,不清楚的可以參考我之前的文章。找到spring-context包進入文件里面找到src/main/resources/META-INF/spring.handlers這樣你可以看到一下內容:
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路徑
創建ClassPathBeanDefinitionScanner對象并且設置springIOC容器所關心的注解@Component換言之:只要類定義上面有@Component注解那么我們的掃描器就需要處理這個類。
設置BeanName生成工具(這里是生成類名的工具有默認的beanName,也有自定義@Service(“abc”))
開始掃描包,使用ClassReader掃描所有類可以得到類的信息,對比是否有@Component注解,如果有生成BeanDefinition=ScannedGenericBeanDefinition
注冊Spring內置的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) {//這里會注冊很多內容BeanPostProcessor類Set<BeanDefinitionHolder> processorDefinitions =AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);for (BeanDefinitionHolder processorDefinition : processorDefinitions) {compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));}}
上面只是注冊了所有內置Annotation工具類,還沒有實例化。接下來我們要進入refresh()方法看看基于注解的類實例化過程
注解類實例過程
在前面基于注解的類已經被掃描成為ScannedGenericBeanDefinition現在就要實例化了。再refresh()方法中首先需要注冊前面說的內置處理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"
//最終這些類變為:
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容器中,然后根據Bean的生命周期中的第6步設置屬性,依據Annotation的方式注入屬性:CommonAnnotationBeanPostProcessor來處理屬性的注入。我們使用了@Resource來配置屬性。