Profile是個好東西,通過Profile,我們可以非常方便地條件化Bean的創建,動態調整應用程式的功能,可是,Profile只能做些簡單的條件化,對于復雜一點的條件化Profile是無法勝任的,比如現有這樣的資料源創建需求:
1.如果類路徑存在DBCP的JAR包,則創建DBCP提供的BasicDataSource資料源,
2.如果類路徑沒有DBCP的JAR包,則創建Spring提供的DriverManagerDataSource資料源,
毫無疑問,這樣的需求Profile是實作不了的,要想實作這樣的需求,還得仰賴Spring提供的,專門用于Bean的條件化創建的,功能遠比Profile強大的Condition,而這,需要我們做好兩件事情:
1.實作Condition介面,以描述Bean的創建條件,
2.往配置方法添加@Conditional注解,告訴Spring容器創建Bean時以某個實作了Condition介面的類作為條件,
Condition介面簽名如下:
1 @FunctionalInterface 2 public interface Condition { 3 boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata); 4 }
其中定義的matches方法回傳一個布爾型別的值:如果回傳的是TRUE,說明條件成立,Spring容器將會創建相應的Bean;如果回傳的是FALSE,說明條件失敗,Spring容器不會創建相應的Bean
另外,matches方法還接受兩個引數:一個引數是ConditionContext型別的,能向我們提供一些諸如Bean的定義,環境變數之類的資訊;一個引數是AnnotatedTypeMetadata型別的,能向我們提供一些諸如配置方法是否帶有某種注解之類的資訊,我們實作matches方法的時候,能用這些資訊進行條件檢查,
因此,為了實作文章開頭提到的需求,我們首先需要做的就是這樣實作Condition介面:
1 public class ConditionOnDriverManagerDataSource implements Condition { 2 @Override 3 public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { 4 var dbcpFileName = "WEB-INF\\lib\\commons-dbcp2-2.8.0.jar"; 5 var resourceLoader = context.getResourceLoader(); 6 var resource = resourceLoader.getResource(dbcpFileName); 7 return !resource.exists(); 8 } 9 } 10 11 public class ConditionOnBasicDataSource implements Condition { 12 @Override 13 public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { 14 var dbcpFileName = "WEB-INF\\lib\\commons-dbcp2-2.8.0.jar"; 15 var resourceLoader = context.getResourceLoader(); 16 var resource = resourceLoader.getResource(dbcpFileName); 17 return resource.exists(); 18 } 19 }
這段代碼定義的兩個類都實作了Condition介面:
1.ConditionOnDriverManagerDataSource能夠檢查類路徑是否存在DBCP的JAR包:如果存在則回傳FALSE;否則回傳TRUE,這個條件能夠告訴Spring容器只有類路徑沒有DBCP的JAR包時,才會創建相應的Bean
2.ConditionOnBasicDataSource能夠檢查類路徑是否存在DBCP的JAR包:如果存在則回傳TRUE;否則回傳FALSE,這個條件能夠告訴Spring容器只有類路徑存在DBCP的JAR包時,才會創建相應的Bean
于是,我們完成了Condition介面的實作,該把它們交給@Conditional注解進行Bean的條件化配置了,@Conditional注解有個Class<T>型別的value屬性,用于指定實作了Condition介面的類的Class物件,告訴Spring容器創建Bean時以哪個Condition作為條件,如下所示:
1 @Configuration 2 public class AppConfig { 3 @Bean 4 @Conditional(value = https://www.cnblogs.com/evanlin/archive/2022/03/29/ConditionOnDriverManagerDataSource.class) 5 public DataSource produceDataSource() { 6 var dataSource = new DriverManagerDataSource(); 7 dataSource.setUsername("root"); 8 dataSource.setPassword("123456"); 9 dataSource.setUrl("jdbc:mysql://localhost:3306/sm_person_rest"); 10 dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); 11 return dataSource; 12 } 13 14 @Bean 15 @Conditional(value = https://www.cnblogs.com/evanlin/archive/2022/03/29/ConditionOnBasicDataSource.class) 16 public DataSource produceBasicDataSource() { 17 var dataSource = new BasicDataSource(); 18 dataSource.setUsername("root"); 19 dataSource.setPassword("123456"); 20 dataSource.setUrl("jdbc:mysql://localhost:3306/sm_person_rest"); 21 dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); 22 return dataSource; 23 } 24 }
這段配置代碼定義了兩個方法:
1.方法produceDataSource帶有@Conditional(ConditionOnDriverManagerDataSource.class)注解,Spring容器瞧見這個注解之后,就會呼叫ConditionOnDriverManagerDataSource的matches方法進行條件判斷:如果matches方法回傳TRUE,則創建DriverManagerDataSource資料源;否則不創建,
2.方法produceBasicDataSource帶有@Conditional(ConditionOnBasicDataSource.class)注解,Spring容器瞧見這個注解之后,就會呼叫ConditionOnBasicDataSource的matches方法進行條件判斷:如果matches方法回傳TRUE,則創建BasicDataSource資料源;否則不創建,
如此一來,Spring容器就能根據類路徑是否存在DBCP的JAR包決定創建哪種資料源了,有趣的是,前文介紹的Profile其實也是Condition的一種實作,如下所示:
1 @Target({ElementType.TYPE, ElementType.METHOD}) 2 @Retention(RetentionPolicy.RUNTIME) 3 @Documented 4 @Conditional({ProfileCondition.class}) 5 public @interface Profile { 6 String[] value(); 7 } 8 9 class ProfileCondition implements Condition { 10 public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { 11 MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName()); 12 if (attrs != null) { 13 Iterator var4 = ((List)attrs.get("value")).iterator(); 14 15 Object value; 16 do { 17 if (!var4.hasNext()) { 18 return false; 19 } 20 21 value =https://www.cnblogs.com/evanlin/archive/2022/03/29/ var4.next(); 22 } while(!context.getEnvironment().acceptsProfiles(Profiles.of((String[])((String[])value)))); 23 24 return true; 25 } else { 26 return true; 27 } 28 } 29 }
至此,關于Condition的介紹也就告一段落了,下章,我們將會開始介紹混合配置,歡迎大家繼續閱讀,謝謝大家!
回傳目錄 下載代碼
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/452000.html
標籤:其他
