先看看@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
{}