SpringBoot啟動流程及自動裝配原理分析


一、SpringApplication類初始化過程

SpringBoot項目的main函數

常規的這個主類如下圖所示,我們一般會這樣去寫。

在這個類中需要關注的是:

  • @SpringBootApplication
  • SpringApplication.run()

關於 @SpringBootApplication 注解,在后面分析SpringBoot自動裝配的章節會展開去分析。

本章節中我們需要關注的就是 SpringApplication.run() 方法。

查看run()方法的實現,如下面代碼所示,我們發現其首先是創建了 SpringApplication 的實例,然后調用了 SpringApplication 的run()方法,那本章我們關注的就是 SpringApplication 創建實例的過程。

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    return (new SpringApplication(primarySources)).run(args);
}
SpringApplication() 構造方法

繼續查看源碼, SpringApplication 實例化過程,首先是進入構造方法,最終回來到兩個參數的構造方法。

public SpringApplication(Class<?>... primarySources) {
    this((ResourceLoader)null, primarySources);
}

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.sources = new LinkedHashSet();
    this.bannerMode = Mode.CONSOLE;
    this.logStartupInfo = true;
    this.addCommandLineProperties = true;
    this.addConversionService = true;
    this.headless = true;
    this.registerShutdownHook = true;
    this.additionalProfiles = new HashSet();
    this.isCustomEnvironment = false;
    this.lazyInitialization = false;
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
    //推斷應用類型,后面會根據類型初始化對應的環境。常用的一般都是servlet環境
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    //初始化classpath下 META-INF/spring.factories中已配置的ApplicationContextInitializer
    this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
    //初始化classpath下所有已配置的 ApplicationListener
    this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
    //根據調用棧,推斷出 main 方法的類名
    this.mainApplicationClass = this.deduceMainApplicationClass();
}
WebApplicationType.deduceFromClasspath();該方法推斷應用的類型。 SERVLET REACTIVE NONE 
public enum WebApplicationType {
    NONE,
    SERVLET,
    REACTIVE;
    
    // 常量值
    private static final String[] SERVLET_INDICATOR_CLASSES = new String[]{"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"};
    private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";
    private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";
    private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";
    private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext";
    private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext";

    private WebApplicationType() {
    }
    
    /**
     * 判斷 應用的類型
     * NONE: 應用程序不是web應用,也不應該用web服務器去啟動
     * SERVLET: 應用程序應作為基於servlet的web應用程序運行,並應啟動嵌入式servlet web(tomcat)服務器。
     * REACTIVE: 應用程序應作為 reactive web應用程序運行,並應啟動嵌入式 reactive web服務器。
     * @return
     */
    static WebApplicationType deduceFromClasspath() {
         //classpath下必須存在org.springframework.web.reactive.DispatcherHandler
        if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {
            return REACTIVE;
        } else {
            String[] var0 = SERVLET_INDICATOR_CLASSES;
            int var1 = var0.length;

            for(int var2 = 0; var2 < var1; ++var2) {
                String className = var0[var2];
                if (!ClassUtils.isPresent(className, (ClassLoader)null)) {
                    return NONE;
                }
            }
            //classpath環境下存在javax.servlet.Servlet或者org.springframework.web.context.ConfigurableWebApplicationContext
            return SERVLET;
        }
    }

    static WebApplicationType deduceFromApplicationContext(Class<?> applicationContextClass) {
        if (isAssignable("org.springframework.web.context.WebApplicationContext", applicationContextClass)) {
            return SERVLET;
        } else {
            return isAssignable("org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext", applicationContextClass) ? REACTIVE : NONE;
        }
    }

    private static boolean isAssignable(String target, Class<?> type) {
        try {
            return ClassUtils.resolveClassName(target, (ClassLoader)null).isAssignableFrom(type);
        } catch (Throwable var3) {
            return false;
        }
    }
}

返回類型是WebApplicationType的枚舉類型, WebApplicationType 有三個枚舉,三個枚舉的解釋如下:

  • WebApplicationType.REACTIVE classpath下存在org.springframework.web.reactive.DispatcherHandler
  • WebApplicationType.SERVLET classpath下存在javax.servlet.Servlet或者org.springframework.web.context.ConfigurableWebApplicationContext
  • WebApplicationType.NONE 不滿足以上條件。
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); 

初始化classpath下 META-INF/spring.factories中已配置的ApplicationContextInitializer。

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
    return this.getSpringFactoriesInstances(type, new Class[0]);
}

/**
 * 通過指定的classloader 從META-INF/spring.factories獲取指定的Spring的工廠實例
 * @param type
 * @param parameterTypes
 * @param args
 * @param <T>
 * @return
 */
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
    ClassLoader classLoader = this.getClassLoader();
    //通過指定的classLoader從 META-INF/spring.factories 的資源文件中,
    //讀取 key 為 type.getName() 的 value
    Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    //創建Spring工廠實例
    List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    //對Spring工廠實例排序(org.springframework.core.annotation.Order注解指定的順序)
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}

看看 getSpringFactoriesInstances 都干了什么,看源碼,有一個方法很重要 loadFactoryNames() 這個方法很重要,它是spring-core中提供的從META-INF/spring.factories中獲取指定的類(key)的同一入口方法。

在這里,獲取的是key為 org.springframework.context.ApplicationContextInitializer 的類。

ApplicationContextInitializer 是Spring框架的類, 這個類的主要目的就是在ConfigurableApplicationContext調用refresh()方法之前,回調這個類的initialize方法。通過ConfigurableApplicationContext 的實例獲取容器的環境Environment,從而實現對配置文件的修改完善等工作。

setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));

初始化classpath下 META-INF/spring.factories中已配置的 ApplicationListener。
ApplicationListener 的加載過程和上面的 ApplicationContextInitializer 類的加載過程是一樣的。不多說了,至於 ApplicationListener 是spring的事件監聽器,典型的觀察者模式,通過 ApplicationEvent 類和 ApplicationListener 接口,可以實現對spring容器全生命周期的監聽,當然也可以自定義監聽事件。

二、SpringApplication的run方法

run方法的源碼

/**
 * 運行spring應用,並刷新一個新的 ApplicationContext(Spring的上下文)
 * ConfigurableApplicationContext 是 ApplicationContext 接口的子接口。在 ApplicationContext
 * 基礎上增加了配置上下文的工具。 ConfigurableApplicationContext是容器的高級接口
 */
public ConfigurableApplicationContext run(String... args) {
    //記錄程序運行時間
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    // ConfigurableApplicationContext Spring 的上下文
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
    this.configureHeadlessProperty();
    //從META-INF/spring.factories中獲取監聽器
    //1、獲取並啟動監聽器
    SpringApplicationRunListeners listeners = this.getRunListeners(args);
    listeners.starting();

    Collection exceptionReporters;
    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        //2、構造應用上下文環境
        ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
        //處理需要忽略的Bean
        this.configureIgnoreBeanInfo(environment);
        //打印banner
        Banner printedBanner = this.printBanner(environment);
        //3、初始化應用上下文
        context = this.createApplicationContext();
        //實例化SpringBootExceptionReporter.class,用來支持報告關於啟動的錯誤
        exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
        //4、刷新應用上下文前的准備階段
        this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        //5、刷新應用上下文
        this.refreshContext(context);
        //刷新應用上下文后的擴展接口
        this.afterRefresh(context, applicationArguments);
        //時間記錄停止
        stopWatch.stop();
        if (this.logStartupInfo) {
            (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
        }
        //發布容器啟動完成事件
        listeners.started(context);
        this.callRunners(context, applicationArguments);
    } catch (Throwable var10) {
        this.handleRunFailure(context, var10, exceptionReporters, listeners);
        throw new IllegalStateException(var10);
    }

    try {
        listeners.running(context);
        return context;
    } catch (Throwable var9) {
        this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
        throw new IllegalStateException(var9);
    }
}

具體的每一行代碼的含義請看注釋,我們在這先總結一下啟動過程中的重要步驟:

第一步:獲取並啟動監聽器
第二步:構造應用上下文環境
第三步:初始化應用上下文
第四步:刷新應用上下文前的准備階段
第五步:刷新應用上下文
第六步:刷新應用上下文后的擴展接口

OK,下面SpringBoot的啟動流程分析,我們就根據這6大步驟進行詳細解讀。最重要的是第四,五步。我們會着重的分析。

第一步:獲取並啟動監聽器

事件機制在Spring是很重要的一部分內容,通過事件機制我們可以監聽Spring容器中正在發生的一些事件,同樣也可以自定義監聽事件。Spring的事件為Bean和Bean之間的消息傳遞提供支持。當一個對象處理完某種任務后,通知另外的對象進行某些處理,常用的場景有進行某些操作后發送通知,消息、郵件等情況。

private SpringApplicationRunListeners getRunListeners(String[] args) {
    Class<?>[] types = new Class<?>[]{SpringApplication.class, String[].class};
    return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
            SpringApplicationRunListener.class, types, this, args));
}

