最近這兩年springboot突然火起來了,那么我們就來看看springboot的運行原理。
一。springboot的三種啟動方式:
1.運行帶有main方法的
2.通過命令 Java -jar命令
3.通過spring-boot-plugin的方式
二。springboot 啟動時執行方法,有兩種方式
第一種方式是用啟動時的main方法加載靜態方法。
另一種是用初始化注解@postconstruct 執行。(注意點必須void並且參數)。
注意點:【1.@PostConstruct會先被執行,靜態方法后被執行。2.如果需要參數的話,只能用靜態方法的方式】
SpringBoot啟動過程原理
從上面代碼看,調用了SpringApplication的靜態方法run。這個run方法會構造一個SpringApplication的實例,然后再調用這里實例的run方法就表示啟動SpringBoot。
具體對象處理流程看下邊時序圖:
概述:
1.構造SpringApplication的實例(時序圖步驟1-2)
2.調用SpringApplication.run()方法(時序圖步驟3)
3.構造SpringApplicationRunListeners 實例(時序圖步驟3.1.1)
4.發布ApplicationStartedEvent事件(時序圖步驟3.1.2)
5.SpringApplicationRunListeners 實例准備環境信息(時序圖步驟3.1.3)
6.創建ApplicationContext對象(時序圖步驟3.1.4)
7.ApplicationContext實例准備環境信息(時序圖步驟3.1.5)
8.刷新的上下文(時序圖步驟3.1.6)
2.啟動加載過程分析
1.2.1 構造SpringApplication的實例(時序圖步驟1-2) 代碼 public static ConfigurableApplicationContext run(Object[] sources, String[] args) { // 步驟1 return new SpringApplication(sources).run(args); } public SpringApplication(Object... sources) { // 步驟1.1 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(); //加載META-INF/spring.factories路徑ApplicationContextInitializer.class getSpringFactoriesInstances( ApplicationContextInitializer.class)); setListeners((Collection) //加載META-INF/spring.factories路徑ApplicationListener.class getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }
分析
⑴.通過ClassLoader.getResources加載META-INF/spring.factories路徑下的
文件信息,從中找key為ApplicationContextInitializer.class,並實例化。
⑵.通過ClassLoader.getResources加載META-INF/spring.factories路徑下的
文件信息ApplicationListener.class對應類,並實例化。
1.2.2 調用SpringApplication.run()方法(時序圖步驟3) 代碼: public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; FailureAnalyzers analyzers = null; configureHeadlessProperty(); // 步驟3.1.1 SpringApplicationRunListeners listeners = getRunListeners(args); // 步驟3.1.2 listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); // 步驟 3.1.3 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); Banner printedBanner = printBanner(environment); // 步驟3.1.4 context = createApplicationContext(); analyzers = new FailureAnalyzers(context); // 步驟3.1.5 prepareContext(context, environment, listeners, applicationArguments, printedBanner); // 步驟3.1.6 refreshContext(context); // 步驟3.1.7 afterRefresh(context, applicationArguments); // 步驟3.1.8 listeners.finished(context, null); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } return context; } catch (Throwable ex) { handleRunFailure(context, listeners, analyzers, ex); throw new IllegalStateException(ex); } }
1.2.2 步驟3.1.1: 代碼 private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; // (1) return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances( SpringApplicationRunListener.class, types, this, args)); } 1 2 3 4 5 6 分析 (1). 通過ClassLoader.getResources加載META-INF/spring.factories路徑下的 文件信息,從中找key為SpringApplicationRunListener對應類,並實例化。
1.2.3 步驟3.1.2: 代碼 public void starting() { for (SpringApplicationRunListener listener : this.listeners) { listener.starting(); } } @Override @SuppressWarnings("deprecation") public void starting() { this.initialMulticaster .multicastEvent(new ApplicationStartedEvent(this.application, this.args)); }
分析
:發布ApplicationStartedEvent事件。
1.2.4 步驟3.1.3: 代碼 private ConfigurableEnvironment prepareEnvironment( SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { // Create and configure the environment // ⑴. 得到環境對象ConfigurableEnvironment ConfigurableEnvironment environment = getOrCreateEnvironment(); // ⑵. 並配置環境信息;對listeners初始化環境屬性 configureEnvironment(environment, applicationArguments.getSourceArgs()); // ⑶. 發布ApplicationEnvironmentPreparedEvent事件。 listeners.environmentPrepared(environment); if (isWebEnvironment(environment) && !this.webEnvironment) { environment = convertToStandardEnvironment(environment); } return environment; }
分析
⑴. 得到環境對象ConfigurableEnvironment
⑵. 並配置環境信息;對listeners初始化環境屬性。
⑶. 發布ApplicationEnvironmentPreparedEvent事件。
步驟3.1.4: 分析 創建ApplicationContext對象 ,其中在實例化ApplicationContext子類 AnnotationConfigApplicationContext時,如代碼: public AnnotationConfigApplicationContext() { this.reader = new AnnotatedBeanDefinitionReader(this); this.scanner = new ClassPathBeanDefinitionScanner(this); }
會創建AnnotatedBeanDefinitionReader對象檢測是否需要將一下對象放到Spring上下文中
// 用戶配置Configuration注解,實現了BeanDefinitionRegistryPostProcessor接口 ConfigurationClassPostProcessor // 用於配置Autowired注解,實現了MergedBeanDefinitionPostProcessor接口 AutowiredAnnotationBeanPostProcessor // 用於配置Required注解,實現了MergedBeanDefinitionPostProcessor接口 RequiredAnnotationBeanPostProcessor // 用於配置JSR-250注解,實現了InstantiationAwareBeanPostProcessor接口 CommonAnnotationBeanPostProcessor // 用於配置JPA注解 PersistenceAnnotationBeanPostProcessor // 用於配置EventListener注解,實現了SmartInitializingSingleton接口 EventListenerMethodProcessor // EventListener工廠 DefaultEventListenerFactory
步驟3.1.5: 代碼 private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { // ⑴.對ApplicationContext設置環境變量; context.setEnvironment(environment); // ⑵.配置屬性ResourceLoader和ClassLoader屬性; postProcessApplicationContext(context); // ⑶.循環初始化繼承了 applyInitializers(context); listeners.contextPrepared(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // Add boot specific singleton beans context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { context.getBeanFactory().registerSingleton("springBootBanner", printedBanner); } // Load the sources Set<Object> sources = getSources(); Assert.notEmpty(sources, "Sources must not be empty"); load(context, sources.toArray(new Object[sources.size()])); listeners.contextLoaded(context); }
分析:
⑴.對ApplicationContext設置環境變量;
⑵.配置屬性ResourceLoader和ClassLoader屬性;
⑶.調用步驟1查詢出來ApplicationContextInitializer子類,循環調用initialize()方法。
@SuppressWarnings({ "rawtypes", "unchecked" }) protected void applyInitializers(ConfigurableApplicationContext context) { for (ApplicationContextInitializer initializer : getInitializers()) { Class<?> requiredType = GenericTypeResolver.resolveTypeArgument( initializer.getClass(), ApplicationContextInitializer.class); Assert.isInstanceOf(requiredType, context, "Unable to call initializer."); initializer.initialize(context); } }
⑷.發布ApplicationPreparedEvent事件。
步驟3.1.6 代碼: @Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // ⑴.准備刷新的上下文環境 prepareRefresh(); // ⑵.初始化BeanFactory ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // ⑶.對BeanFactory進行各種功能填充 prepareBeanFactory(beanFactory); try { // ⑷.子類覆蓋方法做額外的處理 postProcessBeanFactory(beanFactory); // ⑸.激活各種BeanFactory處理器 invokeBeanFactoryPostProcessors(beanFactory); // ⑹.注冊攔截Bean創建的Bean處理,這里只是注冊,真正調用是再拿去Bean的時候 registerBeanPostProcessors(beanFactory); // ⑺.為上下文初始化Message源,即不同語言的消息體,國際化處理 initMessageSource(); // ⑻.初始化應用消息廣播器,並放到applicationEventMulticaster bean中 initApplicationEventMulticaster(); // ⑼.留給子類來初始化其他bean onRefresh(); // ⑽.在所有注冊的bean中查找Listener bean,注冊到消息廣播中 registerListeners(); // ⑾.初始化剩下的單實例(非惰性) finishBeanFactoryInitialization(beanFactory); // ⑿.完成刷新過程,通知生命周期處理器lifecycleProcessor刷新過程,同時發出ContextRefreshEvent通知別人 finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
分析:
⑴.准備刷新的上下文環境
⑵.初始化BeanFactory
⑶.對BeanFactory進行各種功能填充
⑷.子類覆蓋方法做額外的處理
⑸.激活各種BeanFactory處理器
⑹.注冊攔截Bean創建的Bean處理,這里只是注冊,真正調用是再拿去Bean的時候
⑺.為上下文初始化Message源,即不同語言的消息體,國際化處理
⑻.初始化應用消息廣播器,並放到applicationEventMulticaster bean中
⑼.留給子類來初始化其他bean
⑽.在所有注冊的bean中查找Listener bean,注冊到消息廣播中
⑾.初始化剩下的單實例(非惰性)
⑿.完成刷新過程,通知生命周期處理器lifecycleProcessor刷新過程,同時發出ContextRefreshEvent通知別人
總結:
Spring 是一個“引擎”
Spring MVC 是基於 Spring 的一個 MVC 框架
Spring Boot 是基於 Spring4 的條件注冊的一套快速開發整合包
Spring 最初利用“工廠模式”( DI )和“代理模式”( AOP )解耦應用組件,並構建了一些列功能組件。大家覺得挺好用,於是按照 MVC 框架模式,(用Spring 解耦的組件)搞了一個MVC用來開發 web 應用也就是( SpringMVC )。然后有發現每次開發都要搞很多依賴,寫很多樣板代碼很麻煩,於是搞了一些懶人整合包( starter ),這套就是 Spring Boot 。
spring 框架有超多的延伸產品例如 boot security jpa etc... 但它的基礎就是 spring 的 ioc 和 aop ioc 提供了依賴注入的容器 aop 解決了面向橫切面的編程 然后在此兩者的基礎上實現了其他延伸產品的高級功能 Spring MVC 呢是基於 Servlet 的一個 MVC 框架 主要解決 WEB 開發的問題 因為 Spring 的配置太復雜了 各種 XML JavaConfig hin 麻煩 於是懶人改變世界推出了 Spring boot 約定優於配置 簡化了 spring 的配置流程 簡單談下自己的理解 以上來自度娘,感覺和自己的理解相當。直接拿來用,占個坑。以后完善。
springApplication可以讀取不同種類的源文件:
- 類- java類由
AnnotatedBeanDefinitionReader加載。
Resource
- xml資源文件由XmlBeanDefinitionReader讀取
, 或者groovy腳本由GroovyBeanDefinitionReader讀取
Package
- java包文件由ClassPathBeanDefinitionScanner掃描讀取。
CharSequence
- 字符序列可以是類名、資源文件、包名,根據不同方式加載。如果一個字符序列不可以解析程序到類,也不可以解析到資源文件,那么就認為它是一個包。