spring of @ConditionalOnMissingBean comment

Spring4 launched @Conditional comment, convenient program to dynamically inject bean container based on the current environment or circumstances, @Conditional notes are not familiar with the venue to Spring @Conditional friends can comment and explain in detail an example of this blog to learn.

Following @Conditional notes, and based on this comment introduced many derived annotations such as @ ConditionalOnBean, @ ConditionalOnMissingBean, @ ConditionalOnExpression, @ ConditionalOnClass ...... dynamically inject bean easier than ever. This article deals explain @ConditionalOnBean comment.

There are two configuration classes bean Computer classes, a notebook computer, a computer is a spare. If the current bean container has a computer, the standby computer is not injected, and if not, injecting secondary device, needs to be used to @ConditionalOnMissingBean.

@Configuration
public class BeanConfig {

@Bean (name = "NotebookPC")
public Computer Computer1 () {
return new new Computer ( "laptop");
}

@ConditionalOnMissingBean (Computer.class)
@Bean ( "reservePC")
public Computer Computer2 ( ) {
return new new computer ( "backup computer");
}
}
this annotation on the realization of functions, this @ConditionalOnMissingBean for us to do anything at all? We take a closer look ..

Check it out:
First, look at @ConditionalOnMissingBean statement:

// can be marked on the classes and methods
@Target ({ElementType.TYPE, ElementType.METHOD})
@Retention (RetentionPolicy.RUNTIME)
@Documented
// use @Conditional annotation condition class is OnBeanCondition
@Conditional ({OnBeanCondition.class })
public @interface ConditionalOnMissingBean {
<?> Class [] value () {} default;

String [] type () {} default;

Class [] ignored () {} default <?>;

String [] ignoredType () default } {;

Class [] Annotation () {} default <the extends Annotation?>;

String [] name () {} default;

SearchStrategy Search () default SearchStrategy.ALL;
}
At this time, we see the familiar @Conditional notes, OnBeanCondition as a condition of class.

OnBeanCondition class declaration:

// sort order defined annotated assembly, 2147483647 is the default value
the @Order (2147483647)
class OnBeanCondition the extends SpringBootCondition the implements ConfigurationCondition {
which inherits the class SpringBootCondition, OnBeanCondition matches method is not a class, the class has implemented SpringBootCondition matches method. OnBeanCondition also achieved ConfigurationCondition, ConfigurationCondition readers not familiar with the interface to the Spring ConfigurationCondition Interface Detailed understand interface. OnBeanCondition class overrides getConfigurationPhase () method to indicate annotations take effect at the time of registration of the bean:

ConfigurationPhase getConfigurationPhase public () {
return ConfigurationPhase.REGISTER_BEAN;
}
starts from matches method:

// matches method SpringBootCondition class
public Boolean Final The matches (ConditionContext context, AnnotatedTypeMetadata Metadata) {
// get the current class name or method name (denoted by positioning)
String classOrMethodName = getClassOrMethodName (Metadata);

the try {
// Key Code: here will be judged result
ConditionOutcome outcome this.getMatchOutcome = (context, Metadata);
// log stored
this.logOutcome (classOrMethodName, outcome);
// record into the
this.recordEvaluation (context, classOrMethodName, outcome) ;
// the last return ConditionOutcome return a boolean result is isMatch
return outcome.isMatch ();
} the catch (a NoClassDefFoundError var5) {
throw new IllegalStateException("Could not evaluate condition on " + classOrMethodName + " due to " + var5.getMessage() + " not found. Make sure your own configuration does not rely on that class. This can also happen if you are @ComponentScanning a springframework package (e.g. if you put a @ComponentScan in the default package by mistake)", var5);
} catch (RuntimeException var6) {
throw new IllegalStateException("Error processing condition on " + this.getName(metadata), var6);
}
}
关键代码在OnBeanCondition的getMatchOutcome方法上:

/ **
* method for obtaining the determination result, ConditionOutcome class deposit with the results of the boolean
* /
public ConditionOutcome getMatchOutcome (ConditionContext context, AnnotatedTypeMetadata Metadata) {
// Returns a new ConditionMessage
ConditionMessage matchMessage ConditionMessage.empty = ();
OnBeanCondition. spec BeanSearchSpec;
List matching;
// this is the metadata will call isAnnotated method to determine the current annotation is not marked ConditionalOnMissingBean
// actually @ ConditionalOnBean, @ ConditionalOnMissingBean and @ConditionalOnSingleCandidate are using this condition category, so here make a judgment
if (metadata.isAnnotated (ConditionalOnBean.class.getName ())) {
spec = new new OnBeanCondition.BeanSearchSpec (context, Metadata, ConditionalOnBean.class);
matching this.getMatchingBeans = (context, spec);
IF (matching.isEmpty ()) {
return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnBean.class, new Object[]{spec}).didNotFind("any beans").atAll());
}

matchMessage = matchMessage.andCondition(ConditionalOnBean.class, new Object[]{spec}).found("bean", "beans").items(Style.QUOTE, matching);
}