在這里面是不是看到一個熟悉的方法:getSpringFactoriesInstances(),可以看下下面的注釋,前面我們已經詳細介紹過該方法是怎么一步步的獲取到META-INF/spring.factories中的指定的key的value,獲取到以后怎么實例化類的。

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
    ClassLoader classLoader = this.getClassLoader();
    //通過指定的classLoader從 META-INF/spring.factories 的資源文件中,
    //讀取 key 為 type.getName() 的 value
    Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    //創建Spring工廠實例
    List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    //對Spring工廠實例排序(org.springframework.core.annotation.Order注解指定的順序)
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}

回到run方法,debug這個代碼 SpringApplicationRunListeners listeners = getRunListeners(args); 獲取的是EventPublishingRunListener監聽器:

EventPublishingRunListener監聽器是Spring容器的啟動監聽器。
listeners.starting(); 開啟了監聽事件。

第二步:構造應用上下文環境

應用上下文環境包括什么呢?包括計算機的環境,Java環境,Spring的運行環境,Spring項目的配置(在SpringBoot中就是那個熟悉的application.properties/yml)等等。
首先看一下prepareEnvironment()方法。

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
    //創建並配置相應的環境
    ConfigurableEnvironment environment = this.getOrCreateEnvironment();
    //根據用戶配置,配置 environment系統環境
    this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
    ConfigurationPropertySources.attach((Environment)environment);
    // 啟動相應的監聽器,其中一個重要的監聽器 ConfigFileApplicationListener 就是加載項目配置文件的監聽器。
    listeners.environmentPrepared((ConfigurableEnvironment)environment);
    this.bindToSpringApplication((ConfigurableEnvironment)environment);
    if (!this.isCustomEnvironment) {
        environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
    }

    ConfigurationPropertySources.attach((Environment)environment);
    return (ConfigurableEnvironment)environment;
}

看上面的注釋,方法中主要完成的工作,首先是創建並按照相應的應用類型配置相應的環境,然后根據用戶的配置,配置系統環境,然后啟動監聽器,並加載系統配置文件。

ConfigurableEnvironment environment = getOrCreateEnvironment(); 
private ConfigurableEnvironment getOrCreateEnvironment() {
    if (this.environment != null) {
        return this.environment;
    } else {
        switch(this.webApplicationType) {
        case SERVLET:
            //如果應用類型是 SERVLET 則實例化 StandardServletEnvironment
            return new StandardServletEnvironment();
        case REACTIVE:
            return new StandardReactiveWebEnvironment();
        default:
            return new StandardEnvironment();
        }
    }
}

通過代碼可以看到根據不同的應用類型初始化不同的系統環境實例。前面咱們已經說過應用類型是怎么判斷的了,這里就不在贅述了。

從上面的繼承關系可以看出,StandardServletEnvironment是StandardEnvironment的子類。當是web項目的時候,環境上會多一些關於web環境的配置。 

configureEnvironment(environment, applicationArguments.getSourceArgs()); 
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
    if (this.addConversionService) {
        ConversionService conversionService = ApplicationConversionService.getSharedInstance();
        environment.setConversionService((ConfigurableConversionService)conversionService);
    }
    // 將main 函數的args封裝成 SimpleCommandLinePropertySource 加入環境中。
    this.configurePropertySources(environment, args);
     // 激活相應的配置文件
    this.configureProfiles(environment, args);
}

在configurePropertySources(environment, args);中將args封裝成了SimpleCommandLinePropertySource並加入到了environment中。

configureProfiles(environment, args);根據啟動參數激活了相應的配置文件。

 listeners.environmentPrepared(environment); 

進入到方法一路跟下去就到了SimpleApplicationEventMulticaster類的multicastEvent()方法。

public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
    Executor executor = this.getTaskExecutor();
    Iterator var5 = this.getApplicationListeners(event, type).iterator();

    while(var5.hasNext()) {
        ApplicationListener<?> listener = (ApplicationListener)var5.next();
        if (executor != null) {
            executor.execute(() -> {
                this.invokeListener(listener, event);
            });
        } else {
            this.invokeListener(listener, event);
        }
    }

}

查看getApplicationListeners(event, type)執行結果,發現一個重要的監聽器ConfigFileApplicationListener。

先看看這個類的注釋:

/**
 * {@link EnvironmentPostProcessor} that configures the context environment by loading
 * properties from well known file locations. By default properties will be loaded from
 * 'application.properties' and/or 'application.yml' files in the following locations:
 * <ul>
 * <li>classpath:</li>
 * <li>file:./</li>
 * <li>classpath:config/</li>
 * <li>file:./config/:</li>
 * </ul>
 * <p>
 * Alternative search locations and names can be specified using
 * {@link #setSearchLocations(String)} and {@link #setSearchNames(String)}.
 * <p>
 * Additional files will also be loaded based on active profiles. For example if a 'web'
 * profile is active 'application-web.properties' and 'application-web.yml' will be
 * considered.
 * <p>
 * The 'spring.config.name' property can be used to specify an alternative name to load
 * and the 'spring.config.location' property can be used to specify alternative search
 * locations or specific files.
 * <p>
 * 從默認的位置加載配置文件,並將其加入 上下文的 environment變量中
 */

這個監聽器默認的從注釋中<ul>標簽所示的幾個位置加載配置文件,並將其加入 上下文的 environment變量中。當然也可以通過配置指定。

第三步:初始化應用上下文

在SpringBoot工程中,應用類型分為三種,如下代碼所示。

public enum WebApplicationType {
    /**
     * 應用程序不是web應用,也不應該用web服務器去啟動
     */
    NONE,
    /**
     * 應用程序應作為基於servlet的web應用程序運行,並應啟動嵌入式servlet web(tomcat)服務器。
     */
    SERVLET,
    /**
     * 應用程序應作為 reactive web應用程序運行,並應啟動嵌入式 reactive web服務器。
     */
    REACTIVE
}

對應三種應用類型,SpringBoot項目有三種對應的應用上下文,我們以web工程為例,即其上下文為AnnotationConfigServletWebServerApplicationContext。

 protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
                switch(this.webApplicationType) {
                case SERVLET:
                    contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
                    break;
                case REACTIVE:
                    contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
                    break;
                default:
                    contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
                }
            } catch (ClassNotFoundException var3) {
                throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
            }
        }

        return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
    }

我們先看一下AnnotationConfigServletWebServerApplicationContext的設計。

應用上下文可以理解成IoC容器的高級表現形式,應用上下文確實是在IoC容器的基礎上豐富了一些高級功能。
應用上下文對IoC容器是持有的關系。它的一個屬性beanFactory就是IoC容器(DefaultListableBeanFactory)。所以它們之間是持有,和擴展的關系。

接下來看GenericApplicationContext類

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
    private final DefaultListableBeanFactory beanFactory;
    ...
    public GenericApplicationContext() {
        this.beanFactory = new DefaultListableBeanFactory();
    }
    ...
}

beanFactory正是在AnnotationConfigServletWebServerApplicationContext實現的接口GenericApplicationContext中定義的。在上面createApplicationContext()方法中的, BeanUtils.instantiateClass(contextClass) 這個方法中,不但初始化了AnnotationConfigServletWebServerApplicationContext類,也就是我們的上下文context,同樣也觸發了GenericApplicationContext類的構造函數,從而IoC容器也創建了。仔細看他的構造函數,有沒有發現一個很熟悉的類DefaultListableBeanFactory,沒錯,DefaultListableBeanFactory就是IoC容器真實面目了。在后面的refresh()方法分析中,DefaultListableBeanFactory是無處不在的存在感。

