spring啟動簡析

spring類結構

beanFactory結構

todo

applicationContext結構

todo

beanDefinition結構

BeanDefinition是頂層接口,定義了bean的各種屬性锤躁,包括是否懶加載荔烧,類名稱等等哼转,所有bean的基本屬性都是應該通過這個接口獲取议街。BeanDefinition直接繼承的是接口AnnotatedBeanDefinition與AbstractBeanDefinition抽象類,AnnotatedBeanDefinition是在BeanDefinition基礎上增加了AnnotationMetadata屬性數據,這個接口可以理解為帶注解的BeanDefinition;AbstractBeanDefinition是對BeanDefinition的基本實現张抄,把BeanDefinition中大部分方法都實現了,然后這個抽象類有三個子類RootBeanDefinition洼怔、ChildBeanDefinition欣鳖、GenericBeanDefinition,對于前面兩個父子類茴厉,是因為我們定義bean的時候泽台,是可以有parent關系的什荣,RootBeanDefinition是一種merged過的BeanDefinition,是完整的BeanDefinition怀酷,而childBeanDefinition是不完整的BeanDefinition稻爬,必須要包含parent的BeanDefinition;GenericBeanDefinition是新的BeanDefinition蜕依,是用來替換那個root跟child的桅锄,后面新的beandefinition都是基于GenericBeanDefinition實現的。再來看下AnnotatedBeanDefinition的子類有兩個ScannedGenericBeanDefinition跟AnnotatedGenericBeanDefinition样眠,這兩個子類都是基于GenericBeanDefinition實現的友瘤,看下這兩個類的實現是差不多的,這兩個類的區(qū)別在與ScannedGenericBeanDefinition是在component-scan的場景下定義的檐束,就是我們注解@ComponentScan或者<context: component-scan>而AnnotatedGenericBeanDefinition應用的場景是springboot的AnnotationConfigApplicationContext里面以及處理@Configuration注解的bean對象的時候用的辫秧。而普通的GenericBeanDefinition注解在xml中定義的bean應用

metadata結構

todo

namespaceHandler結構

todo

spring中的數據結構

todo

spring 的初始化----refresh

spring啟動過程是以ApplicationContext對象的定義來完成bean的初始化與管理的。然后就可以通過這個context的getbean方法獲取對應bean對象被丧。以ClassPathXmlApplicationContext為例盟戏,當我們new一個ClassPathXmlApplicationContext對象的時候,其spring的bean對象已經被加載好了甥桂。

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
      throws BeansException {

   super(parent);
   setConfigLocations(configLocations);
   if (refresh) {
      refresh();
   }
}

上面代碼中是ClassPathXmlApplicationContext的構造函數柿究,configLocations是用戶指定的配置項路徑地址,不是重點黄选,重點在refresh函數

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()方法做準備工作蝇摸,實現中沒有做什么事。

bean的加載----obtainFreshBeanFactory

obtainFreshBeanFactory是核心方法步驟办陷,這個方法主要就是構建beanFactory以及加載所有需要定義成bean的對象探入,創(chuàng)建對應的beanDefinition。跟蹤obtainFreshBeanFactory的方法懂诗,發(fā)現springcontext中定義的beanfactory是DefaultListableBeanFactory蜂嗽,這個是spring提供的一個默認的bean工廠實現類。

protected final void refreshBeanFactory() throws BeansException {
   if (hasBeanFactory()) {
      destroyBeans();
      closeBeanFactory();
   }
   try {
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      beanFactory.setSerializationId(getId());
      customizeBeanFactory(beanFactory);
      loadBeanDefinitions(beanFactory);
      synchronized (this.beanFactoryMonitor) {
         this.beanFactory = beanFactory;
      }
   }
   catch (IOException ex) {
      throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
   }
}

customizeBeanFactory是對這個beanfactory的定制殃恒,這里定制了兩個屬性植旧,一個是allowBeanDefinitionOverriding,就是是否允許bean覆蓋定義离唐,默認是允許的病附,當有兩個相同名字的bean定義時,后者會覆蓋前者亥鬓;另一個是allowCircularReferences完沪,就是是否允許bean的循環(huán)引用,默認是允許的,后面會講spring是如何解決bean的循環(huán)引用的覆积。默認的DefaultListableBeanFactory這兩個配置項是true听皿,不需要修改。

loadBeanDefinitions方法是核心方法宽档,這個方法就是把spring里面所有需要其管理的bean對象給加載起來(只是定義尉姨,沒有初始化)

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
   // Create a new XmlBeanDefinitionReader for the given BeanFactory.
   XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
   // Configure the bean definition reader with this context's
   // resource loading environment.
   beanDefinitionReader.setEnvironment(this.getEnvironment());
   beanDefinitionReader.setResourceLoader(this);
   beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
   // Allow a subclass to provide custom initialization of the reader,
   // then proceed with actually loading the bean definitions.
   initBeanDefinitionReader(beanDefinitionReader);
   loadBeanDefinitions(beanDefinitionReader);
}

這個XmlBeanDefinitionReader是xml文件的bean解析器,代碼到這里吗冤,beanfactory的bean的定義模型beanDefinition的讀取實際是交給beanDefinitionReader這個對象來做的又厉,因為我們開始選擇的是ClassPathXmlApplicationContext,所以這里加載beandefinition是加載的xml形式定義的椎瘟,所以實際上所有的xml中定義的bean的讀取的就是這個對象XmlBeanDefinitionReader完成的覆致。上面的核心代碼在于loadBeanDefinitions(beanDefinitionReader)這個方法,這個方法里面就把applicationContext的loadBeanDefinition動作交給了XmlBeanDefinitionReader去完成肺蔚,實際上就是XmlBeanDefinitionReader進行l(wèi)oadBeanDefinitions

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
   Resource[] configResources = getConfigResources();
   if (configResources != null) {
      reader.loadBeanDefinitions(configResources);
   }
   String[] configLocations = getConfigLocations();
   if (configLocations != null) {
      reader.loadBeanDefinitions(configLocations);
   }
}

這個方法里面是加載bean對象煌妈,getConfigResources獲取資源配置,這個資源配置就是我們在定義ClassPathXmlApplicationContext對象的時候傳入的婆排,如果為空寂拆,則加載默認的配置文件/WEB-INF/applicationContext.xml(用的云服務nuwa容器啟動時候填硕,會將相關的配置資源加載進去)无牵,跟蹤這個loadBeanDefinitions方法可以看到荒叶,reader是遍歷加載configLocations凡伊,由于applicationcontext繼承ResourcePatternResolver伏嗜,說明applicationcontext的resourceLoader是通配符匹配resource路徑垮斯,然后把每個resourcelocation下正則匹配的resource文件進行解析草戈,繼續(xù)跟蹤代碼走到doLoadBeanDefinitions

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
      throws BeanDefinitionStoreException {
   try {
      Document doc = doLoadDocument(inputSource, resource);
      return registerBeanDefinitions(doc, resource);
   }
   catch (BeanDefinitionStoreException ex) {
      throw ex;
   }
   ...
}

doLoadBeanDefinitions里面有兩行有效代碼坪创,一個doLoadDocument就是從resource資源文件讀取出來炕婶,加載到Document對象中,這里主要是DOM的解析莱预,不做分析柠掂,另外一個registerBeanDefinitions就是真正將doc中定義的bean解析成beanDefinition對象,注冊到beanfactory中依沮。

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        int countBefore = getRegistry().getBeanDefinitionCount();
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }

這里BeanDefinitionDocumentReader 對象是用來讀取一個doc文件中的beandefinition的涯贞,每一個resource都被封裝成一個xmlreaderContext (注意這個xmlreaderContext 里面會指定一個NamespaceHandlerResolver,這個resolver是用來解析我們配置的xml的)危喉。調用的方法registerBeanDefinitions

protected void doRegisterBeanDefinitions(Element root) {
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = createDelegate(getReaderContext(), root, parent);
        if (this.delegate.isDefaultNamespace(root)) {
            String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
            if (StringUtils.hasText(profileSpec)) {
                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                        profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                    if (logger.isInfoEnabled()) {
                        logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                                "] not matching: " + getReaderContext().getResource());
                    }
                    return;
                }
            }
        }
        preProcessXml(root);
        parseBeanDefinitions(root, this.delegate);
        postProcessXml(root);
        this.delegate = parent;
    }

