淺學(xué)Spring Boot
Spring Boot是Spring的擴(kuò)展,在保持了Spring原有兩大特性的前提下又提出了新的功能。
因此,正式介紹Spring Boot之前,我們不妨先來探尋一下Spring是個(gè)什么東西!
Spring
框架開發(fā)的初心都是為了降低程序員寫代碼時(shí)的復(fù)雜度,能夠讓程序員將自己的精力盡可能多的集中到自己的邏輯開發(fā)上面,而不是在開發(fā)環(huán)境的配置上面。為了實(shí)現(xiàn)這一點(diǎn),Spring提出了以下兩個(gè)技術(shù):面向切面編程和依賴注入。
面向切面編程(AOP)
面向切面編程,通俗來說就是把專業(yè)的活交給專業(yè)的人來干。舉個(gè)例子,就像在學(xué)校里有很多食堂,這些食堂都被不同的餐飲公司所承包,這里被承包了的食堂就是切面。這樣做有什么好處呢,很明顯,食堂承包出去之后由于餐飲公司是專門做餐飲的,那飯菜肯定比學(xué)校自己做的好吃,而且學(xué)校將餐飲業(yè)務(wù)承包出去之后,就可以將自己更多的精力放在教書育人上邊,專注于自己的本職業(yè)務(wù),如果對承包商不滿意還可以即時(shí)的更換其他承包商(更換切面),真是個(gè)一舉多得的好事情,在編程當(dāng)中,什么是這些切面呢?對象與對象之間,方法與方法之間,模塊與模塊之間都是一個(gè)個(gè)這樣的切面。
單一職責(zé)原則:類應(yīng)該是純凈的,不應(yīng)含有與本身無關(guān)的邏輯。
面向切面編程,可以帶來代碼的解耦,使得各個(gè)模塊專注于自身的業(yè)務(wù)邏輯,提高開發(fā)效率。
使用AOP之前,我們需要理解幾個(gè)概念。

