日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

springboot启动流程

發布時間:2025/3/21 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 springboot启动流程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一句話總結:在context的refresh方法中,需要注冊bean definition,實例化bean.在加載bean defintion的時候使用ConfigurationClassParser類來解析我們的主類。然后在解析主類的時候發現了@EnableAutoConfiguratio注解中的@Import注解,就去處理@Import注解中的value值,然后就使用ImportSelector來獲取被配置在spring.factories中的類。這些類通常是AutoConfiguration。這些configuration中包含了各種各樣的bean

一切的開始源于AppBootstrap.main方法,它調用了SpringApplication.run(AppBootstrap.class)方法。

在SpringApplication.run(AppBootstrap.class)方法中

//SpringApplication.java public static ConfigurableApplicationContext run(Object[] sources, String[] args) {return (new SpringApplication(sources)).run(args); }

所以我們可以看到spring啟動流程大概分為兩部,new和run。所以本篇文章會從分兩個部分說明springboot的啟動流程。在訴說啟動流程的過程中,會將spring boot 的自動配置有關的東西重點拎出來。因為自動配置,我們可以什么都不做就可以啟動一個web服務,不需要在web.xml中配置servlet,也不需要在applicationcontext.xml中配置componentScan。

new SpringApplication(sources)

public SpringApplication(Object... sources) {//設置打印模式this.bannerMode = Mode.CONSOLE;this.logStartupInfo = true;this.addCommandLineProperties = true;this.headless = true;this.registerShutdownHook = true;this.additionalProfiles = new HashSet();//主要設置listeners,initializer。listeners監聽env,context的事件。initializer是在prepareContext中用來初始化contextthis.initialize(sources);}

屬性設置

headless 刑天模式?
Headless模式是在缺少顯示屏、鍵盤或者鼠標時的系統配置。?
在java.awt.toolkit和java.awt.graphicsenvironment類中有許多方法,除了對字體、圖形和打印的操作外還需要調用顯示器、鍵盤和鼠標的方法。在電腦缺少對應硬件設備的時候會拋出HeadlessException異常。但是有些類,如Canvas也可以在headless下正常使用。?
headless?
headless

初始化

initialize(sources)

private void initialize(Object[] sources) {if (sources != null && sources.length > 0) {this.sources.addAll(Arrays.asList(sources));}/*deduceWebEnvironment方法通過判斷javax.servlet.Servlet,org.springframework.web.context.ConfigurableWebApplicationContext這兩個Class是否存在判斷是否是Web環境*/this.webEnvironment = this.deduceWebEnvironment();this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));//設置mainApplicationClass為AppBootstrapthis.mainApplicationClass = this.deduceMainApplicationClass();}

ApplicationContextInitializer

在setInitializer方法中被實例化的initializer有:?

查看這些initializer的類圖:?

他們都實現了ApplicationContextInitializer。顧名思義,和上下文有關的初始化器。也就是說這些實例將在上下文初始化的時候prepareContext被使用。

public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {void initialize(C var1); }

ApplicationListener

在setListeners方法中被實例的話listener包含:?

這些listener都實現了ApplicationListener接口。這個接口表示這個接口將監聽對應的ApplicationEvent事件

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {void onApplicationEvent(E var1); }

整理幾個listener和其監聽的事件如下:

listener事件
ConfigFileApplicationListenerApplicationEnvironmentPreparedEvent,ApplicationPreparedEvent
AnsiOutputApplicationListenerApplicationEnvironmentPreparedEvent
LoggingApplicationListenerApplicationStartingEvent,ApplicationEnvironmentPreparedEvent,ApplicationPreparedEvent,ContextClosedEvent,ApplicationFailedEvent
ClasspathLoggingApplicationListenerApplicationEnvironmentPreparedEvent,ApplicationFailedEvent
BackgroundPreinitializerApplicationEnvironmentPreparedEvent
DelegatingApplicationListenerApplicationEnvironmentPreparedEvent,**
ParentContextCloserApplicationListenerParentContextAvailableEvent
ClearCachesApplicationListenerContextRefreshedEvent
FileEncodingApplicationListenerApplicationEnvironmentPreparedEvent
LiquibaseServiceLocatorApplicationListenerApplicationStartingEvent

整理這些對應關系的目的在于,在啟動流程中,會出發許多ApplicationEvent。這時會調用對應的listener的onApplicationEvent方法。?
這里是一種觀察者模式。對于觀察者模式,個人的理解為:被觀察者持有觀察者的引用,在發生某些事情的時候,調用觀察者的方法即可

setInitailizers和setListeners方法

在setInitailizers和setListeners方法中都用到了getSpringFactoriesInstances.代碼如下

private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) {return this.getSpringFactoriesInstances(type, new Class[0]);}private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {ClassLoader classLoader = Thread.currentThread().getContextClassLoader();Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);AnnotationAwareOrderComparator.sort(instances);return instances;}

在其中使用SpringFactoriesLoader來根據type,classLoader從幾個jar包之類的spring.factories中獲取類名,之后實例化對應的類。代碼如下:

