這兩年隨着微服務的盛行,SpringBoot框架水到渠成的獲得了高曝光,做爲程序猿的咱們,如今要是不知道一點SpringBoot相關的東西,貌似出去找工做都會被深深地鄙視,不過在咱們開始SpringBoot之旅前,咱們先回顧和探索一下Spring框架的本質,而後一點點的很天然的過渡到SpringBoot,這樣對於咱們深入理解SpringBoot也是很是有幫助的。java
在「黑暗」的EJB1的時代,開發人員很是痛快,這時候解放開發人員的高性能Spring框架千呼萬喚始出來。那是一個J2EE規範統治的時代,基於各類容器和J2EE規範的軟件解決方案是惟一的「正道」,臃腫的生態和沉重的開發模式讓當時的每個開發都痛不欲生。這時候技術大牛Rod Johnson在本身的經典巨做《Expert One-on-One J2EE Design and Development》中描繪了輕量級框架的研發理念,抨擊了原有的笨重的規範,而後基於這本書中的研發理念開發出了最第一版的Spring框架,而後火的一塌糊塗,一直延續至今,已10多年之久仍舊沒有衰敗之勢。spring
Spring框架是構建高性能Java研發體系的最佳實踐之一,經過一系列簡潔而統一的設計,爲廣大Java開發人員劈開了一條光明之路。架構
Spring對Java開發中經常使用的技術作了合理的封裝和設計,包括咱們所熟知的Spring IoC和AOP等,可讓Java開發者避免往日由於API和系統設計不合適而出現的錯誤,還能高效高質量的完成相應問題領域中的開發工做,此乃Java開發必備神器也~框架
我相信不少Java開發者對IoC(Inversion Of Control) 和DI(Dependency Injection)的概念都傻傻分不清楚,認爲這二者是同一個東西。其實它倆是包含和被包含關係,IoC有兩種方式:DI和DL(Dependency Lookup 依賴查找),DI是當前軟件實體被動接受它所依賴的其餘組件被IoC容器注入,而DL是當前實體主動去某個服務註冊中心去查找其依賴的那些組件,概念之間的關係以下圖:微服務
咱們常常說的Spring IoC實際上是指Spring框架給咱們提供的IoC容器實現(IoC Container)。下面咱們看一個Spring IoC容器使用的一個經典案例:性能
public class Demo { public static void main(String[] args) { ApplicationContext context = new FileSystemXmlApplicationContext("config-file-path") DemoService service = context.getBean(DemoService.class); service.doSomething(); } }
我相信每個使用Spring框架構建的獨立的Java應用,一般都會存在相似context.getBean(...)
的代碼,其實這行代碼作的事情就是DL,並且構建每一種IoC容器背後發生的事情,更多的是DI的過程,當前也可能會有部分DL的邏輯用來對接舊的遺留系統。學習
Spring的IoC容器的依賴注入工做分爲兩步走:ui
階段1、收集和註冊Beanspa
這個階段中,開發者經過XML或者Java代碼的方式來定義bean,而後以手動組裝或讓容器基於特定的機制自動掃描的形式,將這些定義好的bean收集到IoC容器中。.net
假如咱們以XML配置的方式來收集和註冊以下一個單一bean,通常來講形式以下:
<bean id="DemoService" class="x.x.DemoService"> ... </bean>
隨着咱們項目中bean愈來愈多,這樣逐個手動配置比較麻煩,咱們還可使用以下方式配置來批量掃描並採集和註冊一批bean:
<context:component-scan base-package="x.x"/>
階段2、分析和組裝
第一個階段完成之後,咱們能夠先暫時認爲IoC容器中保存着一個個相互獨立的bean,它們之間尚未任何關係,可是實際項目中它們之間是有着不可或缺的關係的,因此呢,Ioc容器第二個階段須要作的工做就是分析這些已經在IoC容器中bean,根據它們的依賴關係前後按順序組裝它們,工做原來是這樣的:IoC發現一個bean依賴另一個bean,那麼它會將另外一個bean注入給依賴它的那個bean,一直到全部的bean的依賴都完成注入。這個時候容器中全部的bean都已經準備好待使用,也就標誌着整個IoC容器的工做完成。
那麼IoC容器分析和組裝的依據是啥呢?Spring框架其實最先的時候只能經過XML配置文件來描述bean和bean之間的關係,可是隨着Java生態研發技術以及理念的轉變,又出現了基於Java代碼和Annotation元信息的描述方式(好比@AutoWired和@Inject)。可是呢,不管使用哪種配置方式,目的都是爲了簡化綁定邏輯描述的各類表象,最終也都是爲本階段的最終目的來服務。
Java 5的出世,加上當時基於純Java Annatation的依賴注入框架Guice的出現,就使得Spring框架和社區不得不順應民意,出版並持續完善了基於Java代碼和Annotation元信息的依賴關係綁定描述方式,就是JavaConfig項目。
基於JavaConfig方式的依賴關係描述基本映射了早期基於XML方式的配置,好比:
1. 表達形式
XML配置方式以下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> // bean定義 </beans>
JavaConfig的配置方式以下:
@Configuration public class DemoConfiguration { // bean定義 }
也就是說任何一個被標註了
@Configuration
註解的Java類都是一個JavaConfig配置類。
2. 註冊bean定義
XML配置方式:
<bean id="demoService" class="x.x.DemoServiceImpl"> ... </bean>
JavaConfig配置方式:
@Configuration public class DemoConfiguration { @Bean public DemoService demoService() { return new DemoServiceImpl(); } }
也就是說任何一個標註了
@Bean
註解的方法,它的返回值就將做爲一個bean定義註冊到Spring的IoC容器,方法名將默認成爲該bean在容器中的id.
3. 表達依賴注入關係
XML配置形式:
<bean id="aService" class="x.x.AServiceImpl"> <bean id="bService" class="x.x.BServiceImpl"> <property name="dependencyService" ref="aService"/> </bean>
JavaConfig形式:
@Configuration public class DemoConfiguration { @Bean public AService aService() { return new AServiceImpl(); } @Bean public BService bService() { return new BServiceImpl(aService()); } }
也就是說若是一個bean定義了依賴其餘bean,就直接調用其對應JavaConfig類中依賴bean的建立方法便可。
從以上種種表象咱們能夠看出,之前Spring IoC容器中具備的特性在JavaConfig中均可以進行表述,只是換了另外的一種形式而已。而且經過聲明相應的Java Annotation反而「內聚」一塊兒了,變得更加簡潔了。
1. @ComponentScan
該註解對應的是XML配置中的<context:component-scan>
元素,用於配合一些元信息Java Annotation,好比@Component
和@Repository
等,將標註了這些註解的bean定義類批量採集到Spring的IoC容器中。
咱們能夠經過basePackage等屬性來細粒度的定製該註解自動掃描的範圍,若是沒有指定的話,則默認Spring框架會從聲明@ComponentScan
註解所在的類的package進行掃描
這裏還要說的@ComponentScan
是SpringBoot框架得以實現的一個重要組件,咱們之後還能在碰到它,也會作深刻講解。
2. @PropertySource
和@PropertySources
註解@PropertySource
用來從指定的地方來加載.properties
配置文件,而且將其中的屬性加載到IoC容器中,以便咱們能用來填充一些bean定義的屬性佔位符(placeholder),固然它的實現須要PropertySourcesPlaceHolderConfigurer的配合。
若咱們使用Java8或者更高的版本,那麼咱們能夠並行聲明多個@PropertySource
,如:
@Configuration @PropertySource("classpath:1.properties") @PropertySource("classpath:2.properties") @PropertySource("...") public class XConfiguration { ... }
若咱們使用低於Java8版本的JDK進行開發Spring應用,咱們就必須藉助@PropertySources
註解來實現聲明多個@PropertySource
了,以下:
@Configuration @PropertySources({ @PropertySource("classpath:1.properties"), @PropertySource("classpath:2.properties"), ... }) public class XConfiguration { ... }
3. @Import
和@ImportSource
在之前XML配置方式中,咱們能夠經過<import resource="xxx.xml"/>
來將多個分開的容器配置合併到一個配置中,在JavaConfig形式的配置中,咱們可使用@Import
這個註解完成一樣的目的:
@Configuration @Import(DemoConfiguration.class) public class XConfiguration { ... }
註解@Import
只能將以JavaConfig形式定義的配置引入到IoC容器,而若咱們有一些之前遺留的配置或者遺留的系統須要以XML形式來配置(如Dubbo框架),咱們就須要使用@ImportSource
註解來將它們一塊兒合併到以JavaConfig配置形式配置的容器中:
@Configuration @Import @ImportSource(...) public class XConfiguration { ... }
經過本文,咱們就回顧了Spring框架以及IoC的概念剖析,還了解到了SpringBoot的實現基石:JavaConfig。而後還介紹了在SpringBoot中最經常使用幾個註解。爲咱們之後學習和快速上手SpringBoot打下了良好的基礎。加油,筒子們…