SpringBoot的@ConditionalOnMissingBean注解的作用

1、@ConditionalOnMissingBean
@ConditionalOnMissingBean,它是修饰bean的一个注解,主要实现的是,当你的bean被注册之后,如果而注册相同类型的bean,就不会成功,它会保证你的bean只有一个,即你的实例只有一个。

如果不加@ConditionalOnMissingBean,当你注册多个相同的bean时,会出现异常,以此来告诉开发人员。

package ljxwtl.cn.bean;
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
/**
 * @author: wtl
 * @License: (C) Copyright 2021, wtl Corporation Limited.
 * @Contact: 1050100468@qq.com
 * @Date: 2021/12/29 10:29 上午
 * @Version: 1.0
 * @Description:
 */
@Configuration
public class UserConfigure {
 
    @Bean
    public MyTestInjection createBean1(){
        return new MyTestInjection();
    }
 
    @Bean
    public MyTestInjection createBean2(){
        return new MyTestInjection();
    }
}

这样就会报错!!!

报错信息如下:

当我们把 @ConditionalOnMissingBean放到一个bean注入时,则就不会报错:

package ljxwtl.cn.bean;
 
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
/**
 * @author: wtl
 * @License: (C) Copyright 2021, wtl Corporation Limited.
 * @Contact: 1050100468@qq.com
 * @Date: 2021/12/29 10:29 上午
 * @Version: 1.0
 * @Description:
 */
@Configuration
public class UserConfigure {
 
    @Bean
    public MyTestInjection createBean1(){
        return new MyTestInjection();
    }
 
    @Bean
    @ConditionalOnMissingBean
    public MyTestInjection createBean2(){
        return new MyTestInjection();
    }
}

当我们把 @ConditionalOnMissingBean 去掉之后,你的bean可以注册多次,这时需要用的@Primary来确定你要哪个实现;一般来说,对于自定义的配置类,我们应该加上@ConditionalOnMissingBean注解,以避免多个配置同时注入的风险

2、@Primary

package ljxwtl.cn.bean;
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
 
/**
 * @author: wtl
 * @License: (C) Copyright 2021, wtl Corporation Limited.
 * @Contact: 1050100468@qq.com
 * @Version: 1.0
 * @Description:
 */
@Configuration
public class UserConfigure {
 
    @Bean
    public MyTestInjection createBean1(){
        return new MyTestInjection();
    }
 
    @Bean
    @Primary
    public MyTestInjection createBean2(){
        return new MyTestInjection();
    }
}

3、@ConditionalOnProperty

通过其三个属性prefix,name以及havingValue来实现的,其中prefix表示配置文件里节点前缀,name用来从application.properties中读取某个属性值,havingValue表示目标值。

  • 如果该值为空,则返回false;
  • 如果值不为空,则将该值与havingValue指定的值进行比较,如果一样则返回true;否则返回false。
  • 返回值为false,则该configuration不生效;为true则生效。

下面代码演示为配置文件lind.redis.enable为true时才会注册RedisFactory这个bean:

package ljxwtl.cn.bean;
 
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
 
/**
 * @author: wtl
 * @License: (C) Copyright 2021, wtl Corporation Limited.
 * @Contact: 1050100468@qq.com
 * @Version: 1.0
 * @Description:
 */
@Configuration
@ConditionalOnProperty(prefix="lind.redis",name = "enable", havingValue = "true")
public class UserConfigure {
 
    @Bean
    public MyTestInjection createBean1(){
        return new MyTestInjection();
    }
}

 然后再application.properties里配置:

这样就成功了!!!

4、@ConditionalOnBean

@ConditionalOnBean // 当给定的在bean存在时,则实例化当前Bean
 
@ConditionalOnMissingBean // 当给定的在bean不存在时,则实例化当前Bean 
@ConditionalOnClass // 当给定的类名在类路径上存在,则实例化当前Bean 
 
@ConditionalOnMissingClass // 当给定的类名在类路径上不存在,则实例化当前Bean

需求场景 :

比如下面一种场景,我在实例化People对象的时候,需要注入一个City对象。这个时候问题来了,如果city没有实例化,那么下面就会报空指针或者直接报错。
所以这里需求很简单,就是当前city存在则实例化people,如果不存在则不实例化people,这个时候@ConditionalOnBean 的作用来了。

