docs/Spring全家桶/Spring源码分析/Spring重要机制探秘/ConfigurationClassPostProcessor(四):处理@Conditional注解.md
ConfigurationClassPostProcessor ĵƪҪǷ spring @Conditional עĴ̡
@Conditional Ĵǰ ConfigurationClassParser#processConfigurationClass ʱôһУ
class ConfigurationClassParser {
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
// жǷҪ @Conditional ע⣬жǷ
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(),
ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
...
}
...
}
conditionEvaluator.shouldSkip(...) @Conditional עģĴ̣ٷʲô @Conditional ע⣺
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
/**
*
*/
Class<? extends Condition>[] value();
}
@Conditional עdzһԣֵ Class[]ұ Condition ࡣ Condition
public interface Condition {
/**
* ָƥ
*/
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
Condition ӿڽһ matches ǿָƥ
conditionEvaluator.shouldSkip(...) Ĵ̣
class ConditionEvaluator {
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata,
@Nullable ConfigurationPhase phase) {
// Ƿ @Conditional
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
return false;
}
// жϴ phase
if (phase == null) {
if (metadata instanceof AnnotationMetadata &&
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
}
return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
}
// ʵ condition conditions
List<Condition> conditions = new ArrayList<>();
// 1\. getConditionClasses(metadata)ȡ @Conditional ָж
for (String[] conditionClasses : getConditionClasses(metadata)) {
for (String conditionClass : conditionClasses) {
// 2\. ʵõĻǷ䣩ͳһŵ conditions
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
conditions.add(condition);
}
}
// 3\. õ condition ʵ
AnnotationAwareOrderComparator.sort(conditions);
// õ conditions
for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition) {
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}
// 4\. Condition#matches ж
if ((requiredPhase == null || requiredPhase == phase) &&
!condition.matches(this.context, metadata)) {
return true;
}
}
return false;
}
...
}
÷Ĵ£
@Conditional ָж࣬ @Conditional value ֵconditionsǸ List Уconditionsconditions Condition#matches ƥ䡣@Conditional ĴǷdzģʹʾ
@Conditional ʹʾʵָܣָʱŽ spring bean Ĵʼ£
һ bean:
public class BeanObj {
}
ʵ Condition ӿڣﴦж
public class MyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String className = "java.lang.Object";
try {
// жǷ
Class.forName(className);
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
}
matches(...) ָ className Ϊ java.lang.ObjectȻжǷڣжϷʽҲ ʮּ ʹ java ķƣClass.forName(...)ʱ׳ ClassNotFoundExceptionǿԲ쳣Ӷ֪ڲˡ
@ComponentScan
public class BeanConfigs {
@Bean
@Conditional(MyCondition.class)
public BeanObj beanObj() {
return new BeanObj();
}
}
ȽϼҪע beanObj() ϵ @Conditional ע⣬ָƥ MyConditionƥнеġ
public class Demo06Main {
public static void main(String[] args) {
ApplicationContext context
= new AnnotationConfigApplicationContext(BeanConfigs.class);
try {
Object obj = context.getBean("beanObj");
System.out.println("beanObj ڣ");
} catch (Exception e) {
System.out.println("beanObj ڣ");
}
}
}
У£
beanObj ڣ
MyCondition#matches УжϵǵǰĿǷ java.lang.ObjectȻǴڵģ beanObj spring Уǻ className:
public class MyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//
String className = "java.lang.Object111";
...
}
}
Ȼjava.lang.Object111 DzڵǰĿеģУ£
beanObj ڣ
ʾ 1 Уͨ MyCondition#matches className ı beanObj еĴĿзdzҪĴмأʵֶ MyCondition
磬 A Ҫ A1 ĴжǷгʼ B Ҫ B1 ĴжǷгʼ C Ҫ C1 ĴжǷгʼ... ǷҪֱΪA``B``C ʵ ConditionڸԵ match(...) нж
ʵϣDzҪôͨ spring עķϹܡ
һ beanʾ 1
public class BeanObj {
}
ע @ConditionalForClassע @Conditional ĹܣƥΪ MyCondition``className ԾDZڵࣺ
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
// @Conditional ĹܣƥΪ MyCondition
@Conditional(MyCondition.class)
public @interface ConditionalForClass {
/**
* ָڵ
*/
String className();
}
MyConditionעʾIJڣclassName ڸ÷ж壬 @ConditionalForClass 룺
public class MyCondition implements Condition {
/**
* ﴦƥעʾ1е
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// ȡ @ConditionalForClass עֵ
Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(
ConditionalForClass.class.getName());
// ȡclassNameֵ @ConditionalForClass className
String className = (String)annotationAttributes.get("className");
if(null == className || className.length() <= 0) {
return true;
}
try {
// жǷ
Class.forName(className);
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
}
࣬ʱעΪ @ConditionalForClass
@ComponentScan
public class BeanConfigs {
@Bean
/**
* @ConditionalForClass ָ
*/
@ConditionalForClass(className = "java.lang.Object")
public BeanObj beanObj() {
return new BeanObj();
}
}
࣬ʾ 1
public class Demo07Main {
public static void main(String[] args) {
ApplicationContext context
= new AnnotationConfigApplicationContext(BeanConfigs.class);
try {
Object obj = context.getBean("beanObj");
System.out.println("beanObj ڣ");
} catch (Exception e) {
System.out.println("beanObj ڣ");
}
}
}
ͨԶע @ConditionalForClass ָ java.lang.Object ʱbeanObj Żᱻӵ spring УȻУ£
beanObj ڣ
@ConditionalForClass className ֵ
@ComponentScan
public class BeanConfigs {
@Bean
// @ConditionalForClassclassNameֵ
@ConditionalForClass(className = "java.lang.Object1111")
public BeanObj beanObj() {
return new BeanObj();
}
}
ォ @ConditionalForClass className ֵΪ java.lang.Object1111ȻಢڵǰĿУн£
beanObj ڣ
Ҳǵһ¡
ǻصڿͷ⣺磬 A Ҫ A1 ĴжǷгʼ B Ҫ B1 ĴжǷгʼ C Ҫ C1 ĴжǷгʼ... ǷҪֱΪA``B``C ʵ ConditionڸԵ match(...) нж
@ConditionalForClass עDzҪô鷳ֻҪڸԵ @Bean @ConditionalForClass ˣ
@Bean
@ConditionalForClass(className = "A1")
public A a() {
return new A();
}
@Bean
@ConditionalForClass(className = "B1")
public B b() {
return new B();
}
@Bean
@ConditionalForClass(className = "B1")
public C c() {
return new C();
}
...
ע @ConditionalForClass ʵ֣springboot е @ConditionalOnClass ǰ˼·ʵֵġ
Ҫ spring @Conditional ̣Ƚϼյõ Condition#matches ƥģƥ Condition ʵָ
Ϊ˸õ˵ @Conditional ʹãʹʾرʾ 2Ҫرᣬspringboot е @ConditionalOnClass ǻʾ 2 ˼·ʵֵģ⣬springboot еĶעҲǶ @Conditional չ
ԭӣhttps://my.oschina.net/funcy/blog/4873444 ߸ˮƽд֮ӭָԭףҵתϵȨҵתע