Springboot Code (一)源碼學習

微服務中文介紹:https://www.cnblogs.com/liuning8023/p/4493156.html

Springboot中文學習文檔:http://felord.cn/_doc/_springboot/2.1.5.RELEASE/_book/

簡單閱覽下學習文檔,梳理下Springboot的使用功能:

  • 外部化配置

1、yaml腳本存放位置的優先級;

2、spring.profiles.active多環境yaml配置;

3、@Value與@ConfigurationProperties獲取配置文件對應key的值(區別:哪個支持寬鬆綁定?支持表達式及表達式函數?);

4、@Validated+諸如@Email進行配置信息校驗;

5、新增banner.txt來更改啓動日誌Logo;

6、使用@Target@Retention@Documented自定義註解,使用@Aspect@Before進行aop分析;

  • 開發web應用程序

1、熱部署插件JRebel(非免費)或spring-boot-devtools;

2、用@WebServlet@ServletComponentScan創建servlet加入springboot容器,運用ServletRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean去裝載自定義servlet、fileter和listener;

3、thymeleaf的依賴配置與語法使用,及國際化配置(i18n);

4、數據源配置(含druid的依賴)與JDBCTemplate對數據庫數據的操作;

5、多數據源的動態切換(自定義註解 or 層級目錄兩種方式);

下面進入源碼學習的正題:(當前以最新SpringbootV2.4.4版本進行學習)

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

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

此處可以分爲兩個流程:new SpringApplication和run方法。

第一個步驟:new SpringApplication

  • resourceLoader從註解來看是一個資源加載loader,這裏傳入的是null,應該後續會使用到默認值 。
  • primarySources傳入的是我們main方法的啓動類,從這裏可以看出能傳入多個,這裏我們傳入的就一個 。
    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 = Collections.emptySet();
        this.isCustomEnvironment = false;
        this.lazyInitialization = false;
        this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
        this.applicationStartup = ApplicationStartup.DEFAULT;
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        this.bootstrappers = new ArrayList(this.getSpringFactoriesInstances(Bootstrapper.class));
        this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }

1、在new SpringApplication中,配置source、是否web環境等準備工作;

2、webApplicationType表示web服務類型,從這個枚舉類內部代碼可以看出有none,servlet,reactive三種,根據依賴包來進行判斷的;

3、創建初始化構造器和應用監聽器,使用this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class/ApplicationListener.class));

  • ApplicationContextInitializer通過接口註解瞭解到:

①用於在ConfigurableApplicationContext執行refresh操作之前對它進行一些初始化操作;

②通常被用作web應用,在一些程序設計在spring容器初始化使用。

③支持Spring中的Ordered接口以及@Order註解來對多ApplicationContextInitializer實例進行排序,按照排序後的順序依次執行回調

  • ApplicationListener基於觀察者模式實現的一種application程序啓動過程中觀察程序狀態過程變更的一種機制,可以自定義實現ApplicationListener用於觀察ApplicationEvent或者某種Event,甚至可以自定義Event,然後手動出發publishEvent。
    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
        return this.getSpringFactoriesInstances(type, new Class[0]);
    }

    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = this.getClassLoader();
        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.loadFactoryNames 和 this.createSpringFactoriesInstances 兩個方法。發現創建 ApplicationContextInitializerApplicationListener 兩個類的初始化構造器,方便後續邏輯可以獲取構造器(工廠)對象。

    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        ClassLoader classLoaderToUse = classLoader;
        if (classLoader == null) {
            classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
        }

        String factoryTypeName = factoryType.getName();
        return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
    }

    private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
        Map<String, List<String>> result = (Map)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            HashMap result = new HashMap();

            try {
                Enumeration urls = classLoader.getResources("META-INF/spring.factories");

                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) {
                        Entry<?, ?> entry = (Entry)var6.next();
                        String factoryTypeName = ((String)entry.getKey()).trim();
                        String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        String[] var10 = factoryImplementationNames;
                        int var11 = factoryImplementationNames.length;

                        for(int var12 = 0; var12 < var11; ++var12) {
                            String factoryImplementationName = var10[var12];
                            ((List)result.computeIfAbsent(factoryTypeName, (key) -> {
                                return new ArrayList();
                            })).add(factoryImplementationName.trim());
                        }
                    }
                }

                result.replaceAll((factoryType, implementations) -> {
                    return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
                });
                cache.put(classLoader, result);
                return result;
            } catch (IOException var14) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
            }
        }
    }

