拒絕作菜dog——初探Spring源碼

1、前言

    話說最近我們組瘋狂招人中,組裏的幾位資深大佬在瘋狂面試,從早到晚就是在語音和視頻,昨晚要加班,下樓跟大手子們去吃飯,聊起面試狀況,一位大佬VV哥開始瘋狂輸出:「我這面試一天,基本上沒幾個能把Spring的加載過程說清楚的,基本上一問就支支吾吾,如今這API調用工程師太多了」,另外一位大佬髒髒哥瘋狂附和,我在一邊聽到流下了沒有技術的「冷汗」,這......不就是說的我嘛,天天寫寫業務代碼,調調接口,寫寫SQL,搞搞TestCase,屬實是最底層的搬磚工,瘋狂扒拉兩口飯,立馬逃離大型審判現場,跑到工位坐下開始 看!源!碼!整活~菜狗要翻身!前端

2、體系

   那其實講到Spring,咱們能夠這麼看:java

   由於Spring 最初利用「工廠模式」( DI )和「代理模式」( AOP )解耦應用組件。你們以爲挺好用,因而按照這種模式搞了一個 MVC 框架(一些用 Spring 解耦的組件),用開發 web 應用( SpringMVC)。而後呢,又發現每次開發都要搞不少依賴,寫不少樣板代碼很麻煩,那就很煩躁了,因而乎大牛們就搞了一些懶人整合包( starter ),這套玩意就是 Spring Boot ,具體介紹以下:
web

  1. Spring是一個一站式的輕量級的java開發框架,核心是控制反轉(IOC)和麪向切面(AOP),針對於開發的WEB層(springMvc)、業務層(Ioc)、持久層(jdbcTemplate)等都提供了多種配置解決方案;  
  2. SpringMVC是spring基礎之上的一個MVC框架,主要處理web開發的路徑映射和視圖渲染,涵蓋麪包括前端視圖開發、文件配置、後臺接口邏輯開發等,XML、config等配置相對比較繁瑣複雜,屬於spring框架中WEB層開發的一部分;,
  3. Spring Boot使用了默認大於配置的理念,集成了快速開發的Spring多個插件,同時自動過濾不須要配置的多餘的插件,簡化了項目的開發配置流程,必定程度上取消xml配置,是一套快速配置開發的腳手架,能快速開發單個微服務;

3、開搞開搞

     廢話很少說了,如今就跟你們來一次對Spring的源碼追蹤一波,本菜狗今天就要看一看Spring究竟是怎麼進行的初始化的,它如何建立的bean,咱們此次就從spring-boot-1.5.13進行追蹤一步步往下看吧;
面試

1.默認的spring啓動器,直接從這個地兒進去,沒毛病:spring

public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}複製代碼

2.下面的代碼 new SpringApplication(sources).run(args) 建立了一個SpringApplication,執行了一個run方法,返回的是一個ConfigurableApplicationContext,這只是一個接口,根據他的命名來看的話,是一個可配置的應用上下文對象;緩存

下面的run方面看起來就是咱們要看的重點吧?Emmmm....不慌不慌,繼續往下點就完事了;bash

/**
 * Static helper that can be used to run a {@link SpringApplication} from the
 * specified source using default settings.
 * @param source the source to load
 * @param args the application arguments (usually passed from a Java main method)
 * @return the running {@link ApplicationContext}
 */
   public static ConfigurableApplicationContext run(Object source, String... args) {
   return run(new Object[] { source }, args);
}

/**
 * Static helper that can be used to run a {@link SpringApplication} from the
 * specified sources using default settings and user supplied arguments.
 * @param sources the sources to load
 * @param args the application arguments (usually passed from a Java main method)
 * @return the running {@link ApplicationContext}
 */
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
   return new SpringApplication(sources).run(args);
}複製代碼

3.進去run方法後,哦豁,這一大堆玩意兒,也不知道這都是些啥,哎,硬着頭皮往下看吧,衝!兄弟們!app