但是這里用了一個BeanDefinitionParserDelegate宋渔,這個delegate是readerContext的代理,這個方法中辜限,核心代碼是parseBeanDefinitions

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
   if (delegate.isDefaultNamespace(root)) {
      NodeList nl = root.getChildNodes();
      for (int i = 0; i < nl.getLength(); i++) {
         Node node = nl.item(i);
         if (node instanceof Element) {
            Element ele = (Element) node;
            if (delegate.isDefaultNamespace(ele)) {
               parseDefaultElement(ele, delegate);
            }
            else {
               delegate.parseCustomElement(ele);
            }
         }
      }
   }
   else {
      delegate.parseCustomElement(root);
   }
}

解析過程是從root開始的皇拣,每個元素進行解析,根據元素的命名空間區(qū)分是自帶的還是用戶自定義的薄嫡,先看下系統自帶的元素

public static final String ALIAS_ATTRIBUTE = "alias";
public static final String IMPORT_ELEMENT = "import";
public static final String RESOURCE_ATTRIBUTE = "resource";
public static final String NESTED_BEANS_ELEMENT = "beans";
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
   if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
      importBeanDefinitionResource(ele);
   }
   else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
      processAliasRegistration(ele);
   }
   else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
      processBeanDefinition(ele, delegate);
   }
   else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
      // recurse
      doRegisterBeanDefinitions(ele);
   }
}

可以看出這里就是解析幾種常見的配置bean的元素氧急,注意在處理beans的時候颗胡,是用遞歸的方式處理bean的加載。下面看下custom的方式态蒂,在配置xml中有很多是自定義的杭措,比如<aop/>,<dubbo/>等等,這里講下這些自定義格式的bean的加載與解析钾恢。

自定義標簽----元素解析

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
   String namespaceUri = getNamespaceURI(ele);
   NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
   if (handler == null) {
      error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
      return null;
   }
   return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

首先獲取元素的命名空間手素,根據命名空間獲取對應的解析器,然后用解析器去執(zhí)行元素的解析工作瘩蚪,這里看下handler對象是從readerContext中獲取的泉懦,分析下這個handler代碼,getNamespaceHandlerResolver獲取命名空間對應的處理器的解析器疹瘦,spring中提供了一個默認的解析器DefaultNamespaceHandlerResolver崩哩,維護namespace跟handler的解析關系,核心點在于維護一個map言沐,key就是namespace邓嘹,value就是對應的handler

public NamespaceHandler resolve(String namespaceUri) {
   Map<String, Object> handlerMappings = getHandlerMappings();
   Object handlerOrClassName = handlerMappings.get(namespaceUri);
   if (handlerOrClassName == null) {
      return null;
   }
   else if (handlerOrClassName instanceof NamespaceHandler) {
      return (NamespaceHandler) handlerOrClassName;
   }
   else {
      String className = (String) handlerOrClassName;
      try {
         Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
         if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
            throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
                  "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
         }
         NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
         namespaceHandler.init();
         handlerMappings.put(namespaceUri, namespaceHandler);
         return namespaceHandler;
      }
      catch (ClassNotFoundException ex) {
         throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" +
               namespaceUri + "] not found", ex);
      }
      catch (LinkageError err) {
         throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" +
               namespaceUri + "]: problem with handler class file or dependent class", err);
      }
   }
}

上面的代碼邏輯比較簡單,就是從一個map中獲取這個namespace對應的handler险胰,這個handler對象可以是handler實例本身汹押,也可以是類名稱,如果是類名稱的話起便,就類加載器加載棚贾,NamespaceHandler是一個接口,spring提供了一個適配器類NamespaceHandlerSupport榆综,實現了NamespaceHandler接口的通用方法妙痹,把配置解析綁定到BeanDefinitionParser上,一個配置對應一個BeanDefinitionParser鼻疮,維護到一個map里面怯伊,那么NamespaceHandler的parse接口,就是獲取對應parser來處理判沟。

public BeanDefinition parse(Element element, ParserContext parserContext) {
   return findParserForElement(element, parserContext).parse(element, parserContext);
}
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
   String localName = parserContext.getDelegate().getLocalName(element);
   BeanDefinitionParser parser = this.parsers.get(localName);
   if (parser == null) {
      parserContext.getReaderContext().fatal(
            "Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
   }
   return parser;
}

所以我們可以看到一個NamespaceHandler對應的是一種namespace處理器耿芹,一般也是一個xml里面,比如我們說的<dubbo/>對應的就一個DubboNamespaceHandler水评,而一個xml里面可以有多種配置前綴猩系,比如<dubbo/>里面有<dubbo-module/>、<dubbo-protocol/>等中燥,里面每一個小的配置類型對應的是一個parser寇甸,這個parser做的事情就是把對應的配置定義轉換成beanDefinition,注冊到beanfactory中(這個beanfactory在對應的readerContext里面)所以我們看下dubbo的DubboNamespaceHandler的類的定義

public class DubboNamespaceHandler extends NamespaceHandlerSupport {
    static {
        Version.checkDuplicate(DubboNamespaceHandler.class);
    }
    @Override
    public void init() {
        registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
        registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
        registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
        registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
        registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
        registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
        registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
        registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
        registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
        registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
    }

在init方法地方把每個配置類型以及對應的parser注冊到namespaceHandler里面,然后這個DubboNamespaceHandler又通過SPI方式注冊到NamespaceHandlerResolver里面拿霉,我們看下前面提到的DefaultNamespaceHandlerResolver里面如何加載這些定義的namespaceHandler的吟秩。

private Map<String, Object> getHandlerMappings() {
   if (this.handlerMappings == null) {
      synchronized (this) {
         if (this.handlerMappings == null) {
            try {
               Properties mappings =
                     PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
               if (logger.isDebugEnabled()) {
                  logger.debug("Loaded NamespaceHandler mappings: " + mappings);
               }
               Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>(mappings.size());
               CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
               this.handlerMappings = handlerMappings;
            }
            catch (IOException ex) {
               throw new IllegalStateException(
                     "Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
            }
         }
      }
   }
   return this.handlerMappings;
}
public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";

里面的PropertiesLoaderUtils.loadAllProperties就是用來加載namespaceHandler,這里的this.handlerMappingsLocation 最終初始化的是META-INF/spring.handlers绽淘。至于自定義的parser如何解析這里就不分析了涵防。
里面的PropertiesLoaderUtils.loadAllProperties就是用來加載namespaceHandler,這里的this.handlerMappingsLocation 最終初始化的是META-INF/spring.handlers沪铭。至于自定義的parser如何解析這里就不分析了壮池。

小結

spring對bean的解析(xml)有兩種,原生定義了幾種標簽杀怠,比如<bean>椰憋、<beans>、<import>等赔退,這些spring提供默認的處理橙依,還可以支持拓展的,spring中也拓展了很多bean格式硕旗,比如context標簽窗骑,dubbo也拓展了<dubbo>,拓展bean的標簽的目的是用戶自定義bean的創(chuàng)建方式漆枚。對應的步驟如下:

  1. 首先要定義dtd文件创译,定義自己要用的標簽元素、屬性以及對應的子元素等等
  2. 自定義NamespaceHandler子類浪读,可以繼承NamespaceHandlerSupport昔榴,然后對于每個子配置類型辛藻,需要自定義對應的BeanDefinitionParser碘橘,每個parser就是對我們自定義標簽的解析。
  3. 然后在對應的NamespaceHandler類里面進行注冊----在init方法中調用registerBeanDefinitionParser方法吱肌,把每個parser注冊進去痘拆。
  4. 在META-INF/spring.handlers文件里面按照SPI配置自定義的NamespaceHandler由DefaultNamespaceHandlerResolver加載。

自定義配置案例分析----componant-scan氮墨、annotation-config配置解析

component-scan配置就是自定義配置的一種纺蛆,就是xml配置中<context/>配置,他的作用是用來掃描包路徑下所有的類文件规揪,對表明@Component注解的類加載成bean對象桥氏。對應的NamespaceHandler是ContextNamespaceHandler,舉例一個配置

<context:component-scan base-package="com.vrv.paw.dao,com.vrv.paw.service,com.vrv.paw.action" />

代碼如下

public class ContextNamespaceHandler extends NamespaceHandlerSupport {
   @Override
   public void init() {
      registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
      registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
      registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
      registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
      registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
      registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
      registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
      registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
   }
}

看到component-scan子配置對應的解析類為ComponentScanBeanDefinitionParser猛铅,查看對應的parse實現

public BeanDefinition parse(Element element, ParserContext parserContext) {
   String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
   basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
   String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
         ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);

   // Actually scan for bean definitions and register them.
   ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
   Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
   registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

   return null;
}

BASE_PACKAGE_ATTRIBUTE對應的配置項就是 base-package字支,解析獲取對應的package列表,創(chuàng)建ClassPathBeanDefinitionScanner對象scanner,來掃描這些base-packages下的bean注解定義堕伪,然后把掃描出來的beanDefinitions注冊到beanfactory中揖庄,這里的核心方法就是doScan。注意下在doScan之前的方法configureScanner欠雌,這個就是為了獲取一個scanner蹄梢,后面會講到這個方法。

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
   Assert.notEmpty(basePackages, "At least one base package must be specified");
   Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
   for (String basePackage : basePackages) {
      Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
      for (BeanDefinition candidate : candidates) {
         ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
         candidate.setScope(scopeMetadata.getScopeName());
         String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
         if (candidate instanceof AbstractBeanDefinition) {
            postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
         }
         if (candidate instanceof AnnotatedBeanDefinition) {
            AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
         }
         if (checkCandidate(beanName, candidate)) {
            BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
            definitionHolder =
                  AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
            beanDefinitions.add(definitionHolder);
            registerBeanDefinition(definitionHolder, this.registry);
         }
      }
   }
   return beanDefinitions;
}