if (metadata.isAnnotated(ConditionalOnSingleCandidate.class.getName())) {
OnBeanCondition.BeanSearchSpec spec = new OnBeanCondition.SingleCandidateBeanSearchSpec(context, metadata, ConditionalOnSingleCandidate.class);
matching = this.getMatchingBeans(context, spec);
if (matching.isEmpty()) {
return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnSingleCandidate.class, new Object[]{spec}).didNotFind("any beans").atAll());
}

IF (! This.hasSingleAutowireCandidate (context.getBeanFactory (), matching, spec.getStrategy () == SearchStrategy.ALL)) {
return ConditionOutcome.noMatch (ConditionMessage.forCondition (ConditionalOnSingleCandidate.class, new new Object [] {} spec) .didNotFind ( "A Primary from the bean Beans") items (Style.QUOTE, matching));.
}

matchMessage = matchMessage.andCondition (ConditionalOnSingleCandidate.class, new new Object [] {} spec) found ( "A Primary Beans from the bean. ") .items (Style.QUOTE, matching);
}

// if the current is injected bean @ConditionalOnMissingBean
IF (metadata.isAnnotated (ConditionalOnMissingBean.class.getName ())) {
// return a spec (below), where spec provides content search, such as the class name search strategies need to search ......
= new new OnBeanCondition.BeanSearchSpec spec (context, Metadata, ConditionalOnMissingBean.class);
// main search method implemented in this, and finally returns a List
matching this.getMatchingBeans = (context, spec);
// search out the results determined
if (! matching.isEmpty ()) {
return ConditionOutcome.noMatch (ConditionMessage.forCondition (ConditionalOnMissingBean.class, new new Object [] {} spec). found ( "the bean", "Beans"). items (Style.QUOTE, matching) );
}

matchMessage = matchMessage.andCondition (ConditionalOnMissingBean.class, new new Object [] {} spec) didNotFind ( "the any Beans") atall ();..
}

return ConditionOutcome.match (matchMessage);
}
spec = new new OnBeanCondition.BeanSearchSpec (context, metadata, ConditionalOnBean.class);

The sentence, attributes corresponding to the annotation from the annotation @ConditionalOnMissingBean taken out in an internal class:

BeanSearchSpec(ConditionContext context, AnnotatedTypeMetadata metadata, Class<?> annotationType) {
this.annotationType = annotationType;
MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(annotationType.getName(), true);
//将attributes这个map中的数据放到对应的list成员变量中
this.collect(attributes, "name", this.names);
this.collect(attributes, "value", this.types);
this.collect(attributes, "type", this.types);
this.collect(attributes, "annotation", this.annotations);
this.collect(attributes, "ignored", this.ignoredTypes);
this.collect(attributes, "ignoredType", this.ignoredTypes);
this.strategy = (SearchStrategy)metadata.getAnnotationAttributes(annotationType.getName()).get("search");
OnBeanCondition.BeanTypeDeductionException deductionException = null;

try {
if (this.types.isEmpty() && this.names.isEmpty()) {
this.addDeducedBeanType(context, metadata, this.types);
}
} catch (OnBeanCondition.BeanTypeDeductionException var7) {
deductionException = var7;
}

this.validate(deductionException);
}

//验证的方法
protected void validate(OnBeanCondition.BeanTypeDeductionException ex) {
if (!this.hasAtLeastOne(this.types, this.names, this.annotations)) {
String message = this.annotationName() + " did not specify a bean using type, name or annotation";
if (ex == null) {
throw new IllegalStateException(message);
} else {
new new IllegalStateException the throw (the Message + "and at The attempt to deduce at The bean's of the type failed The", EX);
}
}
}
look getMatchingBeans method OnBeanCondition class, which is useful to the search strategy, see the search strategy presentation