第四步 刷新應用上下文前的准備階段
prepareContext()方法
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
    //設置容器環境
    context.setEnvironment(environment);
    //執行容器后置處理
    this.postProcessApplicationContext(context);
    //執行容器中的 ApplicationContextInitializer 包括spring.factories和通過三種方式自定義的
    this.applyInitializers(context);
    //向各個監聽器發送容器已經准備好的事件
    listeners.contextPrepared(context);
    if (this.logStartupInfo) {
        this.logStartupInfo(context.getParent() == null);
        this.logStartupProfileInfo(context);
    }

    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    //將main函數中的args參數封裝成單例Bean,注冊進容器
    beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
    //將 printedBanner 也封裝成單例,注冊進容器
    if (printedBanner != null) {
        beanFactory.registerSingleton("springBootBanner", printedBanner);
    }

    if (beanFactory instanceof DefaultListableBeanFactory) {
        ((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
    }

    if (this.lazyInitialization) {
        context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
    }

    Set<Object> sources = this.getAllSources();
    Assert.notEmpty(sources, "Sources must not be empty");
    //加載我們的啟動類,將啟動類注入容器
    this.load(context, sources.toArray(new Object[0]));
    //發布容器已加載事件
    listeners.contextLoaded(context);
}

首先看這行 Set<Object> sources = getAllSources(); 在getAllSources()中拿到了我們的啟動類。  
我們重點講解這行 load(context, sources.toArray(new Object[0]));

跟進load()方法,看源碼:

protected void load(ApplicationContext context, Object[] sources) {
    if (logger.isDebugEnabled()) {
        logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
    }
    //創建 BeanDefinitionLoader 
    BeanDefinitionLoader loader = this.createBeanDefinitionLoader(this.getBeanDefinitionRegistry(context), sources);
    if (this.beanNameGenerator != null) {
        loader.setBeanNameGenerator(this.beanNameGenerator);
    }

    if (this.resourceLoader != null) {
        loader.setResourceLoader(this.resourceLoader);
    }

    if (this.environment != null) {
        loader.setEnvironment(this.environment);
    }

    loader.load();
}

1、getBeanDefinitionRegistry()

繼續看getBeanDefinitionRegistry()方法的源碼

private BeanDefinitionRegistry getBeanDefinitionRegistry(ApplicationContext context) {
    if (context instanceof BeanDefinitionRegistry) {
        return (BeanDefinitionRegistry)context;
    } else if (context instanceof AbstractApplicationContext) {
        return (BeanDefinitionRegistry)((AbstractApplicationContext)context).getBeanFactory();
    } else {
        throw new IllegalStateException("Could not locate BeanDefinitionRegistry");
    }
}

這里將我們前文創建的上下文強轉為BeanDefinitionRegistry,是不是很熟悉。BeanDefinitionRegistry定義了很重要的方法registerBeanDefinition(),該方法將BeanDefinition注冊進DefaultListableBeanFactory容器的beanDefinitionMap中。

2、createBeanDefinitionLoader()

繼續看createBeanDefinitionLoader()方法,最終進入了BeanDefinitionLoader類的構造方法,如下

BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
    Assert.notNull(registry, "Registry must not be null");
    Assert.notEmpty(sources, "Sources must not be empty");
    this.sources = sources;
    //注解形式的Bean定義讀取器 比如:@Configuration @Bean @Component @Controller @Service等等
    this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
    //XML形式的Bean定義讀取器
    this.xmlReader = new XmlBeanDefinitionReader(registry);
    if (this.isGroovyPresent()) {
        this.groovyReader = new GroovyBeanDefinitionReader(registry);
    }
    //類路徑掃描器
    this.scanner = new ClassPathBeanDefinitionScanner(registry);
    //掃描器添加排除過濾器
    this.scanner.addExcludeFilter(new BeanDefinitionLoader.ClassExcludeFilter(sources));
}

前面的文章,我們說過,IoC容器的初始化分為三個步驟,上面三個屬性在,BeanDefinition的Resource定位,和BeanDefinition的注冊中起到了很重要的作用。

3、loader.load();

跟進load()方法

private int load(Object source) {
    Assert.notNull(source, "Source must not be null");
    if (source instanceof Class) {
        // 從Class加載
        return this.load((Class)source);
    } else if (source instanceof Resource) {
        // 從Resource加載
        return this.load((Resource)source);
    } else if (source instanceof Package) {
        // 從Package加載
        return this.load((Package)source);
    } else if (source instanceof CharSequence) {
        // 從 CharSequence 加載
        return this.load((CharSequence)source);
    } else {
        throw new IllegalArgumentException("Invalid source type " + source.getClass());
    }
}

當前我們的主類會按Class加載。

繼續跟進load()方法。

private int load(Class<?> source) {
    if (this.isGroovyPresent() && BeanDefinitionLoader.GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
        BeanDefinitionLoader.GroovyBeanDefinitionSource loader = (BeanDefinitionLoader.GroovyBeanDefinitionSource)BeanUtils.instantiateClass(source, BeanDefinitionLoader.GroovyBeanDefinitionSource.class);
        this.load(loader);
    }

    if (this.isEligible(source)) {
        //將 啟動類的 BeanDefinition注冊進 beanDefinitionMap
        this.annotatedReader.register(new Class[]{source});
        return 1;
    } else {
        return 0;
    }
}

isComponent(source)判斷主類是不是存在@Component注解,主類@SpringBootApplication是一個組合注解,包含@Component。

this.annotatedReader.register(source);跟進register()方法,最終進到AnnotatedBeanDefinitionReader類的doRegisterBean()方法。

private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier, @Nullable BeanDefinitionCustomizer[] customizers) {
    //將指定的類 封裝為AnnotatedGenericBeanDefinition
    AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
    if (!this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
        abd.setInstanceSupplier(supplier);
        // 獲取該類的 scope 屬性
        ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
        abd.setScope(scopeMetadata.getScopeName());
        String beanName = name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry);
        AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
        int var10;
        int var11;
        if (qualifiers != null) {
            Class[] var9 = qualifiers;
            var10 = qualifiers.length;

            for(var11 = 0; var11 < var10; ++var11) {
                Class<? extends Annotation> qualifier = var9[var11];
                if (Primary.class == qualifier) {
                    abd.setPrimary(true);
                } else if (Lazy.class == qualifier) {
                    abd.setLazyInit(true);
                } else {
                    abd.addQualifier(new AutowireCandidateQualifier(qualifier));
                }
            }
        }

        if (customizers != null) {
            BeanDefinitionCustomizer[] var13 = customizers;
            var10 = customizers.length;

            for(var11 = 0; var11 < var10; ++var11) {
                BeanDefinitionCustomizer customizer = var13[var11];
                customizer.customize(abd);
            }
        }

        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
        definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
        // 將該BeanDefinition注冊到IoC容器的beanDefinitionMap中
        BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
    }
}

在該方法中將主類封裝成AnnotatedGenericBeanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);方法將BeanDefinition注冊進beanDefinitionMap

public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
    String beanName = definitionHolder.getBeanName();
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    // 注冊別名
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
        String[] var4 = aliases;
        int var5 = aliases.length;

        for(int var6 = 0; var6 < var5; ++var6) {
            String alias = var4[var6];
            registry.registerAlias(beanName, alias);
        }
    }

}

繼續跟進registerBeanDefinition()方法。

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
    Assert.hasText(beanName, "Bean name must not be empty");
    Assert.notNull(beanDefinition, "BeanDefinition must not be null");
    if (beanDefinition instanceof AbstractBeanDefinition) {
        try {
            // 最后一次校驗了
            // 對bean的Overrides進行校驗,還不知道會在哪處理這些overrides
            ((AbstractBeanDefinition)beanDefinition).validate();
        } catch (BeanDefinitionValidationException var8) {
            throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var8);
        }
    }
    // 判斷是否存在重復名字的bean,之后看允不允許override
    // 以前使用synchronized實現互斥訪問,現在采用ConcurrentHashMap
    BeanDefinition existingDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
    if (existingDefinition != null) {
         //如果該類不允許 Overriding 直接拋出異常
        if (!this.isAllowBeanDefinitionOverriding()) {
            throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
        }

        if (existingDefinition.getRole() < beanDefinition.getRole()) {
            if (this.logger.isInfoEnabled()) {
                this.logger.info("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
            }
        } else if (!beanDefinition.equals(existingDefinition)) {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
            }
        } else if (this.logger.isTraceEnabled()) {
            this.logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
        }
        //注冊進beanDefinitionMap
        this.beanDefinitionMap.put(beanName, beanDefinition);
    } else {
        if (this.hasBeanCreationStarted()) {
            synchronized(this.beanDefinitionMap) {
                this.beanDefinitionMap.put(beanName, beanDefinition);
                List<String> updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1);
                updatedDefinitions.addAll(this.beanDefinitionNames);
                updatedDefinitions.add(beanName);
                this.beanDefinitionNames = updatedDefinitions;
                this.removeManualSingletonName(beanName);
            }
        } else {
            //如果仍處於啟動注冊階段,注冊進beanDefinitionMap
            this.beanDefinitionMap.put(beanName, beanDefinition);
            this.beanDefinitionNames.add(beanName);
            this.removeManualSingletonName(beanName);
        }

        this.frozenBeanDefinitionNames = null;
    }

    if (existingDefinition == null && !this.containsSingleton(beanName)) {
        if (this.isConfigurationFrozen()) {
            this.clearByTypeCache();
        }
    } else {
        this.resetBeanDefinition(beanName);
    }

}

最終來到DefaultListableBeanFactory類的registerBeanDefinition()方法,DefaultListableBeanFactory類還熟悉嗎?DefaultListableBeanFactory是IoC容器的具體產品。
仔細看這個方法registerBeanDefinition(),首先會檢查是否已經存在,如果存在並且不允許被覆蓋則直接拋出異常。不存在的話就直接注冊進beanDefinitionMap中。

第五步 刷新應用上下文(IoC容器的初始化過程)

IoC容器的初始化過程,主要分下面三步:

  • BeanDefinition的Resource定位
  • BeanDefinition的載入
  • 向IoC容器注冊BeanDefinition

從run方法的,refreshContext()方法一路跟下去,最終來到AbstractApplicationContext類的refresh()方法。