這個方法就是遍歷所有的basePackage富俄,把對應package下的bean都加載起來禁炒,掃描的方法是findCandidateComponents,進入這個方法(篩選主要部分)

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
   Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
   try {
      String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
            resolveBasePackage(basePackage) + '/' + this.resourcePattern;
      Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
      boolean traceEnabled = logger.isTraceEnabled();
      boolean debugEnabled = logger.isDebugEnabled();
      for (Resource resource : resources) {
         if (traceEnabled) {
            logger.trace("Scanning " + resource);
         }
         if (resource.isReadable()) {
            try {
               MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
               if (isCandidateComponent(metadataReader)) {
                  ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                  sbd.setResource(resource);
                  sbd.setSource(resource);
                  if (isCandidateComponent(sbd)) {
                     candidates.add(sbd);
                  }
             ...
   return candidates;
}

從上面代碼可以看出先用resourcePatternResolver獲取這個basePackage下的class文件霍比,加載成resource齐苛,這個resourcePatternResolver對應的類是PathMatchingResourcePatternResolver,就是類路徑資源解析器桂塞,不進入分析凹蜂。下面是對每個resource獲取對應的MetadataReader,這個MetadataReader對象是用來獲取class類文件的元數據的阁危,包括注解玛痊、Class類元數據等。然后isCandidateComponent方法就是判斷這個類是否有注解

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
   for (TypeFilter tf : this.excludeFilters) {
      if (tf.match(metadataReader, this.metadataReaderFactory)) {
         return false;
      }
   }
   for (TypeFilter tf : this.includeFilters) {
      if (tf.match(metadataReader, this.metadataReaderFactory)) {
         return isConditionMatch(metadataReader);
      }
   }
   return false;
}

這里就是把metadata數據判斷是否滿足過濾器狂打,也就是我們配置在<context: component-scan/>的子元素<context: include-filter/>中擂煞,這個子元素的配置是可以讓我們自定義bean注解(比如這里我們配置com.huawei.chj.ChjAnnotation,那么@ChjAnnotation注解的類就會被掃描成bean)趴乡,一般的我們不會去配置這個值对省,而是用默認的配置,對應的是屬性use-default-filters=true晾捏,默認就是true蒿涎,所以這里的includeFilters就是默認的filter,可以看下對應的定義惦辛,就是在前面我們調用configureScanner方法里面劳秋,我們回過來看下這個方法實現

protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) {
   boolean useDefaultFilters = true;
   if (element.hasAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)) {
      useDefaultFilters = Boolean.valueOf(element.getAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE));
   }

   // Delegate bean definition registration to scanner class.
   ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters);
   scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults());
   scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns());

   if (element.hasAttribute(RESOURCE_PATTERN_ATTRIBUTE)) {
      scanner.setResourcePattern(element.getAttribute(RESOURCE_PATTERN_ATTRIBUTE));
   }

   try {
      parseBeanNameGenerator(element, scanner);
   }
   catch (Exception ex) {
      parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
   }

   try {
      parseScope(element, scanner);
   }
   catch (Exception ex) {
      parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
   }

   parseTypeFilters(element, scanner, parserContext);

   return scanner;
}

protected ClassPathBeanDefinitionScanner createScanner(XmlReaderContext readerContext, boolean useDefaultFilters) {
        return new ClassPathBeanDefinitionScanner(readerContext.getRegistry(), useDefaultFilters,
                readerContext.getEnvironment(), readerContext.getResourceLoader());
}

在這個方法里面就會調用createScanner方法創(chuàng)建scanner(其他的先不關注),里面就是new一個ClassPathBeanDefinitionScanner胖齐,看下這個類的構造函數:

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
      Environment environment, ResourceLoader resourceLoader) {

   Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
   this.registry = registry;

   if (useDefaultFilters) {
      registerDefaultFilters();
   }
   setEnvironment(environment);
   setResourceLoader(resourceLoader);
}

到這里可以看到會調用registerDefaultFilters來初始化默認的filter玻淑,進入這個方法看下

