@Conditional为按照条件配置spring的bean提供了支持,即满足某种条件下,怎么配置对应的bean;
应用场景
- 当某一个jar包在classpath中的时候,配置某几个bean;
- 当某一个bean配置好后,会自动配置一个特定的bean;
- 当某种环境变量被设置后,创建某个bean;
- @Conditional为敏捷开发所提倡的原则"习惯优于配置"提供了支持;
- @Conditional是Spring Boot快速开发框架实现"习惯优于配置"的核心技术;
样例
我们构建一个会议服务接口,其下分别有远程会议服务,本地会议服务,然后根据系统运行时的环境信息动态获取会议服务实例执行。
IMeetingService
/**
* 会议服务
*/
public interface IMeetingService {
/**
* 开会
* @param cmd
* @return
*/
void meeting(String cmd);
}
LocalMeetingServiceImpl
/**
* 本地会议服务
*/
public class LocalMeetingServiceImpl implements IMeetingService {
@Override
public void meeting(String cmd) {
System.out.println("this is Local Meeting!");
}
}
RomteMeetingServiceImpl
/**
* 远程会议服务
*/
public class RomteMeetingServiceImpl implements IMeetingService {
@Override
public void meeting(String cmd) {
System.out.println("this is Romte Meeting!");
}
}
实现Conditional注解的执行接口:
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函数调用测试:
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();
}
上面用例执行结果为(表明RomteMeetingServiceImpl实现):
this is Romte Meeting!
当我们 设置System.setProperty("meeting_type","locale"); 或者直接注释掉这行时结果:
this is Local Meeting!
这样就通过Conditional注解完成了根据条件去创建具体的实例,动态根据环境的信息去实例化服务,达到服务智能化创建调用
springboot条件注解的实现方式
上面的例子提供了两个Condition分别为RomteConditional与LocalConditional,相对来说比较复杂,下面我们按照springboot实现条件判断注解的思路完善上面样例:
- 定义条件注解Conditional的包装注解ConditionalOnMeetType
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Conditional(OnMeetTypeCondition.class)
public @interface ConditionalOnMeetType {
/**
* 默认为local
*
* @return
*/
String value() default "local";
}
- 定义条件注解Conditional处理实现类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) {
//此处根据方法获取方法的注解ConditionalOnMeetType传入的值,根据值与系统设置值是否一致判断,当前方法定义的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的条件注解大多基于这种方式实现,简单清晰。
springboot 提供了如下条件注解:
- ConditionalOnBean
- ConditionalOnClass
- ConditionalOnExpression
- ConditionalOnJava
- ConditionalOnMissingBean
- ConditionalOnMissingClass
等等