此處可以發現讀取了spring的默認配置spring.factories(jar:file:/C:/Users/Administrator/.m2/repository/org/springframework/boot/spring-boot/2.4.4/spring-boot-2.4.4.jar!/META-INF/spring.factories)

# Logging Systems
org.springframework.boot.logging.LoggingSystemFactory=\
org.springframework.boot.logging.logback.LogbackLoggingSystem.Factory,\
org.springframework.boot.logging.log4j2.Log4J2LoggingSystem.Factory,\
org.springframework.boot.logging.java.JavaLoggingSystem.Factory

# PropertySource Loaders
org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader

# ConfigData Location Resolvers
org.springframework.boot.context.config.ConfigDataLocationResolver=\
org.springframework.boot.context.config.ConfigTreeConfigDataLocationResolver,\
org.springframework.boot.context.config.StandardConfigDataLocationResolver

# ConfigData Loaders
org.springframework.boot.context.config.ConfigDataLoader=\
org.springframework.boot.context.config.ConfigTreeConfigDataLoader,\
org.springframework.boot.context.config.StandardConfigDataLoader

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

# Error Reporters
org.springframework.boot.SpringBootExceptionReporter=\
org.springframework.boot.diagnostics.FailureAnalyzers

# 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.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.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.DelegatingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.env.EnvironmentPostProcessorApplicationListener

# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor,\
org.springframework.boot.env.RandomValuePropertySourceEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\
org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor,\
org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor

# Failure Analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.context.config.ConfigDataNotFoundFailureAnalyzer,\
org.springframework.boot.context.properties.IncompatibleConfigurationFailureAnalyzer,\
org.springframework.boot.context.properties.NotConstructorBoundInjectionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanDefinitionOverrideFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.PatternParseFailureAnalyzer,\
org.springframework.boot.liquibase.LiquibaseChangelogMissingFailureAnalyzer

# Failure Analysis Reporters
org.springframework.boot.diagnostics.FailureAnalysisReporter=\
org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter

# DataSource Initializer Detectors
org.springframework.boot.jdbc.init.dependency.DataSourceInitializerDetector=\
org.springframework.boot.flyway.FlywayDataSourceInitializerDetector,\
org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializerDetector,\
org.springframework.boot.liquibase.LiquibaseDataSourceInitializerDetector,\
org.springframework.boot.orm.jpa.JpaDataSourceInitializerDetector

# Depends On DataSource Initialization Detectors
org.springframework.boot.jdbc.init.dependency.DependsOnDataSourceInitializationDetector=\
org.springframework.boot.jdbc.init.dependency.AnnotationDependsOnDataSourceInitializationDetector,\
org.springframework.boot.jdbc.SpringJdbcDependsOnDataSourceInitializationDetector,\
org.springframework.boot.jooq.JooqDependsOnDataSourceInitializationDetector,\
org.springframework.boot.orm.jpa.JpaDependsOnDataSourceInitializationDetector
    private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) {
        List<T> instances = new ArrayList(names.size());
        Iterator var7 = names.iterator();

        while(var7.hasNext()) {
            String name = (String)var7.next();

            try {
                Class<?> instanceClass = ClassUtils.forName(name, classLoader);
                Assert.isAssignable(type, instanceClass);
                Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
                T instance = BeanUtils.instantiateClass(constructor, args);
                instances.add(instance);
            } catch (Throwable var12) {
                throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, var12);
            }
        }

        return instances;
    }

4、 mainApplicationClass通過deduceMainApplicationClass方法獲取main啓動類(異常類堆棧的方式),這裏可以看出main啓動類和primarySources對應的類可以不一樣。 也就是爲什麼不直接用primarySources作爲啓動類的原因。deduceMainApplicationClass方法通過創建異常的方式獲取方發棧,然後逐級推斷出啓動類。

    private Class<?> deduceMainApplicationClass() {
        try {
            StackTraceElement[] stackTrace = (new RuntimeException()).getStackTrace();
            StackTraceElement[] var2 = stackTrace;
            int var3 = stackTrace.length;

            for(int var4 = 0; var4 < var3; ++var4) {
                StackTraceElement stackTraceElement = var2[var4];
                if ("main".equals(stackTraceElement.getMethodName())) {
                    return Class.forName(stackTraceElement.getClassName());
                }
            }
        } catch (ClassNotFoundException var6) {
        }

        return null;
    }

 