javaprotected void registerDefaultFilters() {
   this.includeFilters.add(new AnnotationTypeFilter(Component.class));
   ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
   try {
      this.includeFilters.add(new AnnotationTypeFilter(
            ((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
      logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
   }
   catch (ClassNotFoundException ex) {
      // JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
   }
   try {
      this.includeFilters.add(new AnnotationTypeFilter(
            ((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
      logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
   }
   catch (ClassNotFoundException ex) {
      // JSR-330 API not available - simply skip.
   }
}

到這里我們就看到了這個filters里面把Component注解類加到filter中去了,這就是我們在類上配置@Component注解就會被掃描成bean的原因呀伙,當然這里不僅僅添加了Component补履,還有javax.annotation.ManagedBean跟javax.inject.Named,所以實際上我們在類上配置@ManagedBean跟@Named都是可以被掃描成bean的剿另。

回到前面講的findCandidateComponents方法箫锤,通過這個方法把所有的basePackage里面的類中注解@Component的加載成beandefinition帅腌,這些都是“候選”bean對象,接下來要對這些對象進行處理麻汰,主要方法是AnnotationConfigUtils.processCommonDefinitionAnnotations速客,進入這個方法分析下:

static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
   AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
   if (lazy != null) {
      abd.setLazyInit(lazy.getBoolean("value"));
   }
   else if (abd.getMetadata() != metadata) {
      lazy = attributesFor(abd.getMetadata(), Lazy.class);
      if (lazy != null) {
         abd.setLazyInit(lazy.getBoolean("value"));
      }
   }

   if (metadata.isAnnotated(Primary.class.getName())) {
      abd.setPrimary(true);
   }
   AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
   if (dependsOn != null) {
      abd.setDependsOn(dependsOn.getStringArray("value"));
   }

   AnnotationAttributes role = attributesFor(metadata, Role.class);
   if (role != null) {
      abd.setRole(role.getNumber("value").intValue());
   }
   AnnotationAttributes description = attributesFor(metadata, Description.class);
   if (description != null) {
      abd.setDescription(description.getString("value"));
   }
}

這里所說對common屬性就是定義bean對屬性,包括是否懶加載五鲫,是否有依賴的類溺职,是否有描述的注解等等。這些在xml配置中是不要處理的位喂,會在解析xml對時候就處理了浪耘。

到此doscan已經完成,此時所有對注解對bean都被掃描到了塑崖,但是還沒有初始化七冲,接下來的方法registerComponents很重要,網上資料說<context :component-scan>標簽有了就不需要<context :annotation-config>规婆,包含進去了澜躺,具體實現就在這個方法中:

protected void registerComponents(
      XmlReaderContext readerContext, Set<BeanDefinitionHolder> beanDefinitions, Element element) {

   Object source = readerContext.extractSource(element);
   CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), source);

   for (BeanDefinitionHolder beanDefHolder : beanDefinitions) {
      compositeDef.addNestedComponent(new BeanComponentDefinition(beanDefHolder));
   }

   // Register annotation config processors, if necessary.
   boolean annotationConfig = true;
   if (element.hasAttribute(ANNOTATION_CONFIG_ATTRIBUTE)) {
      annotationConfig = Boolean.parseBoolean(element.getAttribute(ANNOTATION_CONFIG_ATTRIBUTE));
   }
   if (annotationConfig) {
      Set<BeanDefinitionHolder> processorDefinitions =
            AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
      for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
         compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));
      }
   }

   readerContext.fireComponentRegistered(compositeDef);
}

前面的compositeDef先不用管,直接看到annotationConfig抒蚜,默認這個配置是true掘鄙,那么就會執(zhí)行AnnotationConfigUtils.registerAnnotationConfigProcessors,這個方法比較長嗡髓,但是做對事情比較簡單操漠,就是把ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor饿这、CommonAnnotationBeanPostProcessor(JSR-250)等processor加進來浊伙,這幾個類ConfigurationClassPostProcessor-----處理@Configuration注解;AutowiredAnnotationBeanPostProcessor-----處理Autowired长捧、value嚣鄙、inject注解;CommonAnnotationBeanPostProcessor----處理JSR-250標準對注解唆姐,比如說我們用的@Resource注解拗慨。<context :annotation-config>這個注解對應對parser類就不再分析類廓八,核心功能就是上面這個方法奉芦。

小結

回顧整個component-scan的流程,首先是我們在解析xml中剧蹂,發(fā)現了有自定義的標簽了声功,然后從用resolver解析器找到這個標簽對應的namespaceHandler,這個namespaceHandler是保存在map中宠叼,初始化是通過SPI方式加載進來的(namespace-handler配置)先巴。找到這個namespaceHandler后其爵,解析標簽,找到ComponentScanBeanDefinitionParser解析類伸蚯,這個類就會根據component-scan中配置的basePackage來掃描對應的class類摩渺,把有注解@Component的類作為候選bean,處理下這些類上的其他的類注解:比如是否懶加載剂邮、是否有依賴摇幻、是否有描述等等。處理好了后就把這些beandefinition注冊到beanfactory中挥萌,最后再添加@Configuration绰姻、@Autowire 的注解處理器。這樣這個scan流程就完成了引瀑。

所以可以知道xml中定義的bean跟@Component注解的bean在構建beanfactory的時候就已經加載到beanfactory中狂芋,但是@Configuration注解的類以及類里面@Bean注解的方法此時還沒有加載,以及每個bean中的IOC都沒有做憨栽,這些事情是在后面調用

小結

到這里此時完成了方法obtainFreshBeanFactory()帜矾,僅僅把所有的xml中定義的bean以及@Component注解的bean都已經加載到beanfatcory中了,流程比較清晰屑柔,先創(chuàng)建一個默認的beanfactory黍特,然后把指定location的resource給加載解析,從xml中分析出bean對象來锯蛀,注冊到beanfactory中灭衷,這里的beandefinition是無差別的,不管是普通的bean旁涤,還是factorybean翔曲,還是各種processor。

beanfactory后置處理----invokeBeanFactoryPostProcessors

此時的bean還是一個beanDefinition對象劈愚,沒有初始化瞳遍,只是做了構造創(chuàng)建。接下來prepareBeanFactory菌羽、postProcessBeanFactory做了初步配置掠械,暫時不做分析,下面是invokeBeanFactoryPostProcessors方法注祖,這個是spring的非常核心的一個方法調用猾蒂,很多的業(yè)務定制都在這里完成的,比如說我們的@Configuration是晨。這個方法是調用所有beanfactoryPostProcessor肚菠,執(zhí)行對應的postProcessBeanFactory方法。

spring提供了beanfactoryPostProcessor接口罩缴,這個是spring在加載beandefinition后蚊逢,初始化bean前层扶,做的操作,用來給給我們對beanfactory中的beandefinition做一些定制烙荷。另外還有一個BeanDefinitionRegistryPostProcessor接口镜会,這個接口用來給業(yè)務做自定義的beandefinition的注冊

這個里面主要是用到對應的代理方法:PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors,這個方法很長终抽,逐步來分析

public static void invokeBeanFactoryPostProcessors(
      ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
   // Invoke BeanDefinitionRegistryPostProcessors first, if any.
   Set<String> processedBeans = new HashSet<String>();

   if (beanFactory instanceof BeanDefinitionRegistry) {
      BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
      List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>();
      List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList<BeanDefinitionRegistryPostProcessor>();

      for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
         if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
            BeanDefinitionRegistryPostProcessor registryProcessor =
                  (BeanDefinitionRegistryPostProcessor) postProcessor;
            registryProcessor.postProcessBeanDefinitionRegistry(registry);
            registryProcessors.add(registryProcessor);
         }
         else {
            regularPostProcessors.add(postProcessor);
         }
      }
   // Do not initialize FactoryBeans here: We need to leave all regular beans
   // uninitialized to let the bean factory post-processors apply to them!
   // Separate between BeanDefinitionRegistryPostProcessors that implement
   // PriorityOrdered, Ordered, and the rest.
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();

    // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
    if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
        currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
        processedBeans.add(ppName);
    }
} 
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
       稚叹。。拿诸。

這個方法很長扒袖,干的事情很清晰,就是把spring容器中BeanFactoryPostProcessor類型的bean單獨拿出來處理這個流程整理如下:

  1. 從beanfactory中取出類型BeanDefinitionRegistryPostProcessor的beandefinistion列表
  2. 過濾出實現接口PriorityOrdered的Processors,然后排序
  3. 執(zhí)行這些BeanDefinitionRegistryPostProcessors的postProcessBeanDefinitionRegistry方法
  4. 重新從beanfactory中取出類型BeanDefinitionRegistryPostProcessor的beandefinistion列表
  5. 過濾出實現接口Ordered的Processors,然后排序
  6. 執(zhí)行這些BeanDefinitionRegistryPostProcessors的postProcessBeanDefinitionRegistry方法
  7. 重新從beanfactory中取出類型BeanDefinitionRegistryPostProcessor的beandefinistion列表
  8. 執(zhí)行這些BeanDefinitionRegistryPostProcessors的postProcessBeanDefinitionRegistry方法
  9. 執(zhí)行上面這些BeanDefinitionRegistryPostProcessors的postProcessBeanFactory方法
  10. 從beanfactory中取出類型BeanFactoryPostProcessor的beandefinistion列表
  11. 按照上面的順序從PriorityOrdered买鸽、Ordered、普通的三種順序來執(zhí)行對應的postProcessBeanFactory

說明1:對于步驟4跟步驟7飒泻,需要重新從beanfactory中獲取beandefinistion列表是因為前面每一次操作都可能會創(chuàng)建新的BeanDefinitionRegistryPostProcessor的beandefinition,所以需要重新獲取

說明2:每次處理低優(yōu)先級的processor時吏廉,都會去檢查已處理列表泞遗,避免被多次執(zhí)行。

這樣整理下流程就比較清晰席覆。前面在處理自定義標簽<context>的時候史辙,在對應的namespaceHandler里面,doScan的時候佩伤,我們注冊了三個processor聊倔,其中有一個是ConfigurationClassPostProcessor,這個是處理@Configuration的生巡,以這個為例分析下BeanDefinitionRegistryPostProcessor的具體處理過程

BeanDefinitionRegistryPostProcessor處理分析----ConfigurationClassPostProcessor