List Private <String> getMatchingBeans (ConditionContext context, OnBeanCondition.BeanSearchSpec Beans) {
// get the current bean plants
ConfigurableListableBeanFactory context.getBeanFactory beanFactory = ();
// current search strategy determines whether or PARENTS ANCESTORS, defaults to ALL
IF (Beans .getStrategy () == SearchStrategy.PARENTS beans.getStrategy || () == SearchStrategy.ANCESTORS) {
the BeanFactory parent beanFactory.getParentBeanFactory = ();
Assert.isInstanceOf (ConfigurableListableBeanFactory.class, parent, "Unable to use SearchStrategy.PARENTS" );
// if PARENTS or ANCESTORS, the current parent plant with the factory bean
beanFactory = (ConfigurableListableBeanFactory) parent;
}

IF (beanFactory == null) {
return Collections.emptyList ();
} the else {
List <String> = beanNames new new ArrayList ();
// if the current search strategy equal to CURRENT, as to true
boolean considerHierarchy beans.getStrategy = () = SearchStrategy.CURRENT;!
// here is the need to find the type of bean types
// Hereinafter, the properties will find from the bean
the Iterator var6 = beans.getTypes () Iterator ();.

String the beanName;
the while (var6.hasNext ()) {
the beanName = (String) var6.next ();
// if the type found , instance name, the name of the method to find the next sample is to look at the bottom depending on the type of the bean, is actually a getNamesForType
beanNames.addAll (this.getBeanNamesForType (beanFactory, the beanName, context.getClassLoader (), considerHierarchy));
}

var6 = . beans.getIgnoredTypes () Iterator ();

the while (var6.hasNext ()) {
the beanName = (String) var6.next ();
beanNames.removeAll (this.getBeanNamesForType (beanFactory, beanName, context.getClassLoader (), considerHierarchy));
}

Var6 beans.getAnnotations = (). Iterator ();

While (var6.hasNext ()) {
beanName = (String) var6.next ();
beanNames.addAll (Arrays.asList (this.getBeanNamesForAnnotation (beanFactory, beanName, context.getClassLoader (), considerHierarchy)));
}

Var6 beans.getNames = (). Iterator ();

While (var6.hasNext ()) {
beanName = (String) var6.next ();
IF (this.containsBean (beanFactory, beanName, considerHierarchy)) {
beanNames.add (beanName);
}
}
// woman将存放实例名的返回list
Return beanNames;
}
}



// woman根据类型获取的name
private Collection<String> getBeanNamesForType(ListableBeanFactory beanFactory, String type, ClassLoader classLoader, boolean considerHierarchy) throws LinkageError {
try {
Set<String> result = new LinkedHashSet();
this.collectBeanNamesForType(result, beanFactory, ClassUtils.forName(type, classLoader), considerHierarchy);
return result;
} catch (ClassNotFoundException var6) {
return Collections.emptySet();
} catch (NoClassDefFoundError var7) {
return Collections.emptySet();
}
}

private void collectBeanNamesForType(Set<String> result, ListableBeanFactory beanFactory, Class<?> type, boolean considerHierarchy) {
result.addAll(BeanTypeRegistry.get(beanFactory).getNamesForType(type));
IF (considerHierarchy && beanFactory the instanceof HierarchicalBeanFactory) {
the BeanFactory parent = ((HierarchicalBeanFactory) beanFactory) .getParentBeanFactory ();
IF (the instanceof ListableBeanFactory parent) {
this.collectBeanNamesForType (Result, (ListableBeanFactory) parent, type, considerHierarchy);
}
}

}
find after completion of bean, back to just the code:

// If the current is injected bean @ConditionalOnMissingBean
IF (metadata.isAnnotated (ConditionalOnMissingBean.class.getName ())) {
// return a spec (description), spec here provides content search, such as search strategy, we need to search the class name ......
spec = new new OnBeanCondition.BeanSearchSpec (context, Metadata, ConditionalOnMissingBean.class);
matching this.getMatchingBeans = (context, spec);
IF (! matching.isEmpty ()) {
return ConditionOutcome.noMatch (. ConditionMessage.forCondition (ConditionalOnMissingBean.class, new new Object [] {} spec) found ( "the bean", "Beans") items (Style.QUOTE, matching).);
}

matchMessage = matchMessage.andCondition (ConditionalOnMissingBean.class, . new new Object [] {} spec) didNotFind ( "the any Beans") atall ();.
}
If the return line 5 list is not empty, the object returns ConditionOutcome noMatch method represents a mismatch. ConditionOutcome filter class for storing a result, only two variables:

/ **
* Results based filter
* /
public class ConditionOutcome {
/ **
* matching results or to false to true
* /
Private Final Boolean match;
/ **
* matching result information
* /
Private ConditionMessage Final Message;
two differences:
@ConditionOnBean in when judging list, if the list has no value, it returns false, true otherwise

@ConditionOnMissingBean when the judge list, and if the list has no value, returns true, otherwise it returns false, the other are the same logic

Examples:
@ConditionalOnBean (javax.sql.DataSource.class)    
the Spring container or require the presence of all parent vessel at least one instance of the class javax.sql.DataSource

 

Guess you like

Origin www.cnblogs.com/YuyuanNo1/p/12511121.html