package ljxwtl.cn.bean;
 
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
 
/**
 * @author: wtl
 * @License: (C) Copyright 2021, wtl Corporation Limited.
 * @Contact: 1050100468@qq.com
 * @Version: 1.0
 * @Description:
 */
@Configuration
public class UserConfigure {
 
    @Bean
    @ConditionalOnBean(name = "city")
    public People createPeople(City city){
        System.out.println(city.getCityName());
        return new People();
    }
 
    @Bean
    public City createCity(){
        City city = new City();
        city.setCityName("北京");
        return city;
    }
}

在spring ioc的过程中,优先解析@Component,@Service,@Controller注解的类。其次解析配置类,也就是@Configuration标注的类。最后开始解析配置类中定义的bean。

示例代码中people是定义在配置类中的,当执行到配置类解析的时候,@Component,@Service,@Controller ,@Configuration标注的类已经全部被解析,所以这些BeanDifinition已经被同步。

但是bean1的条件注解依赖的是city,city是被定义的配置类中的,因为两个Bean都是配置类中Bean,所以此时配置类的解析无法保证先后顺序,就会出现不生效的情况。

同样的道理,如果依赖的是FeignClient,也有可能会出现不生效的情况。因为FeignClient最终还是由配置类触发,解析的先后顺序也不能保证。

解决
有两种方式:

项目中条件注解依赖的类,大多会交给spring容器管理,所以如果要在配置中Bean通过@ConditionalOnBean依赖配置中的Bean时,完全可以用@ConditionalOnClass(Bean2.class)来代替。
如果一定要区分两个配置类的先后顺序,可以将这两个类交与EnableAutoConfiguration管理和触发。也就是定义在META-INF\spring.factories中声明是配置类,然后通过@AutoConfigureBefore、AutoConfigureAfter、AutoConfigureOrder控制先后顺序。因为这三个注解只对自动配置类生效。

                        
原文链接:https://blog.csdn.net/wtl1992/article/details/122210599

 

SpringBoot中,使用@ConditionalOnMissingBean注解可以实现按需自动配置。当原本已经存在的Bean不存在时,该注解才会进行自动配置。 在使用该注解时,需要在配置类或者注解类上进行标注。在类上标注时,需要添加@Component注解并指明其扫描路径。然后,使用@ConditionalOnMissingBean注解来判定是否需要自动配置。当原本存在的Bean不存在时,该注解会根据指定的判断条件完成自动配置。 例如,我们需要根据条件来判定是否需要自动配置数据源,可以使用@ConditionalOnMissingBean注解。在使用该注解时,我们需要指定检测的bean类型和对应的bean名称,如果检测到该bean不存在,则进行自动配置。具体实现如下: @Configuration public class DataSourceConfig { @Bean(name = "dataSource") @ConditionalOnMissingBean(name = "dataSource") public DataSource dataSource() { // 数据库连接等代码 return dataSource; } } 在该配置类中,我们使用@ConditionalOnMissingBean标注了成员函数dataSource(),并且指定了该函数返回的Bean的名称为“dataSource”。当判定不存在该名称的Bean时,就会自动进行配置。 除了根据bean名称判断外,@ConditionalOnMissingBean注解还可以根据Bean类型和条件进行判断。例如,我们需要判断一个接口实现是否存在,可以使用@ConditionalOnMissingBean注解结合@ConditionalOnClass注解进行判定。 @Configuration public class ServiceConfig { @Bean @ConditionalOnMissingBean(IService.class) @ConditionalOnClass(IService.class) public IService iService() { // 接口实现代码 return iService; } } 在该配置类中,我们使用@ConditionalOnMissingBean注解结合@ConditionalOnClass注解判断接口实现是否存在。当判定该接口实现不存在时,就会自动进行配置。 总之,@ConditionalOnMissingBean注解为我们带来了更多自动配置的灵活性,可以根据不同的条件进行自动配置,提高了开发效率,减少了代码冗余。它是SpringBoot中一个非常实用的注解,开发者可以灵活运用该注解,并根据业务需求进行适当的配置,以满足项目的要求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值