public void refresh() throws BeansException, IllegalStateException {
    synchronized(this.startupShutdownMonitor) {
         //刷新上下文環境
        this.prepareRefresh();
        //這里是在子類中啟動 refreshBeanFactory() 的地方
        ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
        //准備bean工廠,以便在此上下文中使用
        this.prepareBeanFactory(beanFactory);

        try {
            //設置 beanFactory 的后置處理
            this.postProcessBeanFactory(beanFactory);
            //調用 BeanFactory 的后處理器,這些處理器是在Bean 定義中向容器注冊的
            this.invokeBeanFactoryPostProcessors(beanFactory);
            //注冊Bean的后處理器,在Bean創建過程中調用
            this.registerBeanPostProcessors(beanFactory);
            //對上下文中的消息源進行初始化
            this.initMessageSource();
            //初始化上下文中的事件機制
            this.initApplicationEventMulticaster();
            //初始化其他特殊的Bean
            this.onRefresh();
            //檢查監聽Bean並且將這些監聽Bean向容器注冊
            this.registerListeners();
            //實例化所有的(non-lazy-init)單件
            this.finishBeanFactoryInitialization(beanFactory);
            //發布容器事件,結束Refresh過程
            this.finishRefresh();
        } catch (BeansException var9) {
            if (this.logger.isWarnEnabled()) {
                this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
            }

            this.destroyBeans();
            this.cancelRefresh(var9);
            throw var9;
        } finally {
            this.resetCommonCaches();
        }

    }
}

從以上代碼中我們可以看到,refresh()方法中所作的工作也挺多,我們沒辦法面面俱到,主要根據IoC容器的初始化步驟和IoC依賴注入的過程進行分析,圍繞以上兩個過程,我們主要介紹重要的方法。

obtainFreshBeanFactory();

在啟動流程的第三步:初始化應用上下文。中我們創建了應用的上下文,並觸發了GenericApplicationContext類的構造方法如下所示,創建了beanFactory,也就是創建了DefaultListableBeanFactory類。

public GenericApplicationContext() {
    this.beanFactory = new DefaultListableBeanFactory();
}

關於obtainFreshBeanFactory()方法,其實就是拿到我們之前創建的beanFactory。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    //刷新BeanFactory
    this.refreshBeanFactory();
    //獲取beanFactory
    return this.getBeanFactory();
}

從上面代碼可知,在該方法中主要做了三個工作,刷新beanFactory,獲取beanFactory,返回beanFactory。
首先看一下refreshBeanFactory()方法,跟下去來到GenericApplicationContext類的refreshBeanFactory()發現也沒做什么。

protected final void refreshBeanFactory() throws IllegalStateException {
    if (!this.refreshed.compareAndSet(false, true)) {
        throw new IllegalStateException("GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
    } else {
        this.beanFactory.setSerializationId(this.getId());
    }
}

AbstractApplicationContext類有兩個子類實現了refreshBeanFactory(),但是在前面第三步初始化上下文的時候,實例化了GenericApplicationContext類,所以沒有進入AbstractRefreshableApplicationContext中的refreshBeanFactory()方法。

this.refreshed.compareAndSet(false, true) ,這行代碼在這里表示:GenericApplicationContext只允許刷新一次 。這行代碼,很重要,不是在Spring中很重要,而是這行代碼本身。首先看一下this.refreshed屬性: 

private final AtomicBoolean refreshed = new AtomicBoolean();

java J.U.C並發包中很重要的一個原子類AtomicBoolean。通過該類的compareAndSet()方法可以實現一段代碼絕對只實現一次的功能。

prepareBeanFactory(beanFactory);

從字面意思上可以看出准備BeanFactory。
看代碼,具體看看做了哪些准備工作。這個方法不是重點,看注釋吧。

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // 配置類加載器:默認使用當前上下文的類加載器
    beanFactory.setBeanClassLoader(this.getClassLoader());
    // 配置EL表達式:在Bean初始化完成,填充屬性的時候會用到
    beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    // 添加屬性編輯器 PropertyEditor
    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment()));
    // 添加Bean的后置處理器
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    // 忽略裝配以下指定的類
    beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
    beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
    beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
    beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
     // 將以下類注冊到 beanFactory(DefaultListableBeanFactory) 的resolvableDependencies屬性中
    beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
    beanFactory.registerResolvableDependency(ResourceLoader.class, this);
    beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
    beanFactory.registerResolvableDependency(ApplicationContext.class, this);
    // 將早期后處理器注冊為application監聽器,用於檢測內部bean
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
    // 如果當前BeanFactory包含loadTimeWeaver Bean,說明存在類加載期織入AspectJ,
    // 則把當前BeanFactory交給類加載期BeanPostProcessor實現類LoadTimeWeaverAwareProcessor來處理,
    // 從而實現類加載期織入AspectJ的目的。
    if (beanFactory.containsBean("loadTimeWeaver")) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }
    // 將當前環境變量(environment) 注冊為單例bean
    if (!beanFactory.containsLocalBean("environment")) {
        beanFactory.registerSingleton("environment", this.getEnvironment());
    }
    // 將當前系統配置(systemProperties) 注冊為單例Bean
    if (!beanFactory.containsLocalBean("systemProperties")) {
        beanFactory.registerSingleton("systemProperties", this.getEnvironment().getSystemProperties());
    }
    // 將當前系統環境 (systemEnvironment) 注冊為單例Bean
    if (!beanFactory.containsLocalBean("systemEnvironment")) {
        beanFactory.registerSingleton("systemEnvironment", this.getEnvironment().getSystemEnvironment());
    }

}
postProcessBeanFactory(beanFactory);

postProcessBeanFactory()方法向上下文中添加了一系列的Bean的后置處理器。后置處理器工作的時機是在所有的beanDenifition加載完成之后,bean實例化之前執行。簡單來說Bean的后置處理器可以修改BeanDefinition的屬性信息。

invokeBeanFactoryPostProcessors(beanFactory);(重點)

上面說過,IoC容器的初始化過程包括三個步驟,在invokeBeanFactoryPostProcessors()方法中完成了IoC容器初始化過程的三個步驟。

第一步:Resource定位

在SpringBoot中,我們都知道他的包掃描是從主類所在的包開始掃描的,prepareContext()方法中,會先將主類解析成BeanDefinition,然后在refresh()方法的invokeBeanFactoryPostProcessors()方法中解析主類的BeanDefinition獲取basePackage的路徑。這樣就完成了定位的過程。其次SpringBoot的各種starter是通過SPI擴展機制實現的自動裝配,SpringBoot的自動裝配同樣也是在invokeBeanFactoryPostProcessors()方法中實現的。還有一種情況,在SpringBoot中有很多的@EnableXXX注解,細心點進去看的應該就知道其底層是@Import注解,在invokeBeanFactoryPostProcessors()方法中也實現了對該注解指定的配置類的定位加載。

常規的在SpringBoot中有三種實現定位,第一個是主類所在包的,第二個是SPI擴展機制實現的自動裝配(比如各種starter),第三種就是@Import注解指定的類。

第二步:BeanDefinition的載入

第一步中說了三種Resource的定位情況,定位后緊接着就是BeanDefinition的分別載入。所謂的載入就是通過上面的定位得到的basePackage,SpringBoot會將該路徑拼接成:classpath*:org/springframework/boot/demo/**/*.class這樣的形式,然后一個叫做PathMatchingResourcePatternResolver的類會將該路徑下所有的.class文件都加載進來,然后遍歷判斷是不是有@Component注解,如果有的話,就是我們要裝載的BeanDefinition。大致過程就是這樣的了。 

注:@Configuration,@Controller,@Service等注解底層都是@Component注解,只不過包裝了一層罷了。

第三個過程:注冊BeanDefinition

這個過程通過調用上文提到的BeanDefinitionRegister接口的實現來完成。這個注冊過程把載入過程中解析得到的BeanDefinition向IoC容器進行注冊。通過上文的分析,我們可以看到,在IoC容器中將BeanDefinition注入到一個ConcurrentHashMap中,IoC容器就是通過這個HashMap來持有這些BeanDefinition數據的。比如DefaultListableBeanFactory 中的beanDefinitionMap屬性。

OK,總結完了,接下來我們通過代碼看看具體是怎么實現的。

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
    ...
}
// PostProcessorRegistrationDelegate類
public static void invokeBeanFactoryPostProcessors(
        ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
    ...
    invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
    ...
}
// PostProcessorRegistrationDelegate類
private static void invokeBeanDefinitionRegistryPostProcessors(
        Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {

    for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
        postProcessor.postProcessBeanDefinitionRegistry(registry);
    }
}
// ConfigurationClassPostProcessor類
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    ...
    processConfigBeanDefinitions(registry);
}
// ConfigurationClassPostProcessor類
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    ...
    do {
        parser.parse(candidates);
        parser.validate();
        ...
    }
    ...
}

一路跟蹤調用棧,來到ConfigurationClassParser類的parse()方法。

