spring @Conditional的使用与扩展源码分析

网友投稿 299 2022-08-17


spring @Conditional的使用与扩展源码分析

目录@Conditional的使用WindowsConditionlinuxConditionConditional的扩展ConditionalOnBeanConditionalOnProperty源码分析

@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 annotationAttributes = metadata.getAnnotationAttributes(ConditionalOnBean.class.getName());

Class>[] clazz = (Class>[]) annotationAttributes.get("value");

for (Class> aClass : clazz) {

Map 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;

ihttp://mport 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 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 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;

}


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Spring高级之注解@PropertySource的原理
下一篇:Netty启动步骤绑定端口源码分析
相关文章

 发表评论

暂时没有评论,来抢沙发吧~