spring @Conditional条件注解以及扩展

@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实现条件判断注解的思路完善上面样例:

  1. 定义条件注解Conditional的包装注解ConditionalOnMeetType
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Conditional(OnMeetTypeCondition.class)
public @interface ConditionalOnMeetType {

    /**
     * 默认为local
     *
     * @return
     */
    String value() default "local";
}
  1. 定义条件注解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 annMap = methodMetadata
                    .getAllAnnotationAttributes(ConditionalOnMeetType.class.getName());
            String meetType = (String) annMap.getFirst("value");
            return type.equalsIgnoreCase(meetType);
        }
        return false;
    }
}
  1. 定义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
    等等

你可能感兴趣的:(spring @Conditional条件注解以及扩展)