最近在學習spring源碼,把自己的學習筆記記錄一下,分享出來,如果有理解錯的,也希望各位能提出來,大家一起學習
首先spring源碼的入口方法:
1 public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) { 2 //在this()中調用父類的方法 創建了 DefaultListableBeanFactory(這就是平常說的springbean工廠) 3 this(); 4 //把annotatedClasses(AppConfig.java)放到spring容器中,最底層調用的是DefautListableBeanFactory.registerBeanDefinition()方法,將配置類put到beanDefinitionMap中 5 register(annotatedClasses); 6 refresh(); 7 } 8 9 //這個方法是this()調用的 10 public AnnotationConfigApplicationContext() { 11 /** 12 * 創建一個讀取注解的bean定義讀取器 13 * bean定義其實就是beanDefinition 14 * 在這個方法里面 聲明了六個比較重要的bean,並將這個幾個bean存到了beanDefinitionMap里面 15 * CommonAnnotationBeanPostProcessor 16 * RequiredAnnotationBeanPostProcessor 17 * AutowiredAnnotationBeanPostProcessor 18 * ConfigurationClassPostProcessor 19 */ 20 this.reader = new AnnotatedBeanDefinitionReader(this); 21 /** 22 * 實際上完成包掃描並不是這里的scanner完成的。而是spring在掃描包的時候,又重新new了一個ClassPathBeanDefinitionScanner完成的 23 * 這里的scanner是為了程序員能夠在外部調用annotationConfigApplicationbContext對象 24 */ 25 this.scanner = new ClassPathBeanDefinitionScanner(this); 26 }
在spring初始化過程中,最重要的方法就是refresh()方法,在refresh中完成了bean的掃描、初始化、以及AOP動態代理對象的生成等等,我們來一點一點分析
1 public void refresh() throws BeansException, IllegalStateException { 2 synchronized (this.startupShutdownMonitor) { 3 // Prepare this context for refreshing. 4 //准備工作包括設置啟動時間、是否激活標志位、初始化屬性源配置 5 prepareRefresh(); 6 7 // Tell the subclass to refresh the internal bean factory. 8 //返回一個factory 9 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 10 11 // Prepare the bean factory for use in this context. 12 //准備工廠 13 prepareBeanFactory(beanFactory); 14 15 try { 16 // Allows post-processing of the bean factory in context subclasses. 17 postProcessBeanFactory(beanFactory); 18 19 // Invoke factory processors registered as beans in the context. 20 /** 21 * TODO 22 * 完成對bean的掃描,將beanDefinition存到map中 23 * 24 26 * 27 * 在這個方法中,注入bean,分為了三種 28 * 一、普通bean:@Component注解的bean30 * 31 * 1.獲取到所有的beanFactoryPostProcessor 32 * 2.執行 bean后置處理器的postProcessBeanFactory(configurationClassPostProcessor),該方法會把beanFactory作為入參傳到方法里面 33 * 3.從beanFactory中獲取到所有的beanName 打斷點看一下 org.springframework.context.annotation .ConfigurationClassPostProcessor#processConfigBeanDefinitions 34 * 35 * 4.然后將所有的bean包裝成beanDefinitionHolder,在后面又根據beanName和bean的metadata包裝成了ConfigurationClass 36 * 5.把所有包含@ComponentScan的類取出來,遍歷每一個componentScan,調用 ClassPathBeanDefinitionScanner.doScan(basePackages)方法 37 * 6.在doScan方法中,會遍歷basePackages,因為一個ComponentScan中可以配置多個要掃描的包 38 * 7.獲取每個包下面的 *.class文件,registerBeanDefinition(definitionHolder, this.registry); 這個方法底層就是調用org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition方法 把當前bean put到beanDefinitionMap中 39 * 40 * 二、是通過ImportSelector注解注入的bean 41 * 42 * 三、ImportBeanDefinitionRegistrar注入的bean 43 */ 44 invokeBeanFactoryPostProcessors(beanFactory); 45 46 // Register bean processors that intercept bean creation. 47 //注冊beanPostProcessor;方法里面調用的是 beanFactory.addBeanPostProcessor(postProcessor); 48 registerBeanPostProcessors(beanFactory); 49 50 // Initialize message source for this context. 51 initMessageSource(); 52 53 // Initialize event multicaster for this context. 54 /** 55 * 注冊一個多事件派發器 56 * 先從beanFactory獲取,如果沒有,就創建一個,並將創建的派發器放到beanFactory中 57 */ 58 initApplicationEventMulticaster(); 59 60 // Initialize other special beans in specific context subclasses. 61 onRefresh(); 62 63 // Check for listener beans and register them. 64 /** 65 * 注冊所有的事件監聽器 66 * 將容器中的時間監聽器添加到 applicationEventMulticaster 中 67 */ 68 69 registerListeners(); 70 71 // Instantiate all remaining (non-lazy-init) singletons. 72 /** 73 * TODO 74 * 完成對bean的實例化 75 */ 76 finishBeanFactoryInitialization(beanFactory); 77 78 // Last step: publish corresponding event. 79 /** 80 * 當容器刷新完成之后,發送容器刷新完成事件 81 * publishEvent(new ContextRefreshedEvent(this)); 82 */ 83 finishRefresh(); 84 } 85 86 catch (BeansException ex) { 87 88 } 89 90 finally { 91 // Reset common introspection caches in Spring's core, since we 92 // might not ever need metadata for singleton beans anymore... 93 resetCommonCaches(); 94 } 95 } 96 }
在refresh方法中,個人覺得比較重要的是
invokeBeanFactoryPostProcessors(beanFactory);
finishBeanFactoryInitialization(beanFactory);
其他幾個方法,還沒來得及進行深入的研究,本次主要來分析這兩個方法
首先說,一個bean要在spring中完成初始化,簡單來說,分為兩步(當前,這是個人目前的理解)
1.首先要把bean掃描到容器中,然后再將bean實例化;invokeBeanFactoryPostProcessors這個方法個人理解:主要是完成了bean的掃描,將要注入的bean掃描到beanDefinitionMap中;這個map是用來存放
spring中要實例化的bean,key值是beanName,value值是一個beanDefinition對象,beanDefinition存放的是對bean的一些描述信息;
2.當bean被掃描到beanDefinitionMap中之后,就需要調用bean的構造方法等來實例化,然后在調用bean的初始化方法來進行初始化;以及bean的屬性注入等;這個工作是在finishBeanFactoryInitialization方法中完成;
一、
我們首先來說在invokeBeanFactoryPostProcessors方法中是如何完成bean的掃描的;
先說結論吧:spring在將bean注入到容器中,有幾種方式:
1.@Component注解+@ComponeneScan注解
2.@Import注解注入,import注入的話分兩種,一種是注入ImportSelector,一種是注入ImportBeanDefinitionRegistrar
3.@Bean 在配置類中,直接通過該注解將bean注入到容器中
1.那我們首先來說@Component注解這種注入方式的源碼:
由於這里的調用鏈比較長,所以直接截圖放出來,不一個一個手打了;
在前面,spring將配置類注入到了beanDefinitionMap中,在這個方法里面,會獲取到配置類;
然后獲取到配置類的ComponentScan注解的值,由於ComponentScan可以指定多個包,所以會循環每個包,在doScan方法中獲取到當前包下所有的*.class文件;將掃描的文件,put到beanDefinitionMap中
這是通過掃描注入bean的方式原理
2.那通過ImportSelector和importBeanDefinitionRegistrar方式注入的bean,是這樣注入的
org.springframework.context.annotation.ConfigurationClassParser#processImports
在這個方法中完成了對這兩種方式注入的bean的掃描;方法中,會區分是ImportSelector.class還是ImportBeanDefinitionRegistrar.class;
稍微說一下這兩個接口的區別:
①.ImportSelector接口中selectImports方法返回的是一個String[] 數組對象,返回數組中,包含的是要注入的bean的全類名
②.ImportBeanDefinitionRegistrar接口中的方法可以直接注冊bean,因為接口中的方法可以得到BeanDefinitionRegisty對象
我們接着說注入:對於ImportSelector注入的bean會存入到configurationClasses中;對於ibdr(importbeanDefinitionRegistrar)注入的bean會存到importBeanDefinitionRegistrars中
在處理完這些之后,在 org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitions方法中,對import注入的bean和@Bean注入的bean進行注入
1 private void loadBeanDefinitionsForConfigurationClass( 2 ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) { 3 4 if (trackedConditionEvaluator.shouldSkip(configClass)) { 5 String beanName = configClass.getBeanName(); 6 if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) { 7 this.registry.removeBeanDefinition(beanName); 8 } 9 this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName()); 10 return; 11 } 12 13 //這里是對importSelector注入的bean進行初始化 14 if (configClass.isImported()) { 15 registerBeanDefinitionForImportedConfigurationClass(configClass); 16 } 17 18 //@Bean 注解需要注入的bean對象 19 for (BeanMethod beanMethod : configClass.getBeanMethods()) { 20 loadBeanDefinitionsForBeanMethod(beanMethod); 21 } 22 23 loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); 24 //這里是對ImportBeanDefinitionRegistrar注入的bean進行初始化 25 loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); 26 }
這個方法執行完之后,所有的bean就被注入到了beanDefinitionMap中
在invokebeanFactoryPostProcessors方法中,還有很多細節,比如對配置類上加@Configuration注解與不加@Configuration注解的處理,對importSelector注入bean的遞歸調用等等。,如果展開了,不知道該怎么寫,細節點太多,太碎,所以本次只把主干流程簡單說了一下,對於源碼解讀的注釋,可以參考本人在GitHub上傳的注釋來看。https://github.com/mapy95/spring-sourceCode
這上面是spring的源碼學習的一些注釋,對於spring源碼的學習筆記還在持續更新哈。