導圖梳理springboot手動、自動裝配,讓springboot不再難懂
- 2019 年 10 月 5 日
- 筆記
思維導圖梳理

(基本概念)

(裝配方式)
什麼是springboot
在學springboot之前,你必須有spring、spring mvc基礎,springboot的誕生其實就是用來簡化新Spring應用的初始搭建以及開發過程,該框架使用了特定的方式來進行配置,從而使開發人員不再需要定義樣板化的配置。
它集成了大量常用的第三方庫配置(例如JDBC, Mongodb, Redis, Mail,rabbitmq等等),所以在Spring Boot應用中這些第三方庫幾乎可以零配置的開箱即用(out-of-the-box),大部分的Spring Boot應用都只需要非常少量的配置程式碼,開發者能夠更加專註於業務邏輯。
也就是說,以前集成ssm框架需要一大堆的xml配置文件,效率底下,而使用了springboot之後,很多時候我們不需要寫任何配置了,有時候直接通過@EnableXXX就能開啟某個模組的功能。
現在問題來了,你知道@EnableXXX是什麼原理嗎?
mvc、boot、cloud
這裡直接引用網友的總結給大家介紹一下:
Spring 是一個「引擎」;springmvc是框架,web項目中實際運行的程式碼;spring boot只是一個配置工具,整合工具,輔助工具,是一套快速開發整合包。
Spring Boot :J2EE一站式解決方案 Spring Cloud :分散式整體解決方案
約定大於配置的體現
在於減少軟體開發人員所需要做出的決定的數量,從而獲得簡單的好處,而又不失去其中的靈活性。
1、Spring Boot默認提供靜態資源目錄位置需置於classpath下,目錄名需符合如下規則:/static /public /resources /META-INF/resources 優先順序:META/resources > resources > static > public

2、spring boot默認的配置文件必須是,也只能是application或application-xxx命名的yml文件或者properties文件,我推薦盡量使用yml文件~ 3、application.yml中默認屬性:a、資料庫連接資訊必須是以spring: datasource: 為前綴,如:
spring: datasource: driverClassName: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/demo username: root password: root
b、多環境配置。該屬性可以根據運行環境自動讀取不同的配置文件。例如將該屬性定義為dev的話,Spring Boot會額外從 application-dev.yml 文件中讀取該環境的配置。
spring: profiles.active: dev
c、修改埠號、請求路徑
server: port: 8080 context-path: /demo
4、starter啟動器,開箱即用的Starter依賴讓springboot可以實現零配置即可自動完成框架的整合。
- spring-boot-starter-web
- 嵌入tomcat和web開發需要servlet與jsp支援
- spring-boot-starter-data-jpa
- 資料庫支援
- spring-boot-starter-data-redis
- redis資料庫支援
- spring-boot-starter-data-solr
- solr支援
- mybatis-spring-boot-starter
- 第三方的mybatis集成starter
接下來我們來分析一下springboot注入bean有多少種方式。
手動裝配
在學習springboot中,我喜歡把總結springboot的一些特性,以及使用springboot的一些規律,比如:在springboot載入bean的過程我分為了
- 手動裝配
- 自動裝配
兩種方式,而手動裝配又分為了
- 模式註解裝配
- @Enable模組裝配
- 條件裝配
3種方式,接下來我們來一一探討每種。
首先來看下手動裝配:
1、模式註解裝配
其實就是使用@Component註解,或者@Component註解的拓展,比如@Controller、@Service、Repository、@Configruation等,
這也是我們最常用的一種方式,直接通過spring mvc的註解把組件bean注入到spring容器中。
2、@Enable模組裝配
- 基於介面驅動實現
當我們需要開啟springboot項目的快取功能時候,我們直接打開@EnableCaching註解就可以注入Caching 模組,這時候我們就可以開心使用@Cacheable、@CacheEvict等註解,這是怎麼做到的?
其實你打開@EnableCaching的源碼你就能看到:
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Import({CachingConfigurationSelector.class}) public @interface EnableCaching { boolean proxyTargetClass() default false; AdviceMode mode() default AdviceMode.PROXY; int order() default 2147483647; }
上面最重要的一句程式碼就是@Import({CachingConfigurationSelector.class}),你會發現,其實使用@EnableCaching,就是為了導入CachingConfigurationSelector.class這配置類。
而這個CachingConfigurationSelector,其實實現了ImportSelector介面,ImportSelector介面是spring中導入外部配置的核心介面,只有一個方法selectImports,其實就是根據EnableCaching的元數據屬性(proxyTargetClass、mode、order),選擇出需要轉配的Configuration。
public interface ImportSelector { String[] selectImports(AnnotationMetadata var1); }
總結其實是這樣子,@EnableCaching其實就是根據元數據屬性然後選擇性條件判斷注入需要的配置,比較靈活。
- 基於註解驅動實現
然後我們來看另一種沒有元數據屬性的@EnableWebMvc。
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) @Documented @Import({DelegatingWebMvcConfiguration.class}) public @interface EnableWebMvc { }
可以很直觀看到,其實@EnableWebMvc其實就是為了導入DelegatingWebMvcConfiguration配置類,某種程度上,可以認為@EnableWebMvc其實和@Import({DelegatingWebMvcConfiguration.class})是對等的,只是起了一個有意義的名字而已。
所以我們總結一下@EnableXXX模組注入,基於介面驅動實現是實現ImportSelector介面,通過註解參數選擇需要導入的配置,而基於註解驅動實現其實就是@Import的派生註解,直接導入某個配置類。
思維導圖總結如下:

3、條件裝配
所謂條件裝配,其實是Bean裝配的前置條件,我們先來看一下例子:
- @ConditionalOnBean
- 僅僅在當前上下文中存在某個對象時,才會實例化一個Bean
- @ConditionalOnExpression
- 當表達式為true的時候,才會實例化一個Bean
- @ConditionalOnMissingClass
- 某個class類路徑上不存在的時候,才會實例化一個Bean
- @ConditionalOnNotWebApplication
- 不是web應用
這就是條件裝配,當這些條件註解放在某個bean上面的時候,只有滿足了條件才能注入bean,這也是為什麼springboot能這麼智慧,知道哪些模組需要開啟,哪些不需要,比如當你導入Freemaker的jar包之後,就自動幫你載入Freemaker的的相關配置,其實你看下程式碼:
@Configuration @ConditionalOnClass({freemarker.template.Configuration.class, FreeMarkerConfigurationFactory.class}) @EnableConfigurationProperties({FreeMarkerProperties.class}) @Import({FreeMarkerServletWebConfiguration.class, FreeMarkerReactiveWebConfiguration.class, FreeMarkerNonWebConfiguration.class}) public class FreeMarkerAutoConfiguration { ... }
這些springboot的自動配置類上面一般是不是都有@ConditionalOnClass註解,這裡是說當發現項目有freemarker.template.Configuration.class, FreeMarkerConfigurationFactory.class這兩個Class存在時候,我就載入這個FreeMarkerAutoConfiguration,什麼時候才會存在這兩個Class?當我們導入jar包時候:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency>
所以,當我們沒有導入相關jar包時候,我們不用擔心springboot會自動開啟某些功能,而是會智慧判斷哪些需要開啟,哪些需要跳過。
我們打開@ConditionalOnClass的源碼,發現其實是@Conditional拓展出來的註解。
@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Conditional({OnClassCondition.class}) public @interface ConditionalOnClass { Class<?>[] value() default {}; String[] name() default {}; }
實現邏輯如下:OnClassCondition.class實現Condition介面,並實現matches()方法,如果matches方法返回true,那麼帶有@Conditional註解的bean就會裝載,false就不會裝載。
思維導圖總結如下:

自動裝配
ok,剛才我們已經說了很多關於手動裝配部分的東西,現在我們來看下自動裝配,其實很多時候自動裝配就是手動裝配的綜合運用,只不過在轉配bean或配置類時候,我們不在需要使用@EnableXXX來導入功能,而是通過自動注入方式。
這時候自動注入的條件判斷(@Conditional)就顯得非常重要了。
我們再用剛才說的Freemaker作為例子,springboot集成freemaker非常簡單,只需要導入starter的jar包就會自動實現注入,這個自動集成就是FreeMarkerAutoConfiguration這裡配置的。
這裡有個問題,你知道為什麼springboot會自動去判斷和載入FreeMarkerAutoConfiguration這個配置類嗎?我沒有寫類似的@EnableFreemaker,那項目怎麼識別的。
其實如果你看過springboot的源碼,你就會發現:
- org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getCandidateConfigurations
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct."); return configurations; }
上面的意思是去掃描項目下所有的META-INF/spring.factories文件,然後把EnableAutoConfiguration.class作為key找出對應的值,這個值是個List。那麼我們來看下其中一個spring.factories長什麼樣子的。
- spring-boot-autoconfigure/2.1.2.RELEASE/spring-boot-autoconfigure-2.1.2.RELEASE.jar!/META-INF/spring.factories

可以看到EnableAutoConfiguration作為key有很多個值,比如RabbitMq的自動配置類等,而你認證點看,就能找到FreeMarkerAutoConfiguration這配置類了。
所以情況是這個的,當springboot項目啟動時候,項目會去載入所有的spring.factories文件,然後在EnableAutoConfiguration後面的所有配置類其實都是可以實現自動裝配的配置,至於需不需要裝配,就需要條件裝配來判定是否滿足特定的條件了。
有了這點基礎之後,我們就可以自己去寫自動裝配了。
第一步、編寫需要自動裝載的配置類。
說明:@Configuration表示是個配置類 @ConditionalOnSystemProperty表示需要滿足當前系統是win10系統
@Configuration @ConditionalOnSystemProperty(value = "Windows 10") public class SayHelloWorldAutoConfiguration { @Bean SayHelloWorld autoSayHelloWorld() { System.out.println("here to !!auto!!loading bean autoSayHelloWorld!"); return new SayHelloWorld(); } }
第二步、在resources目錄下新建META-INF文件夾,編寫spring.factories。
# Auto Configure 自動裝配自定義的配置 org.springframework.boot.autoconfigure.EnableAutoConfiguration= com.other.configuration.SayHelloWorldAutoConfiguration
啟動springboot之後就會自動載入這個配置類,於是,我們就注入了SayHelloWorld這個業務bean,項目中就可以直接注入使用啦~
有人說,這和直接寫個@Configruation有啥區別,區別在於@Configruation的配置必須寫在Spring能掃描到的目錄下,而自動裝配不需要。
思維導圖總結如下:

– 精選文章 –