/**
 * Run the Spring application, creating and refreshing a new
 * {@link ApplicationContext}.
 * @param args the application arguments (usually passed from a Java main method)
 * @return a running {@link ApplicationContext}
 */
public ConfigurableApplicationContext run(String... args) {
   StopWatch stopWatch = new StopWatch();
   stopWatch.start();
   ConfigurableApplicationContext context = null;
   FailureAnalyzers analyzers = null;
   configureHeadlessProperty();
   SpringApplicationRunListeners listeners = getRunListeners(args);
   listeners.starting();
   try {
       //參數封裝,在命令行下啓動應用帶的參數
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(
            args);
       //
      ConfigurableEnvironment environment = prepareEnvironment(listeners,
            applicationArguments);
      Banner printedBanner = printBanner(environment);
      context = createApplicationContext();
      analyzers = new FailureAnalyzers(context);
      prepareContext(context, environment, listeners, applicationArguments,
            printedBanner);
      refreshContext(context);
      afterRefresh(context, applicationArguments);
      listeners.finished(context, null);
      stopWatch.stop();
      if (this.logStartupInfo) {
         new StartupInfoLogger(this.mainApplicationClass)
               .logStarted(getApplicationLog(), stopWatch);
      }
      return context;
   }
   catch (Throwable ex) {
      handleRunFailure(context, listeners, analyzers, ex);
      throw new IllegalStateException(ex);
   }
}複製代碼

3.嗨呀,乍一看好像也就這麼些東西,核心的東西都在try{}裏面,咱們一個個看,前面幾行就是獲取args參數和準備獲取一些環境配置的東西,問題不大;
框架

ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
 ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);複製代碼

4.接下來,嘿,好傢伙,開始建立context對象了,看到context = createApplicationContext這行;less

context = createApplicationContext();複製代碼

而後進入,由於咱們剛剛在建立ConfigurableApplicationContext時並無給 context賦值,因此此時context = null,那麼便會建立指定的兩個applicationContext中的一個,返回一個剛剛建立的context,這個context即是咱們的基礎,由於我們如今爲web環境,因此建立的context爲 AnnotationConfigEmbeddedWebApplicationContext

protected ConfigurableApplicationContext createApplicationContext() {
   Class<?> contextClass = this.applicationContextClass;
   if (contextClass == null) {
      try {
         contextClass = Class.forName(this.webEnvironment
               ? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
      }
      catch (ClassNotFoundException ex) {
         throw new IllegalStateException(
               "Unable create a default ApplicationContext, "
                     + "please specify an ApplicationContextClass",
               ex);
      }
   }
   return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
}

public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework."
      + "boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext";

private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
      "org.springframework.web.context.ConfigurableWebApplicationContext" };
複製代碼

5.這些事幹完以後,就到了準備上下文了;

prepareContext(context, environment, listeners, applicationArguments,printedBanner);
複製代碼
private void prepareContext(ConfigurableApplicationContext context,
      ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
      ApplicationArguments applicationArguments, Banner printedBanner) {
 
    //設置context上下文的environment,簡單 設置環境相關的配置唄
   context.setEnvironment(environment);
    // 應用上下文後處理
   postProcessApplicationContext(context);
    //在context refresh以前,對其應用ApplicationContextInitializer
   applyInitializers(context);
   // 上下文準備(這個裏面是空實現,這是Spring預留擴展用的)
   listeners.contextPrepared(context);
    // 打印啓動日誌和啓動應用的Profile
   if (this.logStartupInfo) {
      logStartupInfo(context.getParent() == null);
      logStartupProfileInfo(context);
   }

   // Add boot specific singleton beans
   context.getBeanFactory().registerSingleton("springApplicationArguments",
         applicationArguments);
   if (printedBanner != null) {
      context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
   }

   // Load the sources
   Set<Object> sources = getSources();
   Assert.notEmpty(sources, "Sources must not be empty");
   load(context, sources.toArray(new Object[sources.size()]));
   listeners.contextLoaded(context);
}複製代碼

6.上面這些看無缺像也沒啥,接下來,重頭戲應該要來了吧;