ConfigurationClassPostProcessor是用來處理@Configurtaion的耙蔑,看下對應的處理方法

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
   int registryId = System.identityHashCode(registry);
   if (this.registriesPostProcessed.contains(registryId)) {
      throw new IllegalStateException(
            "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
   }
   if (this.factoriesPostProcessed.contains(registryId)) {
      throw new IllegalStateException(
            "postProcessBeanFactory already called on this post-processor against " + registry);
   }
   this.registriesPostProcessed.add(registryId);
   processConfigBeanDefinitions(registry);
}
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
        List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
        String[] candidateNames = registry.getBeanDefinitionNames();
         // 1、從所有的候選的bean中孤荣,篩選出@Configuration注解的bean
        for (String beanName : candidateNames) {
            BeanDefinition beanDef = registry.getBeanDefinition(beanName);
            if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
                }
            }
            else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
                configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
            }
        }
        // Return immediately if no @Configuration classes were found
        if (configCandidates.isEmpty()) {
            return;
        }
        // Sort by previously determined @Order value, if applicable
        configCandidates.sort((bd1, bd2) -> {
            int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
            int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
            return Integer.compare(i1, i2);
        });
        // Detect any custom bean name generation strategy supplied through the enclosing application context
        SingletonBeanRegistry sbr = null;
        if (registry instanceof SingletonBeanRegistry) {
            sbr = (SingletonBeanRegistry) registry;
            if (!this.localBeanNameGeneratorSet) {
                BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
                        AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
                if (generator != null) {
                    this.componentScanBeanNameGenerator = generator;
                    this.importBeanNameGenerator = generator;
                }
            }
        }
        if (this.environment == null) {
            this.environment = new StandardEnvironment();
        }
        // Parse each @Configuration class
        ConfigurationClassParser parser = new ConfigurationClassParser(
                this.metadataReaderFactory, this.problemReporter, this.environment,
                this.resourceLoader, this.componentScanBeanNameGenerator, registry);

        Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
        Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
        do {
            StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
            // 解析bean
            parser.parse(candidates);
            parser.validate();

            Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
            configClasses.removeAll(alreadyParsed);

            // Read the model and create bean definitions based on its content
            if (this.reader == null) {
                this.reader = new ConfigurationClassBeanDefinitionReader(
                        registry, this.sourceExtractor, this.resourceLoader, this.environment,
                        this.importBeanNameGenerator, parser.getImportRegistry());
            }
            this.reader.loadBeanDefinitions(configClasses);
            alreadyParsed.addAll(configClasses);
            processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();

            candidates.clear();
            if (registry.getBeanDefinitionCount() > candidateNames.length) {
                String[] newCandidateNames = registry.getBeanDefinitionNames();
                Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
                Set<String> alreadyParsedClasses = new HashSet<>();
                for (ConfigurationClass configurationClass : alreadyParsed) {
                    alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
                }
                for (String candidateName : newCandidateNames) {
                    if (!oldCandidateNames.contains(candidateName)) {
                        BeanDefinition bd = registry.getBeanDefinition(candidateName);
                        if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
                                !alreadyParsedClasses.contains(bd.getBeanClassName())) {
                            candidates.add(new BeanDefinitionHolder(bd, candidateName));
                        }
                    }
                }
                candidateNames = newCandidateNames;
            }
        }
        while (!candidates.isEmpty());
        // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
        if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
            sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
        }
        if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
            // Clear cache in externally provided MetadataReaderFactory; this is a no-op
            // for a shared cache since it'll be cleared by the ApplicationContext.
            ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
        }
    }
public static boolean checkConfigurationClassCandidate(
      BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
   String className = beanDef.getBeanClassName();
   if (className == null || beanDef.getFactoryMethodName() != null) {
      return false;
   }
   AnnotationMetadata metadata;
   if (beanDef instanceof AnnotatedBeanDefinition &&
         className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
      // Can reuse the pre-parsed metadata from the given BeanDefinition...
      metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
   }
   else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
      // Check already loaded Class if present...
      // since we possibly can't even load the class file for this Class.
      Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
      if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
            BeanPostProcessor.class.isAssignableFrom(beanClass) ||
            AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
            EventListenerFactory.class.isAssignableFrom(beanClass)) {
         return false;
      }
      metadata = AnnotationMetadata.introspect(beanClass);
   }
   else {
      try {
         MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
         metadata = metadataReader.getAnnotationMetadata();
      }
      catch (IOException ex) {
         if (logger.isDebugEnabled()) {
            logger.debug("Could not find class file for introspecting configuration annotations: " +
                  className, ex);
         }
         return false;
      }
   }
   Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
   if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
      beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
   }
   else if (config != null || isConfigurationCandidate(metadata)) {
      beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
   }
   else {
      return false;
   }
   // It's a full or lite configuration candidate... Let's determine the order value, if any.
   Integer order = getOrder(metadata);
   if (order != null) {
      beanDef.setAttribute(ORDER_ATTRIBUTE, order);
   }
   return true;
}
  1. 首先是從所有的beandefinition中獲取@configuration注解的bean甸陌,主要是方法ConfigurationClassUtils.checkConfigurationClassCandidate,這個檢查動作主要就是獲取bean的注解是否是@configuration盐股,是就作為注解類
  2. 將待處理的bean進行處理钱豁,處理流程主要是在doProcessConfigurationClass方法中完成, 在@Configurtaion中主要處理的事情:
  3. 處理內部類的注解(包含component遂庄,import寥院,configuration、@bean等等)涛目,這個是一個遞歸處理
  4. 處理@PropertySource 注解
  5. 處理@Component-scan注解
  6. 處理@import @importSource注解
  7. 處理@Bean注解秸谢,注意這里處理bean注解不是直接解析bean,而是把方法加入到beanMethod中霹肝,待后面處理

注意下估蹄,這里說的各種注解必須是在@Configuration注解下的,否則不會被處理沫换,這是因為這些注解的處理都是在處理@Configuration中處理的臭蚁。@PropertySource 是導入配置文件,configruationPlaceHolder就是處理各種PropertySource對象讯赏,@Import處理導入的對象為bean垮兑,@ImportSource處理導入的xml配置

這里有processMemberClasses的方法,可以看下源碼漱挎,因為是遞歸調用系枪。所以當我們內部類之間是循環(huán)導入的就會出現死循環(huán),報錯磕谅,一般很少出現這樣的問題私爷,而且有個問題待驗證:我們在component-scan的時候,會把類以及內部類都掃描到膊夹,如果有注解才會成bean衬浑,那么對于一個普通的含有內部類的bean,這里的內部類是否不需要再處理了放刨?因為已經被scan了工秩,只有是啟動springcontext的那個啟動類本身才需要處理內部類?這個待驗證

protected final SourceClass doProcessConfigurationClass(
      ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
      throws IOException {

   if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
      // Recursively process any member (nested) classes first
      processMemberClasses(configClass, sourceClass, filter);
   }

   // Process any @PropertySource annotations
   for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
         sourceClass.getMetadata(), PropertySources.class,
         org.springframework.context.annotation.PropertySource.class)) {
      if (this.environment instanceof ConfigurableEnvironment) {
         processPropertySource(propertySource);
      }
      else {
         logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
               "]. Reason: Environment must implement ConfigurableEnvironment");
      }
   }

   // Process any @ComponentScan annotations
   Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
         sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
   if (!componentScans.isEmpty() &&
         !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
      for (AnnotationAttributes componentScan : componentScans) {
         // The config class is annotated with @ComponentScan -> perform the scan immediately
         Set<BeanDefinitionHolder> scannedBeanDefinitions =
               this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
         // Check the set of scanned definitions for any further config classes and parse recursively if needed
         for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
            BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
            if (bdCand == null) {
               bdCand = holder.getBeanDefinition();
            }
            if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
               parse(bdCand.getBeanClassName(), holder.getBeanName());
            }
         }
      }
   }

   // Process any @Import annotations
   processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

   // Process any @ImportResource annotations
   AnnotationAttributes importResource =
         AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
   if (importResource != null) {
      String[] resources = importResource.getStringArray("locations");
      Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
      for (String resource : resources) {
         String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
         configClass.addImportedResource(resolvedResource, readerClass);
      }
   }

   // Process individual @Bean methods
   Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
   for (MethodMetadata methodMetadata : beanMethods) {
      configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
   }

   // Process default methods on interfaces
   processInterfaces(configClass, sourceClass);

   // Process superclass, if any
   if (sourceClass.getMetadata().hasSuperClass()) {
      String superclass = sourceClass.getMetadata().getSuperClassName();
      if (superclass != null && !superclass.startsWith("java") &&
            !this.knownSuperclasses.containsKey(superclass)) {
         this.knownSuperclasses.put(superclass, configClass);
         // Superclass found, return its annotation metadata and recurse
         return sourceClass.getSuperClass();
      }
   }

   // No superclass -> processing is complete
   return null;
}

bean的初始化--finishBeanFactoryInitialization

經過前面的beanfactorypostprocessor之后进统,當前spring容器的所有的bean都被加載到容器中拓诸,下面就需要進行實例化與初始化了,這部分的代碼會比較長麻昼。

public void preInstantiateSingletons() throws BeansException {
   if (logger.isTraceEnabled()) {
      logger.trace("Pre-instantiating singletons in " + this);
   }

   // Iterate over a copy to allow for init methods which in turn register new bean definitions.
   // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
   List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

   // Trigger initialization of all non-lazy singleton beans...
   for (String beanName : beanNames) {
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
      if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
         if (isFactoryBean(beanName)) {
            Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
            if (bean instanceof FactoryBean) {
               FactoryBean<?> factory = (FactoryBean<?>) bean;
               boolean isEagerInit;
               if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                  isEagerInit = AccessController.doPrivileged(
                        (PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
                        getAccessControlContext());
               }
               else {
                  isEagerInit = (factory instanceof SmartFactoryBean &&
                        ((SmartFactoryBean<?>) factory).isEagerInit());
               }
               if (isEagerInit) {
                  getBean(beanName);
               }
            }
         }
         else {
            getBean(beanName);
         }
      }
   }

   // Trigger post-initialization callback for all applicable beans...
   for (String beanName : beanNames) {
      Object singletonInstance = getSingleton(beanName);
      if (singletonInstance instanceof SmartInitializingSingleton) {
         StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
               .tag("beanName", beanName);
         SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
         if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
               smartSingleton.afterSingletonsInstantiated();
               return null;
            }, getAccessControlContext());
         }
         else {
            smartSingleton.afterSingletonsInstantiated();
         }
         smartInitialize.end();
      }
   }
}