public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {String factoryClassName = factoryClass.getName();try {//會查找幾個Spring的jar包中的META-INF/spring.factories文件。Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");ArrayList result = new ArrayList();while(urls.hasMoreElements()) {URL url = (URL)urls.nextElement();Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));String factoryClassNames = properties.getProperty(factoryClassName);result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));}return result;} catch (IOException var8) {throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8);}}

SpringFactoriesLoader會查找幾個Spring的jar包中的META-INF/spring.factories文件。被查找的factories文件的內容大致如下:

# PropertySource Loaders org.springframework.boot.env.PropertySourceLoader=\ org.springframework.boot.env.PropertiesPropertySourceLoader,\ org.springframework.boot.env.YamlPropertySourceLoader# Run Listeners org.springframework.boot.SpringApplicationRunListener=\ org.springframework.boot.context.event.EventPublishingRunListener# Application Context Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\ org.springframework.boot.context.ContextIdApplicationContextInitializer,\ org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\ org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer# Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.ClearCachesApplicationListener,\ org.springframework.boot.builder.ParentContextCloserApplicationListener,\ org.springframework.boot.context.FileEncodingApplicationListener,\ org.springframework.boot.context.config.AnsiOutputApplicationListener,\ org.springframework.boot.context.config.ConfigFileApplicationListener,\ org.springframework.boot.context.config.DelegatingApplicationListener,\ org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\ org.springframework.boot.logging.ClasspathLoggingApplicationListener,\ org.springframework.boot.logging.LoggingApplicationListener# Environment Post Processors org.springframework.boot.env.EnvironmentPostProcessor=\ org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\ org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor# Failure Analyzers org.springframework.boot.diagnostics.FailureAnalyzer=\ org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer# FailureAnalysisReporters org.springframework.boot.diagnostics.FailureAnalysisReporter=\ org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter

在本項目中,被查找的有:

  • spring-boot
  • spring-boot-autoconfigure
  • spring-beans
  • spring-boot-test
  • spring-boot-test-autoconfigure
  • spring-test?
    這些jar包都是被直接或者間接的被項目所依賴.

spring.factories文件的作用也就間接的實現了自動化配置。我們可以在項目下創建自己的spring.factories文件。來向spring boot啟動流程中加入我們自己需要的東西。

現在回到SetListener和setInitializer方法。他們使用SpringFactoriesLoader從spring.factories文件中獲取對應type的類名。然后實例化這些類。并將這些實例保存在springApplication的對應屬性中。?
private List<ApplicationContextInitializer<?>> initializers;?
或者private List<ApplicationListener<?>> listeners;

由于listener和initializer的構造函數幾乎為null。所以不用去關心他們在構造函數中做了什么。

run

public ConfigurableApplicationContext run(String... args) {StopWatch stopWatch = new StopWatch();stopWatch.start();//context,上下文,我們的重點對象ConfigurableApplicationContext context = null;FailureAnalyzers analyzers = null;this.configureHeadlessProperty();//new SpringApplicationRunListeners用它來統一管理listeners,在事件發生的時候調用他們SpringApplicationRunListeners listeners = this.getRunListeners(args);listeners.starting();//如果有監聽器監聽啟動事件,則執行對應的動作try {//從命令行中讀取參數作為propertySource,放入到這里,會加入到env中ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);//創建env,加載配置文件,系統的屬性,profile文件,application.yml, 初始化日志系統ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);//打印bannerBanner printedBanner = this.printBanner(environment);//創建contextcontext = this.createApplicationContext();new FailureAnalyzers(context);this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);this.refreshContext(context);this.afterRefresh(context, applicationArguments);listeners.finished(context, (Throwable)null);stopWatch.stop();if (this.logStartupInfo) {(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);}return context;} catch (Throwable var9) {this.handleRunFailure(context, listeners, (FailureAnalyzers)analyzers, var9);throw new IllegalStateException(var9);}}

獲取運行時監聽器監聽運行時發生的事件:getRunListeners

SpringApplicationRunListeners listeners = this.getRunListeners(args);

首先看SpringApplicationRunListeners類。類中包含了一個SpringApplicationRunListener的集合.

class SpringApplicationRunListeners {private final Log log;private final List<SpringApplicationRunListener> listeners; } public interface SpringApplicationRunListener {void starting();void environmentPrepared(ConfigurableEnvironment var1);void contextPrepared(ConfigurableApplicationContext var1);void contextLoaded(ConfigurableApplicationContext var1);void finished(ConfigurableApplicationContext var1, Throwable var2); }

也就是說?
在run方法中構造了一個SpringRunApplicationListeners,其中包含多個SpringRunApplicationListener,用來監聽應用啟動過程中的start,environmentPrepared,contextPrepared,contextLoaded,finished等事件。

SpringRunApplicationLinsteners中到底包含哪些RunListener呢?包含從spring.factories中實例化的。在這里,getSpringFactoroiesIntsances方法返回只包含一個實例的集合,這個實例是EventPublishingRunListener

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

下面看EventPublishingRunListener類。

public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {private final SpringApplication application;private final String[] args;private final SimpleApplicationEventMulticaster initialMulticaster;public EventPublishingRunListener(SpringApplication application, String[] args) {//在這里,application即SpringApplicationthis.application = application;this.args = args;this.initialMulticaster = new SimpleApplicationEventMulticaster();Iterator var3 = application.getListeners().iterator();//在SpringApplication.initailize()方法中初始化的listeners被加入到EventPublishingRunListener里面的initialMulticaster中while(var3.hasNext()) {ApplicationListener<?> listener = (ApplicationListener)var3.next();this.initialMulticaster.addApplicationListener(listener);}} }

EventPublishingRunListener通過引用SimpleApplicationEventMulticaster來完成事件的發布和ApplicationListener的管理。

接下來我們仔細看SimpleApplicationEventMulticaster這個類。?

從SimpleApplicationEventMulticaster類的結構中可以看到multicaster使用ListenerRetriever來管理ApplicationListener。使用了retrieverCache:ConcurrentHashMap

廣播ApplicationStartedEvent事件:listeners.starting()

在上一步使用SpringRunApplicationListeners將所有的listener管理起來后,開始傳播start事件

//EventPublishingRunListenerpublic void starting() {this.initialMulticaster.multicastEvent(new ApplicationStartedEvent(this.application, this.args));}

需要注意的是:

public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);//在這一步getApplicationListeners(event,type)中,會從所有的listener中取出支持這個事件類型的listener,一個新的retriever會持有這些listener的引用作為value,另外以(event,source)作為key,存在retrieverCache中。Iterator var4 = this.getApplicationListeners(event, type).iterator();while(var4.hasNext()) {final ApplicationListener<?> listener = (ApplicationListener)var4.next();Executor executor = this.getTaskExecutor();if (executor != null) {executor.execute(new Runnable() {public void run() {SimpleApplicationEventMulticaster.this.invokeListener(listener, event);}});} else {this.invokeListener(listener, event);}}}

在listener.starting()這一部中,幾個listener都沒有做什么動作。

構造應用參數:new DefaultApplicationArguments(args)

創建DefaultApplicationArguments的作用是將參數存儲在DefaultApplicationArguments的內部類Source中。?
其中Source的類結構如圖:?

我們追尋Source的構造函數可以發現,使用SimpleCommandLineArgsParser來解析參數,將解析后的參數存到PropertySource的source屬性中。?
這里由于沒有什么參數,所以略過。

創建和準備環境:environment

ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {//創建env,如果是web環境,則創建StandardServletEnvironment,如果不是StandardEnvironmentConfigurableEnvironment environment = this.getOrCreateEnvironment();//配置envthis.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());//廣播environment事件listeners.environmentPrepared((ConfigurableEnvironment)environment);if (!this.webEnvironment) {environment = (new EnvironmentConverter(this.getClassLoader())).convertToStandardEnvironmentIfNecessary((ConfigurableEnvironment)environment);}return (ConfigurableEnvironment)environment;}

這段代碼主要分為幾個步驟:?
1. 創建Env?
2. 配置Env?
3. 調用監聽器廣播ApplicationEnvironmentPreparedEvent事件

創建Env

private ConfigurableEnvironment getOrCreateEnvironment() {if (this.environment != null) {return this.environment;} else {return (ConfigurableEnvironment)(this.webEnvironment ? new StandardServletEnvironment() : new StandardEnvironment());}}

如果是Web環境,則創建StandardServletEnvironment,否則創建StandardEnvironment.?
下面的代碼是有關Environment和ConfigurableEnvironment接口.?
我們可以從接口中看出Environment主要作用為:獲取系統的環境和spring的profile文件中的內容,存儲到PropertySource中。

public interface Environment extends PropertyResolver {String[] getActiveProfiles();String[] getDefaultProfiles();boolean acceptsProfiles(String... var1); } public interface ConfigurableEnvironment extends Environment, ConfigurablePropertyResolver {void setActiveProfiles(String... var1);void addActiveProfile(String var1);void setDefaultProfiles(String... var1);MutablePropertySources getPropertySources();Map<String, Object> getSystemEnvironment();Map<String, Object> getSystemProperties();void merge(ConfigurableEnvironment var1); }

有關Env的類圖:?

在environment初始化之后,PropertySources中包含的幾個PropertySource為4個:?
1. servletContextInitParam?
2. servletConfigInitParams?
3. systemEnv?
4. systemProperties

簡單說下PropertySource的結構

//代表了name/value屬性對的資源。source可以任何一種封裝了屬性值得類型。可以是Properties,Map,ServletContext,ServletConfig //一般都很少單獨使用PropertySource,而是使用PropertySources public abstract class PropertySource<T> {protected final Log logger;protected final String name;protected final T source; } //PropertySources中聚合了多個PropertySource,包含PropertyResolver的實現可以實現從PropertySource中搜索 public interface PropertySources extends Iterable<PropertySource<?>> {boolean contains(String var1);PropertySource<?> get(String var1); }

當和@Configuration一起工作時,@PropertySource注解可以方便得為當前環境加入配置文件?
和PropertySource相關的類圖:?

配置env

protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {this.configurePropertySources(environment, args);this.configureProfiles(environment, args);}//這兩個函數分別用來添加命令行參數的PropertySource和設置activeProfile。由于項目中沒有這些則略過

廣播ApplicationEnvironmentPreparedEvent事件

調用RunListener,廣播ApplicationEnvironmentPreparedEvent事件。受到影響的listener列在下表

listener事件
ConfigFileApplicationListenerApplicationEnvironmentPreparedEvent,ApplicationPreparedEvent
AnsiOutputApplicationListenerApplicationEnvironmentPreparedEvent
LoggingApplicationListenerApplicationStartingEvent,ApplicationEnvironmentPreparedEvent,ApplicationPreparedEvent,ContextClosedEvent,ApplicationFailedEvent
ClasspathLoggingApplicationListenerApplicationEnvironmentPreparedEvent,ApplicationFailedEvent
BackgroundPreinitializerApplicationEnvironmentPreparedEvent
DelegatingApplicationListenerApplicationEnvironmentPreparedEvent,**
FileEncodingApplicationListenerApplicationEnvironmentPreparedEvent

加載配置文件:ConfigFileApplicationListener。注意application.proporties文件在這一步加載

private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {//ConfigFileApplicationListener使用EnvironmentPostProcessor來處理environmentList<EnvironmentPostProcessor> postProcessors = this.loadPostProcessors();postProcessors.add(this);AnnotationAwareOrderComparator.sort(postProcessors);Iterator var3 = postProcessors.iterator();while(var3.hasNext()) {EnvironmentPostProcessor postProcessor = (EnvironmentPostProcessor)var3.next();postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());}}

EnvironmentPostProcessor會在應用上下文刷新之前定制應用的環境。EnvironmentPostProcessor的實現類需要注冊在META-INF/spring.factories文件中,并且用類的全路徑名作為key。并且其實現類被鼓勵實現Ordered接口或者@Order注解,Ordered接口和@Order的作用在于將容器內的bean排序。?
EnvironmentPostProcessor從中所周知的路徑中加載屬性文件用來配置應用上下文的環境。默認情況是:從classpath:,file:./,classpath:config/,file:./config/:四個位置加載applicatin.properties或者application.yml。?
我們可以將EnvironmentPostProcessor作為一個動態管理配置文件的接口。?
EnvironmentPostProcessor的擴展

回到ConfigFileApplicationListener的onApplicationEnvironmentPreparedEvent方法,它獲取所有的EnvironmentPostProcessor來postProcessEnvironment。

1. SpringApplicationJsonEnvironmentPostProcessor?
? ? 從Env中現有的配置解析spring.application.json.如果有值,則向env中添加一個MapPropertySource。spring.applictaion.json的值可以通過命令行參數傳遞進來
2. CloudFoundryVcapEnvironmentPostProcessor?
? ? 從已經存在的env中尋找到VCAP
3. ConfigFileApplicationListener?
? 從配置路徑中加載application.properties/yml/xml

Spring Boot允許針對不同的環境配置不同的配置參數,可以使用 properties文件、YAML 文件、環境變量或者命令行參數來修改應用的配置。你可以在代碼中使用@Value注解來獲取配置參數的值

經過這一步加載過后env中包含的ProperytySource有:

  • 命令行參數
  • 來自SPRING_APPLICATION_JSON的屬性
  • java:comp/env 中的 JNDI 屬性
  • Java系統環境變量
  • 操作系統環境變量
  • RandomValuePropertySource,隨機值,使用 random.* 來定義
  • jar包外的 Profile 配置文件,如 application-{profile}.properties 和 YAML 文件
  • jar包內的Profile 配置文件,如 application-{profile}.properties 和 YAML 文件
  • jar包外的Application 配置,如 application.properties 和 application.yml
  • 文件jar 包內的Application 配置,如 application.properties 和application.yml 文件
  • 在標有@Configuration 注解的類標有@PropertySource注解的
  • 默認值,使用SpringApplication.setDefaultProperties 設置的
  • 設置輸出格式AnsiOutputApplicationListener

    AnsiOutputApplicationListener 根據spring.output.ansi.enabled的值來配置AnsiOutput

    完成日志系統的集成:LoggingApplicationListener

    SpringBoot在這一步完成與日志系統的集成。項目中如果使用了spring boot starter則默認使用logback。我們可以使用自己需要用的日志。只需要將適當的庫添加到classpath,便激活各種日志系統。在classpath根目錄可以提供一個合適命名的配置文件來定制日志系統。我們不需要在application.properties中做額外的操作。?
    spring的日志管理,寫的很贊的一篇?
    在ApplicationStartedEvent事件中,LoggingApplicationListener尋找合適的日志系統?
    在ApplicationEnvironmentPrepared事件中,LoggingApplicationListener尋找到配置文件并且初始化日志系統

    加快應用初始化BackgroundPreinitializer

    spring boot 為了加速應用的初始化,在后臺線程提前初始化一些耗時的任務

    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {try {Thread thread = new Thread(new Runnable() {public void run() {this.runSafely(new BackgroundPreinitializer.MessageConverterInitializer(null));this.runSafely(new BackgroundPreinitializer.MBeanFactoryInitializer(null));this.runSafely(new BackgroundPreinitializer.ValidationInitializer(null));this.runSafely(new BackgroundPreinitializer.JacksonInitializer(null));this.runSafely(new BackgroundPreinitializer.ConversionServiceInitializer(null));}public void runSafely(Runnable runnable) {try {runnable.run();} catch (Throwable var3) {;}}}, "background-preinit");thread.start();} catch (Exception var3) {;}}

    創建和準備環境這一步做的事情總結如下:?
    1. 加載配置文件?
    2. 初始化日志系統?
    3. 提前加載某些后臺的進程。在這些進程中創建一些消息轉換器等

    打印Banner


    Banners:持有多個Bannner,循環打印?
    PrintBanner:持有一個Banner,打印?
    Banner可以打印在Console,也可以打印到日志文件中。所以有不同的輸出路徑。print函數應該有一個參數為OutputStream,用來做不同的輸出方式?
    感興趣的是使用?
    AnsiOutput.toString(new Object[]{AnsiColor.GREEN, ” :: Spring Boot :: “, AnsiColor.DEFAULT, padding, AnsiStyle.FAINT, version})方法輸出有顏色的

    創建應用上下文 createApplicationContext

    protected ConfigurableApplicationContext createApplicationContext() {Class<?> contextClass = this.applicationContextClass;if (contextClass == null) {try {contextClass = Class.forName(this.webEnvironment ? "org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext" : "org.springframework.context.annotation.AnnotationConfigApplicationContext");} catch (ClassNotFoundException var3) {throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);}}return (ConfigurableApplicationContext)BeanUtils.instantiate(contextClass);}

    如果當前是Web應用,則實例化AnnotationConfigEmbeddedWebApplicationContext,否則實例化AnnotationConfigApplicationContext;?
    想要了解ApplicationContext的實例化過程中都做了什么,必須了解其類結構。

    ApplicationContext有關的類結構

    作為一個Context,ApplicationContext被賦予了很多功能。
    ? ? EnvironmentCapable,攜帶環境的
    ? ? ApplicationEventPublisher:發布事件
    ? ? SingletonBeanRegistry:注冊單例bean
    ? ? ListableBeanFactory:bean工廠
    ? ? DefaultResourceLoader:加載資源
    ? ? BeanDefinitionRegistry:注冊bean定義

    我們追尋其構造方法,發現分別在AbstractApplicationContext和GenericApplicationContext和AnnotationConfigEmbeddedWebApplicationContext三個類中有構造方法。?
    AbstractApplicationContext

    1. 設置Log
    2. 設置id和displayName
    3. **初始化BeanFactoryPostProcessor的集合**
    4. active,closed初始化
    5. 初始化ApplicationListener的集合
    6. 設置resourcePatternResolver

    2. GenericApplicationContext

    1. customClassLoader = false
    2. refreshed = false
    3. **beanFactory = new DefaultListableBeanFactory**

    3. AnnotationConfigEmbeddedWebApplicationContext

    1. **this.reader = new AnnotatedBeanDefinitionReader(this);**
    2. **this.scanner = new ClassPathBeanDefinitionScanner(this);**

    我們簡單介紹context中幾個比較重要的類

    BeanFactoryPostProcessor,DefaultListableBeanFactory,?
    AnnotatedBeanDefinitionReader,ClassPathBeanDefinitionScanner;

    BeanFactoryPostProcessor

    可以修改應用上下文的bean definition,以適應上下文底層bean工廠的屬性?
    spring boot會給我們提供一些默認的PostProcessor

    DefaultListableBeanFactory

    BeanFactory

    Bean容器的根接口。這個接口需要被含有許多bean definition(每一個bean definition有一個唯一的String名字來標識)的對象所實現。根據bean definition,bean容器會返回一個獨立的實例或者一個共享的單例。具體返回哪種,需要根據bean 容器的配置。這里說的類型就是Scope?
    BeanFactory是應用組件的集中注冊器。我們在使用中最好使用DI(push推配置)來通過構造器或者settter方法來配置對象。而不是使用任何的pull配置來配置對象,比如通過一個BeanFactory查找。Spring的DI是被BeanFactory及其子類來實現的。?
    和ListableBeanFactory相反的是,HierarachalBeanFactory會在查找parent factory。如果一個bean沒有查找到,會查找parent factory。子層次中的beans可以覆蓋父層次中的相同名字的bean.

    Bean Factory的實現需要支持標準的bean 的生命周期。下面是全部的初始化方法和他們的排序。?
    BeanNameAware’s setBeanName?
    BeanClassLoaderAware’s setBeanClassLoader?
    BeanFactoryAware’s setBeanFactory?
    EnvironmentAware’s setEnvironment?
    EmbeddedValueResolverAware’s setEmbeddedValueResolver?
    ResourceLoaderAware’s setResourceLoader (only applicable when running in an application context)?
    ApplicationEventPublisherAware’s setApplicationEventPublisher (only applicable when running in an application context)?
    MessageSourceAware’s setMessageSource (only applicable when running in an application context)?
    ApplicationContextAware’s setApplicationContext (only applicable when running in an application context)?
    ServletContextAware’s setServletContext (only applicable when running in a web application context)?
    postProcessBeforeInitialization methods of BeanPostProcessors?
    InitializingBean’s afterPropertiesSet?
    a custom init-method definition?
    postProcessAfterInitialization methods of BeanPostProcessors?
    在一個bean fatcory被關閉的時候,需要執行的生命周期的方法是:

    postProcessBeforeDestruction methods of DestructionAwareBeanPostProcessors?
    DisposableBean’s destroy?
    a custom destroy-method definitions.?
    BeanDefinitionRegistry?
    注冊bean definition的接口。通常有BeanFactories來實現。Spring 的bean definition Reader需要使用這個接口。眾所周知的實現是DefaultListableBeanFactory 和GenericApplicationContext.

    DefaultListableBeanFactory?
    ListableBeanFactory和BeanDefinitionRegistry的實現。基于bean definition的bean factory.典型的用法是在獲取bean之前,注冊所有的bean definition。因此 bean definition的查找實在本地的集合中通過預先構建的bean definition metedata進行,是一項輕松的操作。?
    可以被作為一個標準的bean factory,或者是一個自定義工廠的父類。特定類型的bean definition 格式的讀取器是獨立實現的,而不是作為bean factory的子類。比如 PropertiesBeanDefinitionReader和XmlBeanDefinitionReader

    AnnotatedBeanDefinitionReader

    顧名思義:讀取注解的bean definition的定義。?
    在GenericWebApplicationContext中構造了它的一個實例。看一下他的構造函數。

    public class AnnotatedBeanDefinitionReader {private final BeanDefinitionRegistry registry;//context本身private BeanNameGenerator beanNameGenerator;private ScopeMetadataResolver scopeMetadataResolver;private ConditionEvaluator conditionEvaluator;public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {this(registry, getOrCreateEnvironment(registry));}public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {//bean的名字生成器this.beanNameGenerator = new AnnotationBeanNameGenerator();//用來解析scope元數據this.scopeMetadataResolver = new AnnotationScopeMetadataResolver();Assert.notNull(registry, "BeanDefinitionRegistry must not be null");Assert.notNull(environment, "Environment must not be null");this.registry = registry;//bean定義注冊器,用來容納bean definitionthis.conditionEvaluator = new ConditionEvaluator(registry, environment, (ResourceLoader)null);//用來判斷是否需要跳過注解//我們需要關注這一步。原因是它注冊了一個 ConfigurationClassPostProcessor AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);} }

    我們可以看到AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);這個方法里面做了這幾件事情:?
    1. 設置beanfactory的依賴比較器?
    2. 設置beanfactory的autowire候選解析器?
    3. 給beanfatory注冊幾個postprocessor的bean definition。

    這幾個PostProcessor中含有一個特別重要的ConfigurationClassPostProcessor。就是這個類使用ConfigurationClassParser完成了basepackage目錄下的bean的掃描,并循環處理這些類(處理其中的內部類,methodbean,import,接口,importResource,ProportyResource類)。

    //AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {registerAnnotationConfigProcessors(registry, (Object)null);}public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, Object source) {DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);...Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet(4);RootBeanDefinition def;if (!registry.containsBeanDefinition("org.springframework.context.annotation.internalConfigurationAnnotationProcessor")) {//這里這里這里def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, "org.springframework.context.annotation.internalConfigurationAnnotationProcessor"));}....return beanDefs;}private static BeanDefinitionHolder registerPostProcessor(BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {definition.setRole(2);registry.registerBeanDefinition(beanName, definition);return new BeanDefinitionHolder(definition, beanName);}

    ClassPathBeanDefinitionScanner

    同樣,一個好的名字能夠讓人理解這個類的功能。?
    ClassPathBeanDefinitionScanner是一個bean definition的掃描器,可以掃描類路徑下的候選的bean,并在給定的registry注冊bean definition。?
    需要配置類型過濾器來發現候選bean。默認的filters包含@Component,@Repository,@Service,@Controller注解。同樣支持Java EE 6’s的ManagedBean和JSR-330’s Named 的注解

    public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {this(registry, true);}public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {this(registry, useDefaultFilters, getOrCreateEnvironment(registry));}public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment) {this(registry, useDefaultFilters, environment, registry instanceof ResourceLoader ? (ResourceLoader)registry : null);}public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment, ResourceLoader resourceLoader) {this.beanDefinitionDefaults = new BeanDefinitionDefaults();//beanName生成器this.beanNameGenerator = new AnnotationBeanNameGenerator();//scope元數據解析器this.scopeMetadataResolver = new AnnotationScopeMetadataResolver();this.includeAnnotationConfig = true;Assert.notNull(registry, "BeanDefinitionRegistry must not be null");this.registry = registry;//是否使用默認的類型過濾器。如果是,則注冊默認的類型過濾器。if (useDefaultFilters) {this.registerDefaultFilters();}this.setEnvironment(environment);this.setResourceLoader(resourceLoader);}protected void registerDefaultFilters() {this.includeFilters.add(new AnnotationTypeFilter(Component.class));ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();try {this.includeFilters.add(new AnnotationTypeFilter(ClassUtils.forName("javax.annotation.ManagedBean", cl), false));this.logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");} catch (ClassNotFoundException var4) {;}try {this.includeFilters.add(new AnnotationTypeFilter(ClassUtils.forName("javax.inject.Named", cl), false));this.logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");} catch (ClassNotFoundException var3) {;}}

    我們可以在BeanDefinitionDefaults發現一些東西。

    public class BeanDefinitionDefaults {private boolean lazyInit;private int dependencyCheck = 0;private int autowireMode = 0;private String initMethodName;private String destroyMethodName; }

    初始化過程

    至此,context的初始化過程完畢。我們回顧一下context在構造函數中做了什么?
    AbstractApplicationContext?
    1. 設置Log?
    2. 設置id和displayName?
    3.?初始化BeanFactoryPostProcessor的集合?
    4. active,closed初始化?
    5. 初始化ApplicationListener的集合?
    6. 設置resourcePatternResolver?
    GenericApplicationContext?
    1. customClassLoader = false?
    2. refreshed = false?
    3.?beanFactory = new DefaultListableBeanFactory?
    AnnotationConfigEmbeddedWebApplicationContext?
    1.?this.reader = new AnnotatedBeanDefinitionReader(this);注冊了幾個BeanDefinition,最重要的是CongiurationClassPostProcessor的bean definition?
    2.?this.scanner = new ClassPathBeanDefinitionScanner(this);設置了需要識別的注解的類型

    失敗分析器

    準備上下文prepareContext

    我們初始化之后的ApplicationContext是最原始的狀態。需要配置之前創建好的Environment,SpringApplicationRunListeners,ApplicationArguments,Banner

    private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {context.setEnvironment(environment);//設置envthis.postProcessApplicationContext(context);//如果SpringApplication類的beanNameGenerator,resourceLoader不為null,則設置到context中去。//使用initializer做些初始化的動作//1. 調用用戶配置的initializer的方法//2. 設置context的Id//3. context注冊 ConfigurationWarningsPostProcessor用于檢查錯誤的配置//4. 向env中設置實際的端口//5. SharedMetadataReaderFactoryContextInitializer.CachingMetadataReaderFactoryPostProcessor//6. 設置ContextRefreshedEvent監聽器,打印ConditionEvaluationReport日志this.applyInitializers(context);listeners.contextPrepared(context);if (this.logStartupInfo) {this.logStartupInfo(context.getParent() == null);this.logStartupProfileInfo(context);}context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments);if (printedBanner != null) {context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);}Set<Object> sources = this.getSources();Assert.notEmpty(sources, "Sources must not be empty");this.load(context, sources.toArray(new Object[sources.size()]));listeners.contextLoaded(context);}

    使用initializer初始化context

    protected void applyInitializers(ConfigurableApplicationContext context) {Iterator var2 = this.getInitializers().iterator();while(var2.hasNext()) {ApplicationContextInitializer initializer = (ApplicationContextInitializer)var2.next();//獲取initailizer的類型參數的類型Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ApplicationContextInitializer.class);Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");//使用initializer來初始化contextinitializer.initialize(context);}} initializer用途
    DelegatingApplicationContextInitializer從context中獲取env,從中獲取用戶是否配置了context.initializer.classes類。如果配置了這些類,則初始化他們并調用對應的initialize方法
    ContextIdApplicationContextInitializer從env中解析名字和端口號,最后兩者組合,設置為applicationContext的Id.我們在context的構造函數中給context設置的id值是context.toString即org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@2b43529a。這一步之后,Id值為application:9188
    ConfigurationWarningsApplicationContextInitializer這個初始化器的作用在于向context中注冊ConfigurationWarningsPostProcessor,用于檢查錯誤的配置和報告錯誤
    ServerPortInfoApplicationContextInitializerApplicationContextInitializer向env設置EmbeddedServletContainer服務器實際監聽的端口。實現這個功能的方法是:向context添加一個ApplicationListener,監聽EmbeddedServletContainerInitializedEvent事件。當事件到達時,設置env中的local.server.port為實際端口值
    SharedMetadataReaderFactoryContextInitializer?
    AutoConfigurationReportLoggingInitializer向applicationContext添加ApplicationListener用來監聽ContextRefreshedEvent或者ApplicationFailedEvent事件。當事件發生時,打印ConditionEvaluationReport日志到info級別,如果出錯,則打印到debug級別

    總的來說:applyInitializers的所作的事情:?
    1. 調用用戶配置的initializer的方法?
    2. 設置context的Id?
    3. context注冊 ConfigurationWarningsPostProcessor用于檢查錯誤的配置?
    4. 向env中設置實際的端口?
    5. SharedMetadataReaderFactoryContextInitializer.CachingMetadataReaderFactoryPostProcessor?
    6. 設置ContextRefreshedEvent監聽器,打印ConditionEvaluationReport日志

    向listeners廣播contextPrepared

    EventPublishingSpringApplicationRunListener中什么都沒有做

    打印啟動日志

    if (this.logStartupInfo) {//使用StartupInfoLogger打印啟動信息.StartUpInfoLogger可以打印應用的starting,started的信息this.logStartupInfo(context.getParent() == null);this.logStartupProfileInfo(context);}protected void logStartupProfileInfo(ConfigurableApplicationContext context) {Log log = this.getApplicationLog();if (log.isInfoEnabled()) {String[] activeProfiles = context.getEnvironment().getActiveProfiles();if (ObjectUtils.isEmpty(activeProfiles)) {String[] defaultProfiles = context.getEnvironment().getDefaultProfiles();log.info("No active profile set, falling back to default profiles: " + StringUtils.arrayToCommaDelimitedString(defaultProfiles));} else {log.info("The following profiles are active: " + StringUtils.arrayToCommaDelimitedString(activeProfiles));}}}

    打印結果為

    INFO [11:57:12.206][main][org.springframework.boot.StartupInfoLogger][48]:Starting AppBootstrap on candydeMacBook-Pro.local with PID 19129 (/Users/maoyanyule/IdeaProjects/movie-pressurer/provider/target/classes started by maoyanyule in /Users/maoyanyule/IdeaProjects/movie-pressurer) INFO [11:58:25.218][main][org.springframework.boot.SpringApplication][593]:No active profile set, falling back to default profiles: default

    注冊兩個兩個單例bean

    context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments);if (printedBanner != null) {context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);}

    此時context.singletonObject中有三個對象:?
    1. springApplicationArguments?
    2. springBootBanner?
    3. autoConfigurationReport

    將source加載到context中

    protected void load(ApplicationContext context, Object[] sources) {if (logger.isDebugEnabled()) {logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));}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();}

    創建BeanDefinitionLoader,加載bean definition

    創建bean definition Loader

    BeanDefinitionLoaderbean 定義加載器。考慮bean definition的幾種方式。有注解和Xml類型,同時需要掃描主類所在的目錄。所以應該有AnnotatedBeanDefinitionReader,XmlBeanDefinitionReader

    BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {Assert.notNull(registry, "Registry must not be null");Assert.notEmpty(sources, "Sources must not be empty");this.sources = sources;this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);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));}

    AnnotatedBeanDefinitionReader,ClassPathBeanDefinitionScanner在前文已經解釋過?
    XmlBeanDefinitionReader?加載XML文件,并委托BeanDefinitionDocumentReader讀取Xml文件,BeanDefinitionDocumentReader會在給定的bean fatcory注冊bean definition。

    加載bean definition

    調用BeanDefinitionLoader.load()方法

    //循環加載所有的sources public int load() {int count = 0;Object[] var2 = this.sources;//這里的sources只有主類一個int var3 = var2.length;for(int var4 = 0; var4 < var3; ++var4) {Object source = var2[var4];count += this.load(source);}return count;}//根據不同的source類型使用不同的方法加載private int load(Object source) {Assert.notNull(source, "Source must not be null");if (source instanceof Class) {return this.load((Class)source);} else if (source instanceof Resource) {return this.load((Resource)source);} else if (source instanceof Package) {return this.load((Package)source);} else if (source instanceof CharSequence) {return this.load((CharSequence)source);} else {throw new IllegalArgumentException("Invalid source type " + source.getClass());}}//因為source為主類,所以是這個方法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);}//如果source被component注解,則使用AnnotatedBeanDefinitionReader來注冊source的bean definitionif (this.isComponent(source)) {this.annotatedReader.register(new Class[]{source});return 1;} else {return 0;}}

    我們來看AnnotatedBeanDefinitionReader是如何注冊一個source 的bean definition的

    public void register(Class... annotatedClasses) {Class[] var2 = annotatedClasses;int var3 = annotatedClasses.length;for(int var4 = 0; var4 < var3; ++var4) {Class<?> annotatedClass = var2[var4];this.registerBean(annotatedClass);}}public void registerBean(Class<?> annotatedClass) {this.registerBean(annotatedClass, (String)null, (Class[])null);}public void registerBean(Class<?> annotatedClass, Class... qualifiers) {this.registerBean(annotatedClass, (String)null, qualifiers);}//主要是在這里public void registerBean(Class<?> annotatedClass, String name, Class... qualifiers) {//獲取一個Class的bean定義,初始獲取的bean definition。AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);//判斷是否應該跳過這次注冊if (!this.conditionEvaluator.shouldSkip(abd.getMetadata())) {//從source的注解中獲取作用域,并設置到bean definition中ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);abd.setScope(scopeMetadata.getScopeName());//獲取bean的名字String beanName = name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry);//處理bean definition中的一些屬性AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);if (qualifiers != null) {Class[] var7 = qualifiers;int var8 = qualifiers.length;for(int var9 = 0; var9 < var8; ++var9) {Class<? extends Annotation> qualifier = var7[var9];if (Primary.class == qualifier) {abd.setPrimary(true);} else if (Lazy.class == qualifier) {abd.setLazyInit(true);} else {abd.addQualifier(new AutowireCandidateQualifier(qualifier));}}}//BeanDefinitionHolder中含有beanName,bean definitionBeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);//將作用域作用在bean definition 上definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);//在context中注冊bean definition BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);}}

    在這里涉及到了 bean definition 的注冊。?
    BeanDefinition的類圖?

    我們從AbstaractBeanDefinition可以看出一些眼熟的東西:

    public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor implements BeanDefinition, Cloneable {public static final String SCOPE_DEFAULT = "";//autowire類型,和AutowireCapableBeanFactory是對應的public static final int AUTOWIRE_NO = 0;public static final int AUTOWIRE_BY_NAME = 1;public static final int AUTOWIRE_BY_TYPE = 2;public static final int AUTOWIRE_CONSTRUCTOR = 3;/** @deprecated */@Deprecatedpublic static final int AUTOWIRE_AUTODETECT = 4;//dependency_check類型public static final int DEPENDENCY_CHECK_NONE = 0;public static final int DEPENDENCY_CHECK_OBJECTS = 1;public static final int DEPENDENCY_CHECK_SIMPLE = 2;public static final int DEPENDENCY_CHECK_ALL = 3;public static final String INFER_METHOD = "(inferred)";//bean classprivate volatile Object beanClass;private String scope;private boolean abstractFlag;private boolean lazyInit;private int autowireMode;private int dependencyCheck;private String[] dependsOn;private boolean autowireCandidate;private boolean primary;private final Map<String, AutowireCandidateQualifier> qualifiers;private boolean nonPublicAccessAllowed;private boolean lenientConstructorResolution;private String factoryBeanName;private String factoryMethodName;private ConstructorArgumentValues constructorArgumentValues;private MutablePropertyValues propertyValues;private MethodOverrides methodOverrides;private String initMethodName;private String destroyMethodName;private boolean enforceInitMethod;private boolean enforceDestroyMethod;private boolean synthetic;private int role;private String description;private Resource resource; }

    在這一步完成之后,context中包含了一個和主類有關的bean definition.

    廣播contextLoaded事件

    public void contextLoaded(ConfigurableApplicationContext context) {ApplicationListener listener;//在spring boot initializ()方法中初始化的listeners直到這一步才被添加到context的listener中for(Iterator var2 = this.application.getListeners().iterator(); var2.hasNext(); context.addApplicationListener(listener)) {listener = (ApplicationListener)var2.next();//如果listener中需要context實例,則設置if (listener instanceof ApplicationContextAware) {((ApplicationContextAware)listener).setApplicationContext(context);}}//廣播ApplicationPreparedEvent事件this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));} listener事件
    ConfigFileApplicationListenerApplicationEnvironmentPreparedEvent,ApplicationPreparedEvent
    LoggingApplicationListenerApplicationStartingEvent,ApplicationEnvironmentPreparedEvent,ApplicationPreparedEvent,ContextClosedEvent,ApplicationFailedEvent
    DelegatingApplicationListenerApplicationEnvironmentPreparedEvent,**

    我們有三個listener關心ApplicationPreparedEvent事件?
    ConfigFileApplicationListener?
    向context中添加ConfigFileApplicationListener.PropertySourceOrderingPostProcessor?
    LoggingApplicationListener?
    向context中注冊單例bean:springBootLoggingSystem?
    DelegatingApplicationListener繼續想其他listeners廣播事件

    prepareContext回顧

  • 調用用戶配置的initializer的方法
  • 設置context的Id
  • context注冊 ConfigurationWarningsPostProcessor用于檢查錯誤的配置
  • 向env中設置實際的端口
  • SharedMetadataReaderFactoryContextInitializer.CachingMetadataReaderFactoryPostProcessor
  • 設置ContextRefreshedEvent監聽器,打印ConditionEvaluationReport日志
  • 打印啟動日志
  • 注冊固定的單例bean
  • 加載主類的bean definition
  • 向context中添加ConfigFileApplicationListener.PropertySourceOrderingPostProcessor
  • 刷新context refreshContext

    private void refreshContext(ConfigurableApplicationContext context) {this.refresh(context);if (this.registerShutdownHook) {try {context.registerShutdownHook();} catch (AccessControlException var3) {;}}}protected void refresh(ApplicationContext applicationContext) {Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);//最終調用了applicationContext的refresh()函數((AbstractApplicationContext)applicationContext).refresh();}

    而查看applicationContext.refresh()方法時需要注意其繼承結構。附上applicationContext的類圖?

    //EmbeddedWebApplicationContext.java public final void refresh() throws BeansException, IllegalStateException {try {super.refresh();//調用的是AbstractApplicationContext} catch (RuntimeException var2) {this.stopAndReleaseEmbeddedServletContainer();throw var2;}} //AbstractApplicationContext.java public void refresh() throws BeansException, IllegalStateException {Object var1 = this.startupShutdownMonitor;synchronized(this.startupShutdownMonitor) {//1. 清空scanner中的resource和metadataReader之間的對應關系 //2. 設置applicationcontext中的初始狀態 //3. 打印啟動日志 //4. 設置env中的servletContext和serveltConfig //5. 驗證是否缺失了必須配置的參數this.prepareRefresh();//ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();this.prepareBeanFactory(beanFactory);try {this.postProcessBeanFactory(beanFactory);this.invokeBeanFactoryPostProcessors(beanFactory);this.registerBeanPostProcessors(beanFactory);this.initMessageSource();this.initApplicationEventMulticaster();this.onRefresh();this.registerListeners();this.finishBeanFactoryInitialization(beanFactory);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();}}}

    為刷新context做準備: prepareRefresh()

    //AnnotationConfigEmbeddedWebApplicationContext protected void prepareRefresh() {this.scanner.clearCache();super.prepareRefresh();//調用AbstractApplicationContext中的prepareRefresh();}

    應該記得在構造函數中創建的ClassPathBeanDefinitionScanner。?

    在ClassPathBeanDefinitionScanner持有了一個Map:Resource, MetadataReader metadataReaderCache,用來保存resource和metadataReader;?
    scanner.clearCache()即清空該map的元素

    //AbstractApplicationContext.java protected void prepareRefresh() {this.startupDate = System.currentTimeMillis();this.closed.set(false);//設置application狀態this.active.set(true);//設置application狀態if (this.logger.isInfoEnabled()) {this.logger.info("Refreshing " + this);}this.initPropertySources();//調用的是GenericApplicationContext中的方法this.getEnvironment().validateRequiredProperties();//檢查是否缺失了必須配置的屬性this.earlyApplicationEvents = new LinkedHashSet();//初始化}
  • initPropertySources
  • //GenericApplicationContext.java protected void initPropertySources() {ConfigurableEnvironment env = this.getEnvironment();if (env instanceof ConfigurableWebEnvironment) {((ConfigurableWebEnvironment)env).initPropertySources(this.servletContext, (ServletConfig)null);//使用這里的servletContext和servletConfig來替換env中的propertySources}}
  • this.getEnvironment().validateRequiredProperties();?
    回顧env的類圖。查看代碼,可發現validateRequiredProperties是調用了AbstractProportyReslover.validateRequiredProperties()方法.作用是檢查是否缺失了必須配置的屬性?
  • public void validateRequiredProperties() {MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();Iterator var2 = this.requiredProperties.iterator();while(var2.hasNext()) {String key = (String)var2.next();if (this.getProperty(key) == null) {ex.addMissingRequiredProperty(key);}}if (!ex.getMissingRequiredProperties().isEmpty()) {throw ex;}}

    回顧prepareRefresh()這一步的動作:?
    1. 清空scanner中的resource和metadataReader之間的對應關系?
    2. 設置applicationcontext中的初始狀態?
    3. 打印啟動日志?
    4. 設置env中的servletContext和serveltConfig?
    5. 驗證是否缺失了必須配置的參數

    獲取bean factory

    //AbstractApplicationContext protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {this.refreshBeanFactory();//刷新bean factoryConfigurableListableBeanFactory beanFactory = this.getBeanFactory();//獲取beanFactoryif (this.logger.isDebugEnabled()) {this.logger.debug("Bean factory for " + this.getDisplayName() + ": " + beanFactory);}return beanFactory;} //GenericApplicationContext.java protected final void refreshBeanFactory() throws IllegalStateException {if (!this.refreshed.compareAndSet(false, true)) {//bean factory值可以刷新一次throw new IllegalStateException("GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");} else {//設置beanFactory的serializationId和向//Map<String, Reference<DefaultListableBeanFactory>> serializableFactories添加serializationId, new WeakReference(this)this.beanFactory.setSerializationId(this.getId());}}

    準備bean factory

    protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {//設置類加載器beanFactory.setBeanClassLoader(this.getClassLoader());//BeanExpressionResolver的標準實現用來解析spring el表達式,可以使用#{bean.xxx}的方式來調用相關屬性值beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));//通過資源編輯器 操作一個給定的PropertyEditorRegistry.并在所有bean創建的過程中應用PropertyEditorRegistry.沒有用過?beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment()));//ApplicationContextAwareProcessor用于上下文回調,它是BeanPostProcessor的實現類,跟一下這個接口的兩個方法postProcessBeforeInitialization和postProcessAfterInitialization//如果Bean是EmbeddedValueResolverAware接口的實現類,則調用setEmbeddedValueResolver方法,傳入當前BeanFactory//如果Bean是ResourceLoaderAware接口的實現類,則調用setResourceLoader方法,傳入當前上下文ApplicationContext//如果Bean是ApplicationEventPublisherAware的實現類,則調用setApplicationEventPublisher方法,傳入當前上下文ApplicationContext//如果Bean是MessageSourceAware的實現類,則調用setMessageSource方法,傳入當前上下文ApplicationContext//如果Bean是ApplicationContextAware的實現類,則調用setApplicationContext方法,傳入當前上下文ApplicationContext//https://www.cnblogs.com/xrq730/p/6670457.htmlbeanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));//定義了在依賴檢查和自動綁定時要忽略的依賴接口,是一組類對象,默認情況下,只有beanFactory接口被忽略。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接口的實現類,則修正為當前BeanFactorybeanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);beanFactory.registerResolvableDependency(ResourceLoader.class, this);beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);beanFactory.registerResolvableDependency(ApplicationContext.class, this);beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));if (beanFactory.containsBean("loadTimeWeaver")) {beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));}//注冊enviroment單例if (!beanFactory.containsLocalBean("environment")) {beanFactory.registerSingleton("environment", this.getEnvironment());}//注冊systemProperties單例if (!beanFactory.containsLocalBean("systemProperties")) {beanFactory.registerSingleton("systemProperties", this.getEnvironment().getSystemProperties());}//注冊systemEnvironment單例if (!beanFactory.containsLocalBean("systemEnvironment")) {beanFactory.registerSingleton("systemEnvironment", this.getEnvironment().getSystemEnvironment());}}

    PostProcessorBeanFactory

    //添加beanPostProcessor由于這里的basePackages為null,所以并不掃描 //這一步的作用主要是注冊BeanPostProcessors //AnnotationConfigEmbeddedWebApplicationContext.java protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {super.postProcessBeanFactory(beanFactory);if (this.basePackages != null && this.basePackages.length > 0) {this.scanner.scan(this.basePackages);}if (this.annotatedClasses != null && this.annotatedClasses.length > 0) {this.reader.register(this.annotatedClasses);}} //EmbeddedWebApplicationContext.java protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));beanFactory.ignoreDependencyInterface(ServletContextAware.class);}

    invokeBeanFactoryPostProcessors

    主要是實例化和調用所有已注冊的BeanFactoryPostProcessors.需要在所有的bean實例化之前調用。?
    這個是整個Spring流程中非常重要的一部分,是Spring留給用戶的一個非常有用的擴展點,BeanPostProcessor接口針對的是每個Bean初始化前后做的操作而BeanFactoryPostProcessor接口針對的是所有Bean實例化前的操作

    關于如何使用BeanFactoryPostProcessors作為擴展點,可以參考這篇博文容器擴展點BeanFactoryPostProcessors

    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors());if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean("loadTimeWeaver")) {beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));}}

    這里委托了PostProcessorRegistrationDelegate工具類來調用BeanFactoryPostProcessor

    public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {// Invoke BeanDefinitionRegistryPostProcessors first, if any.// 如果有BeanDefinitionRegistryPostProcessors 的話,就先調用它們// 處理過的BeansSet<String> processedBeans = new HashSet<String>();// 是否是BeanDefinitionRegistry類型的BeanFactory. BeanDefinitionRegistry的作用是可以用來注冊,刪除,獲取BeanDefinitionsif (beanFactory instanceof BeanDefinitionRegistry) {BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;// 普通類型的BeanFactoryPostProcessor集合List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>();// BeanDefinitionRegistry類型的BeanFactoryPostProcessor集合(BeanDefinitionRegistryPostProcessor繼承于BeanFactoryPostProcessor)List<BeanDefinitionRegistryPostProcessor> registryPostProcessors =new LinkedList<BeanDefinitionRegistryPostProcessor>();// 對集合beanFactoryPostProcessors進行分類,如果是BeanDefinitionRegistry類型的BeanFactoryPostProcessor;則調用方法 - postProcessBeanDefinitionRegistry()。// postProcessBeanDefinitionRegistry(BeanDefinitionRegistry)該方法的作用是在標準的BeanDefinitions初始化完成后可以修改容器上下文內部的beanDefinition。for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {BeanDefinitionRegistryPostProcessor registryPostProcessor =(BeanDefinitionRegistryPostProcessor) postProcessor;registryPostProcessor.postProcessBeanDefinitionRegistry(registry);registryPostProcessors.add(registryPostProcessor);}else {regularPostProcessors.add(postProcessor);}}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!// Separate between BeanDefinitionRegistryPostProcessors that implement// PriorityOrdered, Ordered, and the rest.// 這里不要初始化FactoryBeans,//我們需要保留這些普通的beans 不在這里初始化,目的是為了讓bean factory post-processor去處理他們。// 根據BeanDefinitionRegistryPostProcessors 實現的不同接口PriorityOrdered,Ordered,或者不實現兩者,拆分開來去調用他們。String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.// 首先,調用實現了優先級接口 - PriorityOrdered的BeanDefinitionRegistryPostProcessors List<BeanDefinitionRegistryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();for (String ppName : postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}// 排序sortPostProcessors(beanFactory, priorityOrderedPostProcessors);// 添加排序好的優先級PostProcessors到registryPostProcessors集合registryPostProcessors.addAll(priorityOrderedPostProcessors);// 調用排序好的優先級BeanDefinitionRegistryPostProcessors,postProcessBeanDefinitionRegistry方法會被調用,用來修改,獲取,刪除容器上下文中的bean定義。//!!!!!這里是比較重要的一個點。priorityOrderedPostProcessors因為包含ConfigurationClassPostProcessor所以掃描了根目錄下的所有類,加載了對應的bean定義之所以從這個步驟中取到了 ConfigurationClassPostProcessor,是因為當初AnnotatedBeanDefinitionReader只注冊了bean definition。 invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.// 調用實現了Ordered接口的BeanDefinitionRegistryPostProcessors ,大致邏輯同上PriorityOrdered的處理postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);List<BeanDefinitionRegistryPostProcessor> orderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {orderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(beanFactory, orderedPostProcessors);registryPostProcessors.addAll(orderedPostProcessors);invokeBeanDefinitionRegistryPostProcessors(orderedPostProcessors, registry);// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.// 調用所有其它類型的BeanDefinitionRegistryPostProcessorsboolean reiterate = true;while (reiterate) {reiterate = false;postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName)) {BeanDefinitionRegistryPostProcessor pp = beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class);registryPostProcessors.add(pp);processedBeans.add(ppName);pp.postProcessBeanDefinitionRegistry(registry);reiterate = true;}}}// Now, invoke the postProcessBeanFactory callback of all processors handled so far.// 調用所有的BeanDefinitionRegistryPostProcessor的postProcessBeanFactory 方法。invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory);// 調用容器中BeanFactoryPostProcessor類型的bean(不包含BeanDefinitionRegistryPostProcessor類型的beans)。invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);}else {// Invoke factory processors registered with the context instance.// 若beanFactory不是BeanDefinitionRegistry類型的,則直接調用容器中所有的BeanFactoryPostProcessor的postProcessBeanFactory 方法。invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,// Ordered, and the rest.//將BeanFactoryPostProcessors分為3類,PriorityOrdered,Ordered,其他List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();List<String> orderedPostProcessorNames = new ArrayList<String>();List<String> nonOrderedPostProcessorNames = new ArrayList<String>();for (String ppName : postProcessorNames) {if (processedBeans.contains(ppName)) {//如果前面已經處理過過postprocessor,則跳過// skip - already processed in first phase above}else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));}else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {orderedPostProcessorNames.add(ppName);}else {nonOrderedPostProcessorNames.add(ppName);}}// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.//首先處理實現了PriorityOrdered接口的postProcessorsortPostProcessors(beanFactory, priorityOrderedPostProcessors);invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);// Next, invoke the BeanFactoryPostProcessors that implement Ordered.//其次處理實現了Ordered接口的postprocessorList<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();for (String postProcessorName : orderedPostProcessorNames) {orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}sortPostProcessors(beanFactory, orderedPostProcessors);invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);// Finally, invoke all other BeanFactoryPostProcessors.//最終調用其他的postprocessorList<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();for (String postProcessorName : nonOrderedPostProcessorNames) {nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);// Clear cached merged bean definitions since the post-processors might have// modified the original metadata, e.g. replacing placeholders in values...//postprocessor可能更改了原始數據的bean definition。所以清空緩存beanFactory.clearMetadataCache();}

    priorityOrderedPostProcessors因為包含ConfigurationClassPostProcessor所以掃描了根目錄下的所有類,加載了對應的bean定義而在加載bean definition的時候,將自動配置的bean defintion也加載了進來。?
    invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);

    我們需要了解一下ConfigurationClassPostProcessor類的processConfigBeanDefinitions方法。

    public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {//候選的待解析的含有@Configuration注解的類List<BeanDefinitionHolder> configCandidates = new ArrayList();//從現有的的bean definition中獲取待解析類的nameString[] candidateNames = registry.getBeanDefinitionNames();String[] var4 = candidateNames;int var5 = candidateNames.length;for(int var6 = 0; var6 < var5; ++var6) {String beanName = var4[var6];BeanDefinition beanDef = registry.getBeanDefinition(beanName);//如果當前的beanDef即不是full,也不是lite//在沒有checkConfigurationClassCandidate之前,beanDef的CONFIGURATION_CLASS_ATTRIBUTE屬性是沒有設置的if (!ConfigurationClassUtils.isFullConfigurationClass(beanDef) && !ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {//如果beanDef有@Configuration注解,則設置CONFIGURATION_CLASS_ATTRIBUTE為full,返回true//如果beanDef有Component,ComponentScan,Import,ImportResource注解中的一個,則CONFIGURATION_CLASS_ATTRIBUTE設置為lite,返回true//返回true,則加入configCandidatesif (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));}} else if (this.logger.isDebugEnabled()) {this.logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);}}if (!configCandidates.isEmpty()) {//首先對configCandidates進行排序Collections.sort(configCandidates, new Comparator<BeanDefinitionHolder>() {public int compare(BeanDefinitionHolder bd1, BeanDefinitionHolder bd2) {int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());return i1 < i2 ? -1 : (i1 > i2 ? 1 : 0);}});SingletonBeanRegistry sbr = null;if (registry instanceof SingletonBeanRegistry) {sbr = (SingletonBeanRegistry)registry;//如果當前沒有設置過beanNameGenerator,則設置if (!this.localBeanNameGeneratorSet && sbr.containsSingleton("org.springframework.context.annotation.internalConfigurationBeanNameGenerator")) {BeanNameGenerator generator = (BeanNameGenerator)sbr.getSingleton("org.springframework.context.annotation.internalConfigurationBeanNameGenerator");this.componentScanBeanNameGenerator = generator;this.importBeanNameGenerator = generator;}}//創建ConfigurationClass的解析器ConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry);//待解析的configurationClass的bean defSet<BeanDefinitionHolder> candidates = new LinkedHashSet(configCandidates);//已經解析過的,元素為ConfigurationClassHashSet alreadyParsed = new HashSet(configCandidates.size());do {//解析parser.parse(candidates);parser.validate();//在解析的過程中會遇到很多的需要依賴的bean defSet<ConfigurationClass> configClasses = new LinkedHashSet(parser.getConfigurationClasses());configClasses.removeAll(alreadyParsed);//去重if (this.reader == null) {this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment, this.importBeanNameGenerator, parser.getImportRegistry());}//加載這些依賴的bean defthis.reader.loadBeanDefinitions(configClasses);alreadyParsed.addAll(configClasses);candidates.clear();//如果registry中的bean def的數量比candidateNames要多,說明還有一些bean def沒有被處理。if (registry.getBeanDefinitionCount() > candidateNames.length) {String[] newCandidateNames = registry.getBeanDefinitionNames();Set<String> oldCandidateNames = new HashSet(Arrays.asList(candidateNames));Set<String> alreadyParsedClasses = new HashSet();Iterator var12 = alreadyParsed.iterator();while(var12.hasNext()) {ConfigurationClass configurationClass = (ConfigurationClass)var12.next();alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());}String[] var23 = newCandidateNames;int var24 = newCandidateNames.length;for(int var14 = 0; var14 < var24; ++var14) {String candidateName = var23[var14];//如果之前沒有遇到過這個候選的bean nameif (!oldCandidateNames.contains(candidateName)) {BeanDefinition bd = registry.getBeanDefinition(candidateName);//如果這個類含有對應的注解,且沒有被解析過,則加入到candidates中if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) && !alreadyParsedClasses.contains(bd.getBeanClassName())) {candidates.add(new BeanDefinitionHolder(bd, candidateName));}}}candidateNames = newCandidateNames;}} while(!candidates.isEmpty());if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());}if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {((CachingMetadataReaderFactory)this.metadataReaderFactory).clearCache();}}}

    我們需要關注的是其中的兩行代碼:parser.parse(candidates);用來解析候選類。在解析候選類的過程中會遇到很多以來的bean definition,this.reader.loadBeanDefinitions(configClasses);將注冊新發現的bean defintion

    parser.parse(candidates);parser.validate();//在解析的過程中會遇到很多的需要依賴的bean defSet<ConfigurationClass> configClasses = new LinkedHashSet(parser.getConfigurationClasses());configClasses.removeAll(alreadyParsed);//去重if (this.reader == null) {this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment, this.importBeanNameGenerator, parser.getImportRegistry());}//加載這些依賴的bean defthis.reader.loadBeanDefinitions(configClasses);

    ConfigurationClassParser用來解析一個beanDefition。因為在這次的場景中只有AppBootStrap這一個類。我們就從ConfigurationClassParser對這一個類的解析來說。

    注冊beanPostProcessor

    將beanPostProcessor分為4類,實現了PriorityOrdered接口的,實現了Ordered接口的,兩者都沒有實現的,是MergedBeanDefinitionPostProcessor的。這4類分別排序,被添加進入beanFactory的一個beanPostProcessor的list中,這里并不會調用BeanPostProcessor接口的方法。到時候在bean的初始化前后按順序調用他們

    這里就根據代碼總結一下BeanPostProcessor接口的調用順序:

  • 優先調用PriorityOrdered接口的子接口,調用順序依照接口方法getOrder的返回值從小到大排序
  • 其次調用Ordered接口的子接口,調用順序依照接口方法getOrder的返回值從小到大排序
  • 接著按照BeanPostProcessor實現類在配置文件中定義的順序進行調用
  • 最后調用MergedBeanDefinitionPostProcessor接口的實現Bean,同樣按照在配置文件中定義的順序進行調用
  • public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;beanFactory.addBeanPostProcessor(new PostProcessorRegistrationDelegate.BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList();List<BeanPostProcessor> internalPostProcessors = new ArrayList();List<String> orderedPostProcessorNames = new ArrayList();List<String> nonOrderedPostProcessorNames = new ArrayList();String[] var8 = postProcessorNames;int var9 = postProcessorNames.length;String ppName;BeanPostProcessor pp;for(int var10 = 0; var10 < var9; ++var10) {ppName = var8[var10];if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {pp = (BeanPostProcessor)beanFactory.getBean(ppName, BeanPostProcessor.class);priorityOrderedPostProcessors.add(pp);if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}} else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {orderedPostProcessorNames.add(ppName);} else {nonOrderedPostProcessorNames.add(ppName);}}sortPostProcessors(beanFactory, priorityOrderedPostProcessors);registerBeanPostProcessors(beanFactory, (List)priorityOrderedPostProcessors);List<BeanPostProcessor> orderedPostProcessors = new ArrayList();Iterator var14 = orderedPostProcessorNames.iterator();while(var14.hasNext()) {String ppName = (String)var14.next();BeanPostProcessor pp = (BeanPostProcessor)beanFactory.getBean(ppName, BeanPostProcessor.class);orderedPostProcessors.add(pp);if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}}sortPostProcessors(beanFactory, orderedPostProcessors);registerBeanPostProcessors(beanFactory, (List)orderedPostProcessors);List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList();Iterator var17 = nonOrderedPostProcessorNames.iterator();while(var17.hasNext()) {ppName = (String)var17.next();pp = (BeanPostProcessor)beanFactory.getBean(ppName, BeanPostProcessor.class);nonOrderedPostProcessors.add(pp);if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}}registerBeanPostProcessors(beanFactory, (List)nonOrderedPostProcessors);sortPostProcessors(beanFactory, internalPostProcessors);registerBeanPostProcessors(beanFactory, (List)internalPostProcessors);beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));}

    initMessageSource用于創建messageSource

    initApplicationEventMulticaster用于創建上下文事件廣播器

    onRefresh創建Web容器

    首先 onfresh():?
    一個模板方法,重寫它的作用是添加特殊上下文刷新的工作,在特殊Bean的初始化時、初始化之前被調用。在Spring中,AbstractRefreshableWebApplicationContext、GenericWebApplicationContext、StaticWebApplicationContext都實現了這個方法。這三個類都是用它來配置themeSource。在EmbeddedWebApplicationContext中則創建和啟動了servlet容器。需要在bean實例化之前創建servletcontainer

    //EmbeddedWebApplicationContext.java protected void onRefresh() {super.onRefresh();try {this.createEmbeddedServletContainer();//} catch (Throwable var2) {throw new ApplicationContextException("Unable to start embedded container", var2);}}private void createEmbeddedServletContainer() {EmbeddedServletContainer localContainer = this.embeddedServletContainer;ServletContext localServletContext = this.getServletContext();if (localContainer == null && localServletContext == null) {//如果用戶有配置過,則使用用戶配置的containerFactory,否則使用默認的。EmbeddedServletContainerFactory containerFactory = this.getEmbeddedServletContainerFactory();//獲取到containerFactory之后就可以使用containerFactory獲取servletContainer。//而這里在獲取servletContainer的時候,直接啟動了Jetty中的server//另外還需要關注的是我們傳遞了一個initailizer進去this.embeddedServletContainer = containerFactory.getEmbeddedServletContainer(new ServletContextInitializer[]{this.getSelfInitializer()});} else if (localServletContext != null) {try {this.getSelfInitializer().onStartup(localServletContext);} catch (ServletException var4) {throw new ApplicationContextException("Cannot initialize servlet context", var4);}}//重新設置context中和servlet有關的幾個屬性this.initPropertySources();}protected EmbeddedServletContainerFactory getEmbeddedServletContainerFactory() {//如果配置了JettyConfig,則是我們配置的那個,否在是通過自動配置注入進來的//如果沒有配置過,且有Jetty,則是jettyEmbeddedServletContainerFactoryString[] beanNames = this.getBeanFactory().getBeanNamesForType(EmbeddedServletContainerFactory.class);if (beanNames.length == 0) {throw new ApplicationContextException("Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.");} else if (beanNames.length > 1) {throw new ApplicationContextException("Unable to start EmbeddedWebApplicationContext due to multiple EmbeddedServletContainerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));} else {return (EmbeddedServletContainerFactory)this.getBeanFactory().getBean(beanNames[0], EmbeddedServletContainerFactory.class);}} //JettyEmbeddedServletContainerFactory.class public EmbeddedServletContainer getEmbeddedServletContainer(ServletContextInitializer... initializers) {JettyEmbeddedWebAppContext context = new JettyEmbeddedWebAppContext();int port = this.getPort() >= 0 ? this.getPort() : 0;InetSocketAddress address = new InetSocketAddress(this.getAddress(), port);Server server = this.createServer(address);this.configureWebAppContext(context, initializers);server.setHandler(this.addHandlerWrappers(context));this.logger.info("Server initialized with port: " + port);if (this.getSsl() != null && this.getSsl().isEnabled()) {SslContextFactory sslContextFactory = new SslContextFactory();this.configureSsl(sslContextFactory, this.getSsl());AbstractConnector connector = this.getSslServerConnectorFactory().getConnector(server, sslContextFactory, port);server.setConnectors(new Connector[]{connector});}Iterator var8 = this.getServerCustomizers().iterator();while(var8.hasNext()) {JettyServerCustomizer customizer = (JettyServerCustomizer)var8.next();customizer.customize(server);}if (this.useForwardHeaders) {(new JettyEmbeddedServletContainerFactory.ForwardHeadersCustomizer(null)).customize(server);}return this.getJettyEmbeddedServletContainer(server);}protected JettyEmbeddedServletContainer getJettyEmbeddedServletContainer(Server server) {return new JettyEmbeddedServletContainer(server, this.getPort() >= 0);} //JettyEmbeddedServletContainer.java public JettyEmbeddedServletContainer(Server server, boolean autoStart) {this.monitor = new Object();this.autoStart = autoStart;Assert.notNull(server, "Jetty Server must not be null");this.server = server;this.initialize();}private void initialize() {Object var1 = this.monitor;synchronized(this.monitor) {try {this.connectors = this.server.getConnectors();this.server.addBean(new AbstractLifeCycle() {protected void doStart() throws Exception {Connector[] var1 = JettyEmbeddedServletContainer.this.connectors;int var2 = var1.length;for(int var3 = 0; var3 < var2; ++var3) {Connector connector = var1[var3];Assert.state(connector.isStopped(), "Connector " + connector + " has been started prematurely");}JettyEmbeddedServletContainer.this.server.setConnectors((Connector[])null);}});this.server.start();//這里啟動了jettythis.server.setStopAtShutdown(false);} catch (Exception var4) {this.stopSilently();throw new EmbeddedServletContainerException("Unable to start embedded Jetty servlet container", var4);}}}

    我們在創建ServletContainer的時候,傳遞了一個initializer進去。在servlet容器創建后執行一些初始化動作

    private void selfInitialize(ServletContext servletContext) throws ServletException {//我們需要重點關注這個方法this.prepareEmbeddedWebApplicationContext(servletContext);ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();EmbeddedWebApplicationContext.ExistingWebApplicationScopes existingScopes = new EmbeddedWebApplicationContext.ExistingWebApplicationScopes(beanFactory);WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.getServletContext());existingScopes.restore();WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.getServletContext());Iterator var4 = this.getServletContextInitializerBeans().iterator();while(var4.hasNext()) {ServletContextInitializer beans = (ServletContextInitializer)var4.next();beans.onStartup(servletContext);}}//關注這個方法的原因是我們在這個方法中設置了servletContext的ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE屬性為我們之前applicationContext,也設置了我們applicationContext中的serveltContext屬性為在創建servlet容器時創建的servletContext protected void prepareEmbeddedWebApplicationContext(ServletContext servletContext) {Object rootContext = servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);if (rootContext != null) {if (rootContext == this) {throw new IllegalStateException("Cannot initialize context because there is already a root application context present - check whether you have multiple ServletContextInitializers!");}} else {Log logger = LogFactory.getLog(ContextLoader.class);servletContext.log("Initializing Spring embedded WebApplicationContext");try {servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this);if (logger.isDebugEnabled()) {logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");}this.setServletContext(servletContext);if (logger.isInfoEnabled()) {long elapsedTime = System.currentTimeMillis() - this.getStartupDate();logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");}} catch (RuntimeException var6) {logger.error("Context initialization failed", var6);servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, var6);throw var6;} catch (Error var7) {logger.error("Context initialization failed", var7);servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, var7);throw var7;}}}

    AfterFresh

    spring boot在這一步中完成對Runners的調用?
    參考CommandLineRunner,ApplicationRunner

    protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {this.callRunners(context, args);}private void callRunners(ApplicationContext context, ApplicationArguments args) {List<Object> runners = new ArrayList();runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());AnnotationAwareOrderComparator.sort(runners);Iterator var4 = (new LinkedHashSet(runners)).iterator();while(var4.hasNext()) {Object runner = var4.next();if (runner instanceof ApplicationRunner) {this.callRunner((ApplicationRunner)runner, args);}if (runner instanceof CommandLineRunner) {this.callRunner((CommandLineRunner)runner, args);}}}

    參考資料

    講bean definition的加載過程的更詳細的一篇博文?
    spring boot源碼解析專欄?
    PostProcessorRegistrationDelegate?
    詳解ImportSelector接口?
    關于springboot 的啟動流程?
    BeanPostProcessor擴展點?
    非懶加載bean初始化的過程,特別贊,作者還有關于spring的一系列的文章,建議可以去看?
    refresh方法?
    Jetty的工作原理?
    Spring中的bean工廠后置處理器

    總結

    以上是生活随笔為你收集整理的springboot启动流程的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    久久精品欧美一区 | 亚洲闷骚少妇在线观看网站 | 日韩精品极品视频 | www91在线观看| 久久久久国产一区二区三区 | 中文字幕在线色 | 中文字幕免费一区二区 | 狠狠成人| 国产亚洲精品久久久久秋 | 国产成人精品a | 精品福利av | av成人免费 | 久久黄色影院 | 精品国产乱码久久久久久浪潮 | 国产99久久99热这里精品5 | 国产手机精品视频 | 天天干,天天射,天天操,天天摸 | 在线日本v二区不卡 | 国产99久久九九精品免费 | 日韩激情视频在线 | 精品免费久久久久久 | 操操操操网 | 国产视频不卡一区 | 免费看片网址 | 国产一区二区高清不卡 | 91成人在线观看高潮 | 久久av中文字幕片 | 99亚洲天堂| 亚洲最新av在线网址 | 成年人免费在线 | 国产精品字幕 | av在线免费观看不卡 | 国产精品欧美一区二区三区不卡 | 欧美日韩在线免费视频 | 天天插天天 | 91福利社在线观看 | 国产精品一区二区三区电影 | 手机看片1042 | 人人干干人人 | 国产亚洲精品久久久久久网站 | 操操操av | 免费观看一级一片 | 国产精品高清一区二区三区 | 久久婷婷一区二区三区 | 亚洲日本在线视频观看 | 狠狠干夜夜操天天爽 | 国产视频手机在线 | 综合伊人av | 国产精品自产拍在线观看网站 | 在线91精品| 亚洲欧美精品在线 | 人人爽人人爽人人片av | 国产精品不卡在线 | 综合婷婷丁香 | 日韩精品极品视频 | 国产一区自拍视频 | 日韩欧美在线观看 | 韩国av不卡 | 国产小视频免费在线网址 | 欧美激情精品一区 | 丁香六月网 | 国产亚洲激情视频在线 | 96av在线视频 | 69精品在线观看 | 一级黄色片在线 | 在线亚洲欧美日韩 | 国产成人精品一区一区一区 | 超碰人人99 | 天天干夜夜爱 | 国产99久久久国产精品成人免费 | 亚洲免费国产视频 | 欧美在线视频一区二区 | 成人视屏免费看 | 国产精品成人在线观看 | 国产精品久久久久久久久久白浆 | 欧美日韩性生活 | 亚洲综合色丁香婷婷六月图片 | 99精品国产高清在线观看 | 黄色免费高清视频 | 午夜色影院 | 久久精品视频在线 | 欧美黄色高清 | 狠狠狠狠狠狠狠狠 | 国产精品原创av片国产免费 | 国产成人黄色在线 | 99爱这里只有精品 | 亚洲午夜精品久久久久久久久久久久 | 美女国产 | 四虎欧美| 亚洲黄色区 | 中文字幕在线观看2018 | 激情图片qvod | 伊甸园永久入口www 99热 精品在线 | 天天干天天干天天干 | 激情五月综合网 | 成人蜜桃视频 | 一区二区中文字幕在线 | 91香蕉视频好色先生 | 国产福利免费在线观看 | 日韩特级黄色片 | 亚洲午夜久久久久久久久久久 | 日韩一区在线免费观看 | 亚洲欧洲一区二区在线观看 | 美女视频黄色免费 | 色永久免费视频 | 黄色网在线免费观看 | 午夜日b视频 | 久久精品看 | 日本爱爱片 | 久久久久久久久毛片 | 久久精品婷婷 | 国产精品黄网站在线观看 | 成年人视频在线免费观看 | 丁香花在线观看免费完整版视频 | 网址你懂的在线观看 | 18做爰免费视频网站 | 亚洲精品动漫成人3d无尽在线 | 亚洲 欧美 成人 | 91精品在线麻豆 | 亚洲aⅴ乱码精品成人区 | 成人黄色在线播放 | 色偷偷88888欧美精品久久久 | 成人黄色大片在线观看 | 黄色网址在线播放 | 成人在线观看免费视频 | 激情九九 | 毛片永久免费 | a久久久久 | 97香蕉久久超级碰碰高清版 | 久久久天堂 | 精品免费久久久久久 | a在线免费观看视频 | 狠狠色丁香婷婷综合久小说久 | 国产精品99久久久久的智能播放 | 一区二区中文字幕在线播放 | 日批网站免费观看 | 久久精品999 | 国产黄色在线 | av在线播放国产 | 日韩一区二区三 | 99久热 | 又紧又大又爽精品一区二区 | 久久精品国产免费看久久精品 | www.色爱| 韩日精品视频 | 国产在线超碰 | 五月婷婷操 | 天天干天天干天天干 | 黄色一级大片在线观看 | 亚洲精品久久激情国产片 | 国产精品入口66mio女同 | 天堂av影院| 国产小视频免费观看 | 久久精品小视频 | 国产视频在线免费 | 国产精品久久伊人 | 久久爱综合| 黄色片亚洲 | 国产91在线看 | 久久久蜜桃 | 91久久精品一区二区三区 | 香蕉久久久久久久 | 欧美日韩视频网站 | 人人爱夜夜操 | 99久久精品国产一区二区成人 | 爱干视频| 国产成人三级一区二区在线观看一 | 天天干天天操天天干 | 99色国产 | 97人人看| 亚洲激情av | 波多野结衣精品 | 久久综合九色九九 | 久久久久久国产精品美女 | 99视频精品全部免费 在线 | 免费色视频网址 | 日韩美女黄色片 | 国产亚洲精品久久久网站好莱 | 色网址99| 色视频一区 | 久久综合免费视频 | 波多野结衣综合网 | 久久久久亚洲精品男人的天堂 | 久久一区二区三区国产精品 | 婷婷香蕉 | 久久久久影视 | 国产一级做a | 亚洲在线视频网站 | 91精品视频在线免费观看 | 人人爱人人做人人爽 | 9在线观看免费高清完整版 玖玖爱免费视频 | 波多野结衣在线观看视频 | 欧美肥妇free | 亚洲欧洲av在线 | 99在线热播精品免费99热 | av在线免费网 | 亚洲欧美日韩国产精品一区午夜 | 日韩一二三在线 | 97视频人人免费看 | 久久综合狠狠狠色97 | 国产精彩视频一区二区 | 国产九色视频在线观看 | 亚洲乱码在线 | 婷婷久久网 | 四虎影视成人 | 欧美激情视频一区二区三区 | 超碰99在线 | 97超碰国产精品女人人人爽 | 日本动漫做毛片一区二区 | 成人黄色小说视频 | 日本中文字幕在线免费观看 | 亚洲视频一区二区三区在线观看 | 国产成人a亚洲精品v | 国产一区av在线 | 欧美一区二区三区在线观看 | 狠狠色丁香婷婷综合橹88 | 国产精品嫩草影视久久久 | 99久久精品午夜一区二区小说 | 国产破处视频在线播放 | 99久久综合狠狠综合久久 | 午夜性福利 | 亚洲免费观看在线视频 | 激情开心 | 成人精品一区二区三区电影免费 | 久久精品国产免费看久久精品 | 中文字幕在线观看第一区 | 日韩视频在线不卡 | 99爱这里只有精品 | 日韩av成人在线观看 | 国产成人区| 99中文字幕 | 久久综合九色欧美综合狠狠 | 一区二区亚洲精品 | 日日干激情五月 | 国产日产精品一区二区三区四区的观看方式 | 91精品伦理| 嫩草av在线| 国产偷国产偷亚洲清高 | 亚洲一区二区视频在线 | 不卡的av在线播放 | 午夜视频播放 | 久久精品—区二区三区 | 国产视频 亚洲精品 | 香蕉久草 | 91精品在线免费观看 | 久久99精品久久久久婷婷 | 久久人视频 | 正在播放国产一区二区 | 日日麻批40分钟视频免费观看 | 国产精品一区免费看8c0m | 午夜久久久久 | 国产在线观看中文字幕 | 色多视频在线观看 | 天天鲁一鲁摸一摸爽一爽 | 午夜av影院 | 久久久2o19精品 | av在线播放快速免费阴 | 中文字幕在线观看资源 | 狠狠狠狠狠狠狠狠 | 久久久三级视频 | 色婷婷av国产精品 | 国产精品嫩草影院123 | 日韩精品一区二区三区视频播放 | 国产乱对白刺激视频在线观看女王 | 精品特级毛片 | 中文字幕在 | 精品久久久久久综合 | 欧美激情综合网 | 国产在线黄 | 欧美一区二区三区免费看 | 在线国产中文 | 波多野结衣一区二区三区中文字幕 | 亚洲视频久久久久 | 不卡国产视频 | 国内精品久久久久久久97牛牛 | 精品一区在线看 | 国产日产精品一区二区三区四区 | 91传媒免费在线观看 | 精品一区二区免费在线观看 | 国产午夜精品av一区二区 | 啪啪激情网 | av网站手机在线观看 | 九九九免费视频 | 国产在线视频一区二区三区 | 在线观看视频97 | 久草影视在线观看 | 欧美激情另类 | 久久久久久久99 | 国产欧美日韩视频 | 黄色软件在线观看免费 | 久久成人高清 | 免费av黄色 | 91pony九色丨交换 | 91精品第一页 | 久久久精品国产免费观看一区二区 | 久久久久国产成人免费精品免费 | 99在线精品免费视频九九视 | 亚洲一级久久 | 久久有精品 | 亚洲不卡在线 | 久久国产影院 | 精品久久久精品 | 亚洲午夜av久久乱码 | 久久狠狠一本精品综合网 | 美女免费网视频 | 69av久久| 亚洲精品系列 | 六月丁香久久 | 欧美精品九九99久久 | 色九九视频 | 国产久草在线 | 日韩三级视频 | 又黄又刺激的视频 | 91免费在线看片 | 国产一级精品视频 | 欧美午夜a | 91久久丝袜国产露脸动漫 | 久久久国产高清 | 丁香婷婷成人 | 亚洲经典在线 | 成人午夜电影网站 | 国产精品高潮呻吟久久av无 | 天天综合操 | 日本爱爱片 | 久久在线视频精品 | 久久久国产精品成人免费 | 国产一区二区电影在线观看 | 国产精品激情偷乱一区二区∴ | 亚洲天堂激情 | 91人人揉日日捏人人看 | 国产免费一区二区三区最新6 | 国产美女被啪进深处喷白浆视频 | 精品国产一区二区三区久久久 | 欧美日韩在线看 | 人人爽久久久噜噜噜电影 | 国产黄色片免费观看 | 夜夜爽88888免费视频4848 | 成人av免费在线看 | 在线电影播放 | 久久99精品久久久久婷婷 | 国产夫妻性生活自拍 | 婷婷丁香导航 | 国产成人免费观看久久久 | 黄色片网站av | 国产丝袜制服在线 | 欧美日韩大片在线观看 | 国内精品国产三级国产aⅴ久 | 国产又粗又猛又色又黄视频 | 国产成人一级 | 久久视频免费看 | 免费a视频在线观看 | 国产精品久久久久9999吃药 | 97精品国产97久久久久久免费 | 欧美在线观看视频一区二区三区 | 超碰在线94 | 久久国产欧美日韩精品 | 超碰在线日韩 | 久久精国产| 亚洲黄污| av一区二区三区在线观看 | 一区二区三区视频在线 | av电影av在线 | 久热av| 精品福利视频在线 | 91精品国产欧美一区二区成人 | 久久伊99综合婷婷久久伊 | 91精品一区二区三区久久久久久 | 一区二区三区电影在线播 | 视频成人 | 五月天天av| 欧美一级片在线播放 | 久久久久久久久国产 | 一级性视频 | 免费看黄在线 | 二区三区在线视频 | 精品亚洲免a | 日韩伦理片一区二区三区 | 亚洲美女精品区人人人人 | 精品视频免费久久久看 | 国产精品久久一 | a视频在线观看 | 日韩在线视频网 | 久草在线一免费新视频 | 正在播放日韩 | 国产精品高潮久久av | 日韩理论在线观看 | 成人黄色小说视频 | 激情久久婷婷 | 久久久久久不卡 | 中文字幕免费中文 | 91看片在线观看 | 久久尤物电影视频在线观看 | 手机av在线免费观看 | www国产亚洲精品 | 日韩一区二区三区高清免费看看 | 天天玩夜夜操 | 久香蕉| 综合久色 | 在线观看中文字幕一区二区 | 午夜av免费看 | 国产伦理剧 | 91中文字幕在线观看 | 毛片网站免费 | 日韩在线视频免费观看 | 亚洲狠狠婷婷综合久久久 | 黄色一级免费电影 | 一二三区在线 | 99超碰在线播放 | 99热这里只有精品8 久久综合毛片 | 欧美成人理伦片 | 996久久国产精品线观看 | 久久久久久久久久久网 | 久精品视频在线观看 | 97电影手机 | 国产精品永久在线观看 | 久久久999精品视频 国产美女免费观看 | 91av大全| 久久精品久久久久 | 久久久官网| 中文字幕在线国产精品 | 欧美日韩69 | 色综合天天综合网国产成人网 | 亚洲午夜小视频 | 中文字幕超清在线免费 | 伊人婷婷激情 | 久久婷婷一区 | 日韩理论| 国产一区观看 | 福利一区二区 | 久久99国产综合精品免费 | 在线一级片 | 中文字幕日韩高清 | 久操中文字幕在线观看 | 国产一级大片在线观看 | 中文字幕av最新 | 97精产国品一二三产区在线 | 男女日麻批 | www.亚洲激情.com | 亚洲精品播放 | 免费观看一级特黄欧美大片 | 国产一区二区久久精品 | 免费视频成人 | 激情欧美一区二区三区免费看 | 亚洲欧美激情插 | 最近2019中文免费高清视频观看www99 | 免费国产黄线在线观看视频 | 日日摸日日添日日躁av | 美女网站在线观看 | 日韩免费在线观看网站 | 欧美激情精品一区 | 国产精品 日韩 | 色鬼综合网 | 最新av在线免费观看 | 天天天天天天干 | 亚洲日本精品视频 | 久久新视频 | 色综合久久精品 | 成人激情开心网 | 亚洲干视频在线观看 | 五月天精品视频 | 国产精品午夜免费福利视频 | 日韩一区二区免费视频 | 国产黑丝袜在线 | 国产黄色大全 | 久一在线| 天天操天天曰 | 精品国产一区二区三区在线 | 欧美日韩免费观看一区二区三区 | 波多野结衣视频一区 | 久久婷婷综合激情 | 韩国av免费 | av不卡中文字幕 | 国产第一页福利影院 | 亚洲精品ww | 欧美一级在线观看视频 | 国产剧情一区二区在线观看 | a天堂免费 | 国产精品99久久久久久久久久久久 | 伊人精品在线 | 成人97视频| 91av久久| 成年美女黄网站色大片免费看 | 亚洲美女视频在线 | 五月婷婷综合在线观看 | 亚洲 欧洲 国产 精品 | 亚洲综合色激情五月 | 国产精品3区 | 波多野结依在线观看 | 国产精品久久一区二区无卡 | 亚洲成a人片77777kkkk1在线观看 | 国产亚洲久一区二区 | 亚洲高清激情 | 99国产一区 | 久久精品一区二区三区视频 | 中文字幕免费看 | 天天爽夜夜爽人人爽一区二区 | 国产一区高清在线 | 啪啪精品 | 久久久久久久久久久影院 | 精品一区电影 | 日韩精品欧美专区 | 91福利影院在线观看 | 中文在线www | av.com在线| 亚洲精品影视在线观看 | 亚洲精品免费在线观看视频 | 99久久999久久久精玫瑰 | 69视频网站 | 五月天综合婷婷 | 亚洲欧美日韩国产精品一区午夜 | 国产精品都在这里 | 五月婷婷在线视频 | 国产精品观看在线亚洲人成网 | 国产成人性色生活片 | 亚洲在线高清 | 麻豆久久久 | www日韩精品 | 欧美精品中文字幕亚洲专区 | 麻豆视频一区 | 免费精品在线观看 | 五月婷婷六月丁香在线观看 | 欧美精品久久久久久久久久白贞 | 天天干天天插 | 91伊人久久大香线蕉蜜芽人口 | 欧美日韩成人一区 | 日韩中文字幕免费看 | 99久久婷婷 | 久久96国产精品久久99漫画 | 欧美一级电影免费观看 | 99精品小视频 | 91毛片在线 | 中文字幕在线字幕中文 | 激情在线网| 亚洲精品免费在线 | 激情五月婷婷综合网 | 中文字幕频道 | 五月激情综合婷婷 | 园产精品久久久久久久7电影 | 日韩一区在线播放 | 天天射天天干 | 日韩黄色在线观看 | 中文在线最新版天堂 | 久草视频免费在线播放 | 天天爱天天舔 | 午夜av激情 | 午夜体验区 | 日本xxxx裸体xxxx17 | 波多野结衣动态图 | 麻豆系列在线观看 | 激情婷婷在线 | 国内精品久久久久久久久久久久 | 一本一本久久a久久精品综合 | 国产黄色免费看 | 国产色视频网站2 | 亚洲精品国产精品乱码在线观看 | 久99精品| 久久99国产精品视频 | 久久综合干| 日韩中文字幕在线观看 | 亚洲综合视频在线 | 久久热首页 | 久久99亚洲热视 | 激情久久综合网 | 中文字幕免费 | 国产精品 日韩 欧美 | 国产一级视频在线观看 | 欧美久久九九 | 亚洲日本国产精品 | 国产成人在线观看免费 | 国产精品福利在线播放 | 午夜手机电影 | 久青草影院 | 在线有码中文 | 色哟哟国产精品 | 午夜婷婷在线播放 | 天堂黄色片 | 麻豆精品视频在线观看免费 | av中文字幕网站 | 国产成人av片 | av官网在线 | 91色在线观看 | 91精彩在线视频 | 2021国产在线 | 久热久草| 国产一级性生活视频 | 精品夜夜嗨av一区二区三区 | 色婷婷综合久久久中文字幕 | www.com黄| 亚洲精品国精品久久99热 | 欧美国产高清 | 亚洲va在线va天堂 | 亚洲高清在线精品 | 久久天堂精品视频 | 成人h在线播放 | 久久久久国产免费免费 | 久草视频在线免费 | 精品国产乱码久久久久久三级人 | 96视频在线 | 亚洲国内精品 | 成人污视频在线观看 | 久久久久福利视频 | 手机在线观看国产精品 | 丝袜av网站| 在线视频99| 亚洲精品一区二区18漫画 | 日韩久久久久久久久久 | 日韩欧美综合在线视频 | 91社区国产高清 | 九色在线视频 | 国产精品成人av久久 | 精品 激情 | 精品国产片| 一级黄色av | 99热最新网址 | 精品国产成人在线 | 国产中文字幕在线播放 | 在线看一区二区 | 网站在线观看你们懂的 | 看片的网址 | 日韩欧美一区二区三区黑寡妇 | 激情图片区 | 色插综合| 色婷婷国产精品一区在线观看 | 久久精品影片 | 在线精品观看 | 成人黄在线观看 | www.五月婷婷 | 丝袜美腿在线 | 日韩在线观看电影 | 久久草草热国产精品直播 | 国产精品麻豆三级一区视频 | 久青草国产在线 | av天天澡天天爽天天av | 不卡视频在线看 | 91福利视频在线 | 公与妇乱理三级xxx 在线观看视频在线观看 | 久久久国产精品一区二区三区 | av免费观看网站 | 最近中文字幕高清字幕在线视频 | 日韩无在线 | 亚洲视频 在线观看 | 亚洲精选99 | 精品女同一区二区三区在线观看 | 欧美日一级片 | 又黄又网站 | 一级黄色视屏 | 亚洲精品美女久久久久网站 | 中文字幕中文字幕 | 91在线免费播放视频 | 在线观看视频中文字幕 | 久久久久久99精品 | 免费成人在线观看 | 在线观看免费国产小视频 | 欧美日韩一区二区三区免费视频 | 久久全国免费视频 | 亚洲高清色综合 | 成人一区二区三区中文字幕 | 亚洲人久久久 | 狠狠干网址 | 久久高视频 | 久久超碰在线 | 激情五月婷婷综合 | 欧美日韩1区| 亚洲精品小视频 | 日韩手机在线 | 五月婷婷在线视频 | 亚洲欧洲精品在线 | a级片久久久 | 亚洲精品在线免费看 | 欧美亚洲国产一卡 | 日本在线视频一区二区三区 | 在线导航av | 中文字幕刺激在线 | 婷婷网在线 | 成人午夜免费剧场 | 国产精品一区二区三区免费看 | 视频二区在线 | 国产一区二区三区免费观看视频 | 国产香蕉视频 | 亚洲一区日韩精品 | 在线免费视频a | 91久久爱热色涩涩 | 久久久久久久久久久久影院 | 人人添人人澡人人澡人人人爽 | 最近免费中文字幕大全高清10 | 日日噜噜噜噜夜夜爽亚洲精品 | 狠狠狠色丁香婷婷综合久久88 | 国产不卡在线视频 | 狠狠狠色丁香综合久久天下网 | 日韩成人xxxx| 欧美日韩在线网站 | 人人插人人干 | 日韩a在线看 | 国产精品久久久久久久久久久久午 | 丁香六月欧美 | 日韩色高清 | 日韩午夜网站 | 久久99精品一区二区三区三区 | 日韩欧美有码在线 | 99视频在线免费播放 | 99超碰在线播放 | 成人av观看 | 成年人视频在线免费 | 久久久久 免费视频 | 中文字幕一区二区在线播放 | 综合网天天 | 九九九热精品免费视频观看网站 | 国产精品观看在线亚洲人成网 | 欧美日韩一二三四区 | 精品欧美一区二区三区久久久 | 亚洲欧美va | 狠狠色丁香婷婷综合基地 | 狠狠色丁香婷婷综合久久片 | 免费看成人av | 午夜精品一区二区三区免费 | 日韩免费二区 | 久久香蕉国产精品麻豆粉嫩av | 激情久久一区二区三区 | 久久久免费观看完整版 | 国产一性一爱一乱一交 | 午夜视频一区二区三区 | 99久久这里只有精品 | 最近高清中文字幕 | 9999免费视频| 一区二区国产精品 | 韩国av电影网| 色大片免费看 | 国产中文字幕在线看 | 色综合久久66 | 丁香六月婷婷开心 | 91综合久久一区二区 | 免费黄色一区 | 久久艹久久 | 亚洲欧美视频一区二区三区 | 久久久久久久久黄色 | 国产一区不卡在线 | 国产美女视频黄a视频免费 久久综合九色欧美综合狠狠 | 国产一级电影免费观看 | 日本xxxx.com | 日韩欧美视频免费在线观看 | av电影一区 | 黄色小说免费在线观看 | av在线免费不卡 | 成人性生活大片 | 日韩系列在线 | 高清日韩一区二区 | 视频二区在线视频 | 日韩两性视频 | 美女网站黄免费 | 久久精品3 | av一区二区三区在线观看 | 中文字幕在 | 爱情影院aqdy鲁丝片二区 | 国产亚洲视频在线观看 | 91porny九色91啦中文 | h视频日本 | 免费日韩电影 | 欧美少妇xxxxxx | 国产做a爱一级久久 | 国产精品久久久久永久免费观看 | 精品二区视频 | 国产午夜精品一区二区三区欧美 | 夜夜天天干 | 欧美精品v国产精品 | 色99久久 | 国产一区免费视频 | 久国产在线播放 | 亚洲精品乱码久久久久久久久久 | 在线日本看片免费人成视久网 | 亚洲精品福利在线 | 国产成人精品免高潮在线观看 | 国产一级二级在线播放 | 特级毛片在线免费观看 | 波多野结衣在线视频一区 | 日本系列中文字幕 | 中日韩欧美精彩视频 | 91手机电影 | 国产精品成人一区二区 | 在线观看成人一级片 | 99超碰在线播放 | 中文字幕在线观看免费 | 亚洲欧美日韩一区二区三区在线观看 | 欧美天天干 | 人人爽人人av | 视频在线观看亚洲 | 欧美一级日韩三级 | 免费的国产精品 | a级国产毛片 | 97在线免费视频 | 国产一区二区午夜 | 热久久免费国产视频 | 亚洲免费在线视频 | 久久国产电影院 | 亚洲一区二区高潮无套美女 | 91亚洲精品在线观看 | 亚洲国产中文字幕在线观看 | 五月综合激情婷婷 | 中文字幕在线观看国产 | 亚州成人av在线 | 91日韩精品 | 亚洲高清在线视频 | 免费av在线 | 国产精品久久久久久一区二区三区 | www在线观看视频 | 在线91色 | 偷拍区另类综合在线 | 亚洲国产三级 | 中文在线免费观看 | av在线免费网站 | 日韩va亚洲va欧美va久久 | 在线韩国电影免费观影完整版 | 成人av片免费看 | 午夜av免费在线观看 | 92精品国产成人观看免费 | 国产系列在线观看 | 天天干天天干天天操 | 99久久久久免费精品国产 | 96视频免费在线观看 | 五月婷婷播播 | 在线激情av电影 | 欧美久久久久久久 | 日韩高清在线不卡 | 人人舔人人爱 | 欧美一级小视频 | 精品视频专区 | 色婷婷久久一区二区 | av丝袜制服 | 亚洲激情综合 | 98超碰在线观看 | 国产精品美 | 高清在线一区二区 | 曰本免费av | 国产99黄 | 国产裸体永久免费视频网站 | 伊人黄| 亚洲激情p | 精品在线一区二区三区 | 69av久久 | 国产99久久99热这里精品5 | 久久精品三 | 国内精品亚洲 | 国产一级二级av | 国产人成在线视频 | 综合网天天 | 91免费试看 | 黄色大片免费网站 | 天天做综合网 | 久久综合给合久久狠狠色 | 亚洲日韩精品欧美一区二区 | 久久久国产精品亚洲一区 | 中文字幕在线成人 | 97福利 | 日韩av看片 | 日韩 在线a | 亚洲国产精品成人av | 国产午夜精品一区二区三区在线观看 | 91漂亮少妇露脸在线播放 | 九九爱免费视频在线观看 | 日韩美精品视频 | 久热免费在线 | 在线看中文字幕 | 亚洲国产一二三 | 日日操天天爽 | 国产在线中文字幕 | 在线免费观看视频你懂的 | 久久婷婷一区二区三区 | 亚洲电影网站 | 日韩精品免费在线 | 超碰在线1 | 婷婷激情五月 | 国产一级久久久 | 一级黄色电影网站 | 国产黄色视 | 超碰免费公开 | 久草视频精品 | 特级毛片在线 | 欧美色综合天天久久综合精品 | 日韩美精品视频 | 91在线影视 | 狠狠色狠狠色综合日日小说 | 91精品国产麻豆 | 日韩三级视频 | 久久国产a| 欧美在线18 | 久久久91精品国产一区二区三区 | 五月婷婷伊人网 | 欧美一区在线看 | 久草青青在线观看 | 天天视频色 | 91av在线免费观看 | 伊人色综合久久天天网 | 久久精品aaa | 亚洲热久久 | 最新国产中文字幕 | 亚洲1级片 | 在线免费观看视频一区 | 麻豆小视频在线观看 | 久草视频观看 | 久久不卡日韩美女 | av千婊在线免费观看 | 色香蕉视频 | 成片免费观看视频大全 | 91av视频观看 | 在线免费亚洲 | 99这里都是精品 | 国产精品毛片一区视频播 | 99免费精品 | 国产精品福利无圣光在线一区 | 国产精品美女久久久免费 | av成人在线电影 | 国产中文字幕视频在线观看 | 蜜臀av夜夜澡人人爽人人桃色 | 久热av | 国产美女视频 | 亚洲精品五月天 | 色综合久久网 | 精品一区二区影视 | 夜添久久精品亚洲国产精品 | 国产成人一区二区啪在线观看 | 日韩av区| 亚洲欧美国产视频 | 人人草在线视频 | 免费在线观看中文字幕 | 久久久综合九色合综国产精品 | 国产91勾搭技师精品 | 精品91| 国产香蕉久久精品综合网 | 激情久久伊人 | 日韩精品在线视频免费观看 | 亚洲日本成人网 | www夜夜操| 亚洲日本va中文字幕 | 国产亚洲精品久久久久久久久久 | 日韩国产精品久久 | 麻豆精品传媒视频 | 成人国产网址 | 福利片视频区 | 中日韩免费视频 | 日韩欧美高清不卡 | 444av| 国产一区二区高清视频 | 久久免费看a级毛毛片 | 久久天天拍 | 中文字幕在线影院 | 99精品视频在线观看视频 | 黄色毛片视频免费观看中文 | 91在线操| 久久久久久久久久久久久影院 | 色人久久 | 麻豆视传媒官网免费观看 | 二区视频在线观看 | 婷婷亚洲五月色综合 | 亚洲综合婷婷 | 狠狠gao| 亚洲欧美国产日韩在线观看 | 久草在线最新 | 韩国三级在线一区 | 欧美老少交 | av导航福利 | 成人av免费播放 | 日韩在线中文字幕 | 久精品视频在线观看 | 欧美精品乱码久久久久 | 中文字幕av专区 | 91精品国产一区二区三区 | a视频免费在线观看 | 在线免费观看的av | 国产又粗又猛又黄又爽的视频 | 丝袜制服综合网 | 精品一区二区免费视频 | 久久久久久美女 | 中文在线天堂资源 | 欧美动漫一区二区三区 | 国产精品久久一区二区三区不卡 | 久久一线| 97精品国产97久久久久久免费 | 日本一区二区三区免费看 | 一级黄色片在线观看 | 日韩中文幕 | 精品国产三级 | 亚洲高清在线精品 | 日韩在线国产精品 | 亚洲一区二区视频在线播放 | 三级在线视频播放 | 日韩中文字幕a | 91精品国产99久久久久久久 | 九九免费精品视频在线观看 | www.com在线观看 | 午夜影院一级片 | 51久久夜色精品国产麻豆 | 亚洲va在线va天堂 | 亚洲视频在线观看 | 亚洲区精品 | 特级黄色一级 | 色丁香综合 | 一区二区三区四区影院 | 日本视频高清 | 久久久综合香蕉尹人综合网 |