refreshContext(context);複製代碼

這個方法好像有點狠,看着架勢是用來準備容器和刷新應用上下文的,我們點進去看看;

private void refreshContext(ConfigurableApplicationContext context) {
   refresh(context);
   if (this.registerShutdownHook) {
      try {
         context.registerShutdownHook();
      }
      catch (AccessControlException ex) {
         // Not allowed in some environments.
      }
   }
}複製代碼

誒,還有個方法,繼續點進去;

protected void refresh(ApplicationContext applicationContext) {
   Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
   ((AbstractApplicationContext) applicationContext).refresh();
}複製代碼

Emmmmm...乖乖,都是AbstractApplicationContext.class是這個玩意在從中做梗,我們繼續進去!衝!

PS:只要咱們進入了refresh(context)這個方法,無論進入哪個實現類,最終進入的都是AbstractApplicationContext.java這個類:

來到了咱們的核心,AbstractApplicationContext類,refresh方法就很貼心,裏面每一個方法幹了啥都有註釋,這就很舒服,減小了我們理解的難度(這時候坐我旁邊的粉粉同窗看到了就開始小聲bb:這英文註釋就很煩,在下立馬強勢回懟:快,趕忙裝個翻譯插件去,快,跑步前進~);

@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.
      //簡單的獲取beanFactory
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // Prepare the bean factory for use in this context.
      //將context中的一些屬性設置到beanFactory中 
      prepareBeanFactory(beanFactory);

      try {
         // Allows post-processing of the bean factory in context subclasses.
         //這個地方空實現,也沒幹啥,Spring預留的擴展
         postProcessBeanFactory(beanFactory);

         // Invoke factory processors registered as beans in the context.
         //解析配置文件、生成全部的beanDefinitions
         invokeBeanFactoryPostProcessors(beanFactory);

         // Register bean processors that intercept bean creation.
         //分類、排序、註冊(注入)全部的BeanPostProcessors,用於處理 bean 的初始化流程
         registerBeanPostProcessors(beanFactory);

         // Initialize message source for this context.
         //這玩意就是用來作國際化的
         initMessageSource();

         // Initialize event multicaster for this context.
         //註冊 applicationEventMulticaster SingletonBean
         initApplicationEventMulticaster();

         // Initialize other special beans in specific context subclasses.
         //這裏主要建立和初始化容器
         onRefresh();

         // Check for listener beans and register them.
        //檢查監聽器bean並註冊它們
         registerListeners();

         // Instantiate all remaining (non-lazy-init) singletons.
         //主要是初始化非懶加載單例
         finishBeanFactoryInitialization(beanFactory);

         // Last step: publish corresponding event.
         //大功告成,而後開啓Web容器
         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(); } } }複製代碼

上面這些代碼總結一波:

其實上面的方法中,咱們須要比較注意的地方有兩個,其實加載bean主要是在這兩個方法裏面取作的,咱們看代碼:

1.invokeBeanFactoryPostProcessors(beanFactory);

2.finishBeanFactoryInitialization(beanFactory);

咱們進入invokeBeanFactoryPostProcessors,而後繼續走着,找到這一行

PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());複製代碼

而後繼續在這個方法中找到

invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);複製代碼

進入到該方法內部裏面以後,有一個循環,進入內部方法 :

postProcessor.postProcessBeanDefinitionRegistry(registry)

此時傳入的registry就是咱們context中的beanfactory,由於其實現了BeanDefinitionRegistry接口,而此時的postProcessor實現類爲ConfigurationClassPostProcessor.java

/**
 * Derive further bean definitions from the configuration classes in the registry.
 */
@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);
}複製代碼

進入以後直接看最後面的一個方法,名稱爲processConfigBeanDefinitions(registry),翻譯一波就是用來配置beanDefinitions的流程。

OK,咱們繼續點進去,這裏代碼過於長,我們就不貼了8~~~(偷一波懶);

在processConfigBeanDefinitions(registry)裏,在301行代碼會獲取一個解析器,代碼以下:

ConfigurationClassParser parser = new ConfigurationClassParser(     --301行
      this.metadataReaderFactory, this.problemReporter, this.environment,
      this.resourceLoader, this.componentScanBeanNameGenerator, registry);複製代碼

parser.parse(candidates);  --308行複製代碼

而後308行會執行parser的parse方法,進入parse方法以後,會發現內層還有parse方法,沒關係,繼續進入內層的parse,而後發現有個for循環;

for (BeanDefinitionHolder holder : configCandidates) {
   BeanDefinition bd = holder.getBeanDefinition();
   try {
      if (bd instanceof AnnotatedBeanDefinition) {
         parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
      }
      else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
         parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
      }
      else {
         parse(bd.getBeanClassName(), holder.getBeanName());
      }
   }複製代碼
protected final void parse(String className, String beanName) throws IOException {
   MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
   processConfigurationClass(new ConfigurationClass(reader, beanName));
}

protected final void parse(Class<?> clazz, String beanName) throws IOException {
   processConfigurationClass(new ConfigurationClass(clazz, beanName));
}

protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
   processConfigurationClass(new ConfigurationClass(metadata, beanName));
}複製代碼

注意!這裏有3個parse方法,每一個方法裏面都執行了下面這個方法;

processConfigurationClass(new ConfigurationClass(metadata, beanName));
複製代碼

而後咱們繼續往下走,在processConfigurationClass(ConfigurationClass configClass)方法內,有一個do循環

do {
   sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}複製代碼

咱們繼續進去看看,這個時候,出現了許多咱們經常使用的註解,Spring會找到這些註解,並對它們進行解析。咱們看代碼:

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());
      }
   }
}複製代碼
Set<BeanDefinitionHolder> scannedBeanDefinitions =
      this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());複製代碼

進入 this.componentScanParser.parse,直接進入結尾的scannner.doScan

return scanner.doScan(StringUtils.toStringArray(basePackages));

而後就會開始掃描basePackages,並將掃描到的bean生成一個一個BeanDefinitionHolder,BeanDefinitionHolder中包含有咱們bean的一些相關信息、以及Spring賦予其的額外信息

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);
      }
   }
}複製代碼

而後就開始調用以下方法將bean註冊到BenFactory中!

registerBeanDefinition(definitionHolder, this.registry);複製代碼

OK,註冊完後,invokeBeanFactoryPostProcessors(beanFactory)這個方法也算是使命結束,這個時候咱們直接跳到finishBeanFactoryInitialization(beanFactory)這個方法,咱們點進去:

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
   // Initialize conversion service for this context.
   if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
         beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
      beanFactory.setConversionService(
            beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
   }

   // Register a default embedded value resolver if no bean post-processor
   // (such as a PropertyPlaceholderConfigurer bean) registered any before:
   // at this point, primarily for resolution in annotation attribute values.
   if (!beanFactory.hasEmbeddedValueResolver()) {
      beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
         @Override
         public String resolveStringValue(String strVal) {
            return getEnvironment().resolvePlaceholders(strVal);
         }
      });
   }

   // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
   String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
   for (String weaverAwareName : weaverAwareNames) {
      getBean(weaverAwareName);
   }

   // Stop using the temporary ClassLoader for type matching.
   beanFactory.setTempClassLoader(null);

   // Allow for caching all bean definition metadata, not expecting further changes.
   beanFactory.freezeConfiguration();

   // Instantiate all remaining (non-lazy-init) singletons.
   beanFactory.preInstantiateSingletons();
}複製代碼

到這個階段了,咱們要開始建立bean的實例了,咱們找到下面的代碼:

for (String weaverAwareName : weaverAwareNames) {
      getBean(weaverAwareName);
   }複製代碼

進入getBean!

@Override
public Object getBean(String name) throws BeansException {
   assertBeanFactoryActive();
   return getBeanFactory().getBean(name);
}複製代碼

再進getBean

@Override
public Object getBean(String name) throws BeansException {
   return doGetBean(name, null, null, false);
}複製代碼