上面的流程比較清楚奠支,總結流程如下:

  1. 獲取加載的beandefinition列表,獲取merged過后的beandefinition對象抚芦,getMergedLocalBeanDefinition方法下面重點分析
  2. 過濾出非抽象的倍谜,單例的,非懶加載的beandefinition進行初始化
  3. 判斷是否是factorybean叉抡,如果是尔崔,按照factorybean的方式處理,如果是普通的bean褥民,則調用getbean方式來初始化
  4. 過濾出實現SmartInitializingSingleton的bean季春,做一些初始化后的后置處理

這里面 有兩個核心方法:getMergedLocalBeanDefinition,getBean

bean的整理--getMergedLocalBeanDefinition

前面加載的beandefinition僅僅是定義了bean以及做了簡單的配置消返,有些bean需要合并些配置载弄,比如說父子bean對象耘拇,需要合并后才是一個完整的beandefinition

protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
   // Quick check on the concurrent map first, with minimal locking.
   RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
   if (mbd != null && !mbd.stale) {
      return mbd;
   }
   return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
protected RootBeanDefinition getMergedBeanDefinition(
            String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
            throws BeanDefinitionStoreException {
        synchronized (this.mergedBeanDefinitions) {
            RootBeanDefinition mbd = null;
            RootBeanDefinition previous = null;
            // Check with full lock now in order to enforce the same merged instance.
            if (containingBd == null) {
                mbd = this.mergedBeanDefinitions.get(beanName);
            }
            if (mbd == null || mbd.stale) {
                previous = mbd;
                if (bd.getParentName() == null) {
                    // Use copy of given root bean definition.
                    if (bd instanceof RootBeanDefinition) {
                        mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
                    }
                    else {
                        mbd = new RootBeanDefinition(bd);
                    }
                }
                else {
                    // Child bean definition: needs to be merged with parent.
                    BeanDefinition pbd;
                    try {
                        String parentBeanName = transformedBeanName(bd.getParentName());
                        if (!beanName.equals(parentBeanName)) {
                            pbd = getMergedBeanDefinition(parentBeanName);
                        }
                        else {
                            BeanFactory parent = getParentBeanFactory();
                            if (parent instanceof ConfigurableBeanFactory) {
                                pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
                            }
                            else {
                                throw new NoSuchBeanDefinitionException(parentBeanName,
                                        "Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
                                                "': cannot be resolved without a ConfigurableBeanFactory parent");
                            }
                        }
                    }
                    catch (NoSuchBeanDefinitionException ex) {
                        throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
                                "Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
                    }
                    // Deep copy with overridden values.
                    mbd = new RootBeanDefinition(pbd);
                    mbd.overrideFrom(bd);
                }

                // Set default singleton scope, if not configured before.
                if (!StringUtils.hasLength(mbd.getScope())) {
                    mbd.setScope(SCOPE_SINGLETON);
                }
                // A bean contained in a non-singleton bean cannot be a singleton itself.
                // Let's correct this on the fly here, since this might be the result of
                // parent-child merging for the outer bean, in which case the original inner bean
                // definition will not have inherited the merged outer bean's singleton status.
                if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
                    mbd.setScope(containingBd.getScope());
                }
                // Cache the merged bean definition for the time being
                // (it might still get re-merged later on in order to pick up metadata changes)
                if (containingBd == null && isCacheBeanMetadata()) {
                    this.mergedBeanDefinitions.put(beanName, mbd);
                }
            }
            if (previous != null) {
                copyRelevantMergedBeanDefinitionCaches(previous, mbd);
            }
            return mbd;
        }
    }

這個方法主要是處理那些不是完整的bean的,因為spring支持bean的繼承(類似我們把公共部分提取到parent中)宇攻,parent不支持實例化惫叛,子bean不能直接實例化,所以才有這個方法的逞刷,看下方法的邏輯

  1. 從spring容器beandefinitionMap中根據這個beanName獲取beandefinition嘉涌。
  2. 檢查這個beandefinition是否有parentdefinition,如果沒有夸浅,則說明這個bean就是一個完整的beandefinition仑最,直接將其轉換成RootBeanDefinition。
  3. 如果這個bean有parentdefinition帆喇,則遞歸去獲取parentbeandefinition警医,然后將子beandefinition 與其合并,調用overrideFrom方法完成番枚。

到此法严,所有的bean都是完整的了。

bean初始化與獲取----getBean

spring容器中葫笼,不管是factorybean還是普通的bean深啤,都是通過方法getBean來進行初始化的。這個方法非常長路星,可以分段分析

protected <T> T doGetBean(
      String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
      throws BeansException {

   String beanName = transformedBeanName(name);
   Object bean;

   // Eagerly check singleton cache for manually registered singletons.
   Object sharedInstance = getSingleton(beanName);
   if (sharedInstance != null && args == null) {
      if (logger.isTraceEnabled()) {
         if (isSingletonCurrentlyInCreation(beanName)) {
            logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                  "' that is not fully initialized yet - a consequence of a circular reference");
         }
         else {
            logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
         }
      }
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }

首先是transformedBeanName溯街,這個是獲取bean的Name,在spring中洋丐,對于factorybean呈昔,beanname是有前綴&的,這個方法就是把這個&給過濾掉友绝。然后getSingleton方法從map中獲取這個bean堤尾,因為我們此時初始化bean是單例的,非單例不在這里初始化迁客,獲取的時候優(yōu)先從這個map中獲取郭宝,沒有才考慮去創(chuàng)建。如果map中有的話掷漱,直接去取粘室,但是bean有兩種,一種是factorybean卜范,一種是普通bean衔统,兩種bean的獲取方式是不一樣的,進入這個方法看下具體的實現getObjectForBeanInstance

protected Object getObjectForBeanInstance(
      Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

   // Don't let calling code try to dereference the factory if the bean isn't a factory.
   if (BeanFactoryUtils.isFactoryDereference(name)) {
      if (beanInstance instanceof NullBean) {
         return beanInstance;
      }
      if (!(beanInstance instanceof FactoryBean)) {
         throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
      }
      if (mbd != null) {
         mbd.isFactoryBean = true;
      }
      return beanInstance;
   }

   // Now we have the bean instance, which may be a normal bean or a FactoryBean.
   // If it's a FactoryBean, we use it to create a bean instance, unless the
   // caller actually wants a reference to the factory.
   if (!(beanInstance instanceof FactoryBean)) {
      return beanInstance;
   }

   Object object = null;
   if (mbd != null) {
      mbd.isFactoryBean = true;
   }
   else {
      object = getCachedObjectForFactoryBean(beanName);
   }
   if (object == null) {
      // Return bean instance from factory.
      FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
      // Caches object obtained from FactoryBean if it is a singleton.
      if (mbd == null && containsBeanDefinition(beanName)) {
         mbd = getMergedLocalBeanDefinition(beanName);
      }
      boolean synthetic = (mbd != null && mbd.isSynthetic());
      object = getObjectFromFactoryBean(factory, beanName, !synthetic);
   }
   return object;
}
  1. 這個方法,首先是用BeanFactoryUtils.isFactoryDereference(name)判斷是否是factorybean锦爵,如果是以&開頭舱殿,則必須是factorybean(但是這里注意下并不是所有的factorybean的name都是以&開頭,對于不去顯示配置beanname的bean棉浸,spring會給他分配一個beanname怀薛,以&開頭)刺彩,然后直接返回這個bean迷郑;
  2. 如果查詢的name是一個普通的name,對應的bean可能也是factorybean创倔,如果是普通的bean嗡害,那么就直接返回
  3. 如果是一個factorybean,先從對應的緩存加載畦攘,如果緩存沒有霸妹,則直接從factorybean中創(chuàng)建

factorybean創(chuàng)建bean

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
   if (factory.isSingleton() && containsSingleton(beanName)) {
      synchronized (getSingletonMutex()) {
         Object object = this.factoryBeanObjectCache.get(beanName);
         if (object == null) {
            object = doGetObjectFromFactoryBean(factory, beanName);
            // Only post-process and store if not put there already during getObject() call above
            // (e.g. because of circular reference processing triggered by custom getBean calls)
            Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
            if (already There != null) {
               object = alreadyThere;
            }
            else {
               if (shouldPostProcess) {
                  if (isSingletonCurrentlyInCreation(beanName)) {
                     // Temporarily return non-post-processed object, not storing it yet..
                     return object;
                  }
                  beforeSingletonCreation(beanName);
                  try {
                     object = postProcessObjectFromFactoryBean(object, beanName);
                  }
                  catch (Throwable ex) {
                     throw new BeanCreationException(beanName,
                           "Post-processing of FactoryBean's singleton object failed", ex);
                  }
                  finally {
                     afterSingletonCreation(beanName);
                  }
               }
               if (containsSingleton(beanName)) {
                  this.factoryBeanObjectCache.put(beanName, object);
               }
            }
         }
         return object;
      
   }
   else {
      Object object = doGetObjectFromFactoryBean(factory, beanName);
      if (shouldPostProcess) {
         try {
            object = postProcessObjectFromFactoryBean(object, beanName);
         }
         catch (Throwable ex) {
            throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
         }
      }
      return object;
   }
}
private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
        Object object;
        try {
            if (System.getSecurityManager() != null) {
                AccessControlContext acc = getAccessControlContext();
                try {
                    object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
                }
                catch (PrivilegedActionException pae) {
                    throw pae.getException();
                }
            }
            else {
                object = factory.getObject();
            }
        }
        catch (FactoryBeanNotInitializedException ex) {
            throw new BeanCurrentlyInCreationException(beanName, ex.toString());
        }
        catch (Throwable ex) {
            throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
        }

        // Do not accept a null value for a FactoryBean that's not fully
        // initialized yet: Many FactoryBeans just return null then.
        if (object == null) {
            if (isSingletonCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(
                        beanName, "FactoryBean which is currently in creation returned null from getObject");
            }
            object = new NullBean();
        }
        return object;
    }

