SpringBoot 之如何自定义条件装配

先看看@ConditionalOnClass注解是怎么做的?

1、@ConditionalOnClass

在这里插入图片描述
@ConditionalOnClass注解被@Conditional(OnClassCondition.class)注解标注,因此@ConditionalOnClass的条件装配判断逻辑依赖于Condition接口的实现类OnClassCondition

OnClassCondition的类图:
在这里插入图片描述
OnClassCondition并没有自己去实现Condition接口的matches(ConditionContext, AnnotatedTypeMetadata)方法,而是由它的父类SpringBootCondition来完成。
在这里插入图片描述

2、自定义条件装配注解 @ConditionalOnSystemProperty

@ConditionalOnSystemProperty注解的作用是获取到启动jar程序命令行中的Program arguments属性的名称与属性值做匹配进而决定是否装配类。

整体代码目录结构如下:
在这里插入图片描述

1> 自定义Condition

package com.saint.autoconfigure.condition;

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

import java.util.Objects;

/**
 * 系统属性值与值匹配条件
 *
 * @author Saint
 */
public class OnSystemPropertyCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        MultiValueMap<String, Object> attributes =
                metadata.getAllAnnotationAttributes(ConditionalOnSystemProperty.class.getName());
        String name = (String) attributes.getFirst("name");
        String value = (String) attributes.getFirst("value");
        String systemPropertyValue = System.getProperty(name);
        // 比较系统属性值和方法的值
        if (Objects.equals(systemPropertyValue, value)) {
            System.out.printf("系统属性【名称: %s】找到匹配值:%s \n", name, value);
            return true;
        }
        return false;
    }
}

2> 自定义条件装配注解

package com.saint.autoconfigure.condition;

import org.springframework.context.annotation.Conditional;

import java.lang.annotation.*;

/**
 * 系统属性名称与属性值匹配条件注解
 *
 * @author Saint
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnSystemPropertyCondition.class)
public @interface ConditionalOnSystemProperty {

    /**
     * 属性名
     */
    String name();

    /**
     * 属性值
     */
    String value();
}

3> 在配置类中使用条件装配注解

package com.saint.config;

import com.saint.autoconfigure.condition.ConditionalOnSystemProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 条件配置类
 *
 * @author Saint
 */
@Configuration
public class MyConditionalConfiguration {

    /**
     * 当存在key为language,value为Chinese的property属性时,加载当前方法
     *
     * @return
     */
    @ConditionalOnSystemProperty(name = "language", value = "Chinese")
    @Bean("message")
    public String chinese() {
        return "你好,世界!";
    }

    /**
     * 当存在key为language,value为English的property属性时,加载当前方法
     *
     * @return
     */
    @ConditionalOnSystemProperty(name = "language", value = "English")
    @Bean("message")
    public String english() {
        return "Hello, World";
    }
}

4> 测试

package com.saint;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class SaintSpringbootApplication {

    public static void main(String[] args) {
        // 设置language属性值,也可以通过--language=English在Program arguments中设置
        System.setProperty("language", "English");

        ConfigurableApplicationContext context = SpringApplication.run(SaintSpringbootApplication.class, args);

        // 从Spring上下文中获取beanName为message的类
        String message = context.getBean("message", String.class);
        System.out.println("当前message类型为:" + message);
    }
}

运行结果输出如下:
在这里插入图片描述
从结果可以看出,@ConditionalOnSystemProperty注解条件装配生效。


3、自定义Condition做条件装配

根据当前操作系统来注入bean,windows下注入bill,linux下注入linus。

1> User类:

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
 
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Long userId;
    private String userName;
}

2> 自定义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;

public class WindowsCondition implements Condition {

    /**
     * @param conditionContext:判断条件能使用的上下文环境
     * @param annotatedTypeMetadata:注解所在位置的注释信息
     */
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        //获取当前环境信息
        Environment environment = conditionContext.getEnvironment();
        //获得当前系统名
        String property = environment.getProperty("os.name");
        //包含Windows则说明是windows系统,返回true
        return property.contains("Windows");
    }
}
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class LinuxCondition implements Condition {

    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        Environment environment = conditionContext.getEnvironment();
        String property = environment.getProperty("os.name");
        return property.contains("Linux");
    }
}

3> 定义配置类,并在方法上标注注解

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
 
@Configuration
public class BeanConfig {

    @Conditional({WindowsCondition.class})
    @Bean(name = "bill")
    public User person1(){
        return new User(1L, "bill");
    }

    @Conditional({LinuxCondition.class})
    @Bean("linux")
    public User person2(){
        return new User(2L, "linux");
    }
}

4> 测试1

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 
import java.util.Map;
 
public class ConditionalTest {
 
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);
 
    @Test
	public void test1() {
	    String osName = applicationContext.getEnvironment().getProperty("os.name");
	    System.out.println("当前系统为:" + osName);
	    Map<String, User> map = applicationContext.getBeansOfType(User.class);
	    System.out.println(map);
	}
}

运行结果如下:

当前系统为:Windows 10
{bill=User(userId=1, userName=bill)}

5> 测试2:重新定义配置类,并在类上标注注解

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

@Configuration
@Conditional({WindowsCondition.class})
public class BeanConfig {

    @Bean(name = "bill")
    public User person1(){
        return new User(1L, "bill");
    }

    @Bean("linux")
    public User person2(){
        return new User(2L, "linux");
    }
}

运行结果如下:

当前系统为:Windows 10
{bill=User(userId=1, userName=bill), linux=User(userId=2, userName=linux)}

6> 测试3:多个条件

public class FalseCondition implements Condition {

    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
         return false;
    }
}

修改配置类BeanConfig:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

@Configuration
@Conditional({WindowsCondition.class, FalseCondition.class})
public class BeanConfig {

    @Bean(name = "bill")
    public User person1(){
        return new User(1L, "bill");
    }

    @Bean("linux")
    public User person2(){
        return new User(2L, "linux");
    }
}

运行结果如下:

当前系统为:Windows 10
{}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值