哎喲,我去,還有一層啊,有點煩!再進去!

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

   final 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.isDebugEnabled()) {
         if (isSingletonCurrentlyInCreation(beanName)) {
            logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                  "' that is not fully initialized yet - a consequence of a circular reference");
         }
         else {
            logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
         }
      }
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }

   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 (args != null) {
            // Delegation to parent with explicit args.
            return (T) parentBeanFactory.getBean(nameToLookup, args);
         }
         else {
            // No args -> delegate to standard getBean method.
            return parentBeanFactory.getBean(nameToLookup, requiredType);
         }
      }

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

      try {
         final 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, new ObjectFactory<Object>() {
               @Override
               public Object getObject() throws BeansException {
                  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(); final 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, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } } }); bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider " + "defining a scoped proxy for this bean if you intend to refer to it from a singleton", ex); } } } catch (BeansException ex) { cleanupAfterBeanCreationFailure(beanName); throw ex; } } // Check if required type matches the type of the actual bean instance. if (requiredType != null && bean != null && !requiredType.isInstance(bean)) { try { return getTypeConverter().convertIfNecessary(bean, requiredType); } catch (TypeMismatchException ex) { if (logger.isDebugEnabled()) { logger.debug("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", ex); } throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } } return (T) bean; }複製代碼

而後咱們繼續哐哐哐往下整吧(任重道遠啊!好多層!)

從上面的代碼找到這一行,看名字就是建立Bean,咱們繼續點進去

prototypeInstance = createBean(beanName, mbd, args);複製代碼

這個方法進去後,找到下面這行,繼續進去(要瘋了,兄弟們)

Object beanInstance = doCreateBean(beanName, mbdToUse, args);
複製代碼

OKKKKK,這個進去後還有,找到下面代碼:

if (instanceWrapper == null) {
   instanceWrapper = createBeanInstance(beanName, mbd, args);
}複製代碼

而後再進入createBeanInstance方法,找到下面的代碼

if (autowireNecessary) {
   return autowireConstructor(beanName, mbd, null, null);
}複製代碼

進入autowireConstructor(很明顯,註解構造器),而後.....Emmm....裏面還有,咱們在裏面找到下面這段代碼:

if (System.getSecurityManager() != null) {
   final Constructor<?> ctorToUse = constructorToUse;
   final Object[] argumentsToUse = argsToUse;
   beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
      @Override
      public Object run() {
         return beanFactory.getInstantiationStrategy().instantiate(
               mbd, beanName, beanFactory, ctorToUse, argumentsToUse);
      }
   }, beanFactory.getAccessControlContext());
}
else {
   beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(
         mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
}複製代碼

啥也別說了,繼續進入這個方法,好像到一個工具類了,看到但願了!!!

@Override
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner,
      final Constructor<?> ctor, Object... args) {

   if (bd.getMethodOverrides().isEmpty()) {
      if (System.getSecurityManager() != null) {
         // use own privileged to change accessibility (when security is on)
         AccessController.doPrivileged(new PrivilegedAction<Object>() {
            @Override
            public Object run() {
               ReflectionUtils.makeAccessible(ctor);
               return null;
            }
         });
      }
      return BeanUtils.instantiateClass(ctor, args);
   }
   else {
      return instantiateWithMethodInjection(bd, beanName, owner, ctor, args);
   }
}複製代碼
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
   Assert.notNull(ctor, "Constructor must not be null");
   try {
      ReflectionUtils.makeAccessible(ctor);
      return ctor.newInstance(args);
   }
   catch (InstantiationException ex) {
      throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
   }
   catch (IllegalAccessException ex) {
      throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
   }
   catch (IllegalArgumentException ex) {
      throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
   }
   catch (InvocationTargetException ex) {
      throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
   }
}複製代碼
@CallerSensitive
public T newInstance(Object ... initargs)
    throws InstantiationException, IllegalAccessException,
           IllegalArgumentException, InvocationTargetException
{
    if (!override) {
        if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
            Class<?> caller = Reflection.getCallerClass();
            checkAccess(caller, clazz, null, modifiers);
        }
    }
    if ((clazz.getModifiers() & Modifier.ENUM) != 0)
        throw new IllegalArgumentException("Cannot reflectively create enum objects");
    ConstructorAccessor ca = constructorAccessor;   // read volatile
    if (ca == null) {
        ca = acquireConstructorAccessor();
    }
    @SuppressWarnings("unchecked")
    T inst = (T) ca.newInstance(initargs);
    return inst;
}複製代碼

