首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringBoot根据条件注入Bean@Condition用法

SpringBoot根据条件注入Bean@Condition用法

作者头像
时光_赌徒
修改2020-05-25 18:08:52
2.2K0
修改2020-05-25 18:08:52
举报
文章被收录于专栏:记录记录

@Condition:这个注解在Spring4中引入,其主要作用就是判断条件是否满足,从而决定是否初始化并向容器注册Bean!

1. 定义

@Conditional注解定义如下,其内部主要就是利用了Condition接口,来判断是否满足条件,从而决定是否需要加载Bean

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
    Class<? extends Condition>[] value();
}

下面是Condtion接口的定义,这个可以说是最基础的入口了,其他的所有条件注解,归根结底,都是通过实现这个接口进行扩展的

@FunctionalInterface
public interface Condition {
    boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2);
}

这个接口中,有个参数比较有意思ConditionContext,它持有不少有用的对象,可以用来获取很多系统相关的信息,来丰富条件判断,接口定义如下

public interface ConditionContext {
    // 获取Bean定义
    BeanDefinitionRegistry getRegistry();

    // 获取Bean工程,因此就可以获取容器中的所有bean
    @Nullable
    ConfigurableListableBeanFactory getBeanFactory();

    // environment 持有所有的配置信息
    Environment getEnvironment();
    
    // 资源信息
    ResourceLoader getResourceLoader();

    // 类加载信息
    @Nullable
    ClassLoader getClassLoader();
}

2. 使用说明

通过一个小例子,简单的说一下如何使用Condition和@Conditional注解,来实现bean的条件加载

首先我们定义一个随机产生数据的类,其功能就是随机生成一些数据

public class RandDataComponent<T> {
    private Supplier<T> rand;

    public RandDataComponent(Supplier<T> rand) {
        this.rand = rand;
    }

    public T rand() {
        return rand.get();
    }
}

我们目前提供两种随机数据生成的bean,但是需要根据配置来选择具体选中的方式,因此我们如下定义Bean

@Configuration
public class ConditionalAutoConfig {

    @Bean
    @Conditional(RandIntCondition.class)
    public RandDataComponent<Integer> randIntComponent() {
        return new RandDataComponent<>(() -> {
            Random random = new Random();
            return random.nextInt(1024);
        });
    }

    @Bean
    @Conditional(RandBooleanCondition.class)
    public RandDataComponent<Boolean> randBooleanComponent() {
        return new RandDataComponent<>(() -> {
            Random random = new Random();
            return random.nextBoolean();
        });
    }
}

上面的配置,先不管@Conditional注解的内容,单看两个Bean的定义,一个是定义int随机数生成;一个是定义boolean随机生成;

但是我们的系统中,只需要一个随机数据生成器即可,我们选择根据配置conditional.rand.type的值来选择到底用哪个,配置如下

# int 表示选择随机产生int数据; 非int 表示随机产生boolean数据
conditional.rand.type=int

接下来就得看这个条件如何加上了,也就是上面配置类ConditionalAutoConfig中两个注解的内容了,两个类都是实现Condition的接口,具体如下

public class RandBooleanCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        String type = conditionContext.getEnvironment().getProperty("conditional.rand.type");
        return "boolean".equalsIgnoreCase(type);
    }
}

public class RandIntCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        String type = conditionContext.getEnvironment().getProperty("conditional.rand.type");
        return "int".equalsIgnoreCase(type);
    }
}

上面的实现也比较清晰,获取配置值,然后判断,并返回true/fase;返回true,则表示这个条件满足,那么这个Bean就可以被加载了;否则这个Bean就不会创建;

3.举例:多台服务定时任务指定服务器启动:

public class SchedulerTaskCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        Environment environment = conditionContext.getEnvironment();//可以用来区分不同的环境
        boolean proBool= environment.acceptsProfiles("pro");
        String linuxLocalIp = getLinuxLocalIp();
        //"127.0.0.1" 换成需要走定时任务的服务器地址
        if(proBool && linuxLocalIp.equals("127.0.0.1")){
            return true;
        }
        return false;
    }
    
    
     private static String getLinuxLocalIp() {
        String ip = "";
        try {
            for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
                NetworkInterface intf = en.nextElement();
                String name = intf.getName();
                if (!name.contains("docker") && !name.contains("lo")) {
                    for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
                        InetAddress inetAddress = enumIpAddr.nextElement();
                        if (!inetAddress.isLoopbackAddress()) {
                            String ipaddress = inetAddress.getHostAddress().toString();
                            if (!ipaddress.contains("::") && !ipaddress.contains("0:0:") && !ipaddress.contains("fe80")) {
                                ip = ipaddress;
                                System.out.println(ipaddress);
                            }
                        }
                    }
                }
            }
        } catch (SocketException ex) {
            System.out.println("获取ip地址异常");
            ip = "127.0.0.1";
            ex.printStackTrace();
        }
        System.out.println("IP:" + ip);
        return ip;
    }
}

//定时任务类添加注解,即可
@Conditional({SchedulerTaskCondition.class})

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 定义
  • 2. 使用说明
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档