@Conditional為按照條件配置spring的bean提供了支持,即滿足某種條件下,怎么配置對應(yīng)的bean;
應(yīng)用場景
- 當(dāng)某一個jar包在classpath中的時候,配置某幾個bean;
- 當(dāng)某一個bean配置好后,會自動配置一個特定的bean;
- 當(dāng)某種環(huán)境變量被設(shè)置后,創(chuàng)建某個bean;
- @Conditional為敏捷開發(fā)所提倡的原則"習(xí)慣優(yōu)于配置"提供了支持;
- @Conditional是Spring Boot快速開發(fā)框架實現(xiàn)"習(xí)慣優(yōu)于配置"的核心技術(shù);
樣例
我們構(gòu)建一個會議服務(wù)接口屈嗤,其下分別有遠(yuǎn)程會議服務(wù)邑彪,本地會議服務(wù),然后根據(jù)系統(tǒng)運(yùn)行時的環(huán)境信息動態(tài)獲取會議服務(wù)實例執(zhí)行诞帐。
IMeetingService
/**
* 會議服務(wù)
*/
public interface IMeetingService {
/**
* 開會
* @param cmd
* @return
*/
void meeting(String cmd);
}
LocalMeetingServiceImpl
/**
* 本地會議服務(wù)
*/
public class LocalMeetingServiceImpl implements IMeetingService {
@Override
public void meeting(String cmd) {
System.out.println("this is Local Meeting!");
}
}
RomteMeetingServiceImpl
/**
* 遠(yuǎn)程會議服務(wù)
*/
public class RomteMeetingServiceImpl implements IMeetingService {
@Override
public void meeting(String cmd) {
System.out.println("this is Romte Meeting!");
}
}
實現(xiàn)Conditional注解的執(zhí)行接口:
LocalConditional
public class LocalConditional implements Condition {
private final static String type = System.getProperty("meeting_type") == null ? "local" :System.getProperty("meeting_type");
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return type.equals("local");
}
}
RomteConditional
public class RomteConditional implements Condition {
private final static String type = System.getProperty("meeting_type") == null ? "local" :System.getProperty("meeting_type");
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return type.equalsIgnoreCase("romte");
}
}
spring Bean配置基于Configuration注解:
MeetingInstanceConfig
@Configuration
public class MeetingInstanceConfig {
@Bean
@Conditional(LocalConditional.class)
public IMeetingService localMeetingService() {
return new LocalMeetingServiceImpl();
}
@Bean
@Conditional(RomteConditional.class)
public IMeetingService romteMeetingService() {
return new RomteMeetingServiceImpl();
}
}
上面完成了我用例的所有代碼角雷,接下來我們通過main函數(shù)調(diào)用測試:
public static void main( String[] args )
{
System.setProperty("meeting_type","romte");
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext("cn.leadeon");
IMeetingService meetingService = context.getBean(IMeetingService.class);
meetingService.meeting("開會");
context.close();
}
上面用例執(zhí)行結(jié)果為(表明RomteMeetingServiceImpl實現(xiàn)):
this is Romte Meeting!
當(dāng)我們 設(shè)置System.setProperty("meeting_type","locale"); 或者直接注釋掉這行時結(jié)果:
this is Local Meeting!
這樣就通過Conditional注解完成了根據(jù)條件去創(chuàng)建具體的實例祸穷,動態(tài)根據(jù)環(huán)境的信息去實例化服務(wù),達(dá)到服務(wù)智能化創(chuàng)建調(diào)用
springboot條件注解的實現(xiàn)方式
上面的例子提供了兩個Condition分別為RomteConditional與LocalConditional勺三,相對來說比較復(fù)雜雷滚,下面我們按照springboot實現(xiàn)條件判斷注解的思路完善上面樣例:
- 定義條件注解Conditional的包裝注解ConditionalOnMeetType
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Conditional(OnMeetTypeCondition.class)
public @interface ConditionalOnMeetType {
/**
* 默認(rèn)為local
*
* @return
*/
String value() default "local";
}
- 定義條件注解Conditional處理實現(xiàn)類OnMeetTypeCondition
public class OnMeetTypeCondition implements Condition {
private final static String type =
System.getProperty("meeting_type") == null ? "local" : System.getProperty("meeting_type");
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//此處根據(jù)方法獲取方法的注解ConditionalOnMeetType傳入的值,根據(jù)值與系統(tǒng)設(shè)置值是否一致判斷吗坚,當(dāng)前方法定義的bean是否注冊到容器中
if (metadata instanceof MethodMetadata) {
MethodMetadata methodMetadata = (MethodMetadata) metadata;
MultiValueMap<String, Object> annMap = methodMetadata
.getAllAnnotationAttributes(ConditionalOnMeetType.class.getName());
String meetType = (String) annMap.getFirst("value");
return type.equalsIgnoreCase(meetType);
}
return false;
}
}
- 定義java配置類以 ConditionalOnMeetType修飾bean
@Configuration
public class MeetingInstanceConfig {
@Bean
@ConditionalOnMeetType
public IMeetingService localMeetingService() {
return new LocalMeetingServiceImpl();
}
@Bean
@ConditionalOnMeetType("romte")
public IMeetingService romteMeetingService() {
return new RomteMeetingServiceImpl();
}
}
這三步完成了上面樣例的所有功能祈远,springboot的條件注解大多基于這種方式實現(xiàn),簡單清晰商源。
springboot 提供了如下條件注解:
- ConditionalOnBean
- ConditionalOnClass
- ConditionalOnExpression
- ConditionalOnJava
- ConditionalOnMissingBean
- ConditionalOnMissingClass
等等