傳送門:Spring 之 AOP
- 連接點(diǎn)(Join Point):
所有可能的需要注入切面的地方。比如方法前后,類初始化、屬性初始化前后。
- 切點(diǎn)(Poincut):
需要做某些處理的連接點(diǎn)(連接點(diǎn)有很多,但是真正切入的連接點(diǎn)才叫切點(diǎn)),比如打印日志、處理緩存等,存在于切面當(dāng)中。目前,Spring只支持方法的切點(diǎn)定義。
- 通知(Advice):
定義在什么時(shí)候,做什么事情。Spring支持5種方法上的通知類型。
@Before:在目標(biāo)方法被調(diào)用之前調(diào)用。
@After:通知方法會在目標(biāo)方法返回或拋出異常之后調(diào)用。
@AfterReturning:通知方法會在目標(biāo)方法返回后調(diào)用。
@AfterThrowing:通知方法會在目標(biāo)方法拋出異常之后調(diào)用。
@Around:相當(dāng)于Befor和After的結(jié)合。
- 切面(Aspect)
通知+切點(diǎn)的集合,定義在什么地方什么時(shí)間做什么事情。
@Aspect
public class Audience {
@Autowired
private CriticismEngineImpl criticismEngine;
@Pointcut(
"execution(* com.example.aoptest.impl.Performance.perform(int))"+"&& args(ha)")//將perform函數(shù)視為切點(diǎn)
public void performance(int ha) {}//該方法本身只是個(gè)標(biāo)識,供Advice依附,對performance函數(shù)的通知相當(dāng)于對切點(diǎn)perform函數(shù)的通知。
@Before("performance(ha)")//通知
public void silenceCellPhones(int ha)
{
ha++;
System.out.println(ha);
System.out.println("前置通知:Sillencing cell phones");
}
}
- 引入(Introduction)
允許我們向現(xiàn)有的類添加新方法或?qū)傩浴>褪前亚忻嬗玫侥繕?biāo)類當(dāng)中,在不修改目標(biāo)類的條件下為目標(biāo)類添加新的屬性和方法。
依賴注入
在Java程序中,一個(gè)業(yè)務(wù)邏輯經(jīng)常需要兩個(gè)或兩個(gè)以上的對象協(xié)作來完成,通常每個(gè)對象在使用他的合作對象時(shí),自己均要使用像new object()這樣的語法來完成合作對象的申請工作,這樣會使得對象之間的耦合度較高,程序結(jié)構(gòu)比較復(fù)雜。而依賴注入的思想是:由Spring來負(fù)責(zé)控制對象的生命周期和對象間的關(guān)系,對象只需要負(fù)責(zé)關(guān)心業(yè)務(wù)邏輯就好了。
創(chuàng)建應(yīng)用對象之間協(xié)作關(guān)系的行為通常稱為裝配(wiring),這也是依賴注入的本質(zhì)。在Spring中依賴注入有多種方式,我們在這里先來介紹一下配置Spring容器最常見的三種方法。
自動(dòng)化裝配bean
Spring從兩個(gè)角度來實(shí)現(xiàn)自動(dòng)化裝配:
組件掃描(component scanning):Spring會自動(dòng)發(fā)現(xiàn)應(yīng)用上下文中所創(chuàng)建的bean。
自動(dòng)裝配(autowiring):Spring自動(dòng)實(shí)現(xiàn)bean之間的依賴。
為了闡述組件掃描和裝配,我們需要裝配幾個(gè)bean,它們代表一個(gè)音響系統(tǒng)中的組件。首先,創(chuàng)建一個(gè)CompactDisc接口和它的實(shí)現(xiàn)CompactDiscImp,并將其創(chuàng)建為一個(gè)bean。然后,會創(chuàng)建一個(gè)CDPlayer類,讓Spring發(fā)現(xiàn)它,并將bean注入進(jìn)來。
CompactDisc接口在Java中定義了CD的概念
public interface CompactDisc{
void play();
}
我們將CompactDisc定義為一個(gè)接口,它定義了CD播放器的一系列操作,而且作為接口,它將CD的任意實(shí)現(xiàn)與CD本身的耦合降低到了最小的程度。這里,我們還需要一個(gè)CD的實(shí)現(xiàn),也就是CompactDiscImp類。
CompactDiscImp實(shí)現(xiàn)類
@Component
public class CompactDiscImp implements CompactDisc{
private String title = "這是實(shí)現(xiàn)類";
public void play()
{
System.out.println(title);
}
}
和接口一樣,CompactDiscImp的具體內(nèi)容并不重要,你需要注意的是CompactDiscImp類上使用了@Component注解。這個(gè)簡單的注解表明該類會作為組件類,并告知Spring要為這個(gè)類創(chuàng)建bean。不過,組件掃描默認(rèn)是不啟用的。我們還需要顯示配置Spring,從而命令它去尋找?guī)в蠤Component注解的類,并為其創(chuàng)建bean。
@ComponentScan注解啟用了組件掃描(CDPlayerConfig.class)
@Configurzation
@ComponentScan
public class CDPlayerConfig
{
}
類CDPlayerConfig通過Java代碼定義了Spring的裝配規(guī)則。在本文后部分,我們還會更為詳細(xì)的介紹基于Java的Spring配置。不過,現(xiàn)在我們只需觀察CDPlayerConfig類并沒有顯示地聲明任何bean,只不過它使用了@ComponentScan注解,這個(gè)注解能夠在Spring中啟用組件掃描,使得Spring去尋找?guī)в蠤ComponentScan注解地類,并為其創(chuàng)建bean。(此處也可以通過使用XML來啟用組件掃描,但作者更喜歡使用JAVA配置,這里就不做贅述,如果有對XML配置感興趣的,可以去查看Spring in Action的第二章)
通過自動(dòng)裝配,將一個(gè)CompactDisc注入到CDPlayer之中
public class CDPlayer
{
@Autowired//由于本實(shí)例只有一種實(shí)現(xiàn)類,所以默認(rèn)注入對象為CompactDiscImp的實(shí)例,若有多個(gè)實(shí)現(xiàn)類,可用@Qualifier注解加以區(qū)分
private CompactDisc cd;//不通過new對象的方式,而是通過注入的形式創(chuàng)建了一個(gè)其他類的對象
cd.play();//會打印出“這是實(shí)現(xiàn)類”
}
這就實(shí)現(xiàn)了,自動(dòng)裝備bean的方式。
通過Java代碼裝配bean
盡管在很多場景下通過組件掃描和自動(dòng)裝配實(shí)現(xiàn)Spring的自動(dòng)化配置是更為推薦的方式,但有時(shí)候自動(dòng)化配置的方案行不通,因此需要明確配置Spring。比如說,你想要將第三方庫中的組件配到你的應(yīng)用當(dāng)中,這種情況你無法直接在第三方庫的源碼上添加@Component和@Autowired注解,因此就不能使用自動(dòng)化裝配的方案了。
在這種情況下,你必須要采用顯示裝配的方式。在進(jìn)行顯示配置的時(shí)候,有兩種方案可選:Java和XML。XML我在這里不作贅述,有興趣的同學(xué)可以自行查閱《Spring in Action》第二章第四節(jié),在這里我只介紹使用Java進(jìn)行配置的方式。
進(jìn)行顯示配置時(shí),JavaConfig是更好的方案,因?yàn)樗鼮閺?qiáng)大,類型安全而且對于重構(gòu)比較友好,不同于其他的Java代碼,JavaConfig是配置代碼,它不應(yīng)該含有任何業(yè)務(wù)邏輯,最好將其放在業(yè)務(wù)邏輯之外的包中。還是之前的例子。
@ComponentScan注解啟用了組件掃描(CDPlayerConfig.class)
@Configurzation
@ComponentScan
public class CDPlayerConfig
{
}
創(chuàng)建JavaConfig類的關(guān)鍵在于為其添加@Configuration注解,@Configuration注解表明這個(gè)類是一個(gè)配置類。@ComponentScan啟用了組件掃描,這是實(shí)現(xiàn)自動(dòng)裝配的關(guān)鍵。但如果我們將@ComponentScan注解移除,此時(shí)的@CDPlayerConfig類就不會有任何作用了,現(xiàn)在再運(yùn)行主函數(shù),會拋出BeanCreation-Exception異常。這是因?yàn)橹骱瘮?shù)期望被注入CompactDisc,但是這些bean根本就沒有被創(chuàng)建,那我們?nèi)绾芜M(jìn)行顯式的java配置呢?
要在JavaConfig中聲明bean,我們需要編寫一個(gè)方法,這個(gè)方法會創(chuàng)建所需類型的實(shí)例,然后給這個(gè)方法添加@Bean注解。
使用Javaconfig顯式裝配bean(CDPlayerConfig.class)
@Configurzation
public class CDPlayerConfig
{
@Bean
public CompactDisc javaconfig()
{
return new CompactDiscImp();
}
}
@Bean注解會告訴Spring這個(gè)方法會返回一個(gè)對象,該對象要注冊為Spring應(yīng)用上下文中的bean。
通過Java裝配,將一個(gè)CompactDisc注入到CDPlayer之中
public class CDPlayer
{
@Autowired//由于本實(shí)例只有一種實(shí)現(xiàn)類,所以默認(rèn)注入對象為CompactDiscImp的實(shí)例,若有多個(gè)實(shí)現(xiàn)類,可用@Qualifier注解加以區(qū)分
private CompactDisc cd;//不通過new對象的方式,而是通過注入的形式創(chuàng)建了一個(gè)其他類的對象
cd.play();//會打印出“這是實(shí)現(xiàn)類”
}
Spring Boot
Spring Boot是Spring的擴(kuò)展,在Spring的AOP(面向切面編程)和DI(依賴注入)兩個(gè)特性的基礎(chǔ)上又完善了以下四個(gè)功能。
自動(dòng)配置:針對很多Spring應(yīng)用程序所常見的應(yīng)用功能,Spring boot能自動(dòng)提供相關(guān)配置。
起步依賴:告訴Spring Boot需要什么功能,它就能引入需要的庫。
命令行界面:這是Spring Boot的可選特性,借此你只需寫代碼就能完成完整的應(yīng)用程序,無需傳統(tǒng)項(xiàng)目構(gòu)建。
Actuator:讓你能夠深入運(yùn)行中的Spring Boot應(yīng)用程序,一探究竟。
自動(dòng)配置
在任何Spring應(yīng)用的源碼中,你都會找到Java配置或XML配置(自動(dòng)化配置難以配置第三方庫中的組件),它們?yōu)閼?yīng)用程序開啟了特定的特性和功能。舉個(gè)例子,如果你寫過用JDBC訪問關(guān)系型數(shù)據(jù)庫的應(yīng)用程序,那你一定在Spring應(yīng)用程序上下文里配置過JdbcTemplate這個(gè)Bean。
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource){
return new JdbcTemplate(dataSource);
}
這段非常簡單的Bean聲明創(chuàng)建了一個(gè)JdbcTemplate的實(shí)例,注入了一個(gè)DataSource依賴,這意味著你還需要配置一個(gè)DataSource的Bean,這樣才能滿足依賴。
雖然這兩個(gè)Bean配置方法都不復(fù)雜,也不是很長,但它們只是Spring應(yīng)用程序配置的一小部分。除此之外,還有無數(shù)Sping應(yīng)用程序有著類似的配置方法,簡而言之,這就是個(gè)樣板配置。
既然它如此常見,那我們有沒有辦法可以自動(dòng)配置這些Bean而不是每次手動(dòng)去寫配置代碼呢?
Spring Boot做到了這點(diǎn),它會為這些常見配置場景進(jìn)行自動(dòng)配置。如果Spring Boot在應(yīng)用程序的ClassPath里發(fā)現(xiàn)了JdbcTemplate,那么它會為你配置一個(gè)JdbcTemplate的Bean,如果在應(yīng)用程序的Classpath里發(fā)現(xiàn)了DataSource,那么他還會為你創(chuàng)建一個(gè)DataSource的Bean。你無需擔(dān)心那些Bean的配置,Spring Boot會做好準(zhǔn)備,隨時(shí)都能將其注入到你的Bean當(dāng)中。這就是Spring Boot的自動(dòng)配置.
起步依賴
Spring boot通過起步依賴為項(xiàng)目的依賴管理提供幫助。起步依賴就是特殊的Maven依賴和Gradle依賴,利用傳遞依賴解析,幫常用庫聚合在一起。舉個(gè)例子,假如你正在用Spring MVC構(gòu)造REST API,并使用JSON作為資源表述。此外,你還想使用JSR-303規(guī)范的聲明式校驗(yàn),并使用嵌入式Tomcat服務(wù)器來提供服務(wù)。要實(shí)現(xiàn)以上目標(biāo),你在Maven或Gradle里至少需要以下8個(gè)依賴:
org.springframework:spring-core
org.springframework:spring-web
org.springframework:spring-webmvc
com.fasterxml.jackson.core:jackson-databind
org.hibernate:hibernate-validator
org.apache.tomcat.embed:tomcat-embed-core
org.apache.tomcat.embed:tomcat-embed-el
org.apache.tomcat.embed:tomcat-embed-logging-juli
如果打算使用Spring Boot的起步依賴,你只需要添加Spring Boot的Web起步依賴(org.springframework.boot:spring-boot-starter-web),僅此一個(gè)。它會根據(jù)依賴傳遞把其他所需依賴引入項(xiàng)目里。
比起減少依賴數(shù)量,起步依賴還有一個(gè)好處就是:你不再需要考慮支持某種功能需要使用什么庫了,直接引入相關(guān)依賴就行。如果應(yīng)用是個(gè)Web應(yīng)用,所以加入了Web起步依賴;如果應(yīng)用程序要用到JPA持久化,那么就可以加入JPA起步依賴;需要安全功能,直接加入security起步依賴即可。
命令行界面
除了自動(dòng)配置和起步依賴,Spring Boot還提供了一種很有意思的開發(fā)spring boot應(yīng)用的新方法。Spring Boot Cli讓只寫代碼即可實(shí)現(xiàn)應(yīng)用程序成為可能。
Spring Boot Cli利用了起步依賴和自動(dòng)配置,讓你專注于代碼本身。簡單來說,CLI能檢測到你使用了哪些類,它知道要向Classpath中添加哪些起步依賴才能讓它運(yùn)轉(zhuǎn)起來,一旦那些依賴出現(xiàn)在Classpath中,一系列自動(dòng)配置就會接踵而來。
但同時(shí),Spring Boot Cli是Spring Boot的非必要組成部分,雖然它為Spring帶來了驚人的力量,大大簡化了開發(fā),但也引入了一套不太常規(guī)的開發(fā)模型。如果您還是不太適應(yīng)這種開發(fā)模型,可以拋開CLI,利用Spring Boot提供的其他東西。
Actuator
Spring Boot的最后一個(gè)法寶就是Actuator,其他幾個(gè)部分旨在簡化Spring配置,而Actuator則要在提供運(yùn)行時(shí)檢查應(yīng)用程序內(nèi)部情況的能力。包括以下細(xì)節(jié):
Spring應(yīng)用程序上下文配置的Bean。
應(yīng)用程序取到的環(huán)境變量、系統(tǒng)屬性、配置屬性和命令行參數(shù)。
應(yīng)用程序中線程的當(dāng)前狀態(tài)。
應(yīng)用程序最近處理過的Http請求追蹤情況。
各種和內(nèi)存用量,垃圾回收、Web請求相關(guān)的指標(biāo)。