第二步 run() 方法

     public ConfigurableApplicationContext run(String... args) {
        //1、StopWatch簡單的看成一個stop watch的機制,保存stop的記錄信息。
        //初始化一個計時器,並開始計時
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        //初始化啓動上下文
        DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
        ConfigurableApplicationContext context = null;
        
        //2、configureHeadlessProperty即配置headless模式,這種模式是一種系統缺少顯示設備、鍵盤和鼠標外設的情況模式。
        this.configureHeadlessProperty();

        //3、SpringApplicationListeners爲SpringApplicationRunListener接口實現集合(創建SpringApplicationRunListener初始化構造器)初始化監聽器列表
        //可以理解這個接口就是在spring啓動整個過程都需要回調這些listener
        //debug能發現,拿到了一個名爲EventPublishingRunListener(RunListener構造方法中關聯上了全部applicationListener),這個就是用來進行觸發publishEvent的被觀察者
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        //啓動EventPublishingRunListener,從而過濾並啓動相關Listener
        listeners.starting(bootstrapContext, this.mainApplicationClass);

        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            //4、ConfigurableEnvironment爲配置環境對象,簡單理解所有的配置信息彙總在這個對象中
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            this.configureIgnoreBeanInfo(environment);

            //5、Banner就是我們常在控制檯輸出的畫面橫幅,可以使用圖片或者文本進行替換
            Banner printedBanner = this.printBanner(environment);

            //6、ConfigurableApplicationContext根據webApp…Type進行構造的上下文對象
            context = this.createApplicationContext();
            context.setApplicationStartup(this.applicationStartup);

            //7、接下來進入關鍵步驟的第一步:prepareContext,準備容器階段,將執行所有的initializers邏輯,做初始化準備操作。
            this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);

            //8、refreshContext,可以理解成容器初始化節點,將執行bean的創建和實例化。
            this.refreshContext(context);

            //9、afterRefresh,容器後處理, 可以看到會找到ApplicationRunner和CommandLineRunner的實現類並執行。但從2.x版本來看,似乎這個方法是個空方法,applicationRun和commandRun移到啓動最後。
            this.afterRefresh(context, applicationArguments);

            //10、然後根據stopwatch打印出啓動時間
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
             
            //11、這裏調用ApplicationRunner和CommandLineRunner的實現類
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, listeners);
            throw new IllegalStateException(var10);
        }

        try {
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }
  • StopWatch簡單的看成一個stop watch的機制,保存stop的記錄信息
  • configureHeadlessProperty即配置headless模式,這種模式是一種系統缺少顯示設備、鍵盤和鼠標外設的情況模式
  • SpringApplicationListeners爲SpringApplicationRunListener接口實現集合,可以理解這個接口就是在spring啓動整個過程都需要回調這些listener,debug能發現,拿到了一個名爲EventPublishingRunListener,這個就是用來進行觸發publishEvent的被觀察者。this.getSpringFactoriesInstances方法剛剛在第一步中也使用到了。根據spring.factories的配置返回對應實例EventPublishingRunListener。

    Spring Boot定義的 SpringApplicationRunListener 實現類只有 EventPublishingRunListener ,主要是定義了其生命週期,並且在Spring Boot啓動過程中完成回調。如果自定義實現的話,則需要使用自動裝配的方式將自己添加到META-INF/spring.factories中才能被執行回調。

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

--------> 此時,又多了一個RunListener(也是根據spring.factories中SpringApplicationRunListener配置的value值,之前SpringApplication已加載9個Listener和7個Initializer)<----------

  • listeners.starting(bootstrapContext, this.mainApplicationClass) 發佈springboot啓動事件,通過doWithListeners方法對事件進行發佈。

    void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
        this.doWithListeners("spring.boot.application.starting", (listener) -> {
            listener.starting(bootstrapContext);
        }, (step) -> {
            if (mainApplicationClass != null) {
                step.tag("mainApplicationClass", mainApplicationClass.getName());
            }

        });
    }

    private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction, Consumer<StartupStep> stepAction) {
        StartupStep step = this.applicationStartup.start(stepName);
        this.listeners.forEach(listenerAction);
        if (stepAction != null) {
            stepAction.accept(step);
        }

        step.end();
    }

解析doWithListeners方法:

1、初始化一個StartupStep實例,並命名爲"spring.boot.application.starting",其作用爲:追蹤“執行時間”或其他指標。

2、對內部維護的監聽器列表進行遍歷,執行傳入的listenerAction。由於listeners中只包含一個EventPublishingRunListener對象,故此處是用EventPublishingRunListener實例對象執行starting(bootstrapContext)方法。

