Spring的@Conditional注解

      今天在了解Springboot的自动配置原理的时候,发现绝大多数“xxxAutoConfiguration”类上,都带有@Conditionalxxx的注解。特意对该方面做一些基本的了解。

      话不多说,还是从两个老套路进入了解:是什么?怎么玩?

  1. 什么是 @Conditional注解?
Indicates that a component is only eligible for registration when all {@linkplain #value specified conditions} match
  • 这是来自@Conditional注解的Javadoc。表达的意思是:表示组件仅在全部条件都满足的时候,才有资格注册。

 

    2.@Conditional怎么用?

  1. 举例说明:

不同的宠物,如猫、狗,它们的叫声是不一样的。我们可以这样处理不同宠物的叫声:

   //mock codes
        if (dog) {
            //狗叫声
        } else if (cat) {
            // 猫叫声
        }

 但是如果有成百上千中宠物,这样的if else 显然不太理智,也不太合适。以往我一般想到可以使用工厂模式来解决这个问题:每种宠物定义一个service,所有的service放到一个工厂中,然后根据传入的宠物类型获取对应的service:

    //将所有的service实现类定义到该map中
    private final Map<String, PatService> serviceMap = new HashMap<>();
    
    //根据宠物类型,获取与之对应的service
    public PatService getService(String patType) {
        return serviceMap.get(patType);
    }

这样的方法固然可行。但是,如果有100种宠物,内存中就会存在100个Service,而实际上有可能service根本一次都不会执行到(当然也可能会执行到)。针@Conditional就可以很好地解决这个问题。

  2.代码实现     

(a)前面提到,当满足一定条件的时候,才有资格注册。所谓的条件,就是我们这里Condition这个接口。我们需要去实现它;

(b)当满足条件的时候,将组件注册到IOC容器中。满足条件后,触发注册的触发器,便是这个@Conditional注解。@Conditional的values中的类(都是Condition接口的实现类)的matches方法返回true的时候,@Conditional所注解的类或者方法就会执行。

3.编写Condition实现类

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

/**
 * @author ZhouSicheng
 * @description
 * @date 2019/1/14 下午3:39
 */
public class DogCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String petType = context.getEnvironment().getProperty("pet.type");
        return petType.equalsIgnoreCase("dog");
    }
}

   狗叫的条件:当配置文件中pet.type为dog的时候,matches方法会返回true。



import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

/**
 * @author ZhouSicheng
 * @description
 * @date 2019/1/14 下午3:41
 */
public class CatCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String petType = context.getEnvironment().getProperty("pet.type");
        return petType.equalsIgnoreCase("cat");
    }
}

猫叫的条件:当配置文件中pet.type为cat的时候,matches方法会返回true。

3.接口PatService以及两个实现类



/**
 * @author ZhouSicheng
 * @description
 * @date 2019/1/14 下午3:43
 */
public class DogService implements PatService {
    @Override
    public void voice() {
        System.out.println("汪汪汪.....");
    }
}


/**
 * @author ZhouSicheng
 * @description
 * @date 2019/1/14 下午3:43
 */
public class CatService implements PatService {
    @Override
    public void voice() {
        System.out.println("喵喵喵...");
    }
}

4.配置Config类,根据条件组装不同的PatService实现类


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

/**
 * @author ZhouSicheng
 * @description
 * @date 2019/1/14 下午3:42
 */
@Configuration
public class ConditionConfig {

   //满足哪个Condition,就装配哪个service实现类

    @Bean
    @Conditional(DogCondition.class)
    public PatService dogService() {
        return new DogService();
    }

    @Bean
    @Conditional(CatCondition.class)
    public PatService catService() {
        return new CatService();
    }
}

5.配置文件

pet:
  type: cat

6.测试代码

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.HashMap;
import java.util.Map;

/**
 * @author ZhouSicheng
 * @description
 * @date 2019/1/14 下午3:45
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class ConditionTest {

    @Autowired
    private ApplicationContext applicationContext;

    @Test
    public void testCondition() {
        PatService patService = applicationContext.getBean(PatService.class);
        patService.voice();
    }

    最终的输出结果:

        喵喵喵...    

   好了,到这里,@Conditional的功能就实现了。当然,强大的Spring已经为我们做了很多的条件扩展,可以拿来直接用:

@ConditionalOnBean(仅仅在当前上下文中存在某个对象时,才会实例化一个Bean)
@ConditionalOnClass(某个class位于类路径上,才会实例化一个Bean)
@ConditionalOnExpression(当表达式为true的时候,才会实例化一个Bean)
@ConditionalOnMissingBean(仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean)
@ConditionalOnMissingClass(某个class类路径上不存在的时候,才会实例化一个Bean)
@ConditionalOnNotWebApplication(不是web应用)

转载于:https://my.oschina.net/zhousc1992/blog/3001278

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值