spring @Conditional的使用与扩展源码分析
作者:morris131 发布时间:2022-01-09 05:52:57
标签:spring,@Conditional,使用
@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


猜你喜欢
- Android刚兴起的时候,着实让一些小众软件火了一把,切水果,Tom猫,吹裙子就是其中的代表,当然还有实用性很强的关机重启软件,我们去百度
- 本文实例讲述了Java基于解释器模式实现定义一种简单的语言功能。分享给大家供大家参考,具体如下:一 模式定 * 释器模式:就是给定一个语言的文
- Bezier Curve算法是根据参数曲线方程来得到光滑曲线的一种算法,曲线方程的参数由控制点决定。其本质是由调和函数根据控制点插值而成,其
- 一、Lombok从上一篇博客可看出,DAO接口类的编写变得简单,反过来看模型,编写还需要(私有属性、setter...getter...方法
- 一、定时任务1、cron表达式语法:秒 分 时 日 月 周 年(其中“年”Spring不支持,也就是说在spring定时任务中只能设置:秒
- 如下图所示,你的UI元素可能小于48dp,图标仅有32dp,按钮仅有40dp,但是他们的实际可操作焦点区域最好都应达到48dp的大小。为使小
- 这篇文章主要介绍了Spring Boot项目中定制 * 的方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价
- 前言 OFD是国家标准版式文档格式,于2016年生效。OFD文档国家标准参见《电子文件存储与交换格式版式文档》。既然是国家标准,O
- 本文开始做一个网上商城的项目,首先从搭建环境开始,一步步
- 前言偶然逛国外博客,看到了一个介绍文字动画的库,进入 pub 一看,立马就爱上这个动画库了,几乎你能想到的文字动画效果它都有!现在正式给大家
- 本文实例讲述了java在网页上面抓取邮件地址的方法。分享给大家供大家参考。具体实现方法如下:import java.io.BufferedR
- 比较适合新手。逻辑上仍然有点问题。可以用于学习java文件操作下载地址:http://yun.baidu.com/share/link?sh
- Java中的引用类型有哪几种?Java中的引用类型分成 强引用 , 软引用 , 弱引用 , 虚引用 。1、强引用没有引用指向这个对象,垃圾回
- 有时安全不得不考虑,看看新闻泄漏风波事件就知道了我们在用Spring boot进行开发时,经常要配置很多外置参数ftp、数据库连接信息、支付
- 前言记得去年做一个聊天项目需要实现类似QQ的下拉刷新并且有侧滑删除的功能,在网上找了很久都没有QQ的完美,多多少少存在各种的问题,最后把下拉
- 本文介绍了Flutter 实现下拉刷新上拉加载的示例代码,分享给大家,具体如下:效果图 使用方法添加依赖depende
- 本文实例讲述了WinForm判断关闭事件来源于用户点击右上角“关闭”按钮的方法。分享给大家供大家参考。具体如下:protected over
- 本文实例讲述了Android开发中使用外部应用获取SD卡状态的方法。分享给大家供大家参考,具体如下:先来看看常规获取SD卡状态的方法if (
- RecyclerView的使用比ListView的使用是比较复杂的,ListView的使用是五个步骤,而我们的RecyclerView的使用
- 如下所示:using System;using System.Collections.Generic;using System.Text;n