代碼里面寫的很長,主要的工作就是getObject知押,從這個方法中獲取bean對象叹螟,對于factorybean本身,spring容器中也有對應bean台盯,但是獲取的時候罢绽,只會獲取對應的object對象

回到前面說的doGetbean方法的else部分,此時在緩存中并沒有對應的bean静盅,需要我們創(chuàng)建

else {
      // Fail if we're already creating this bean instance:
      // We're assumably within a circular reference.
      if (isPrototypeCurrentlyInCreation(beanName)) {
         throw new BeanCurrentlyInCreationException(beanName);
      }

      // Check if bean definition exists in this factory.
      BeanFactory parentBeanFactory = getParentBeanFactory();
      if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
         // Not found -> check parent.
         String nameToLookup = originalBeanName(name);
         if (parentBeanFactory instanceof AbstractBeanFactory) {
            return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                  nameToLookup, requiredType, args, typeCheckOnly);
         }
         else if (args != null) {
            // Delegation to parent with explicit args.
            return (T) parentBeanFactory.getBean(nameToLookup, args);
         }
         else if (requiredType != null) {
            // No args -> delegate to standard getBean method.
            return parentBeanFactory.getBean(nameToLookup, requiredType);
         }
         else {
            return (T) parentBeanFactory.getBean(nameToLookup);
         }
      }

      if (!typeCheckOnly) {
         markBeanAsCreated(beanName);
      }

      StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
            .tag("beanName", name);
      try {
         if (requiredType != null) {
            beanCreation.tag("beanType", requiredType::toString);
         }
         RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
         checkMergedBeanDefinition(mbd, beanName, args);

         // Guarantee initialization of beans that the current bean depends on.
         String[] dependsOn = mbd.getDependsOn();
         if (dependsOn != null) {
            for (String dep : dependsOn) {
               if (isDependent(beanName, dep)) {
                  throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
               }
               registerDependentBean(dep, beanName);
               try {
                  getBean(dep);
               }
               catch (NoSuchBeanDefinitionException ex) {
                  throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
               }
            }
         }

         // Create bean instance.
         if (mbd.isSingleton()) {
            sharedInstance = getSingleton(beanName, () -> {
               try {
                  return createBean(beanName, mbd, args);
               }
               catch (BeansException ex) {
                  // Explicitly remove instance from singleton cache: It might have been put there
                  // eagerly by the creation process, to allow for circular reference resolution.
                  // Also remove any beans that received a temporary reference to the bean.
                  destroySingleton(beanName);
                  throw ex;
               }
            });
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
         }

         else if (mbd.isPrototype()) {
            // It's a prototype -> create a new instance.
            Object prototypeInstance = null;
            try {
               beforePrototypeCreation(beanName);
               prototypeInstance = createBean(beanName, mbd, args);
            }
            finally {
               afterPrototypeCreation(beanName);
            }
            bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
         }

         else {
            String scopeName = mbd.getScope();
            if (!StringUtils.hasLength(scopeName)) {
               throw new IllegalStateException("No scope name defined for bean ′" + beanName + "'");
            }
            Scope scope = this.scopes.get(scopeName);
            if (scope == null) {
               throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
            }
            try {
               Object scopedInstance = scope.get(beanName, () -> {
                  beforePrototypeCreation(beanName);
                  try {
                     return createBean(beanName, mbd, args);
                  }
                  finally {
                     afterPrototypeCreation(beanName);
                  }
               });
               bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
            }
            catch (IllegalStateException ex) {
               throw new ScopeNotActiveException(beanName, scopeName, ex);
            }
         }
      }
      catch (BeansException ex) {
         beanCreation.tag("exception", ex.getClass().toString());
         beanCreation.tag("message", String.valueOf(ex.getMessage()));
         cleanupAfterBeanCreationFailure(beanName);
         throw ex;
      }
      finally {
         beanCreation.end();
      }
   }

   // Check if required type matches the type of the actual bean instance.
   if (requiredType != null && !requiredType.isInstance(bean)) {
      try {
         T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
         if (convertedBean == null) {
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
         }
         return convertedBean;
      }
      catch (TypeMismatchException ex) {
         if (logger.isTraceEnabled()) {
            logger.trace("Failed to convert bean '" + name + "' to required type '" +
                  ClassUtils.getQualifiedName(requiredType) + "'", ex);
         }
         throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
      }
   }
   return (T) bean;
}

上面的流程可以歸納為如下:

  1. 檢查這個beandefinition有沒有對應的parentfactory良价,如果有的話并且當前beanfactory中也沒有對應的beandifinition,就用對應的factory創(chuàng)建蒿叠。
  2. 檢查當前獲取bean是否是檢查明垢,如果是則直接返回
  3. 檢查當前beandefinition的depend-on屬性,如果有以來市咽,則先實例化所有的依賴的bean
  4. 根據bean的屬性是否是單例調用對應的createbean方法來實例化bean痊银,然后再調用getObjectForBeanInstance來獲取bean。

核心的方法在于createbean方法

