3.2条件化的bean

本文介绍了Spring中如何使用@Conditional注解来条件化地创建bean,只有当特定条件满足时bean才会被创建。通过自定义Condition实现,可以根据类路径、其他bean的存在或环境变量设置来决定bean是否创建。同时提到了ConditionContext和AnnotatedTypeMetaData接口在检查@Bean注解上的其他注解及其属性的作用,并给出了@Profile注解实现bean加载条件的例子。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

3.2条件化的bean

如果你希望一个或者多个bean只有在应用的类路径夏包含特定的库的时候才创建。

或者希望某个bean只有当另外某个特定的bean也申明了之后才创建。

某个环境变量设置之后,才创建等等。。。

@Conditional 注解

Spring4引入了一个新的注解,可以用在@Bean注解的方法上。如果给定的条件计算结果为true,就会创建这个bean,否则的话,这个bean就会被忽略。

书上的例子不太会配,验证,我找了一个别的例子。

    @Bean
    @Conditional(MagicExistsCondition.class)
    public MagicBean magicBean() {
        return new MagicBean();
    }

这个Bean的配置,@Conditional注解上,配置了一个MagicExistsCondition,这个类继承了Condition接口。

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

这个condition接口,通过判断,来返回true或者false,来决定这个这个Bean是不是被创建!

public class MagicExistsCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        Environment environment = conditionContext.getEnvironment();
        System.out.println(environment.getProperty("os.name"));
        return environment.getProperty("os.name").contains("Linux");
    }
}

这边我选择了一个比较简单的判断法,通过env对象,去获取操做系统的名字,如果是Linux就创建,windows就不创建。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = DataSourceConfig.class)
//@ActiveProfiles("dev")
public class TestAdv {

    @Autowired
    public MagicBean magicBean;

    @Test
    public void testFun(){
        System.out.println(magicBean.getMagic());
    }

}

这边有一个简单的Testcase,可以随便试试,换一下Linux或者windows看看还会不会创建。

这里的例子是一个非常简单的例子,还有更加复杂的例子。

ConditionContext接口

public interface ConditionContext {
    BeanDefinitionRegistry getRegistry(); //检查Bean的定义

    @Nullable
    ConfigurableListableBeanFactory getBeanFactory(); //检查bean是否存在,甚至探查bean的属性

    Environment getEnvironment(); //检查环境变量,及其值

    ResourceLoader getResourceLoader(); //resourceLoader所加载的资源

    @Nullable
    ClassLoader getClassLoader(); //classLoader来检查类是否存在
}

AnnotatedTypeMetaData接口

public interface AnnotatedTypeMetadata {
    boolean isAnnotated(String var1);

    @Nullable
    Map<String, Object> getAnnotationAttributes(String var1);

    @Nullable
    Map<String, Object> getAnnotationAttributes(String var1, boolean var2);

    @Nullable
    MultiValueMap<String, Object> getAllAnnotationAttributes(String var1);

    @Nullable
    MultiValueMap<String, Object> getAllAnnotationAttributes(String var1, boolean var2);
}

这个接口能够让我们检查带有@Bean注解的方法上还有什么其他的注解。借助其他的那些方法,我们能够检查@Bean注解的方法上其他注解的属性。

@Profile的实现

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ProfileCondition.class)
public @interface Profile {

	/**
	 * The set of profiles for which the annotated component should be registered.
	 */
	String[] value();

}

profile也是使用@Conditional注解来判断这个Bean是不是要加载。

class ProfileCondition implements Condition {

	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
		if (attrs != null) {
			for (Object value : attrs.get("value")) {
				if (context.getEnvironment().acceptsProfiles((String[]) value)) {
					return true;
				}
			}
			return false;
		}
		return true;
	}

}

可以看到这个地方的match方法的实现,

1. 通过metaData来获取这个Bean上面Profile相关的注解,例如

@Profile("dev"),这边的attrs就会是一个value->dev

2. 只有配置了这个@Profile注解的Bean才会进入那个if,没有配置的话就直接返回true,就是需要配置!

3. 进入for loop,看profile里面value是不是和环境相一致,比如我激活的profile是dev,那我的环境和dev相同,就会配置那个bean,相反如果是prod,那么就会是false。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值