public void parse(Set<BeanDefinitionHolder> configCandidates) {
    Iterator var2 = configCandidates.iterator();

    while(var2.hasNext()) {
        BeanDefinitionHolder holder = (BeanDefinitionHolder)var2.next();
        BeanDefinition bd = holder.getBeanDefinition();

        try {
            // 如果是SpringBoot項目進來的,bd其實就是前面主類封裝成的 AnnotatedGenericBeanDefinition(AnnotatedBeanDefinition接口的實現類)
            if (bd instanceof AnnotatedBeanDefinition) {
                this.parse(((AnnotatedBeanDefinition)bd).getMetadata(), holder.getBeanName());
            } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition)bd).hasBeanClass()) {
                this.parse(((AbstractBeanDefinition)bd).getBeanClass(), holder.getBeanName());
            } else {
                this.parse(bd.getBeanClassName(), holder.getBeanName());
            }
        } catch (BeanDefinitionStoreException var6) {
            throw var6;
        } catch (Throwable var7) {
            throw new BeanDefinitionStoreException("Failed to parse configuration class [" + bd.getBeanClassName() + "]", var7);
        }
    }
    // 加載默認的配置---》(對springboot項目來說這里就是自動裝配的入口了)
    this.deferredImportSelectorHandler.process();
}

看上面的注釋,在前面的prepareContext()方法中,我們詳細介紹了我們的主類是如何一步步的封裝成AnnotatedGenericBeanDefinition,並注冊進IoC容器的beanDefinitionMap中的。

繼續沿着parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());方法跟下去

// ConfigurationClassParser類
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
    processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
// ConfigurationClassParser類
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
    ...
    // Recursively process the configuration class and its superclass hierarchy.
    //遞歸地處理配置類及其父類層次結構。
    SourceClass sourceClass = asSourceClass(configClass);
    do {
        //遞歸處理Bean,如果有父類,遞歸處理,直到頂層父類
        sourceClass = doProcessConfigurationClass(configClass, sourceClass);
    }
    while (sourceClass != null);

    this.configurationClasses.put(configClass, configClass);
}
// ConfigurationClassParser類
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
        throws IOException {

    // Recursively process any member (nested) classes first
    //首先遞歸處理內部類,(SpringBoot項目的主類一般沒有內部類)
    processMemberClasses(configClass, sourceClass);

    // Process any @PropertySource annotations
    // 針對 @PropertySource 注解的屬性配置處理
    for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
            sourceClass.getMetadata(), PropertySources.class,
            org.springframework.context.annotation.PropertySource.class)) {
        if (this.environment instanceof ConfigurableEnvironment) {
            processPropertySource(propertySource);
        } else {
            logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
                    "]. Reason: Environment must implement ConfigurableEnvironment");
        }
    }

    // Process any @ComponentScan annotations
    // 根據 @ComponentScan 注解,掃描項目中的Bean(SpringBoot 啟動類上有該注解)
    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
            // 立即執行掃描,(SpringBoot項目為什么是從主類所在的包掃描,這就是關鍵了)
            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();
                }
                // 檢查是否是ConfigurationClass(是否有configuration/component兩個注解),如果是,遞歸查找該類相關聯的配置類。
                // 所謂相關的配置類,比如@Configuration中的@Bean定義的bean。或者在有@Component注解的類上繼續存在@Import注解。
                if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                    parse(bdCand.getBeanClassName(), holder.getBeanName());
                }
            }
        }
    }

    // Process any @Import annotations
    //遞歸處理 @Import 注解(SpringBoot項目中經常用的各種@Enable*** 注解基本都是封裝的@Import)
    processImports(configClass, sourceClass, getImports(sourceClass), 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;
}

看doProcessConfigurationClass()方法。(SpringBoot的包掃描的入口方法,重點哦)

for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(... 獲取主類上的@PropertySource注解(關於該注解是怎么用的請自行百度),解析該注解並將該注解指定的properties配置文件中的值存儲到Spring的 Environment中,Environment接口提供方法去讀取配置文件中的值,參數是properties文件中定義的key值。

Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class); 解析主類上的@ComponentScan注解,呃,怎么說呢,42行后面的代碼將會解析該注解並進行包掃描。

processImports(configClass, sourceClass, getImports(sourceClass), true); 解析主類上的@Import注解,並加載該注解指定的配置類。

提示:在spring中好多注解都是一層一層封裝的,比如@EnableXXX,是對@Import注解的二次封裝。@SpringBootApplication注解=@ComponentScan+@EnableAutoConfiguration+@Import+@Configuration+@Component。@Controller,@Service等等是對@Component的二次封裝。

Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); 進入該方法

// ComponentScanAnnotationParser類
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
    ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
            componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
    ...
    // 根據 declaringClass (如果是SpringBoot項目,則參數為主類的全路徑名)
    if (basePackages.isEmpty()) {
        basePackages.add(ClassUtils.getPackageName(declaringClass));
    }
    ...
    // 根據basePackages掃描類
    return scanner.doScan(StringUtils.toStringArray(basePackages));
}

發現有兩行重要的代碼。

到這里呢IoC容器初始化三個步驟的第一步,Resource定位就完成了,成功定位到了主類所在的包。

接着往下看 return scanner.doScan(StringUtils.toStringArray(basePackages)); Spring是如何進行類掃描的。進入doScan()方法。

// ComponentScanAnnotationParser類
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    for (String basePackage : basePackages) {
        // 從指定的包中掃描需要裝載的Bean
        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);
                //將該 Bean 注冊進 IoC容器(beanDefinitionMap)
                registerBeanDefinition(definitionHolder, this.registry);
            }
        }
    }
    return beanDefinitions;
}

這個方法中有兩個比較重要的方法,Set<BeanDefinition> candidates = findCandidateComponents(basePackage); 從basePackage中掃描類並解析成BeanDefinition,拿到所有符合條件的類后在 registerBeanDefinition(definitionHolder, this.registry); 將該類注冊進IoC容器。也就是說在這個方法中完成了IoC容器初始化過程的第二三步,BeanDefinition的載入,和BeanDefinition的注冊。

findCandidateComponents(basePackage);
// ClassPathScanningCandidateComponentProvider類
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
    ...
    else {
        return scanCandidateComponents(basePackage);
    }
}
// ClassPathScanningCandidateComponentProvider類
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
    Set<BeanDefinition> candidates = new LinkedHashSet<>();
    try {
        //拼接掃描路徑,比如:classpath*:org/springframework/boot/demo/**/*.class
        String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                resolveBasePackage(basePackage) + '/' + this.resourcePattern;
        //從 packageSearchPath 路徑中掃描所有的類
        Resource[] resources = getResourcePatternResolver().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 = getMetadataReaderFactory().getMetadataReader(resource);
                    // //判斷該類是不是 @Component 注解標注的類,並且不是需要排除掉的類
                    if (isCandidateComponent(metadataReader)) {
                        //將該類封裝成 ScannedGenericBeanDefinition(BeanDefinition接口的實現類)類
                        ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                        sbd.setResource(resource);
                        sbd.setSource(resource);
                        if (isCandidateComponent(sbd)) {
                            if (debugEnabled) {
                                logger.debug("Identified candidate component class: " + resource);
                            }
                            candidates.add(sbd);
                        } else {
                            if (debugEnabled) {
                                logger.debug("Ignored because not a concrete top-level class: " + resource);
                            }
                        }
                    } else {
                        if (traceEnabled) {
                            logger.trace("Ignored because not matching any filter: " + resource);
                        }
                    }
                } catch (Throwable ex) {
                    throw new BeanDefinitionStoreException(
                            "Failed to read candidate component class: " + resource, ex);
                }
            } else {
                if (traceEnabled) {
                    logger.trace("Ignored because not readable: " + resource);
                }
            }
        }
    } catch (IOException ex) {
        throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
    }
    return candidates;
}

將basePackage拼接成classpath*:org/springframework/boot/demo/**/*.class,在getResources(packageSearchPath);方法中掃描到了該路徑下的所有的類。然后遍歷這些Resources,在isCandidateComponent(metadataReader)方法中判斷該類是不是 @Component 注解標注的類,並且不是需要排除掉的類。ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);將掃描到的類,解析成ScannedGenericBeanDefinition,該類是BeanDefinition接口的實現類。OK,IoC容器的BeanDefinition載入到這里就結束了。

registerBeanDefinition(definitionHolder, this.registry);

查看registerBeanDefinition()方法。是不是有點眼熟,在前面介紹prepareContext()方法時,我們詳細介紹了主類的BeanDefinition是怎么一步一步的注冊進DefaultListableBeanFactory的beanDefinitionMap中的。在此呢我們就省略1w字吧。完成了BeanDefinition的注冊,就完成了IoC容器的初始化過程。此時,在使用的IoC容器DefaultListableFactory中已經建立了整個Bean的配置信息,而這些BeanDefinition已經可以被容器使用了。他們都在BeanbefinitionMap里被檢索和使用。容器的作用就是對這些信息進行處理和維護。這些信息是容器簡歷依賴反轉的基礎。

protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
    BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
}

OK,到這里IoC容器的初始化過程的三個步驟就梳理完了。當然這只是針對SpringBoot的包掃描的定位方式的BeanDefinition的定位,加載,和注冊過程。前面我們說過,還有兩種方式@Import和SPI擴展實現的starter的自動裝配。

