SpringBoot的幕後推手...

1、背景

​  這兩年隨着微服務的盛行,SpringBoot框架水到渠成的獲得了高曝光,做爲程序猿的咱們,如今要是不知道一點SpringBoot相關的東西,貌似出去找工做都會被深深地鄙視,不過在咱們開始SpringBoot之旅前,咱們先回顧和探索一下Spring框架的本質,而後一點點的很天然的過渡到SpringBoot,這樣對於咱們深入理解SpringBoot也是很是有幫助的。java

2、Spring框架的起源

​  在「黑暗」的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開發必備神器也~框架

3、沒想到Spring IoC 竟如此簡單

​  我相信不少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)。可是呢,不管使用哪種配置方式,目的都是爲了簡化綁定邏輯描述的各類表象,最終也都是爲本階段的最終目的來服務。

4、JavaConfig是個什麼鬼?

​  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反而「內聚」一塊兒了,變得更加簡潔了。

5、那些經常使用的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 {
    ...
}

6、總結

​  經過本文,咱們就回顧了Spring框架以及IoC的概念剖析,還了解到了SpringBoot的實現基石:JavaConfig。而後還介紹了在SpringBoot中最經常使用幾個註解。爲咱們之後學習和快速上手SpringBoot打下了良好的基礎。加油,筒子們…

相關文章
相關標籤/搜索