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
投稿

猜你喜欢

  • 教你怎么用java一键自动生成数据库文档

    2021-08-01 02:34:36
  • Zookeeper和Eureka哪个更好?

    2023-11-10 02:57:35
  • 详解spring-boot集成elasticsearch及其简单应用

    2021-08-26 01:09:58
  • Android仿简书搜索框效果的示例代码

    2023-06-18 16:02:58
  • 轻松理解Java面试和开发中的IoC(控制反转)

    2023-08-10 03:00:35
  • log4j2日志异步打印(实例讲解)

    2023-11-12 09:02:13
  • 关于spring的自定义缓存注解分析

    2023-11-28 17:02:50
  • Java内存模型(JMM)及happens-before原理

    2023-11-25 00:41:05
  • Java实现最小生成树算法详解

    2023-11-25 04:51:22
  • 关于SpringBoot使用Redis空指针的问题(不能成功注入的问题)

    2023-09-04 01:30:03
  • c#中CAD文件读取实例

    2023-07-23 19:37:59
  • Java中ArrayList初始化的四种方法详解

    2022-03-29 21:50:13
  • Android客户端与服务端数据加密传输方案详解

    2023-07-14 13:55:37
  • java文件操作练习代码 读取某个盘符下的文件

    2023-11-12 06:34:07
  • java 读取本地文件实例详解

    2023-08-12 20:41:32
  • androidQ sd卡权限使用详解

    2021-09-27 17:38:51
  • 详解Java Proxy动态 代理机制

    2023-07-24 21:01:58
  • java 读取excel文件转换成json格式的实例代码

    2023-09-11 13:07:28
  • Java的Hibernate框架中Criteria查询使用的实例讲解

    2023-08-22 23:25:47
  • SpringBoot项目中新增脱敏功能的实例代码

    2023-11-24 01:32:14
  • asp之家 软件编程 m.aspxhome.com