createbean

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {

   if (logger.isTraceEnabled()) {
      logger.trace("Creating instance of bean '" + beanName + "'");
   }
   RootBeanDefinition mbdToUse = mbd;

   // Make sure bean class is actually resolved at this point, and
   // clone the bean definition in case of a dynamically resolved Class
   // which cannot be stored in the shared merged bean definition.
   Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
   if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
      mbdToUse = new RootBeanDefinition(mbd);
      mbdToUse.setBeanClass(resolvedClass);
   }

   // Prepare method overrides.
   try {
      mbdToUse.prepareMethodOverrides();
   }
   catch (BeanDefinitionValidationException ex) {
      throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
            beanName, "Validation of method overrides failed", ex);
   }

   try {
      // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
      Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
      if (bean != null) {
         return bean;
      }
   }
   catch (Throwable ex) {
      throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
            "BeanPostProcessor before instantiation of bean failed", ex);
   }

   try {
      Object beanInstance = doCreateBean(beanName, mbdToUse, args);
      if (logger.isTraceEnabled()) {
         logger.trace("Finished creating instance of bean '" + beanName + "'");
      }
      return beanInstance;
   }
   catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
      // A previously detected exception with proper bean creation context already,
      // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
      throw ex;
   }
   catch (Throwable ex) {
      throw new BeanCreationException(
            mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
   }
}
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {

        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }

        // Allow post-processors to modify the merged bean definition.
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "Post-processing of merged bean definition failed", ex);
                }
                mbd.postProcessed = true;
            }
        }

        // Eagerly cache singletons to be able to resolve circular references
        // even when triggered by lifecycle interfaces like BeanFactoryAware.
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            if (logger.isTraceEnabled()) {
                logger.trace("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
            populateBean(beanName, mbd, instanceWrapper);
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                throw (BeanCreationException) ex;
            }
            else {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
            }
        }

        if (earlySingletonExposure) {
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                }
                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    String[] dependentBeans = getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
                    for (String dependentBean : dependentBeans) {
                        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }
                    if (!actualDependentBeans.isEmpty()) {
                        throw new BeanCurrentlyInCreationException(beanName,
                                "Bean with name '" + beanName + "' has been injected into other beans [" +
                                StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                                "] in its raw version as part of a circular reference, but has eventually been " +
                                "wrapped. This means that said other beans do not use the final version of the " +
                                "bean. This is often the result of over-eager type matching - consider using " +
                                "'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }

        // Register bean as disposable.
        try {
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
        }

        return exposedObject;
    }

整個創(chuàng)建bean的流程還是比較清晰的施绎,主要流程如下:

  1. 首先檢查容器中是否有InstantiationAwareBeanPostProcessor溯革,這個接口的實現類是用來給我們提供一個拓展能力,進行定制bean粘姜,查看這個接口可以自定義往容器中添加bean鬓照,這個是spring在實例化bean之前,最后一次修改bean的機會孤紧。
  2. 實例化bean豺裆,可以是根據構造函數創(chuàng)建,也可以是工廠方法創(chuàng)建
  3. 獲取MergedBeanDefinitionPostProcessor實例,應用到該bean實例上臭猜,比如說我們的@PostConstructor的解析躺酒,@Resource,@Autowire 在這個階段都有處理蔑歌,注意這里只是做簡單的檢驗等處理羹应,并沒有解析。
  4. populateBean次屠,這個階段處理的事情主要是bean的屬性設置园匹,包括xml中配置的屬性設置,@Autowire方法的注入就是在這里做的劫灶,下面會分析源碼裸违。
  5. initializebean,初始化bean本昏,這里主要包括Aware接口的調用供汛,@PostConstruct初始化方法,InitializeBean接口的方法涌穆,xml中配置的init的處理方法怔昨。

先看下populateBean這個方法的源碼

populateBean

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
   if (bw == null) {
      if (mbd.hasPropertyValues()) {
         throw new BeanCreationException(
               mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
      }
      else {
         // Skip property population phase for null instance.
         return;
      }
   }

   // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
   // state of the bean before properties are set. This can be used, for example,
   // to support styles of field injection.
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
         if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
            return;
         }
      }
   }

   PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

   int resolvedAutowireMode = mbd.getResolvedAutowireMode();
   if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
      MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
      // Add property values based on autowire by name if applicable.
      if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
         autowireByName(beanName, mbd, bw, newPvs);
      }
      // Add property values based on autowire by type if applicable.
      if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
         autowireByType(beanName, mbd, bw, newPvs);
      }
      pvs = newPvs;
   }

   boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
   boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

   PropertyDescriptor[] filteredPds = null;
   if (hasInstAwareBpps) {
      if (pvs == null) {
         pvs = mbd.getPropertyValues();
      }
      for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
         PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
         if (pvsToUse == null) {
            if (filteredPds == null) {
               filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            }
            pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
               return;
            }
         }
         pvs = pvsToUse;
      }
   }
   if (needsDepCheck) {
      if (filteredPds == null) {
         filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
      }
      checkDependencies(beanName, mbd, filteredPds, pvs);
   }

   if (pvs != null) {
      applyPropertyValues(beanName, mbd, bw, pvs);
   }
}
  1. 先處理InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation,這個方法就是用來處理當前的bean的實例化有沒有完成宿稀,如果完成了趁舀,那么就直接返回,目前還沒有什么實現類做這個原叮;
  2. 然后是根據Autowiredmode來處理赫编,這里我們代碼調試mode為AUTOWIRE_NO=0,什么意思呢奋隶,就是不會自動注入擂送,但是顯示的@Autowire方式還是會注入的。這里涉及到一個知識點就是AutowireCapableBeanFactory唯欣,默認的我們的bean的注入會根據bean中有@Autowire的時候會自動注入進來嘹吨,沒有這個注解的話,我們獲取的bean中需要被注入的對象就是null境氢,這個很好理解:A中依賴注入B蟀拷,必須要顯示在屬性B對象上設置@Autowire,這樣我們getbean A的時候里面的屬性B才有萍聊,如果沒有這個顯示注解问芬,屬性B是null,但是如果我們getbean的方法換一種的話寿桨,我們是可以人為的幫A注入B對象此衅,AutowireCapableBeanFactory beanFactory = context.getAutowireCapableBeanFactory();
    A a = (A) beanFactory.autowire(A.class, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false); B b = a.getB();這樣就獲取到B屬性了强戴。通過這種方式,可以人為的給A這個bean注入屬性B了挡鞍。
  3. 然后就是處理它的postProcessProperties方法骑歹,這個方法處理的就包含@Autowire的注入,而且還包含一些屬性的設置墨微,比如我們在xml中配置的屬性值初始化道媚,就是在這里完成的。

populatebean方法完成后翘县,我們的依賴注入就完成了最域,前面createbean方法我們創(chuàng)建了bean對象,這里又設置了初始化屬性值以及IOC依賴注入炼蹦,接下來就是初始化這個bean了

initializeBean

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
   if (System.getSecurityManager() != null) {
      AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
         invokeAwareMethods(beanName, bean);
         return null;
      }, getAccessControlContext());
   }
   else {
      invokeAwareMethods(beanName, bean);
   }

   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }

   try {
      invokeInitMethods(beanName, wrappedBean, mbd);
   }
   catch (Throwable ex) {
      throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
   }
   if (mbd == null || !mbd.isSynthetic()) {
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }

   return wrappedBean;
}

對于這個方法羡宙,不過多的講細節(jié)了狸剃,注意下流程

  1. 首先是invokeAwareMethods方法調用掐隐,這個方法就是我們一系列的Aware接口,比如我們BeanNameAware钞馁,ApplicationContextAware就是在這個環(huán)節(jié)做的
  2. 然后是applyBeanPostProcessorsBeforeInitialization虑省,這個是把所有的BeanPostProcessor里面的postProcessBeforeInitialization執(zhí)行一遍,我們的@PostConstruct注解就是屬于CommonAnnotationBeanPostProcessor這個processor然后被處理的
  3. 然后是invokeInitMethods僧凰,這個方法里面包含兩部分探颈,首先根據當前的bean有沒有實現InitializingBean這個接口,如果實現了就會去執(zhí)行這個接口的afterPropertiesSet方法進行初始化训措;然后再獲取自定義的初始化方法伪节,比如我們在xml中指定的init-Method方法,就會在這里被找出來绩鸣。

所以我們這個的初始化流程就是

  1. 構造函數
  2. IOC依賴注入
  3. 初始化屬性設置
  4. Aware鉤子函數
  5. @PostConstruct注解初始化函數
  6. afterPropertiesSet初始化方法執(zhí)行
  7. init-Method初始化方法執(zhí)行怀大。

到此,我們的spring的初始化流程講完呀闻。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末化借,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子捡多,更是在濱河造成了極大的恐慌蓖康,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件垒手,死亡現場離奇詭異蒜焊,居然都是意外死亡,警方通過查閱死者的電腦和手機科贬,發(fā)現死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門泳梆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事鸭丛【呵睿” “怎么了?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵鳞溉,是天一觀的道長瘾带。 經常有香客問我,道長熟菲,這世上最難降的妖魔是什么看政? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮抄罕,結果婚禮上允蚣,老公的妹妹穿的比我還像新娘。我一直安慰自己呆贿,他們只是感情好嚷兔,可當我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著做入,像睡著了一般冒晰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上竟块,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天壶运,我揣著相機與錄音,去河邊找鬼浪秘。 笑死蒋情,一個胖子當著我的面吹牛,可吹牛的內容都是我干的耸携。 我是一名探鬼主播棵癣,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼违帆!你這毒婦竟也來了浙巫?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤刷后,失蹤者是張志新(化名)和其女友劉穎的畴,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體尝胆,經...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡丧裁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了含衔。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片煎娇。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡二庵,死狀恐怖,靈堂內的尸體忽然破棺而出缓呛,到底是詐尸還是另有隱情催享,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布哟绊,位于F島的核電站因妙,受9級特大地震影響,放射性物質發(fā)生泄漏票髓。R本人自食惡果不足惜攀涵,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望洽沟。 院中可真熱鬧以故,春花似錦、人聲如沸裆操。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽跷车。三九已至棘利,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間朽缴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工水援, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留密强,地道東北人。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓蜗元,卻偏偏與公主長得像或渤,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子奕扣,可洞房花燭夜當晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內容