感動落淚,終於到了Spring bean加載的核心了!對!反射!咱們最後會發現是經過反射newInstance取得的對象實例:

獲取到對象實例以後,咱們要幹啥?填充一波 調用populateBean方法!

try {
   populateBean(beanName, mbd, instanceWrapper);
   if (exposedObject != null) {
      exposedObject = initializeBean(beanName, exposedObject, mbd);
   }
}複製代碼

繼續點進去,進入後便能看到和咱們平時代碼對應的條件了,例如byType注入、byName注入:

if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
      mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
   MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

   // Add property values based on autowire by name if applicable.
   if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
      autowireByName(beanName, mbd, bw, newPvs);
   }

   // Add property values based on autowire by type if applicable.
   if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
      autowireByType(beanName, mbd, bw, newPvs);
   }

   pvs = newPvs;
}複製代碼
if (hasInstAwareBpps) {
   for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof InstantiationAwareBeanPostProcessor) {
         InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
         pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
         if (pvs == null) {
            return;
         }
      }
   }
}複製代碼

這個時候,這一行代碼,就是進行依賴注入的地方了!

pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);複製代碼

這個時候,咱們一點,發現有不少實現類,感受咱們平時項目裏面@Autowired註解用得多一點,咱們就選AutowiredAnnotationBeanPostProcessor這個類吧,點開看看:

@Override
public PropertyValues postProcessPropertyValues(
      PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {

   InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
   try {
      metadata.inject(bean, beanName, pvs);
   }
   catch (BeanCreationException ex) {
      throw ex;
   }
   catch (Throwable ex) {
      throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
   }
   return pvs;複製代碼

看findAutowiringMetadata這個方法名應該是獲取元信息,獲取完後,再調用:

metadata.inject(bean, beanName, pvs);複製代碼
@Override
   protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
      Field field = (Field) this.member;
      Object value;
      if (this.cached) {
         value = resolvedCachedArgument(beanName, this.cachedFieldValue);
      }
      else {
         DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
         desc.setContainingClass(bean.getClass());
         Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
         TypeConverter typeConverter = beanFactory.getTypeConverter();
         try {
            value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
         }
         catch (BeansException ex) {
            throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
         }
         synchronized (this) {
            if (!this.cached) {
               if (value != null || this.required) {
                  this.cachedFieldValue = desc;
                  registerDependentBeans(beanName, autowiredBeanNames);
                  if (autowiredBeanNames.size() == 1) {
                     String autowiredBeanName = autowiredBeanNames.iterator().next();
                     if (beanFactory.containsBean(autowiredBeanName)) {
                        if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
                           this.cachedFieldValue = new ShortcutDependencyDescriptor(
                                 desc, autowiredBeanName, field.getType());
                        }
                     }
                  }
               }
               else {
                  this.cachedFieldValue = null;
               }
               this.cached = true;
            }
         }
      }
      if (value != null) {
         ReflectionUtils.makeAccessible(field);
         field.set(bean, value);
      }
   }
}複製代碼

激動啊,這個莫非就是傳說中替咱們作的set方法??最後完成注入?

field.set(bean, value);

4、總結

寫完這個以後,整體對Spring加載的過程有了更深刻的理解,在看源碼的過程當中,也有不少本身不理解的東西,也綜合了不少信息來幫忙本身理解和完成此次文章,相信大哥們看完可能會發現一些錯誤或者理解不一致處,歡迎指出,共同進步!

相關文章
相關標籤/搜索