Spring @Conditional注解的使用

Spring @Conditional注解的使用

@Conditional是Spring4新提供的注解,它可以标注在类或者方法上,它的作用是按照一定的条件进行判断,满足条件给容器注册bean。

/**
 * Indicates that a component is only eligible for registration when all
 * {@linkplain #value specified conditions} match.
 *
 * 

A condition is any state that can be determined programmatically * before the bean definition is due to be registered (see {@link Condition} for details). * *

The {@code @Conditional} annotation may be used in any of the following ways: *

    *
  • as a type-level annotation on any class directly or indirectly annotated with * {@code @Component}, including {@link Configuration @Configuration} classes
  • *
  • as a meta-annotation, for the purpose of composing custom stereotype * annotations
  • *
  • as a method-level annotation on any {@link Bean @Bean} method
  • *
* *

If a {@code @Configuration} class is marked with {@code @Conditional}, * all of the {@code @Bean} methods, {@link Import @Import} annotations, and * {@link ComponentScan @ComponentScan} annotations associated with that * class will be subject to the conditions. * *

NOTE: Inheritance of {@code @Conditional} annotations * is not supported; any conditions from superclasses or from overridden * methods will not be considered. In order to enforce these semantics, * {@code @Conditional} itself is not declared as * {@link java.lang.annotation.Inherited @Inherited}; furthermore, any * custom composed annotation that is meta-annotated with * {@code @Conditional} must not be declared as {@code @Inherited}. * * @author Phillip Webb * @author Sam Brannen * @since 4.0 * @see Condition */ @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Conditional { /** * All {@link Condition}s that must {@linkplain Condition#matches match} * in order for the component to be registered. */ Class<? extends Condition>[] value(); }

从源码中可以看出,@Conditional使用时必须传入一个继承了Condition类的class类,接着我们看看Condition接口:

/**
 * A single {@code condition} that must be {@linkplain #matches matched} in order
 * for a component to be registered.
 *
 * 

Conditions are checked immediately before the bean-definition is due to be * registered and are free to veto registration based on any criteria that can * be determined at that point. * *

Conditions must follow the same restrictions as {@link BeanFactoryPostProcessor} * and take care to never interact with bean instances. For more fine-grained control * of conditions that interact with {@code @Configuration} beans consider the * {@link ConfigurationCondition} interface. * * @author Phillip Webb * @since 4.0 * @see ConfigurationCondition * @see Conditional * @see ConditionContext */ public interface Condition { /** * Determine if the condition matches. * @param context the condition context * @param metadata metadata of the {@link org.springframework.core.type.AnnotationMetadata class} * or {@link org.springframework.core.type.MethodMetadata method} being checked. * @return {@code true} if the condition matches and the component can be registered * or {@code false} to veto registration. */ boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata); }

该接口的意思就是我们使用@Conditional注解时必须同时传入实现该接口的类并重写matches(ConditionContext context, AnnotatedTypeMetadata metadata)方法,如果方法返回true,就会加载对应的bean到IOC容器中,如果返回false,就不返回。

接下来看看怎么用这个注解:

我们先用@Configuration@Bean往容器中添加两个用户,分别是linus和bill:

@Configuration
public class MainConfig2 {		
	@Bean("bill")
    public User user01() {
        User user = new User();
        user.setUserName("bill gates");
        user.setNation("USA");
        return user;
    }

    @Bean("linus")
    public User user02() {
        User user = new User();
        user.setUserName("linus");
        user.setNation("USA");
        return user;
	}    
}

接下来看看测试类:

public class TestMainConfig2 {
    AnnotationConfigApplicationContext annotationConfigApplicationContext;

    @Before
    public void before() {
        annotationConfigApplicationContext
                = new AnnotationConfigApplicationContext(MainConfig2.class);
    }

    @Test
    public void test() {

        String[] names = annotationConfigApplicationContext.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }
}

看看输出:
Spring @Conditional注解的使用_第1张图片
两个bean都被注入了,接下来我们想要添加条件,即在linux操作系统下才注入linus这个用户,这个时候我们就需要用上@Conditional注解了,我们先写一个LinuxCondition类实现Condition接口:

public class LinuxCondition implements Condition {
    /**
     * ConditionContext:判断条件能使用的上下文(环境)
     * AnnotatedTypeMetadata:注释信息
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // TODO是否linux系统
        //1、能获取到ioc使用的beanfactory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        //2、获取类加载器
        ClassLoader classLoader = context.getClassLoader();
        //3、获取当前环境信息
        Environment environment = context.getEnvironment();
        //4、获取到bean定义的注册类
        BeanDefinitionRegistry registry = context.getRegistry();

        String property = environment.getProperty("os.name");

        //可以判断容器中的bean注册情况,也可以给容器中注册bean
        boolean definition = registry.containsBeanDefinition("person");
        System.out.println("contains person:" + definition);
        if(property.contains("linux")){
            return true;
        }

        return false;
    }
}

然后在bill的bean上加入@Conditional(LinuxCondition .class)

@Bean("linus")
@Conditional(LinuxCondition .class)
public User user01() {
    User user = new User();
    user.setUserName("linus");
    user.setNation("USA");
    return user;
}

这个时候,我们再来看看linus这个bean有没有被注入到容器中,进行test查看打印数据:
Spring @Conditional注解的使用_第2张图片
可以看到linus这个用户已经没有被注入到容器中了。

@Conditional注解也可以用到类上,表名该类中的bean是否被注入:
在这里插入图片描述

你可能感兴趣的:(java,spring)