spring @Conditional的使用与扩展源码分析
作者:morris131 时间:2022-01-09 05:52:57
@Conditional的使用
@Conditional可以根据条件来判断是否注入某些Bean。
package com.morris.spring.config;
import com.morris.spring.condition.LinuxCondition;
import com.morris.spring.condition.WindowsCondition;
import com.morris.spring.entity.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ConditionalConfig {
// 如果是windows系统就注入bill
@Conditional(WindowsCondition.class)
@Bean(name = "user")
public User bill() {
return new User("bill", 22);
}
// 如果是linux系统就注入linus
@Conditional(LinuxCondition.class)
public User linus() {
return new User("linus", 20);
}
WindowsCondition和LinuxCondition都需要实现Condition接口。
WindowsCondition
package com.morris.spring.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class WindowsCondition implements Condition {
/**
* 根据条件判断是否注入对应的Bean
* @param conditionContext 应用上下文
* @param annotatedTypeMetadata 加了@Conditional注解的方法的元数据信息
* @return
*/
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
String osName = conditionContext.getEnvironment().getProperty("os.name");
if(osName.contains("Windows")) {
return true;
}
return false;
}
}
LinuxCondition
package com.morris.spring.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
String osName = conditionContext.getEnvironment().getProperty("os.name");
if(osName.contains("linux")) {
return true;
}
return false;
}
}
如果要测试LinuxCondition并不需要再linux系统下运行,只需要的启动时设置环境参数:-Dos.name=linux
。
Conditional的扩展
ConditionalOnBean
ConditionalOnBeanc.java
package com.morris.spring.condition;
import org.springframework.context.annotation.Conditional;
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnBean {
Class<?>[] value() default {};
}
OnBeanCondition.java
package com.morris.spring.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import java.util.Map;
public class OnBeanCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(ConditionalOnBean.class.getName());
Class<?>[] clazz = (Class<?>[]) annotationAttributes.get("value");
for (Class<?> aClass : clazz) {
Map<String, ?> beans = context.getBeanFactory().getBeansOfType(aClass);
if(beans.isEmpty()) {
return false;
}
}
return true;
}
}
ConditionalOnProperty
ConditionalOnProperty.java
package com.morris.spring.condition;
import org.springframework.context.annotation.Conditional;
import java.lang.annotation.*;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnPropertyCondition.class)
public @interface ConditionalOnProperty {
String[] value() default {};
}
OnPropertyCondition.java
package com.morris.spring.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import java.util.Map;
public class OnPropertyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(ConditionalOnProperty.class.getName());
String[] propertyArray = (String[]) annotationAttributes.get("value");
for (String property : propertyArray) {
if(!context.getEnvironment().containsProperty(property)) {
return false;
}
}
return true;
}
}
源码分析
如果Condition返回的是false,那么spirng就不会对方法或类进行解析。
org.springframework.context.annotation.ConditionEvaluator#shouldSkip
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
// 判断类或方法上面是否有@Conditional注解
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
return false;
}
if (phase == null) {
if (metadata instanceof AnnotationMetadata &&
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
}
return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
List<Condition> conditions = new ArrayList<>();
for (String[] conditionClasses : getConditionClasses(metadata)) {
for (String conditionClass : conditionClasses) {
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
conditions.add(condition);
AnnotationAwareOrderComparator.sort(conditions);
for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition) {
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
// 调用condition.matches方法
if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
return true;
return false;
}
来源:https://blog.csdn.net/u022812849/article/details/123729369
标签:spring,@Conditional,使用
0
投稿
猜你喜欢
Android开源AndroidSideMenu实现抽屉和侧滑菜单
2023-10-09 09:24:51
Java利用移位运算将int型分解成四个byte型的方法
2023-11-09 08:25:00
Android绘制仪表盘指针刻度
2022-06-17 03:23:07
Swagger2匹配多个controller代码实例
2022-07-31 03:42:24
C#探秘系列(三)——StackTrace,Trim
2022-04-27 21:24:03
Java 泛型总结及详解
2023-10-29 07:17:16
java实现简单的英文文本单词翻译器功能示例
2023-11-28 10:22:15
Java设计模式之java命令模式详解
2023-11-13 16:00:36
Android百度地图之方向感应和模式更改
2021-10-08 20:38:39
java生成图片验证码功能
2023-06-27 00:31:55
c# wpf如何更好的使用Application程序集资源
2021-09-30 16:22:17
SpringBoot操作mongo实现方法解析
2023-03-19 00:50:56
clion最新激活码+汉化的步骤详解(亲测可用激活到2089)
2023-07-17 08:03:53
带你详细了解Java值传递和引用传递
2023-02-19 08:42:26
Android 仿苹果IOS6开关按钮
2023-11-21 15:16:08
SpringBoot整合Web开发之Json数据返回的实现
2023-04-27 05:06:51
java结束进程的实例代码
2023-11-10 14:18:38
mybatis-plus分页查询的实现示例
2023-11-25 04:57:57
Java获取时间打印到控制台代码实例
2022-07-20 22:43:48
Android网格布局GridView实现漂亮的多选效果
2023-10-20 08:52:38