条件注解@Conditional

简介

在学习SpringBoot的时候我们会在各种自动配置类中看到大量使用了@Conditional注解,这篇文章主要简单说下@Conditional注解的使用方法。

定义:
按照《Spring Boot实战》书中所说的:“@Conditional根据满足某一特定条件创建一个特定的Bean。比方说,当某一个jar包在一个类路径下的时候,自动配置一个或多个Bean;或者只有某个Bean被创建才会才会创建另外一个Bean。总的来说,就是根据特定判定条件来控制Bean的创建行为,这样我们可以利用这个特性进行一些自动的配置。”

在使用该注解之前我们来看一下@Conditional的源码

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

我们关注下面的两点:

  • @Target({ElementType.TYPE, ElementType.METHOD}):表示该注解可以加在类上,表示该类下面的所有@Bean都会启用配置;也可以加在方法上,只对该方法有效

  • Class<? extends Condition>[] value():表示要传一个Class集合给该注解,即@Conditional({XXX.class,XXX.class}) ,而且XXX类要继承Condition接口。关于Condition下面会说。

示例

我们以自己电脑的操作系统为判定条件,若我们的操作系统为Linux则创建Linux之父的Person的Bean;若操作系统为Windows则创建Windows之父的Person的Bean。

一、首先我们来创建一个Person类:

package com.study.spring.annotation.bean;

/**
 * Created on 2020/3/31
 * Package com.study.spring.annotation.bean
 *
 * @author dsy
 */
public class Person {
    private String name;
    private Integer age;

    public Person() {
    }

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

二、再创建一个配置类MyConfig:

package com.study.spring.annotation.config;

import com.study.spring.annotation.bean.Person;
import com.study.spring.annotation.condition.LinuxCondition;
import com.study.spring.annotation.condition.WindowsCondition;
import org.springframework.context.annotation.*;

/**
 * Created on 2020/3/31
 * Package com.study.spring.annotation.config
 *
 * @author dsy
 */
@Configuration        //标识该类是一个配置类,相当于之前的一个xml配置文件
public class MyConfig {
 
    /**
     * @Conditional({Condition})  注解:按照一定的条件将bean添加到IOC容器中
     */
    @Conditional({LinuxCondition.class})
    @Bean("linux")
    public Person person01(){
        return new Person("linux之父",55);
    }

    @Bean("windows")
    @Conditional({WindowsCondition.class})
    public Person person02(){
        return new Person("windows之父",48);
    }

}

三、接下来创建两个Condition类:LinuxCondition和WindowsCondition:

package com.study.spring.annotation.condition;

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

/**
 * Created on 2020/3/31
 * Package com.study.spring.annotation.condition
 *
 * @author dsy
 */
//判断是否Linux系统 要进行判断必须实现Condition接口
public class LinuxCondition implements Condition {

    /**
     *
     * @param conditionContext  判断条件能使用的上下文环境
     * @param annotatedTypeMetadata 当前标注了@Conditional注解的注释信息
     * @return Boolean
     */
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        Environment environment = conditionContext.getEnvironment();
        String property = environment.getProperty("os.name");
        return property!=null&&property.contains("Linux");
    }
}

package com.study.spring.annotation.condition;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

/**
 * Created on 2020/3/31
 * Package com.study.spring.annotation.condition
 *
 * @author dsy
 */
//判断是否Windows系统 要进行判断必须实现Condition接口
public class WindowsCondition implements Condition {

    /**
     *
     * @param conditionContext  判断条件能使用的上下文环境
     * @param annotatedTypeMetadata 当前标注了@Conditional注解的注释信息
     * @return Boolean
     */
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        Environment environment = conditionContext.getEnvironment();
        String property = environment.getProperty("os.name");
        return property != null && property.contains("Windows");
    }
}

说明: 这两个类均实现了Condition接口,里面只有一个matches方法返回值为boolea类型,也就是说@Conditional({LinuxCondition.class})或者@Conditional({WindowsCondition.class})通过判断注解括号里面条件类的matches方法的返回值来判定要不要在IOC容器中创建由@Conditional注解标识的这个Bean;若matches返回值为true则创建该Bean,若返回false则不创建该Bean。

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

四、测试:

package com.study.spring;

import com.study.spring.annotation.bean.Person;
import com.study.spring.annotation.config.MyConfig;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.Map;

@SpringBootTest
class ApplicationTests {
    /**
     * @Conditional 注解来按照条件获取bean实例
     */
    @Test
    void testAnnotationConfig2(){
        //创建IOC容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
        //getBeanNamesForType方法按照类来获取该类的Bean的id
        String[] names = applicationContext.getBeanNamesForType(Person.class);
        //打印
        for (String name:names){
            System.out.println(name);
        }
        //获取具体的Bean
        Map<String, Person> beans = applicationContext.getBeansOfType(Person.class);
        System.out.println(beans);
    }

}

打印输出:

windows
{windows=Person{name='windows之父', age=48}}

若我们改变运行环境,加上参数:-Dos.name=Linux
在这里插入图片描述
再次运行打印输出:

linux
{linux=Person{name='linux之父', age=55}}

总结

1、@Conditional注解的作用是按照一定的判定条件来控制Bean的创建
2、@Conditional可以加在一个配置类上,表示该类下面的全部的@Bean都会启用配置;也可以加在一个@Bean的方法上面,只对该方法有效
3、判定条件类XXXCondition类要实现Condition接口,并重写matches方法,在该方法里面写自己的判定逻辑

参考资料:《Spring Boot实战》

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值