聊聊SpringBoot自動裝配的魔力
一、 springBoot自動配置的好處
1、 回想一下當你在使用spring來搭建一個項目的時候
你需要編寫很多的有關spring的xml。例如讀取屬性配置的bean、數據源bean、事務管理工廠bean、mybatis與spring整個的bean等等。再次利用該框架搭建項目的時候,又是周而復始的操作。
但是現在當你使用springBoot搭建項目的時候,你會發現所有的配置你都不用去編寫就可以幫你去實現(僅僅需要在連接外部數據庫的時候需要進行配置,其實如果使用內嵌數據庫h2 則你完全不必需要application.properties配置文件)。
你可以在你的具體的業務代碼中使用@AutoWried @Resource註解將數據源,事務工廠等註入到業務層,像是你自己配置那樣。
2、這時我們會有一個疑問
springBoot到底做瞭什麼讓我們可以不用配置,而使用那些功能對象。
其實springBoot使用基於條件的自動註入原理,即為當滿足某個條件的時候,spring會實例化該註解對應的bean,將其放入到Srping上下文中,讓你可以輕松的使用。SpringBoot實現條件配置離不開它的核心組件@Conditional。
下面我們慢慢的來揭開springBoot自動配置的神秘面紗。
二、@Conditional註解相關介紹
1、@Conditional小demo
@Conditional 是個什麼鬼,不解釋來個小的demo大致瞭解一下
描述一下demo場景 :Life實體bean在特定條件(@Conditional)下,被springBoot初始化,並放置到spring上下文環境中。
1.1、 Life 實體類
/** * 夢想存在,生命才有意義 */ public class Life { //工作 private String work; //學習 private String study //愛 private String love; //省略seter /geter }
1.2、 編寫我們自己的條件匹配規則
/** * 實現ConfigurationCondition(該接口繼承瞭Condition) */ public class MyTestConditional implements ConfigurationCondition { /** * 設置使用該類進行解析的時機 * 1、REGISTER_BEAN:會在註冊Bean的時候進行condition的解析 * 即為在對應的@Bean註解和@condition註解組合使用的時候 進行條件的判斷 * @Bean註解對應spring 的xml的<bean/>標簽 * 2、PARSE_CONFIGURATION:會在解析@Configuration時進行condition的解析 * 即為在對應的@Configuration註解和@condition註解組合使用的時候 進行條件的判斷 * @Configuration註解對應spring 的xml的<beans/>標簽 * @return */ @Override public ConfigurationPhase getConfigurationPhase() { return ConfigurationPhase.REGISTER_BEAN; } /** * 該方法為條件判斷的核心 隻有該方法返回為true 則表示其條件成立 ,執行相應的配置 * @param conditionContext * @param annotatedTypeMetadata * @return */ @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { return false; //表示驗證不通過 }
該類實現瞭ConfigurationCondition 有如下兩個方法
1、 getConfigurationPhase() 該條件規則起作用的時候
2、 matches()條件匹配規則 這裡為瞭演示不做具體的邏輯條件的處理
返回一個佈爾值,如果為ture 則表示條件成立 配置生效
反之不生效。
1.3、編寫我們的java實例bean自動配置
@Configuration //@Configuration標註在類上,相當於把該類作為spring的xml配置文件中的<beans>, // 作用為:配置spring容器(應用上下文) public class ServerAutoConfiguration { @Configuration //spring的xml配置文件中的<beans> //使用該註解表明,在springBoot啟動的時候隻有滿足MyTestConditional.class 才生成對應的Life 對象 //即 MyTestConditional中的match()返回true @Bean生效 @Conditional(MyTestConditional.class) public static class StudentAutoConfiguration { @Bean public Life create() { System.out.println("life start...."); return new Life("努力工作","不斷的學習","敢愛敢恨"); } } }
1.4、 springBoot的單元測試
//使用Spring的單元測試環境 @RunWith(SpringRunner.class) //將SpringBoot的上下文環境加載進入單元測試中 @SpringBootTest(classes = AutoApplication.class) public class AutoApplicationTests { //註入springBoot 基於條件的實例化bean @Autowired private Life life; @Test public void showlife() { System.out.println("生命的全部:"+life.toString()); } }
啟動springBoot項目,在控制臺中沒有發現Life對象被創建 且單元測試中無法註入Life
在修改瞭MyTestConditional中的match() 返回true 再次啟動則Life對象被創建
同時使用SpringBoot的單元測試來使用springBoot為我們設置的Life實體
該實體創建流程如下:當springBoot項目啟動的時候,會加載@Configuration(srping的xml配置)下的所有bean,當遇到@Conditional(MyTestConditional.class) 會調用該方法的Match,並根據其返回值來判斷是否實例化該註解下的所有使用@Bean @Import 註解下的類
三、自定義一個條件配置類/springBoot自定義註解
1、簡單解釋@Condition註解傢族
(1)、@Conditional
官方文檔定義:
“Indicates that a component is only eligible for registration when all specified conditions match”
意思是隻有滿足一些列條件之後創建一個bean。 並註冊到spring的上下文環境中
(2)、SpringBoot提供的
@ConditionalOnWebApplication
該應用必須為web應用@ConditionalOnMissingBean
該應用上下文中如果沒有指定的bean@ConditionalOnBean
該應用上下文中如果有指定的bean@ConditionalOnProperty(name,value)
隻有存在對應name的value的配置文件才加載該註解下的bean@ConditionalOnCloudPlatform
匹配當處於雲平臺環境中時後@ConditionalOnClass
該classpath中如果有指定的bean @ConditionalOnExpression 如果對應的表達式成立 成功@ConditionalOnJava
根據應用程序運行的JVM版本進行匹配 成功@ConditionalOnRepositoryType
當特定類型的spring Data JPA啟用的時候 成功@ConditionalOnSingleCandidate
當特定的class對應的bean存在且唯一確定的時候@ConditionalOnJndi
通過JNDI查找制定的條件@Profile
通過特定的條件觸發 (生產環境使用該配置,非生產環境則不是使用)@ConditionalOnResource
從資源文件中查詢@ConditionalOnEnabledResourceChain
從資源鏈中中查詢@ConditionalOnNotWebApplication
如果改應用不是web應用,則該條件起作用@ConditionalOnMissingClass
如果不存在對應的class則創建該對應的bean
滿足條件後則加載該註解作用下的類起作用
(3)、所謂該註解作用下的類起作用是指
這些註解都有如下兩種使用方式
1、作用在類上,則該類下的所有@Bean註解起作用 (條件成立,加載該註解下的所有@Bean的實體類 存放在spring上下文中)
2、作用在方法上 則該方法下對應的@bean註解起作用 (條件成立,加載該註解下使用@Bean的實體類 存放在spring上下文中)
與@Configuration或者@Bean配合使用,當和@Configuration配合使用時,
那麼該類下所有@Bean方法 或者@Import 或者 @ComponentScan都會受到其配置條件的影響
@Configuration
相當於spring的xml配置文件的<beans>標簽@Bean
註解相當於spring的xml配置文件的<bean>標簽@Import(Xxx.class)
將指定的class 實例註入到spring的上下文中@Configuration
標註在類上,相當於把該類作為spring的xml配置文件中的<beans>,作用為:配置spring容器(應用上下文)
2、自定義條件註解
結合demo 來設置一個自定義註解
(1)、 自定義註解
/* 自定義的Conditional 條件註解 */ @Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented @Conditional(MyTestConditional.class) public @interface ConditionalOnLife { Class<?>[] value() default {}; String[] name() default {};}
(2)、進行配置使用
@Configuration //spring的xml配置文件中的<beans> //使用該註解表明,在springBoot啟動的時候隻有滿足MyTestConditional.class 才生成對應的Life 對象 //自定義的條件註解 @ConditionalOnLife //@Conditional(MyTestConditional.class) public static class DreamAutoConfiguration { @Bean public Dream createDream() { //life.toString(); System.out.println("dream start...."); return new Dream(); } }
後臺調用成功創建瞭Dream實體 並放入spring上下文環境中
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- Spring自動配置之condition條件判斷上篇
- Spring @Conditional註解示例詳細講解
- springboot中一些比較常用的註解總結
- Spring自動配置之condition條件判斷下篇
- SpringBoot自動配置特點與原理詳細分析