@Import注解的解析過程

相信不說大家也應該知道了,各種@EnableXXX注解,很大一部分都是對@Import的二次封裝(其實也是為了解耦,比如當@Import導入的類發生變化時,我們的業務系統也不需要改任何代碼)。

我們又要回到上文中的ConfigurationClassParser類的doProcessConfigurationClass方法的processImports(configClass, sourceClass, getImports(sourceClass), true);

processImports(configClass, sourceClass, getImports(sourceClass), true);中configClass和sourceClass參數都是主類相對應的。

首先看getImports(sourceClass);

private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
    Set<SourceClass> imports = new LinkedHashSet<>();
    Set<SourceClass> visited = new LinkedHashSet<>();
    collectImports(sourceClass, imports, visited);
    return imports;
}

三、SpringBoot自動裝配原理實現

通過分析refresh()方法中的invokeBeanFactoryPostProcessors()方法,分析了IoC容器的初始化過程,這一節從代碼上如下所示,接上一節ConfigurationClassParser類中的parse()方法,接着分析SpringBoot的自動裝配原理。

public void parse(Set<BeanDefinitionHolder> configCandidates) {
    Iterator var2 = configCandidates.iterator();

    while(var2.hasNext()) {
        BeanDefinitionHolder holder = (BeanDefinitionHolder)var2.next();
        BeanDefinition bd = holder.getBeanDefinition();

        try {
            // 如果是SpringBoot項目進來的,bd其實就是前面主類封裝成的 AnnotatedGenericBeanDefinition(AnnotatedBeanDefinition接口的實現類)
            if (bd instanceof AnnotatedBeanDefinition) {
                this.parse(((AnnotatedBeanDefinition)bd).getMetadata(), holder.getBeanName());
            } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition)bd).hasBeanClass()) {
                this.parse(((AbstractBeanDefinition)bd).getBeanClass(), holder.getBeanName());
            } else {
                this.parse(bd.getBeanClassName(), holder.getBeanName());
            }
        } catch (BeanDefinitionStoreException var6) {
            throw var6;
        } catch (Throwable var7) {
            throw new BeanDefinitionStoreException("Failed to parse configuration class [" + bd.getBeanClassName() + "]", var7);
        }
    }
    // 加載默認的配置---》(對springboot項目來說這里就是自動裝配的入口了)
    this.deferredImportSelectorHandler.process();
}
@SpringBootApplication注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
    ...
}

接着看@EnableAutoConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    ...
}

OK,看到@Import(AutoConfigurationImportSelector.class)導入了一個重要的類AutoConfigurationImportSelector。

AutoConfigurationImportSelector
//自動裝配
public String[] selectImports(AnnotationMetadata annotationMetadata) {
    if (!this.isEnabled(annotationMetadata)) {
        return NO_IMPORTS;
    } else {
        AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
        return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    }
}

protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    if (!this.isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    } else {
        AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
        //獲取所有的自動配置類(META-INF/spring.factories中配置的key為org.springframework.boot.autoconfigure.EnableAutoConfiguration的類)
        List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
        configurations = this.removeDuplicates(configurations);
        //需要排除的自動裝配類(springboot的主類上 @SpringBootApplication(exclude = {com.demo.starter.config.DemoConfig.class})指定的排除的自動裝配類)
        Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
        this.checkExcludedClasses(configurations, exclusions);
        //將需要排除的類從 configurations remove掉
        configurations.removeAll(exclusions);
        configurations = this.getConfigurationClassFilter().filter(configurations);
        this.fireAutoConfigurationImportEvents(configurations, exclusions);
        return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
    }
}

至於怎么從章節一中提到的ConfigurationClassParser類中的parse()===>deferredImportSelectorHandler.process();==>AutoConfigurationImportSelector#selectImports(),篇幅有限不做過多介紹。

我們來看一下getCandidateConfigurations()方法是怎么拿到這些自動配置類的。

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
    Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
    return configurations;
}

是不是又看到一個十分熟悉的方法loadFactoryNames(),沒錯,其實我們在分析SpringBoot啟動流程的的時候,就已經分析了,SpringBoot是如何從META-INF/spring.factories中加載指定key的value的。

繼續看Set<String> exclusions = getExclusions(annotationMetadata, attributes);方法,該方法是排除主類上@SpringBootApplication注解上排除的自動裝配的類。

configurations = this.getConfigurationClassFilter().filter(configurations);該行代碼將會過濾掉不需要裝配的類。過濾的邏輯有很多,比如我們常用的@ConditionXXX注解。如下所示:

@ConditionalOnBean:容器中有指定的Bean
@ConditionalOnClass:當類路徑下有指定的類
@ConditionalOnExpression:基於SpEL表達式作為判斷條件
@ConditionalOnJava:基於JVM版本作為判斷條件
@ConditionalOnJndi:在JNDI存在的條件下查找指定的位置
@ConditionalOnMissingBean:當容器中沒有指定Bean的情況下
@ConditionalOnMissingClass:當類路徑下沒有指定的類
@ConditionalOnNotWebApplication:當前項目不是Web項目
@ConditionalOnProperty:配置文件中指定的屬性是否有指定的值
@ConditionalOnResource:類路徑下是否有指定的資源
@ConditionalOnSingleCandidate:當指定Bean在容器中只有一個,或者雖然有多個但是指定首選Bean
@ConditionalOnWebApplication:當前項目是Web項目的條件下 

四、IOC容器依賴注入

前面在refresh()-->invokeBeanFactoryPostProcessors(beanFactory);方法中已經完成了IoC容器的初始化並已經載入了我們定義的Bean的信息(BeanDefinition),現在我們開始分析依賴注入的原理。首先需要說明的是依賴注入在用戶第一次向IoC容器索要Bean時觸發,當然也有例外,我們可以在BeanDefinition中中通過控制lazy-init屬性來讓容器完成對Bean的預實例化。這個預實例化實際上也是一個依賴注入的過程,但它是在初始化過程中完成的。

getBean()的過程
// AbstractApplicationContext類
@Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        ...
        try {
            ...
            // Instantiate all remaining (non-lazy-init) singletons.
            finishBeanFactoryInitialization(beanFactory);
            ...
        }
        ...
    }
}
// AbstractApplicationContext類
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    ...
    // Instantiate all remaining (non-lazy-init) singletons.
    // 實例化所有剩余的(non-lazy-init)單例。
    beanFactory.preInstantiateSingletons();
}
// DefaultListableBeanFactory類
@Override
public void preInstantiateSingletons() throws BeansException {
    ...
    // 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) {
                    final 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);
            }
        }
    }
    ...
}

跟蹤其調用棧,看到getBean(beanName);方法,我們再梳理一下getBean()方法,前面總結過該方法在IoC容器的頂層接口BeanFactory中定義,然后在IoC容器的具體產品DefaultListableBeanFactory類的基類AbstractBeanFactory實現了getBean()方法。接着看代碼。

// AbstractBeanFactory類
@Override
public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
}
@Override
public <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException {
    return doGetBean(name, requiredType, null, false);
}
@Override
public Object getBean(String name, Object... args) throws BeansException {
    return doGetBean(name, null, args, false);
}
public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args)
        throws BeansException {
    return doGetBean(name, requiredType, args, false);
}

