<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ## Spring Boot 優勢 * 自動裝配 * 內嵌容器 * 應用監控 * Starter 包簡化集成難度。 自動裝配:Spring Boot 會根據某些規則對所有配置的 Bean 進行初始化。可以減少了很多重復性的工作。比如使用 mybatis時,只需要在 pom.xml 中加入 mybatis的 Starter 包,然后配置 mybatis的連接信息,就可以直接使用 @mapper自動裝配來操作數據庫了。 內嵌容器:Spring Boot 應用程序可以不用部署到外部容器中,比如 Tomcat。Spring Boot 應用程序可以直接通過 Maven 命令編譯成可執行的 jar 包,通過 java -jar 命令啟動即可,非常方便。 應用監控:Spring Boot 中自帶監控功能 Actuator,可以實現對程序內部運行情況進行監控,比如 Bean 加載情況、環境變量、日志信息、線程信息等。當然也可以自定義跟業務相關的監控,通過Actuator 的端點信息進行暴露。 Starter 包簡化框架集成難度:將 Bean 的自動裝配邏輯封裝在 Starter 包內部,同時也簡化了 Maven Jar 包的依賴,對框架的集成只需要加入一個 Starter 包的配置,降低了煩瑣配置的出錯幾率。 ## Spring Boot 框架圖 ![](https://img.kancloud.cn/6b/ba/6bba83f90e6def3167ffa767520d0589_1510x608.png) ## Spring Boot 啟動源碼分析 我們知道 Spring Boot 程序的入口是 SpringApplication.run(Application.class, args) 方法,那么就從 run() 方法開始分析吧,它的源碼如下: ``` public ConfigurableApplicationContext run(String... args) { // 1.創建并啟動計時監控類 StopWatch stopWatch = new StopWatch(); stopWatch.start(); // 2.聲明應用上下文對象和異常報告集合 ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList(); // 3.設置系統屬性 headless 的值 this.configureHeadlessProperty(); // 4.創建所有 Spring 運行監聽器并發布應用啟動事件 SpringApplicationRunListeners listeners = this.getRunListeners(args); listeners.starting(); Collection exceptionReporters; try { // 5.處理 args 參數 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 6.準備環境 ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); this.configureIgnoreBeanInfo(environment); // 7.創建 Banner 的打印類 Banner printedBanner = this.printBanner(environment); // 8.創建應用上下文 context = this.createApplicationContext(); // 9.實例化異常報告器 exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context); // 10.準備應用上下文 this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); // 11.刷新應用上下文 this.refreshContext(context); // 12.應用上下文刷新之后的事件的處理 this.afterRefresh(context, applicationArguments); // 13.停止計時監控類 stopWatch.stop(); // 14.輸出日志記錄執行主類名、時間信息 if (this.logStartupInfo) { (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch); } // 15.發布應用上下文啟動完成事件 listeners.started(context); // 16.執行所有 Runner 運行器 this.callRunners(context, applicationArguments); } catch (Throwable var10) { this.handleRunFailure(context, var10, exceptionReporters, listeners); throw new IllegalStateException(var10); } try { // 17.發布應用上下文就緒事件 listeners.running(context); // 18.返回應用上下文對象 return context; } catch (Throwable var9) { this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null); throw new IllegalStateException(var9); } } ``` ## Spring Boot 的啟動流程 * 1.創建并啟動計時監控類 此計時器是為了監控并記錄 Spring Boot 應用啟動的時間的,它會記錄當前任務的名稱,然后開啟計時器。 * 2.聲明應用上下文對象和異常報告集合 此過程聲明了應用上下文對象和一個異常報告的 ArrayList 集合。 * 3.設置系統屬性 headless 的值 設置 Java.awt.headless = true,其中 awt(Abstract Window Toolkit)的含義是抽象窗口工具集。設置為 true 表示運行一個 headless 服務器,可以用它來作一些簡單的圖像處理。 * 4.創建所有 Spring 運行監聽器并發布應用啟動事件 此過程用于獲取配置的監聽器名稱并實例化所有的類。 * 5.初始化默認應用的參數類 也就是說聲明并創建一個應用參數對象。 * 6.準備環境 創建配置并且綁定環境(通過 property sources 和 profiles 等配置文件)。 * 7.創建 Banner 的打印類 Spring Boot 啟動時會打印 Banner 圖片 * 8.創建應用上下文 根據不同的應用類型來創建不同的 ApplicationContext 上下文對象。 * 9.實例化異常報告器 它調用的是 getSpringFactoriesInstances() 方法來獲取配置異常類的名稱,并實例化所有的異常處理類。 * 10.準備應用上下文 此方法的主要作用是把上面已經創建好的對象,傳遞給 prepareContext 來準備上下文,例如將環境變量 environment 對象綁定到上下文中、配置 bean 生成器以及資源加載器、記錄啟動日志等操作。 * 11.刷新應用上下文 此方法用于解析配置文件,加載 bean 對象,并且啟動內置的 web 容器等操作。bean定位,載入和注冊。 * 12.應用上下文刷新之后的事件處理 這個方法的源碼是空的,可以做一些自定義的后置處理操作。 * 13.停止計時監控類 停止此過程第一步中的程序計時器,并統計任務的執行信息。 * 14.輸出日志信息 把相關的記錄信息,如類名、時間等信息進行控制臺輸出。 * 15.發布應用上下文啟動完成事件 觸發所有 SpringApplicationRunListener 監聽器的 started 事件方法。 * 16.執行所有 Runner 運行器 執行所有的 ApplicationRunner 和 CommandLineRunner 運行器。 * 17.發布應用上下文就緒事件 觸發所有的 SpringApplicationRunListener 監聽器的 running 事件。 * 18.返回應用上下文對象 到此為止 Spring Boot 的啟動程序就結束了,我們就可以正常來使用 Spring Boot 框架了,下面我們具體到代碼分析啟動流程。 ## springboot內置代碼分析 > 運行流程: * 1:判斷是否是web環境 ``` public SpringApplication(Object... sources) { initialize(sources); } @SuppressWarnings({ "unchecked", "rawtypes" }) private void initialize(Object[] sources) { if (sources != null && sources.length > 0) { this.sources.addAll(Arrays.asList(sources)); } this.webEnvironment = deduceWebEnvironment(); setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); } private boolean deduceWebEnvironment() { for (String className : WEB_ENVIRONMENT_CLASSES) { if (!ClassUtils.isPresent(className, null)) { return false; } } return true; } ``` * 2:加載所有classpath下面的META-INF/spring.factories ApplicationContextInitializer ``` @SuppressWarnings({ "unchecked", "rawtypes" }) private void initialize(Object[] sources) { if (sources != null && sources.length > 0) { this.sources.addAll(Arrays.asList(sources)); } this.webEnvironment = deduceWebEnvironment(); setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); } ``` * 3:推斷main方法所在的類 ``` private Class<?> deduceMainApplicationClass() { try { StackTraceElement[] stackTrace = new RuntimeException().getStackTrace(); for (StackTraceElement stackTraceElement : stackTrace) { if ("main".equals(stackTraceElement.getMethodName())) { return Class.forName(stackTraceElement.getClassName()); } } } catch (ClassNotFoundException ex) { // Swallow and continue } return null; } ``` * 4:加載所有classpath下面的META-INF/spring.factories SpringApplicationRunListener ``` SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); ``` * 5:執行所有SpringApplicationRunListener的started方法 * 6:實例化ApplicationArguments對象 * 7:創建environment * 8:配置environment,主要是把run方法的參數配置到environment * 9:執行所有SpringApplicationRunListener的environmentPrepared方法 * 10:如果不是web環境,但是是web的environment,則把這個web的environment轉換成標準的environment * 11:打印Banner ,banner 信息是在 SpringBootBanner 類中定義的,我們可以通過實現 Banner 接口來自定義 banner 信息,然后通過代碼 setBanner() 方法設置 Spring Boot 項目使用自己自定義 Banner 信息,或者是在 resources 下添加一個 banner.txt,把 banner 信息添加到此文件中,就可以實現自定義 banner 的功能了。 * 12:初始化applicationContext, 如果是web環境,則實例化AnnotationConfigEmbeddedWebApplicationContext對象,否則實例化AnnotationConfigApplicationContext對象 * 13:如果beanNameGenerator不為空,就把beanNameGenerator對象注入到context里面去 * 14:回調所有的ApplicationContextInitializer方法 * 15:執行所有SpringApplicationRunListener的contextPrepared方法 * 16:依次往spring容器中注入:ApplicationArguments,Banner * 17:加載所有的源到context里面去 * 18:執行所有SpringApplicationRunListener的contextLoaded方法 * 19:執行context的refresh方法,并且調用context的registerShutdownHook方法(這一步執行完成之后,spring容器就完全初始化好了) ``` @Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { //一些準備工作,列如配置屬性源,記錄啟動時間,環境變量準備,部分map的清理工作 prepareRefresh(); //能對xml讀取,轉換為bean,AbstractApplicationContext因為引用了一個beanFactory //所有她擁有了beanFactory的所有功能。還在此基礎上進一步擴展。做了哪些擴展? //真正的初始化bean Factory ,設置一些參數,并讀取xml文件,轉換為bean Definition ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 準備bean 工廠,對beanFactory進行各種功能填充 // Prepare the bean factory for use in this context. // 此時,spring已經完成對配置文件的解析,也就是beanFactory對bean的解析已經開始 prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. //保留方法 允許在上下文子類中對bean工廠進行后處理。 postProcessBeanFactory(beanFactory); // 激活各種beanFactory 處理器,按順序執行了 invokeBeanFactoryPostProcessors(beanFactory); // 執行完invokeBeanFactoryPostProcessors后,beanDefinition 基本都已經找出來了 ,并且新初始了如下 8個 bean 至此已經初始化16個bean // 注冊攔截bean 創建的 bean 后置處理器 ,執行是在getBean時候 // Register bean processors that intercept bean creation. // 注冊 BeanPostProcessor 處理 bean的 registerBeanPostProcessors(beanFactory); // 執行完 registerBeanPostProcessors()方法后,新增了9個后置處理器 至此已經初始化25個bean // 為此上下文初始化消息源,即不同語言的消息體。國際化處理 // Initialize message source for this context. initMessageSource(); //執行完新增1個bean 至此已經初始化26個bean //messageSource -> {DelegatingMessageSource@5542} //初始化應用消息(事件)廣播器,并放入 ApplicationEventMulticaster bean 中 // Initialize event multicaster for this context. // 廣播器,會保存相關的監聽器,在有事件發生的時候,會調用相關的監聽器的方法, // 讓監聽器去執行內部的監聽邏輯 initApplicationEventMulticaster(); //執行完新增一個bean 至此已經初始化27個bean //applicationEventMulticaster -> {SimpleApplicationEventMulticaster@5595} //留給子類來初始化其他bean // Initialize other special beans in specific context subclasses. onRefresh(); //執行完 onRefresh()新增 29個 bean 至此已經初始化65 個bean // 將所有監聽器bean,注冊到前面剛剛注冊的消息廣播器。 // 并將沒有發出的事件一并發出去。 // Check for listener beans and register them. registerListeners(); // 初始化剩下的,非延遲加載的 bean的初始化工作。(也就是非延遲加載的bean,會在這一步實現初始化,其他bean不會)) // ConversionService 設置(這個是干啥的?) // 配置凍結 、非延遲加載的 bean的初始化工作 // Instantiate all remaining (non-lazy-init) singletons. //這也是context&bean Factory的區別所在 finishBeanFactoryInitialization(beanFactory); // 發布相關事件 Last step: publish corresponding event // 完成刷新過程,通知生命周期處理器,LifecycleProcesser 刷新過程, // 并同時發出ContextRefreshEvent 通知別人(通知被人干啥. finishRefresh(); } } ``` * 20:回調,獲取容器中所有的ApplicationRunner、CommandLineRunner接口,然后排序,依次調用 * 21:執行所有SpringApplicationRunListener的finished方法 ## 工作原理總結 * 引導機制 Spring Boot 使用注解代替 xml 配置文件配置應用上下文,稱之為 auto-configuration。在提供自己的組件時,Spring Boot 不會自己來掃描所有的包,而是通過讀取 classpath 下 META-INF/spring.factories 文件中配置的類來開始加載流程。這可以視為 Spring Boot 的引導機制。 在 spring.factories 中,可以配置: org.springframework.boot.autoconfigure.EnableAutoConfiguration 自動配置類 org.springframework.context.ApplicationContextInitializer 實現該接口可以自定義窗口啟動早期的初始化行為 org.springframework.context.ApplicationListener 實現該接口可以監聽容器事件 配置鍵是接口或注解的全名,配置值是實現類或目標類的全名。在spring.factories中配置的類,都會被 spring 容器加載并實例化為 spring beans。 * Bean裝配 1. 處理注解 @ComponentScan 2. 處理 @Import 注解 3. 處理@ImportResource注解 4. 處理?帶@Bean注解的 方法 抓主線BeanDefinition的定位,載入,注冊過程 * 條件配置 Spring Boot 支持在 @Configuration 和 @Bean 上使用條件注解(Condition annotations),在程序實際運行時動態判定初始化行為。比如根據某配置項、某個類是否存在判斷是否加載某個 bean。 @ConditionalOnClass/@ConditionalOnMissingClass 根據類的存在性判定 @ConditionalOnBean/@ConditionalOnMissingBean 根據bean的存在性判定 @ConditionalOnProperty 根據配置項的存在性判定 @ConditionalOnResource 根據文件的存在性判定 @ConditionalOnWebApplication/@ConditionalOnNotWebApplication 根據是否為Web應用判定 @ConditionalOnExpression 根據 Spring EL 判定 基于“約定優于配置”的思想,條件注解可以用來根據實際情況靈活地配置自己的組件。比如使用@ConditionalOnClass,探測到程序中存在 com.mysql.jdbc.Driver 類,就可以視為應用使用 MySQL 作為數據源,可以自動配置 MySQL 相關的功能;比如使用@ConditionalOnProperty可以根據程序實際的配置項來決定初始化行為。 總結下 Starter 的工作原理 Spring Boot 在啟動時掃描項目所依賴的 JAR 包,尋找包含spring.factories文件的 JAR 包 根據spring.factories 配置加載AutoConfigure類 根據@Conditional注解的條件,進行自動配置并將 Bean 注入 Spring Context。 ## spring bean生命周期 ![](https://img.kancloud.cn/a5/6d/a56d92ea0980751d0387cac41335ed33_725x260.png) ## eureka-server 啟動加載了哪些類 ![](https://img.kancloud.cn/fa/1d/fa1d8f5b77645781d21d7fa81bb14d3a_1260x617.png) ![](https://img.kancloud.cn/68/45/684526d881f27e94e95cbc526189690a_1268x423.png)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看