Spring Boot、Spring MVC 和 Spring 有什么區別?
分別描述各自的特征:
Spring 框架就像一個家族,有眾多衍生產品例如 boot、security、jpa等等;但他們的基礎都是Spring 的ioc和 aop,ioc 提供了依賴注入的容器, aop解決了面向切面編程,然后在此兩者的基礎上實現了其他延伸產品的高級功能。
Spring MVC提供了一種輕度耦合的方式來開發web應用;它是Spring的一個模塊,是一個web框架;通過DispatcherServlet, ModelAndView 和 View Resolver,開發web應用變得很容易;解決的問題領域是網站應用程序或者服務開發——URL路由、Session、模板引擎、靜態Web資源等等。
Spring Boot實現了auto-configuration自動配置(另外三大神器actuator監控,cli命令行接口,starter依賴),降低了項目搭建的復雜度。它主要是為了解決使用Spring框架需要進行大量的配置太麻煩的問題,所以它並不是用來替代Spring的解決方案,而是和Spring框架緊密結合用於提升Spring開發者體驗的工具;同時它集成了大量常用的第三方庫配置(例如Jackson, JDBC, Mongo, Redis, Mail等等),Spring Boot應用中這些第三方庫幾乎可以零配置的開箱即用(out-of-the-box)。
所以,用最簡練的語言概括就是:
Spring 是一個“引擎”;
Spring MVC 是基於Spring的一個 MVC 框架;
Spring Boot 是基於Spring4的條件注冊的一套快速開發整合包。
一 springboot啟動原理及相關流程概覽springboot是基於spring的新型的輕量級框架,最厲害的地方當屬自動配置。那我們就可以根據啟動流程和相關原理來看看,如何實現傳奇的自動配置。
二 springboot的啟動類入口用過springboot的技術人員很顯而易見的兩者之間的差別就是視覺上很直觀的:springboot有自己獨立的啟動類(獨立程序)
從上面代碼可以看出,Annotation定義(@SpringBootApplication)和類定義(SpringApplication.run)最為耀眼,所以要揭開SpringBoot的神秘面紗,我們要從這兩位開始就可以了。
三 單單是SpringBootApplication接口用到了這些注解
在其中比較重要的有三個注解,分別是: 1)@SpringBootConfiguration // 繼承了Configuration,表示當前是注解類 2)@EnableAutoConfiguration // 開啟springboot的注解功能,springboot的四大神器之一,其借助@import的幫助 3)@ComponentScan(excludeFilters = { // 掃描路徑設置(具體使用待確認) 接下來對三個注解一一詳解,增加對springbootApplication的理解: 1)@Configuration注解按照原來xml配置文件的形式,在springboot中我們大多用配置類來解決配置問題 配置bean方式的不同: a)xml配置文件的形式配置bean
b)java configuration的配置形式配置bean
注入bean方式的不同: a)xml配置文件的形式注入bean
b)java configuration的配置形式注入bean
任何一個標注了@Bean的方法,其返回值將作為一個bean定義注冊到Spring的IoC容器,方法名將默認成該bean定義的id。 表達bean之間依賴關系的不同: a)xml配置文件的形式表達依賴關系
b)java configuration配置的形式表達依賴關系(重點) 如果一個bean A的定義依賴其他bean B,則直接調用對應的JavaConfig類中依賴bean B的創建方法就可以了。
2) @ComponentScan注解作用:a)對應xml配置中的元素; b) (重點)ComponentScan的功能其實就是自動掃描並加載符合條件的組件(比如@Component和@Repository等)或者bean定義; c) 將這些bean定義加載到IoC容器中. 我們可以通過basePackages等屬性來細粒度的定制@ComponentScan自動掃描的范圍,如果不指定,則默認Spring框架實現會從聲明@ComponentScan所在類的package進行掃描。
3) @EnableAutoConfiguration此注解顧名思義是可以自動配置,所以應該是springboot中最為重要的注解。 在spring框架中就提供了各種以@Enable開頭的注解,例如: @EnableScheduling、@EnableCaching、@EnableMBeanExport等; @EnableAutoConfiguration的理念和做事方式其實一脈相承簡單概括一下就是,借助@Import的支持,收集和注冊特定場景相關的bean定義。
@EnableAutoConfiguration也是借助@Import的幫助,將所有符合自動配置條件的bean定義加載到IoC容器。 @EnableAutoConfiguration作為一個復合Annotation,其自身定義關鍵信息如下:
其中最重要的兩個注解已經標注:1、@AutoConfigurationPackage【重點注解】2、@Import(AutoConfigurationImportSelector.class)【重點注解】 當然還有其中比較重要的一個類就是:EnableAutoConfigurationImportSelector.class AutoConfigurationPackage注解:
通過@Import(AutoConfigurationPackages.Registrar.class)
它其實是注冊了一個Bean的定義;
new PackageImport(metadata).getPackageName(),它其實返回了
當前主程序類的
同級以及子級的包組件(重點);
(重點)那這總體就是注冊當前主程序類的同級以及子級的包中的符合條件的
Bean的定義?
![]() 以上圖為例,DemoApplication是和demo包同級,但是demo2這個類是DemoApplication的父級,和example包同級 也就是說,DemoApplication啟動加載的Bean中,並不會加載demo2,這也就是為什么,我們要把DemoApplication放在項目的最高級中。
Import(AutoConfigurationImportSelector.class)注解
(重點)可以從圖中看出
AutoConfigurationImportSelector 實現了 DeferredImportSelector 從 ImportSelector繼承的方法:
selectImports。
該方法在springboot啟動流程——bean實例化前被執行,返回要實例化的類信息列表; 如果獲取到類信息,spring可以通過類加載器將類加載到jvm中,現在我們已經通過spring-boot的starter依賴方式依賴了我們需要的組件,那么這些組件的類信息在select方法中就可以被獲取到。
其返回一個自動配置類的類名列表,方法調用了loadFactoryNames方法,查看該方法
自動配置器會跟根據傳入的factoryClass.getName()到項目系統路徑下所有的spring.factories文件中找到相應的key,從而加載里面的類。
這個外部文件,有很多自動配置的類。如下:
(重點)其中,最關鍵的要屬@Import(AutoConfigurationImportSelector.class),借助AutoConfigurationImportSelector,@EnableAutoConfiguration可以幫助SpringBoot應用將所有符合條件(spring.factories)的bean定義(如Java Config@Configuration配置)都加載到當前SpringBoot創建並使用的IoC容器。就像一只“八爪魚”一樣。
自動配置幕后英雄:SpringFactoriesLoader詳解借助於Spring框架原有的一個工具類:SpringFactoriesLoader的支持,@EnableAutoConfiguration可以智能的自動配置功效才得以大功告成! SpringFactoriesLoader屬於Spring框架私有的一種擴展方案,其主要功能就是從指定的配置文件META-INF/spring.factories加載配置,加載工廠類。 SpringFactoriesLoader為Spring工廠加載器,該對象提供了loadFactoryNames方法,入參為factoryClass和classLoader即需要傳入工廠類名稱和對應的類加載器,方法會根據指定的classLoader,加載該類加器搜索路徑下的指定文件,即spring.factories文件; 傳入的工廠類為接口,而文件中對應的類則是接口的實現類,或最終作為實現類。
配合@EnableAutoConfiguration使用的話,它更多是提供一種配置查找的功能支持,即根據@EnableAutoConfiguration的完整類名org.springframework.boot.autoconfigure.EnableAutoConfiguration作為查找的Key,獲取對應的一組@Configuration類 上圖就是從SpringBoot的autoconfigure依賴包中的META-INF/spring.factories配置文件中摘錄的一段內容,可以很好地說明問題。 (重點)所以,@EnableAutoConfiguration自動配置的魔法其實就變成了: 從classpath中搜尋所有的META-INF/spring.factories配置文件,並將其中org.springframework.boot.autoconfigure.EnableAutoConfiguration對應的配置項通過反射(Java Refletion)實例化為對應的標注了@Configuration的JavaConfig形式的IoC容器配置類,然后匯總為一個並加載到IoC容器。
四 springboot啟動流程概覽圖
五 深入探索SpringApplication執行流程
EventPublishingRunListener實現了SpringApplicationRunListener接口; 實現了方法,下面是部分方法源碼
簡單了解下Bean的生命周期
一個Bean的構造函數初始化時是最先執行的,這個時候,bean屬性還沒有被注入; @PostConstruct注解的方法優先於InitializingBean的afterPropertiesSet執行,這時Bean的屬性竟然被注入了; spring很多組件的初始化都放在afterPropertiesSet做,想和spring一起啟動,可以放在這里啟動; spring為bean提供了兩種初始化bean的方式,實現InitializingBean接口,實現afterPropertiesSet方法,或者在配置文件中同過init-method指定,兩種方式可以同時使用; 實現InitializingBean接口是直接調用afterPropertiesSet方法,比通過反射調用init-method指定的方法效率相對來說要高點;但是init-method方式消除了對spring的依賴; 如果調用afterPropertiesSet方法時出錯,則不調用init-method指定的方法。 Bean在實例化的過程中: Constructor > @PostConstruct > InitializingBean > init-method
BeanFactory 和ApplicationContext的區別BeanFactory和ApplicationContext都是接口,並且ApplicationContext間接繼承了BeanFactory。 BeanFactory是Spring中最底層的接口,提供了最簡單的容器的功能,只提供了實例化對象和獲取對象的功能,而ApplicationContext是Spring的一個更高級的容器,提供了更多的有用的功能。 ApplicationContext提供的額外的功能:獲取Bean的詳細信息(如定義、類型)、國際化的功能、統一加載資源的功能、強大的事件機制、對Web應用的支持等等。 加載方式的區別:BeanFactory采用的是延遲加載的形式來注入Bean;ApplicationContext則相反的,它是在Ioc啟動時就一次性創建所有的Bean,好處是可以馬上發現Spring配置文件中的錯誤,壞處是造成浪費。
SpringMVC處理請求的流程1、用戶發送請求至前端控制器DispatcherServlet 2、DispatcherServlet收到請求調用HandlerMapping處理器映射器。 3、處理器映射器根據請求url找到具體的處理器,生成處理器對象Handler及處理器攔截器(如果有則生成)一並返回給DispatcherServlet。 4、DispatcherServlet通過HandlerAdapter(讓Handler實現更加靈活)處理器適配器調用處理器 5、執行處理器(Controller,也叫后端控制器)。 6、Controller執行完成返回ModelAndView(連接業務邏輯層和展示層的橋梁,持有一個ModelMap對象和一個View對象)。 7、HandlerAdapter將controller執行結果ModelAndView返回給DispatcherServlet 8、DispatcherServlet將ModelAndView傳給ViewReslover視圖解析器 9、ViewReslover解析后返回具體View 10、DispatcherServlet對View進行渲染視圖(將ModelMap模型數據填充至視圖中)。 11、DispatcherServlet響應用戶
BEANFACTORY和FACTORYBEAN的區別與聯系
Bean的循環依賴https://blog.csdn.net/itmrchen/article/details/90201279 對於Spring中Bean的管理,下圖一目了然:
先調用構造函數進行實例化,然后填充屬性,再接着進行其他附加操作和初始化,正是這樣的生命周期,才有了Spring的解決循環依賴,這樣的解決機制是根據Spring框架內定義的三級緩存來實現的,也就是說:三級緩存解決了Bean之間的循環依賴。我們從源碼中來說明。 先來看Spring中Bean工廠是怎么獲取Bean的(AbstractBeanFactory中):
一級一級向下尋找,找出了前面提到的三級緩存,也就是三個Map集合類: singletonObjects:第一級緩存,里面放置的是已經實例化好的單例對象; earlySingletonObjects:第二級緩存,里面存放的是提前曝光的單例對象; singletonFactories:第三級緩存,里面存放的是將要被實例化的對象的對象工廠。 所以當一個Bean調用構造函數進行實例化后,即使set屬性還未填充,就可以通過三級緩存向外暴露依賴的引用值進行set(所以循環依賴問題的解決也是基於Java的引用傳遞),這也說明了另外一點,基於構造函數的注入,如果有循環依賴,Spring是不能夠解決的。 還要說明一點,Spring默認的Bean Scope是單例的,而三級緩存中都包含singleton,可見是對於單例Bean之間的循環依賴的解決,Spring是通過三級緩存來實現的。
同一個類中調用 @Transaction注解的方法會有事務效果嗎?沒有,可以Autowired注入自己,然后再調用注入的類中的方法,即自己依賴自己,循環依賴; 這里在一個內部調用應該是相當於單純的調用方法this.methodName(),並沒有AOP動態代理。 |