從上面代碼可知大致可分為兩種獲取Bean的參數,一種是按名獲取,一種是按類獲取。但是最終都進入到了doGetBean()方法。

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

    // bean獲取過程:先獲取bean名字
    // 會把帶有&前綴的去掉,或者去aliasMap中找這個是不是別名,最終確定bean的id是什么
    final String beanName = transformedBeanName(name);
    Object bean;

    // 1.檢查緩存中或者實例工廠中是否有對應的實例
    // 因為在創建單例bean的時候會存在依賴注入的情況,而在創建依賴的時候為了避免循環依賴
    // Spring在創建bean的時候不會等bean創建完成就會將bean的ObjectFactory提早曝光
    // 也就是將ObjectFactory加入到緩存中,一旦下一個要創建的bean需要依賴上個bean則直接使用ObjectFactory
    // 2.spring 默認是單例的,如果能獲取到直接返回,提高效率。
    // 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的正確性,同時如果獲取的是FactoryBean的話還需要調用getObject()方法獲取最終的那個bean實例
        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.
        //這里對IoC容器中的BeanDefinition是否存在進行檢查,檢查是否能在當前的BeanFactory中取得需要的Bean。
        // 如果當前的工廠中取不到,則到雙親BeanFactory中去取。如果當前的雙親工廠取不到,那就順着雙親BeanFactory
        // 鏈一直向上查找。
        BeanFactory parentBeanFactory = getParentBeanFactory();
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            // Not found -> check parent.
            String nameToLookup = originalBeanName(name);
            if (parentBeanFactory instanceof AbstractBeanFactory) {
                // 遞歸調用父bean的doGetBean查找
                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 {
                // No args -> delegate to standard getBean method.
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
        }

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

        try {
            //這里根據Bean的名字取得BeanDefinition
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);

            // Guarantee initialization of beans that the current bean depends on.
            //獲取當前Bean的所有依賴Bean,這里會觸發getBean的遞歸調用。知道取到一個沒有任何依賴的Bean為止。
            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);
                    }
                }
            }

            // 這里通過createBean方法創建singleton Bean的實例 這里還有一個回調函數
            // Create bean instance.
            if (mbd.isSingleton()) {
                sharedInstance = getSingleton(beanName, () -> {
                    try {
                        // 最后在getSingleton中又會調用這個方法
                        // TODO createBean的入口
                        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);
            }
            // 這里是創建prototype bean的地方
            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, () -> {
                        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.
    //這里對創建的Bean進行類型檢查,如果沒有問題,就返回這個新創建的Bean,這個Bean已經是包含了依賴關系的Bean
    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.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;
}

這個就是依賴注入的入口了,依賴注入是在容器的BeanDefinition數據已經建立好的前提下進行的。“程序=數據+算法”,很經典的一句話,前面我們詳細介紹了BeanDefinition的注冊過程,BeanDefinition就是數據。如上面代碼所示,doGetBean()方法不涉及復雜的算法,但是這個過程也不是很簡單,因為我們都知道,對於IoC容器的使用,Spring提供了很多的配置參數,每一個配置參數實際上就代表了一個IoC容器的實現特征,這些特征很多都需要在依賴注入的過程或者對Bean進行生命周期管理的過程中完成。雖然我們可以簡單的將IoC容器描述成一個ConcurrentHashMap,ConcurrentHashMap只是它的數據結構而不是IoC容器的全部。

Object sharedInstance = getSingleton(beanName);如注釋所說,首先回去找在容器中是不是已經存在該單例。

// DefaultSingletonBeanRegistry類
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 由於scope是singleton,所以先從緩存中取單例對象的實例,如果取到直接返回,沒有取到加載bean
    Object singletonObject = this.singletonObjects.get(beanName);
    // 當想要獲取的bean沒有被加載,並且也沒有正在被創建的時候,主動去加載bean
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        // 鎖住單例緩存區加載bean
        synchronized (this.singletonObjects) {
            // singletonObjects ,earlySingletonObjects ,singletonFactories是一個單例實例的三種存在狀態
            // 再去earlySingletonObjects中去找
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                // 去singletonFactories中去找對象的實例
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

在DefaultSingletonBeanRegistry類中的singletonObjects屬性就是存singleton bean的地方。

如果getSingleton()為 null繼續往下看,會在當前的BeanFactory中獲取BeanDefinition,也就是這行方法代碼:final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);在這行代碼拿到BeanDefinition后,首先判斷是不是singleton Bean,如果是的話,開始執行創建Bean,正是return createBean(beanName, mbd, args);這行代碼。如果是原型(Prototype)Bean我們就不分析了。原型bean每次執行getBean()都會創建一個實例。接下來我們看createBean()方法。

createBean()的過程

首先看一下create bean的過程

Bean實例的創建
為Bean實例設置屬性(屬性注入,其實就是依賴注入真正發生的地方)
調用Bean的初始化方法

前面說了getBean()是依賴注入的起點,之后會調用createBean(),下面通過createBean()代碼來了解這個過程。在這個過程中,Bean對象會根據BeanDefinition定義的要求生成。

// AbstractAutowireCapableBeanFactory類
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
        throws BeanCreationException {
    ...
    try {
        // 驗證以及准備override的方法
        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.
        // createBean之前調用BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法
        // 默認不做任何處理所以會返回null
        // 但是如果我們重寫了這兩個方法,那么bean的創建過程就結束了,這里就為以后的annotation自動注入提供了鈎子
        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 {
        // 實際執行createBean的是doCreateBean()方法
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        if (logger.isDebugEnabled()) {
            logger.debug("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);
    }
}

接着往下看doCreateBean()方法。

// AbstractAutowireCapableBeanFactory類
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
        throws BeanCreationException {
    // BeanWrapper是用來持有創建出來的Bean對象
    // Instantiate the bean.
    BeanWrapper instanceWrapper = null;
    // 如果是單例,先把緩存中的同名Bean清除
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    // 這里是創建Bean的地方,由createBeanInstance完成。
    // TODO 完成Bean初始化過程的第一步:創建實例
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    final 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.
    // 是否自動解決循環引用
    // 當bean條件為: 單例&&允許循環引用&&正在創建中這樣的話提早暴露一個ObjectFactory
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
            isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
        if (logger.isDebugEnabled()) {
            logger.debug("Eagerly caching bean '" + beanName +
                    "' to allow for resolving potential circular references");
        }
        // 把ObjectFactory放進singletonFactories中
        // 這里在其他bean在創建的時候會先去singletonFactories中查找有沒有beanName到ObjectFactory的映射
        // 如果有ObjectFactory就調用它的getObject方法獲取實例
        // 但是在這里就可以對一個bean進行保證,代理等等AOP就可以在getEarlyBeanReference這里實現
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }

    // Initialize the bean instance.
    Object exposedObject = bean;
    try {
        // TODO 完成Bean初始化過程的第二步:為Bean的實例設置屬性
        // Bean依賴注入發生的地方
        // 對bean進行屬性填充,如果存在依賴於其他的bean的屬性,則會遞歸的調用初始化依賴的bean
        populateBean(beanName, mbd, instanceWrapper);
        // TODO 完成Bean初始化過程的第三步:調用Bean的初始化方法(init-method)
        // 調用初始化方法,比如init-method方法指定的方法
        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 " +
                            "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                }
            }
        }
    }

    // Register bean as disposable.
    try {
        // 注冊銷毀方法,比如:可以在配置bean的時候指定destory-method方法
        registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }
    catch (BeanDefinitionValidationException ex) {
        throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
    }

    return exposedObject;
}

結合上面的代碼,我們再來看一下創建Bean的三個步驟,是不是有點豁然開朗的感覺。別着急繼續往下看。

Bean實例的創建,instanceWrapper = createBeanInstance(beanName, mbd, args);
為Bean實例設置屬性,populateBean(beanName, mbd, instanceWrapper);
調用Bean的初始化方法,exposedObject = initializeBean(beanName, exposedObject, mbd);
createBeanInstance():Bean實例的創建
// AbstractAutowireCapableBeanFactory類
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    // Make sure bean class is actually resolved at this point.
    // 確認需要創建的Bean的實例的類可以實例化
    Class<?> beanClass = resolveBeanClass(mbd, beanName);

    if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
    }

    Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    if (instanceSupplier != null) {
        return obtainFromSupplier(instanceSupplier, beanName);
    }

    // 當有工廠方法的時候使用工廠方法初始化Bean,就是配置的時候指定FactoryMethod屬性,類似注解中的@Bean把方法的返回值作為Bean
    if (mbd.getFactoryMethodName() != null)  {
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }

    // Shortcut when re-creating the same bean...
    boolean resolved = false;
    boolean autowireNecessary = false;
    if (args == null) {
        synchronized (mbd.constructorArgumentLock) {
            if (mbd.resolvedConstructorOrFactoryMethod != null) {
                resolved = true;
                autowireNecessary = mbd.constructorArgumentsResolved;
            }
        }
    }
    if (resolved) {
        if (autowireNecessary) {
            // 如果有有參數的構造函數,構造函數自動注入
            // 這里spring會花費大量的精力去進行參數的匹配
            return autowireConstructor(beanName, mbd, null, null);
        }
        else {
            // 如果沒有有參構造函數,使用默認構造函數構造
            return instantiateBean(beanName, mbd);
        }
    }

    // Need to determine the constructor...
    // 使用構造函數進行實例化
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    if (ctors != null ||
            mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
            mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
        return autowireConstructor(beanName, mbd, ctors, args);
    }

    // No special handling: simply use no-arg constructor.
    // 使用默認的構造函數對Bean進行實例化
    return instantiateBean(beanName, mbd);
}

我們可以看到在instantiateBean()方法中生成了Bean所包含的Java對象,這個對象的生成有很多種不同的方式,可以通過工廠方法生成,也可以通過容器的autowire特性生成,這些生成方式都是由BeanDefinition決定的。對於上面我們的WebController和WebService兩個類是通過最后一行,使用默認的構造函數進行Bean的實例化。

接着看instantiateBean()方法。

// AbstractAutowireCapableBeanFactory類
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
    // 使用默認的實例化策略對Bean進行實例化,默認的實例化策略是CglibSubclassingInstantiationStrategy,
    // 也就是常說的CGLIB來對Bean進行實例化。PS:面試官常問的字節碼增強
    try {
        Object beanInstance;
        final BeanFactory parent = this;
        if (System.getSecurityManager() != null) {
            beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
                    getInstantiationStrategy().instantiate(mbd, beanName, parent),
                    getAccessControlContext());
        }
        else {
            // getInstantiationStrategy()會返回CglibSubclassingInstantiationStrategy類的實例
            beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
        }
        BeanWrapper bw = new BeanWrapperImpl(beanInstance);
        initBeanWrapper(bw);
        return bw;
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
    }
}

這里使用CGLIB進行Bean的實例化。CGLIB是一個常用的字節碼生成器的類庫,其提供了一系列的API來提供生成和轉換Java字節碼的功能。在Spring AOP中同樣也是使用的CGLIB對Java的字節碼進行增強。在IoC容器中,使用SimpleInstantiationStrategy類。這個類是Spring用來生成Bean對象的默認類,它提供了兩種實例化Java對象的方法,一種是通過BeanUtils,它使用的是JVM的反射功能,一種是通過CGLIB來生成。

getInstantiationStrategy()方法獲取到CglibSubclassingInstantiationStrategy實例,instantiate()是CglibSubclassingInstantiationStrategy類的父類SimpleInstantiationStrategy實現的。

// SimpleInstantiationStrategy類
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
    // Don't override the class with CGLIB if no overrides.
    // 如果BeanFactory重寫了Bean內的方法,則使用CGLIB,否則使用BeanUtils
    if (!bd.hasMethodOverrides()) {
        // 如果bean沒有需要動態替換的方法就直接反射進行創建實例
        Constructor<?> constructorToUse;
        synchronized (bd.constructorArgumentLock) {
            constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
            if (constructorToUse == null) {
                final Class<?> clazz = bd.getBeanClass();
                if (clazz.isInterface()) {
                    throw new BeanInstantiationException(clazz, "Specified class is an interface");
                }
                try {
                    if (System.getSecurityManager() != null) {
                        constructorToUse = AccessController.doPrivileged(
                                (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
                    } else {
                        constructorToUse = clazz.getDeclaredConstructor();
                    }
                    bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                } catch (Throwable ex) {
                    throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                }
            }
        }
        // 通過BeanUtils進行實例化,這個BeanUtils的實例化通過Constructor類實例化Bean
        // 在BeanUtils中可以看到具體的調用ctor.newInstances(args)
        return BeanUtils.instantiateClass(constructorToUse);
    } else {
        // Must generate CGLIB subclass.
        // TODO 使用CGLIB實例化對象
        return instantiateWithMethodInjection(bd, beanName, owner);
    }
}

在SpringBoot中我們一般采用@Autowire的方式進行依賴注入,很少采用像SpringMVC那種在xml中使用<lookup-method>或者<replaced-method>等標簽的方式對注入的屬性進行override,所以在上面的代碼中if(!bd.hasMethodOverrides())中的判斷為true,會采用BeanUtils的實例化方式。

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.
    boolean continueWithPropertyPopulation = true;
    // 調用InstantiationAwareBeanPostProcessor  Bean的后置處理器,在Bean注入屬性前改變BeanDefinition的信息
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                    continueWithPropertyPopulation = false;
                    break;
                }
            }
        }
    }
    if (!continueWithPropertyPopulation) {
        return;
    }
    // 這里取得在BeanDefinition中設置的property值,這些property來自對BeanDefinition的解析
    // 用於在配置文件中通過<property>配置的屬性並且顯示在配置文件中配置了autowireMode屬性
    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
    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.
        // 這里對autowire注入的處理,autowire by name
        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
            autowireByName(beanName, mbd, bw, newPvs);
        }

        // Add property values based on autowire by type if applicable.
        // 這里對autowire注入的處理, autowire by type
        // private List<Test> tests;
        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
            autowireByType(beanName, mbd, bw, newPvs);
        }

        pvs = newPvs;
    }
    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
    if (hasInstAwareBpps || needsDepCheck) {
        if (pvs == null) {
            pvs = mbd.getPropertyValues();
        }
        PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
        if (hasInstAwareBpps) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    // TODO @Autowire @Resource @Value @Inject 等注解的依賴注入過程
                    pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                    if (pvs == null) {
                        return;
                    }
                }
            }
        }
        if (needsDepCheck) {
            checkDependencies(beanName, mbd, filteredPds, pvs);
        }
    }
    if (pvs != null) {
        // 注入配置文件中<property>配置的屬性
        applyPropertyValues(beanName, mbd, bw, pvs);
    }
}

上面方法中的applyPropertyValues()方法基本都是用於SpringMVC中采用xml配置Bean的方法。我們主要看的是pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);這行代碼,這行代碼是真正執行采用@Autowire @Value 等注解的依賴注入過程。

接着往下看

// AutowiredAnnotationBeanPostProcessor類
@Override
public PropertyValues postProcessPropertyValues(
        PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
    // 遍歷,獲取@Autowire,@Resource,@Value,@Inject等具備注入功能的注解
    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;
}

AutowiredAnnotationBeanPostProcessor類實現了postProcessPropertyValues()方法。findAutowiringMetadata(beanName, bean.getClass(), pvs);方法會尋找在當前類中的被@Autowire,@Value等具備注入功能的注解的屬性。

metadata.inject(bean, beanName, pvs);方法開始執行注入的邏輯。

// AutowiredAnnotationBeanPostProcessor類
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    // 需要注入的字段
    Field field = (Field) this.member;
    // 需要注入的屬性值
    Object value;
    if (this.cached) {
        value = resolvedCachedArgument(beanName, this.cachedFieldValue);
    } else {
        // @Autowired(required = false),當在該注解中設置為false的時候,如果有直接注入,沒有跳過,不會報錯。
        DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
        desc.setContainingClass(bean.getClass());
        Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
        Assert.state(beanFactory != null, "No BeanFactory available");
        TypeConverter typeConverter = beanFactory.getTypeConverter();
        try {
            // 通過BeanFactory 解決依賴關系
            // 比如在webController中注入了webService,這個會去BeanFactory中去獲取webService,也就是getBean()的邏輯。
            // 如果存在直接返回,不存在再執行createBean()邏輯。
            // 如果在webService中依然依賴,依然會去遞歸。
            // 這里是一個復雜的遞歸邏輯。
            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) &&
                                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);
    }
}

看這行代碼:value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);注意beanFactory依舊是我們熟悉的IoC容器的具體產品,也就是實現類DefaultListableBeanFactory。見到就說一遍,方便大家記住它,很重要。

在resolveDependency()方法中經過一頓操作,最終又會來到上面的getBean()方法。以上就是依賴注入的整個過程。

initializeBean():調用Bean的初始化方法

設置Bean的初始化方法有兩種方法,一種是在xml或者@Bean指定init-method方法。另一種是讓bean實現InitializingBean接口重寫afterPropertiesSet()方法。

// AbstractAutowireCapableBeanFactory類
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            invokeAwareMethods(beanName, bean);
            return null;
        }, getAccessControlContext());
    }
    else {
        //在調用Bean的初始化方法之前,調用一系列的aware接口實現,把相關的BeanName,BeanClassLoader,以及BeanFactory注入到Bean中去。
        invokeAwareMethods(beanName, bean);
    }

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        // 這些都是鈎子方法,在反復的調用,給Spring帶來了極大的可拓展性
        // 初始化之前調用BeanPostProcessor
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        // 調用指定的init-method方法
        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()) {
        // 這些都是鈎子方法,在反復的調用,給Spring帶來了極大的可拓展性
        // 初始化之后調用BeanPostProcessor
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

在調用Bean的初始化方法之前,調用一系列的aware接口實現,把相關的BeanName,BeanClassLoader,以及BeanFactory注入到Bean中去。接着會執行invokeInitMethods()方法。

// AbstractAutowireCapableBeanFactory類
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
        throws Throwable {
    // 除了使用init-method指定的初始化方法,還可以讓bean實現InitializingBean接口重寫afterPropertiesSet()方法
    boolean isInitializingBean = (bean instanceof InitializingBean);
    if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
        if (logger.isDebugEnabled()) {
            logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
        }
        if (System.getSecurityManager() != null) {
            try {
                AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
                    ((InitializingBean) bean).afterPropertiesSet();
                    return null;
                }, getAccessControlContext());
            }
            catch (PrivilegedActionException pae) {
                throw pae.getException();
            }
        }
        else {
            // 執行afterPropertiesSet()方法進行初始化
            ((InitializingBean) bean).afterPropertiesSet();
        }
    }

    // 先執行afterPropertiesSet()方法,再進行init-method
    if (mbd != null && bean.getClass() != NullBean.class) {
        String initMethodName = mbd.getInitMethodName();
        if (StringUtils.hasLength(initMethodName) &&
                !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                !mbd.isExternallyManagedInitMethod(initMethodName)) {
            invokeCustomInitMethod(beanName, bean, mbd);
        }
    }
}

可見該方法中首先判斷Bean是否配置了init-method方法,如果有,那么通過invokeCustomInitMethod()方法來直接調用。其中在invokeCustomInitMethod()方法中是通過JDK的反射機制得到method對象,然后調用的init-method。最終完成Bean的初始化。

 

備注:因為篇幅太長,所以里面的一些代碼可能會因為版本關系導致代碼不完全一樣,但是處理邏輯基本是一樣的。

轉自:

https://www.cnblogs.com/hello-shf/category/1456313.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM