java架構之路-(spring源碼篇)springIOC容器源碼解析(上)

  • 2019 年 10 月 8 日
  • 筆記

  我們這次來叭叭一下Spring的源碼,這次部落格主要來說說Spring源碼,先粗略的擼一遍,下篇部落格選幾個重點去說,由於過於複雜,我也是看了一點點,我們先來過一遍源碼,然後上流程圖,最後我們再回頭總結一下,我們來循序漸進的叭叭一下。

我們來回顧一下上次Spring部落格的內容,每次都有用到AnnotationConfigApplicationContext來載入我們的配置類,我們就從這裡開始。

/**       * Create a new AnnotationConfigApplicationContext, deriving bean definitions       * from the given annotated classes and automatically refreshing the context.  創建新的注釋configapplicationcontext,獲得bean定義並自動刷新上下文。       * @param annotatedClasses one or more annotated classes,  我們的配置類       * e.g. {@link Configuration @Configuration} classes       */      public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {          this();          register(annotatedClasses);          refresh();      }

  翻譯過來就是“創建新的注釋configapplicationcontext,獲得bean定義並自動刷新上下文”。三個方法,我們先來一個個看,優先看父類有沒有構造方法。AnnotationConfigApplicationContext繼承了GenericApplicationContext類,所以我們先看GenericApplicationContext類的構造方法。程式碼很簡單

父類構造方法

/**   * Create a new GenericApplicationContext.   * @see #registerBeanDefinition   * @see #refresh   */  public GenericApplicationContext() {    this.beanFactory = new DefaultListableBeanFactory();  }

  這裡創建了一個新的DefaultListableBeanFactory對象,也是我們熟悉的beanFactory對象,記住是DefaultListableBeanFactory對象。我們回到AnnotationConfigApplicationContext的this方法。

this

/**   * Create a new AnnotationConfigApplicationContext that needs to be populated   * through {@link #register} calls and then manually {@linkplain #refresh refreshed}.   */  public AnnotationConfigApplicationContext() {      this.reader = new AnnotatedBeanDefinitionReader(this);//註解類型的解析器      this.scanner = new ClassPathBeanDefinitionScanner(this);//包掃描器  }

再往下扒一層。看一下那個AnnotatedBeanDefinitionReader註解類型的解析器是怎麼創建的,裡面都有什麼。

/**   * Create a new {@code AnnotatedBeanDefinitionReader} for the given registry.   * If the registry is {@link EnvironmentCapable}, e.g. is an {@code ApplicationContext},   * the {@link Environment} will be inherited, otherwise a new   * {@link StandardEnvironment} will be created and used.   * @param registry the {@code BeanFactory} to load bean definitions into,   * in the form of a {@code BeanDefinitionRegistry}   * @see #AnnotatedBeanDefinitionReader(BeanDefinitionRegistry, Environment)   * @see #setEnvironment(Environment)   */  public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {      this(registry, getOrCreateEnvironment(registry)); //優先設置了環境並存在快取內  }

設置了環境,將我們的beanFactory作為參數,做了this調用,

/**   * Create a new {@code AnnotatedBeanDefinitionReader} for the given registry and using   * the given {@link Environment}.   用registry和Environment創建一個新的AnnnotatedBeanDefinitionReader   * @param registry the {@code BeanFactory} to load bean definitions into,   * in the form of a {@code BeanDefinitionRegistry}   * @param environment the {@code Environment} to use when evaluating bean definition   * profiles.   * @since 3.1   */  public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {      Assert.notNull(registry, "BeanDefinitionRegistry must not be null");      Assert.notNull(environment, "Environment must not be null");      this.registry = registry;      this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);      AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);  }

前三行不用看,第四行是用來解析我們@Conditional註解的。可以自己打開瞧瞧源程式碼。我們直接看第五行AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); 也是很重要的程式碼,我們繼續叭叭。

/**   * Register all relevant annotation post processors in the given registry.   * @param registry the registry to operate on   * @param source the configuration source element (already extracted)   * that this registration was triggered from. May be {@code null}.   * @return a Set of BeanDefinitionHolders, containing all bean definitions   * that have actually been registered by this call   */  public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(          BeanDefinitionRegistry registry, @Nullable 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<>(8);        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));      }        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));      }        // 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));      }        // Check for JPA support, and if present add the 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;  }

  原文的注釋為在給定的註冊器中處理所有有意義的後置處理器,基本就是是否包含***,如果包含就set進去。這段程式碼是用來初始化內部的組件的。走到這裡就已經初始化的Bean定義。也就是說我們的容器已經注入了定義資訊,還未實例化。