下面將進入EventPublishingRunListener 的starting重寫方法

    public void starting(ConfigurableBootstrapContext bootstrapContext) {
        this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
    }

    public void multicastEvent(ApplicationEvent event) {
        this.multicastEvent(event, this.resolveDefaultEventType(event));
    }

    /**
     * 批量消費事件:對符合要求的監聽器進行遍歷,執行invokeListener(listener, event)方法
    */
    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);
            }
        }

    }

    protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {
        Object source = event.getSource();
        Class<?> sourceType = source != null ? source.getClass() : null;
        AbstractApplicationEventMulticaster.ListenerCacheKey cacheKey = new AbstractApplicationEventMulticaster.ListenerCacheKey(eventType, sourceType);
        AbstractApplicationEventMulticaster.CachedListenerRetriever newRetriever = null;
        AbstractApplicationEventMulticaster.CachedListenerRetriever existingRetriever = (AbstractApplicationEventMulticaster.CachedListenerRetriever)this.retrieverCache.get(cacheKey);
        if (existingRetriever == null && (this.beanClassLoader == null || ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
            newRetriever = new AbstractApplicationEventMulticaster.CachedListenerRetriever();
            existingRetriever = (AbstractApplicationEventMulticaster.CachedListenerRetriever)this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
            if (existingRetriever != null) {
                newRetriever = null;
            }
        }

        if (existingRetriever != null) {
            Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners();
            if (result != null) {
                return result;
            }
        }

        //匹配符合的Listeners,此處符合ApplicationStartingEvent事件的監聽器有:LoggingApplicationListener
        //、BackgroundPreinitializer、DelegatingApplicationListener、LiquibaseServiceLocatorApplicationListener四個
        return this.retrieveApplicationListeners(eventType, sourceType, newRetriever);
    }  

下面跟進invokeListener(listener, event)方法,errorHandler爲空,直接執行doInvokeListener方法。

    protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
        ErrorHandler errorHandler = this.getErrorHandler();
        if (errorHandler != null) {
            try {
                this.doInvokeListener(listener, event);
            } catch (Throwable var5) {
                errorHandler.handleError(var5);
            }
        } else {
            this.doInvokeListener(listener, event);
        }

    }

    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        try {
            listener.onApplicationEvent(event);
        } catch (ClassCastException var6) {
            String msg = var6.getMessage();
            if (msg != null && !this.matchesClassCastMessage(msg, event.getClass()) && (!(event instanceof PayloadApplicationEvent) || !this.matchesClassCastMessage(msg, ((PayloadApplicationEvent)event).getPayload().getClass()))) {
                throw var6;
            }

            Log loggerToUse = this.lazyLogger;
            if (loggerToUse == null) {
                loggerToUse = LogFactory.getLog(this.getClass());
                this.lazyLogger = loggerToUse;
            }

            if (loggerToUse.isTraceEnabled()) {
                loggerToUse.trace("Non-matching event type for listener: " + listener, var6);
            }
        }

    }

當事件爲ApplicationStartingEvent時,以上4個監聽器的onApplicationEvent(event)方法彙總如下,它們分別進行了以下操作:

① LoggingApplicationListener初始化了loggingSystem

② BackgroundPreinitializer:未執行任何操作

③ DelegatingApplicationListener:未執行任何操作

④ LiquibaseServiceLocatorApplicationListener:未執行任何操作


      /**
       * 當listener爲LoggingApplicationListener時
       */
      public void onApplicationEvent(ApplicationEvent event) {
     	if (event instanceof ApplicationStartingEvent) {
      		onApplicationStartingEvent((ApplicationStartingEvent) event);
      	}
     	else if (event instanceof ApplicationEnvironmentPreparedEvent) {
      		onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
      	}
     	else if (event instanceof ApplicationPreparedEvent) {
      		onApplicationPreparedEvent((ApplicationPreparedEvent) event);
      	}
     	else if (event instanceof ContextClosedEvent
      			&& ((ContextClosedEvent) event).getApplicationContext().getParent() == null) {
      		onContextClosedEvent();
      	}
     	else if (event instanceof ApplicationFailedEvent) {
      		onApplicationFailedEvent();
      	}
      }
      private void onApplicationStartingEvent(ApplicationStartingEvent event) {
      // 初始化loggingSystem
     	this.loggingSystem = LoggingSystem.get(event.getSpringApplication().getClassLoader());
     	this.loggingSystem.beforeInitialize();
      }
      // ---------------------------------------------------------------
      /**
       * 當listener爲BackgroundPreinitializer時,由於未識別到ApplicationStartingEvent事件,故不執行任何操作
       */
      public void onApplicationEvent(SpringApplicationEvent event) {
     	if (!ENABLED) {
     		return;
      	}
     	if (event instanceof ApplicationEnvironmentPreparedEvent
      			&& preinitializationStarted.compareAndSet(false, true)) {
      		performPreinitialization();
      	}
     	if ((event instanceof ApplicationReadyEvent || event instanceof ApplicationFailedEvent)
      			&& preinitializationStarted.get()) {
     		try {
      			preinitializationComplete.await();
      		}
     		catch (InterruptedException ex) {
      			Thread.currentThread().interrupt();
      		}
      	}
      }
      /**
      * performPreinitialization方法,執行各種初始化
      **/
      private void performPreinitialization() {
        try {
            Thread thread = new Thread(new Runnable() {
                public void run() {
                    this.runSafely(new BackgroundPreinitializer.ConversionServiceInitializer());
                    this.runSafely(new BackgroundPreinitializer.ValidationInitializer());
                    this.runSafely(new BackgroundPreinitializer.MessageConverterInitializer());
                    this.runSafely(new BackgroundPreinitializer.JacksonInitializer());
                    this.runSafely(new BackgroundPreinitializer.CharsetInitializer());
                    BackgroundPreinitializer.preinitializationComplete.countDown();
                }

                public void runSafely(Runnable runnable) {
                    try {
                        runnable.run();
                    } catch (Throwable var3) {
                    }

                }
            }, "background-preinit");
            thread.start();
        } catch (Exception var2) {
            preinitializationComplete.countDown();
        }

     }
      // ---------------------------------------------------------------
      /**
       * 當listener爲DelegatingApplicationListener時,由於未識別到ApplicationStartingEvent事件,故不執行任何操作
       */
      public void onApplicationEvent(ApplicationEvent event) {
     	if (event instanceof ApplicationEnvironmentPreparedEvent) {
      		List<ApplicationListener<ApplicationEvent>> delegates = getListeners(
       ((ApplicationEnvironmentPreparedEvent) event).getEnvironment());
     		if (delegates.isEmpty()) {
     			return;
      		}
     		this.multicaster = new SimpleApplicationEventMulticaster();
     		for (ApplicationListener<ApplicationEvent> listener : delegates) {
     			this.multicaster.addApplicationListener(listener);
      		}
      	}
     	if (this.multicaster != null) {
     		this.multicaster.multicastEvent(event);
      	}
      }
      // ---------------------------------------------------------------
      /**
       * 當listener爲LiquibaseServiceLocatorApplicationListener時,由於LIQUIBASE_PRESENT爲false,故不執行任何操作
       */
      public void onApplicationEvent(ApplicationStartingEvent event) {
     	if (LIQUIBASE_PRESENT) {
     		new LiquibasePresent().replaceServiceLocator();
      	}
      }
  

彙總一下:

(一)new SpringApplication

  1. 配置source和web環境;
  2. 創建初始化構造器和應用監聽器;
  3. 配置應用的主方法所在類;

(二)run 第一部分

  1. 初始化計時、啓動上下文、設置系統參數;
  2. 初始化監聽器列表;
  3. 發佈springboot開始啓動事件starting;

SpringApplicationRunListener 屬於應用程序啓動層面的監聽器,在springboot啓動時候,調用run方法進行反射加載初始化。此時上下文還沒有加載,如果通過@Compnant是起不了作用的

ApplicationListener 通過spring上下文加載初始化的

剩下的部分將在下一章節,繼續學習:

  • ConfigurableEnvironment爲配置環境對象,簡單理解所有的配置信息彙總在這個對象中
  • Banner就是我們常在控制檯輸出的畫面橫幅,可以使用圖片或者文本進行替換
  • ConfigurableApplicationContext根據webApp…Type進行構造的上下文對象
  • 接下來進入關鍵步驟的第一步:prepareContext,準備容器階段,將執行所有的initializers邏輯,做初始化準備操作
  • refreshContext,可以理解成容器初始化節點,將執行bean的創建和實例化
  • afterRefresh,容器後處理, 可以看到會找到ApplicationRunner和CommandLineRunner的實現類並執行。但從2.x版本來看,似乎這個方法是個空方法,applicationRun和commandRun移到啓動最後。
  • 然後根據stopwatch打印出啓動時間
  • 這裏調用ApplicationRunner和CommandLineRunner的實現類
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章