专栏首页SpringCloud专栏springboot根据不同的条件创建bean,动态创建bean,@Conditional注解使用

springboot根据不同的条件创建bean,动态创建bean,@Conditional注解使用

这个需求应该也比较常见,在不同的条件下创建不同的bean,具体场景很多,能看到这篇的肯定懂我的意思。

倘若不了解spring4.X新加入的@Conditional注解的话,要实现不同条件创建不同的bean还是比较麻烦的,可能需要硬编码一些东西做if判断。那么现在有个@Conditional注解后,事情就简单多了。用法很简单,直接上代码。

新建一个springboot项目,添加一个Configuration标注的类,我们通过不同的条件表达式来创建bean。

package com.tianyalei.condition;

import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

/**
 * Created by wuweifeng on 2017/10/11.
 */
@Configuration
public class Config {

    @Conditional(MyCondition.class)
    @Bean
    public String condition() {
        System.err.println("自定义的condition的match方法返回值为true时,才会进入该方法创建bean");
        return "";
    }

    /**
     * 该Abc class位于类路径上时
     */
    @ConditionalOnClass(Abc.class)
    @Bean
    public String abc() {
        System.err.println("ConditionalOnClass true");
        return "";
    }

//    @ConditionalOnClass(Abc.class)
//    @Bean
//    public Abc newAbc() {
//        System.err.println("ConditionalOnClass true");
//        return new Abc();
//    }

    /**
     * 存在Abc类的实例时
     */
    @ConditionalOnBean(Abc.class)
    @Bean
    public String bean() {
        System.err.println("ConditionalOnBean is exist");
        return "";
    }

    @ConditionalOnMissingBean(Abc.class)
    @Bean
    public String missBean() {
        System.err.println("ConditionalOnBean is missing");
        return "";
    }

    /**
     * 表达式为true时
     */
    @ConditionalOnExpression(value = "true")
    @Bean
    public String expresssion() {
        System.err.println("expresssion is true");
        return "";
    }

    /**
     * 配置文件属性是否为true
     */
    @ConditionalOnProperty(
            value = {"abc.property"},
            matchIfMissing = false)
    @Bean
    public String property() {
        System.err.println("property is true");
        return "";
    }
}

这里面有个空类Abc.class,你可以就创建个叫Abc的类,里面是空的就行。

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

/**
 * Created by wuweifeng on 2017/10/11.
 */
public class MyCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        //判断当前系统是Mac,Windows,Linux
        return conditionContext.getEnvironment().getProperty("os.name").contains("Mac");
    }
}

@Conditional(MyCondition.class) 这句代码可以标注在类上面,表示该类下面的所有@Bean都会启用配置 也可以标注在方法上面,只是对该方法启用配置 除了自己自定义Condition之外,Spring还提供了很多Condition给我们用 @ConditionalOnBean(仅仅在当前上下文中存在某个对象时,才会实例化一个Bean) @ConditionalOnClass(某个class位于类路径上,才会实例化一个Bean) @ConditionalOnExpression(当表达式为true的时候,才会实例化一个Bean) @ConditionalOnMissingBean(仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean) @ConditionalOnMissingClass(某个class类路径上不存在的时候,才会实例化一个Bean) @ConditionalOnNotWebApplication(不是web应用)

以上是一些常用的注解,其实就是条件判断,如果为true了就创建Bean,为false就不创建,就这么简单。

这些注解里的条件可以是多个,也可以赋默认值,也可以标注在类上,如果标注在类上,则对类里的所有@Bean方法都生效。

其中@ConditionalOnProperty是指在application.yml里配置的属性是否为true,其他的几个都是对class的判断。

我在配置里加上abc.property = true这个配置就可以测试上面的代码了。

然后再来一个对类进行多个条件标注的例子:

package com.tianyalei.condition;

import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Created by wuweifeng on 2017/10/11.
 */
@Configuration
@ConditionalOnProperty(
        value = {"abc.property"},
        matchIfMissing = false
)
@ConditionalOnClass(Abc.class)
public class Multi {
    @Bean
    @ConditionalOnMissingBean({Abc.class})
    public String check() {
        System.err.println("multi check");
        return "check";
    }
}

OK,代码很简单,运行看看结果

可能上面的那些你用的地方不常见,那我来举一个我正在使用的例子。我的应用是基于SpringCloud的,在线上部署时有eureka来做注册中心,而在本地环境下,我的应用是单机的,不需要eureka,但是代码里已经引入了eureka了,每次启动就会自动去连接eureka,然后控制台就开始报错。虽然不影响功能,但是看着一直不停的报错也是不顺眼。

那么我就可以使用Condition注解来解决它。

/**
 * @author wuweifeng wrote on 2017/11/25.
 * 根据部署环境动态决定是否启用eureka
 */
@Component
@ConditionalOnProperty(value = "open.eureka")
@EnableDiscoveryClient
public class JudgeEnableDiscoveryClient {
}

我把EnableDiscoveryClient这个注解单独放个类里,里面什么也不写,条件就是application.yml里配置的open.eureka 如果我只想让线上的环境开启eureka,那么我就在application-prod.yml里配上open.eureka=true,其他的yml什么也不写就行了。这样本地启动时就相当于没有开启EnableDiscoveryClient。

使用场景还是蛮多的,具体的看情况,但是需要记住有这么个注解,以便不时之需。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Spring Boot 返回 JSON 数据,一分钟搞定!

    除了 Spring Boot 必须自带的 parent 依赖外,仅仅只需要加入这个 spring-boot-starter-web 包即可,它会自动包含所有 J...

    Java技术栈
  • Spring Boot 之 Profile 使用

    在 applcation.properties 文件中可以通过以下配置来激活 profile:

    静默虚空
  • Spring Boot 完整学习指南

    在过去两三年的 Spring 生态圈,最让人兴奋的莫过于 Spring Boot 框架。Spring Boot 应用本质上就是一个基于 Spring 框架的应用...

    CSDN技术头条
  • Java|使用Spring Boot Actuator监控应用

    微服务的特点决定了功能模块的部署是分布式的,大部分功能模块都是运行在不同的机器上,彼此通过服务调用进行交互,前后台的业务流会经过很多个微服务的处理和传递,出现了...

    黄小怪
  • 后续之《SpringBoot服务器压测对比(jetty、tomcat、undertow)》

        昨天发了一个《SpringBoot服务器压测对比(jetty、tomcat、undertow)》,本是工作的一个笔记,没想到被红薯翻牌了(荣幸之至)。看...

    尚浩宇
  • 使用Spring Boot实现动态健康检查HealthChecks

    lyb-geek
  • SpringBoot服务器压测对比(jetty、tomcat、undertow)

        服务接口:指的是具有一定业务代码的接口,连接数据库/Redis然后返回json数据

    尚浩宇
  • Spring Boot 这样学才对!

    在过去两三年的 Spring 生态圈,最让人兴奋的莫过于 Spring Boot 框架。Spring Boot 应用本质上就是一个基于 Spring 框架的应用...

    CSDN技术头条
  • 在Spring Boot启动时运行定制的代码

    Spring Boot会自动为我们做很多配置,但迟早你需要做一些自定义工作。在本文中,您将学习如何挂钩应用程序引导程序生命周期并在Spring Boot启动时执...

    lyb-geek
  • 2018-12-19 关于SpringBoot启动过程中报NoSuchBeanDefinitionException的异常的问题

    SpringBoot JPA 中无法注入 JpaRepository 接口的问题及解决方案

    Albert陈凯

扫码关注云+社区

领取腾讯云代金券