Spring条件装配
从 Spring Framework 3.1 开始,允许在 Bean 装配时增加前置条件判断
条件注解举例
Spring注解 | 场景说明 | 起始版本 |
---|---|---|
@Profile | 配置化条件装配 | 3.1 |
@Conditional | 编程条件装配 | 4.0 |
配置Profile Bean
在3.1版本中,Spring引入了bean frofile的功能。要使用profile,你首先要将所有不同的bean定义整理到一个或多个profile之中,在将应用部署到每个环境时,要确保对应的profile处于激活(active)状态。
@profile(“dev”)
@profile注解应用在类级别上。他会告诉Spring这个配置类中的bean只有在dev profile激活时才会创建。如果dev profile没有激活的话,那么带有@Bean注解的方法都会被忽略掉
当你有多个profile bean时,在运行期间只会创建一个bean,这取决于激活状态的是哪个profile
Spring在确定哪个profile处于激活状态是需要依赖两个独立的属性:spring.profiles.active和spring.profile.default。他会先查找有没有active设置如果没有再去查找default设置。如果都没有设置那就不会激活profile中的bean。
条件化的bean
假设你希望一个或多个bean只有在应用的类路径下包含特定的库时才创建。或者我们希望某个bean只要当另外某个特定的bean也声明了之后才会创建。我们还可能要求只有某个特定的环境变量设置之后,才会创建某个bean。
在Spring 4引入了一个新的@Conditional注解,他可以用到带有@Bean注解的方法上。如果给定的条件计算结果为true,就会创建这个bean,否则的话,这个bean就会被忽略。
基于配置方式实现 - @Profile
计算服务,多整数求和 sum:
@Profile(“Java7”) : for 循环实现
@Profile(“Java8”) : Lambda实现
定义一个计算服务接口
/**
* 计算服务
*/
public interface CalcService {
public Integer sum(Integer... values);
}
JAVA7 Profile for循环计算和
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
@Profile("java7")
@Service
public class Java7CalcService implements CalcService{
@Override
public Integer sum(Integer... values) {
System.out.println("Java 7 for循环实现");
int nums = 0;
for (int i = 0; i< values.length; i++) {
nums += values[i];
}
return nums;
}
}
JAVA8 Profile Lambda Stream流计算和
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
import java.util.stream.Stream;
@Profile("java8")
@Service
public class Java8CalcService implements CalcService{
@Override
public Integer sum(Integer... values) {
System.out.println("Java 8 Lambda实现");
return Stream.of(values).reduce(0,Integer::sum);
}
}
SpringBoo启动方式:
@SpringBootApplication(scanBasePackages = "com.pingjin.service")
public class CalcServiceBootstrap {
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(CalcServiceBootstrap.class)
.web(WebApplicationType.NONE)
.profiles("java8") //指定profile java8
.run(args);
CalcService calcService = context.getBean(CalcService.class);
System.out.println("最后值为:" + calcService.sum(1,2,3,4,5,6,7,8,9,10));
context.close();
}
}
输出结果:
基于编程方式实现 - @Conditional
根据系统属性条件化装配需要的Bean
自定义注解定义
import org.springframework.context.annotation.Conditional;
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnSystemPropertyCondition.class)
public @interface ConditionalOnSystemProperty {
//键
String name();
//值
String value();
}
OnSystemPropertyCondition实现Condition接口 实现自己条件装配判断:这里简单化将自己本机的系统user.name值用于判断
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import java.util.Map;
public class OnSystemPropertyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(ConditionalOnSystemProperty.class.getName());
String propertyName = String.valueOf(annotationAttributes.get("name"));
String propertyValue = String.valueOf(annotationAttributes.get("value"));
System.out.println("注解键值对为:" + propertyName + "->" + propertyValue);
String systemValue = System.getProperty(propertyName);
System.out.println("系统值:" + systemValue); //这里我的值为Anthony_One
return systemValue.equals(propertyValue);
}
}
SpringBoot项目启动运行:
public class SystemPropertyConditionBootstrap {
@Bean
@ConditionalOnSystemProperty(name = "user.name", value = "Anthony_One")
public String helloWorld() {
return "hello world";
}
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(SystemPropertyConditionBootstrap.class)
.web(WebApplicationType.NONE)
.run(args);
//条件装配不满足的时候,获取HelloWorld Bean的时候 会报异常 No bean named 'helloWorld' available
String helloWorld = context.getBean("helloWorld", String.class);
System.out.println("helloWorld Bean: " + helloWorld);
context.close();
}
}