this方法的上半部分就說完了,我們再來看下半部分的new ClassPathBeanDefinitionScanner,創建一個類路徑掃描器,這個程式碼不多,就是判斷我們是否使用默認的類路徑掃描器。

 1 /**   2  * Create a new {@code ClassPathBeanDefinitionScanner} for the given bean factory and   3  * using the given {@link Environment} when evaluating bean definition profile metadata.   4  * @param registry the {@code BeanFactory} to load bean definitions into, in the form   5  * of a {@code BeanDefinitionRegistry}   6  * @param useDefaultFilters whether to include the default filters for the   7  * {@link org.springframework.stereotype.Component @Component},   8  * {@link org.springframework.stereotype.Repository @Repository},   9  * {@link org.springframework.stereotype.Service @Service}, and  10  * {@link org.springframework.stereotype.Controller @Controller} stereotype annotations  11  * @param environment the Spring {@link Environment} to use when evaluating bean  12  * definition profile metadata  13  * @param resourceLoader the {@link ResourceLoader} to use  14  * @since 4.3.6  15  */  16 public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,  17                                       Environment environment, @Nullable ResourceLoader resourceLoader) {  18  19     Assert.notNull(registry, "BeanDefinitionRegistry must not be null");  20     this.registry = registry;  21  22     if (useDefaultFilters) {  23         registerDefaultFilters();  24     }  25     setEnvironment(environment);  26     setResourceLoader(resourceLoader);  27 }

我們來直接看一下第23行程式碼,是否註冊一個默認的過濾器(掃描策略)。25行設置環境,26行設置資源載入器。

到這裡就已經制定好了我們的掃描策略了。

有點亂啊梳理一下。

 register(annotatedClasses)

this部分就說你完了,再來看看register(annotatedClasses);字面意思來看是帶著我們的配置文件註冊,我們來看一下程式碼。

/**   * Register one or more annotated classes to be processed.   * <p>Note that {@link #refresh()} must be called in order for the context   * to fully process the new classes.   * @param annotatedClasses one or more annotated classes,   * e.g. {@link Configuration @Configuration} classes   * @see #scan(String...)   * @see #refresh()   */  public void register(Class<?>... annotatedClasses) {      Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");      this.reader.register(annotatedClasses);  }

用我們上一步的reader解析器去註冊,裡面是一個循環方法。最終調用doRegisterBean來真正的註冊。這一步我們先來簡單的叫做註冊吧。

 直到這裡其實我們容器還是沒有創建的,這些都是一些前期的準備工作。最後也是最關鍵的一步才是我們的容器的實例化。refresh()方法。內容超多。

@Override  public void refresh() throws BeansException, IllegalStateException {      synchronized (this.startupShutdownMonitor) {          // Prepare this context for refreshing.          prepareRefresh();            // Tell the subclass to refresh the internal bean factory.          ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();            // Prepare the bean factory for use in this context.          prepareBeanFactory(beanFactory);            try {              // Allows post-processing of the bean factory in context subclasses.              postProcessBeanFactory(beanFactory);                // Invoke factory processors registered as beans in the context.              invokeBeanFactoryPostProcessors(beanFactory);                // Register bean processors that intercept bean creation.              registerBeanPostProcessors(beanFactory);                // Initialize message source for this context.              initMessageSource();                // Initialize event multicaster for this context.              initApplicationEventMulticaster();                // Initialize other special beans in specific context subclasses.              onRefresh();                // Check for listener beans and register them.              registerListeners();                // Instantiate all remaining (non-lazy-init) singletons.              finishBeanFactoryInitialization(beanFactory);                // Last step: publish corresponding event.              finishRefresh();          }            catch (BeansException ex) {              if (logger.isWarnEnabled()) {                  logger.warn("Exception encountered during context initialization - " +                          "cancelling refresh attempt: " + ex);              }                // Destroy already created singletons to avoid dangling resources.              destroyBeans();                // Reset 'active' flag.              cancelRefresh(ex);                // Propagate exception to caller.              throw ex;          }            finally {              // Reset common introspection caches in Spring's core, since we              // might not ever need metadata for singleton beans anymore...              resetCommonCaches();          }      }  }

我們來逐個方法看一下都是做什麼的。

prepareRefresh()創建早期程式監聽器。

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory()通知子類刷新Bean工廠

prepareBeanFactory(beanFactory)配置工廠上下文。

postProcessBeanFactory(beanFactory)處理Bean工廠的後置處理

invokeBeanFactoryPostProcessors實例化並調用所有註冊的Bean工廠的後置處理器

registerBeanPostProcessors(beanFactory)註冊Bean工廠的後置處理器

initMessageSource()初始化消息源

initApplicationEventMulticaster()初始化事件多播器

onRefresh()初始化特殊定義的Bean

registerListeners()註冊事件監聽器

finishBeanFactoryInitialization(beanFactory)實例化剩餘非懶載入Bean

finishRefresh()事件發布

resetCommonCaches()刷新快取

就這樣我們的Bean工廠就創建完成了。看著如此簡單吧。後面我們來詳細看一下。內部還有超多的東西。Spring源碼不建議太過於深入的學習,容易陷進去....

最近搞了一個個人公眾號,會每天更新一篇原創博文,java,python,自然語言處理相關的知識有興趣的小夥伴可以關注一下。

Tags: