Preface
Unique annotations are provided inside the Springboot: conditional annotations (Conditional Annotation). such as @conditionalonbean, @ConditionalOnClass, @ConditionalOnExpression, @ConditionalOnMissingBean and so on.
The meaning of conditional annotations lies in dynamic recognition (or code automation). For example, @conditionalonclass will check the class loader for the existence of a corresponding class, if any, the annotated class is eligible to be registered by the spring container, otherwise it will be skip. First, the condition annotation interior
Before analyzing the underlying implementation of conditional annotations, let's take a look at the definition of these conditional annotations. Take the @conditionalonclass annotation as an example, which is defined as follows:
@Target ({elementtype.type, elementtype.method})
@Retention (retentionpolicy.runtime)
@Documented
@ Conditional (onclasscondition.class) public
@interface Conditionalonclass {
class<?>[] value () default {}; Class required to match
string[] name () default {};//Required matching class name
}
It has 2 properties, namely, an array of classes and an array of strings (acting like a different type), and is decorated with @conditional annotations, and this @conditional annotation has a class< named values? Extends Condition >[] type properties. This condition is an interface that is used to match whether a component is eligible to be registered by a container, as defined below:
The public interface Condition {
///Conditioncontext internally stores the spring container, application environment information, resource Loader, ClassLoader, and Class loader
Boolean matches ( Conditioncontext context, annotatedtypemetadata metadata);
}
That is, the @conditional annotation attribute can hold multiple implementations of the condition interface, and all condition interfaces need to be successfully matched to the @conditional modified component to be eligible for registration.
The condition interface has sub-interface configurationcondition:
Public interface Configurationcondition extends Condition {
configurationphase getconfigurationphase ();
public static enum Configurationphase {
parse_configuration,
register_bean
}
}
This sub-interface is a special conditional interface, a Getconfigurationphase method, which is the effective phase of conditional annotations. Only the two stages defined in Configurationphase will take effect.
The condition interface has a conditional class that implements all the conditional annotations in the abstract class Springbootcondition,springboot inherit this abstract class. It implements the Matches method:
@Override Public Final Boolean matches (Conditioncontext context, Annotatedtypemetadata metadata) {String Classo Rmethodname = getclassormethodname (metadata); Get the class name or method name (the class or method that the conditional annotation can act on) try {conditionoutcome outcome = getmatchoutcome (context, metadata);//abstract method, concrete subclass implementation. Conditionoutcome recorded the match result Boolean and log information Logoutcome (classormethodname, outcome); Log records the matching information recordevaluation (context, classormethodname, outcome); The report records the matching information return Outcome.ismatch (); Returns whether the match} catch (Noclassdeffounderror ex) {throw new IllegalStateException ("Could not evaluate con Dition on "+ Classormethodname +" due to "+ ex.getmessage () +" not "+" found. Make sure your own configuration does not rely on ' + ' that class.
This can also happen if you is "+" @ComponentScanning a springframework package (e.g. if you " + "Put a @ComponentScan in the default PackaGE by mistake) ", ex); } catch (RuntimeException ex) {throw new IllegalStateException ("Error processing condition on" + GETN
Ame (metadata), ex);
}
}
second, class-based conditional annotations
Springboot provides two class-based conditional annotations: @ConditionalOnClass (the class loader has the specified class) or @conditionalonmissingclass (the class loader does not exist in the specified class).
The conditional class for the @ConditionalOnClass or @conditionalonmissingclass annotation is onclasscondition, which is defined as follows:
@Order (Ordered.highest_precedence)//priority, highest class Onclasscondition extends Springbootcondition {@Override public Conditionoutcome Getmatchoutcome (conditioncontext context, Annotatedtypemetadata metadata) {StringBuffer mat Chmessage = new StringBuffer (); Record matching information multivaluemap<string, object> onclasses = getattributes (metadata, Conditionalonclass.clas s); Gets the @conditionalonclass annotation property if (onclasses! = null) {//If the attribute exists list<string> missing = Getmatchingclass Es (onclasses, matchtype.missing, context); Get a class that does not exist in the ClassLoader (!missing.isempty ()) {//if there is no corresponding class in the ClassLoader, return a match failed conditionaloutcome return Cond Itionoutcome. NoMatch ("Required @ConditionalOnClass classes not found:" +
Stringutils.collectiontocommadelimitedstring (missing)); }//If there is a corresponding class in the ClassLoader, the matching information is recorded Matchmessage.append ("@ConditionalOnClass classes found: "+ stringutils.collectiontocommadelimitedstring (getmatchingclasses (onclasses,
Matchtype.present, context)); }//Do the same logical processing of @conditionalonmissingclass annotations (stating that @conditionalonclass and @conditionalonmissingclass can be used together) multivaluem
ap<string, object> onmissingclasses = getattributes (metadata, Conditionalonmissingclass.class); if (onmissingclasses! = null) {list<string> present = Getmatchingclasses (Onmissingclasses, Matchtype.presen
T, context); if (!present.isempty ()) {return conditionoutcome. NoMatch ("Required @ConditionalOnMissing
Classes found: "+ stringutils.collectiontocommadelimitedstring (present)); } matchmessage.append (matchmessage.length () = = 0?
"" : " "); Matchmessage.append ("@ConditionalOnMissing Classes not Found:" + STRINGUTILS.COLLECTIONTOCOMMADELIMITEDST Ring (GETMATchingclasses (onmissingclasses, matchtype.missing, context));
}//Return all matching successful conditionaloutcome return Conditionoutcome.match (matchmessage.tostring ()); } private enum MatchType {//enum: Match type.
Used to query whether the class name exists in the corresponding class loader.
PRESENT {///Match succeeded @Override public boolean matches (String ClassName, Conditioncontext context) {
Return Classutils.ispresent (ClassName, Context.getclassloader ()); }}, MISSING {///Match unsuccessful @Override public boolean matches (String ClassName, Conditioncontext Conte XT) {return!
Classutils.ispresent (ClassName, Context.getclassloader ());
}
};
Public abstract Boolean matches (String ClassName, conditioncontext context);
}
}
Springboot also provides other examples such as Conditionalonbean, Conditionalonjava, Conditionalonnotwebapplication, Conditionalonwebapplication, Conditionalonresource, Conditionalonproperty, conditionalonexpression and other conditions annotated, Interested readers can view their underlying processing logic on their own. Iii. Summary of the annotations of various conditions
Conditional Annotations |
the corresponding condition processing class |
processing Logic |
@ConditionalOnBean |
Onbeancondition |
Whether there is a corresponding instance in the Spring container. You can find it in the container by its type, class name, annotations, nickname (you can configure to find from the current container, or look in the parent container, or both). These properties are arrays and are searched with the relationship |
@ConditionalOnClass |
Onclasscondition |
The class loader has a corresponding class. Can be specified by the class designation (Value property) or by the full name of the class (Name property). In the case of multiple classes or multiple class names, relationships are "and" relationships, meaning that these classes or class names must be present in the ClassLoader as well |
@ConditionalOnExpression |
Onexpressioncondition |
Determine if the Spel expression is true |
@ConditionalOnJava |
Onjavacondition |
Specifies whether the Java version meets the requirements. There are 2 properties within the value and range. Value represents the Java version of an enumeration, and range represents a Java version that is older or newer than the specified (the default is new to equals). Internally, the class loader is queried based on certain JDK version-specific classes, such as JDK9, There is a need for java.security.cert.URICertStoreParameters in the ClassLoader, and in the case of JDK8, there is a need for java.util.function.Function in the ClassLoader, and in the case of Jdk7 the ClassLoader needs to exist Java.nio . file. Files; In the case of JDK6, there is a need for java.util.ServiceLoader in the ClassLoader |
@ConditionalOnMissingBean |
Onbeancondition |
The corresponding instance is missing from the spring container. You can find it in the container by its type, class name, annotations, nickname (you can configure to find from the current container, or look in the parent container, or both). There are 2 more attributes ignored (class name) and Ignoredtype (class name), which are ignored during the matching process. |
@ConditionalOnMissingClass |
Onclasscondition |
As with Conditionalonclass's processing logic, except for the condition, the corresponding class does not exist in the ClassLoader |
@ConditionalOnNotWebApplication |
Onwebapplicationcondition |
Whether the application is a non-web program, does not provide a property, just an identity. From the existence of a Web application-specific class, whether the environment is a servlet environment, whether the container is a web container, etc. |
@ConditionalOnProperty |
Onpropertycondition |
Whether there is a presence in the application environment. Provides prefix, name, Havingvalue, and Matchifmissing properties. Prefix represents the prefix of the property name, name is the property name, Havingvalue is the specific property value, Matchifmissing is a Boolean value, if the property does not exist, this matchifmissing is true, it will continue to verify, Otherwise, the property does not exist and is directly equivalent to the unsuccessful match. |
@ConditionalOnResource |
Onresourcecondition |
Whether the specified resource file exists. There is only one property resources, which is a string array. Queries for the existence of the corresponding resource file from the ClassLoader |
@ConditionalOnSingleCandidate |
Onbeancondition |
exists in the spring container and only has one corresponding instance. There are only 3 properties of value, type, search. Same as the 3 attribute values in Conditionalonbean. |
@ConditionalOnWebApplication |
Onwebapplicationcondition |
Whether the application is a Web program, does not provide a property, is just an identity. From the existence of a Web application-specific class, whether the environment is a servlet environment, whether the container is a web container, etc. |
Example |
meaning |
@ConditionalOnBean (Javax.sql.DataSource.class) |
An instance of at least one Javax.sql.DataSource class needs to exist in the spring container or all parent containers |
@ConditionalOnClass ({configuration.class,freemarkerconfigurationfactory.class}) |
The two classes of configuration and freemarkerconfigurationfactory must exist in a ClassLoader |
@ConditionalOnExpression ("' ${server.host} ' = = ' localhost ') |
The value of the Server.host configuration item needs to be localhost |
Conditionalonjava (Javaversion.eight) |
Java version is at least 8 |
@ConditionalOnMissingBean (value = errorcontroller.class, search = searchstrategy.current) |
Spring does not exist in the current container for errorcontroller types of beans |
@ConditionalOnMissingClass ("Genericobjectpool") |
The class Genericobjectpool cannot exist in the class loader |
@ConditionalOnNotWebApplication |
Must not take effect under a non-web app |
@ConditionalOnProperty (prefix = "SPRING.AOP", name = "Auto", Havingvalue = "true", matchifmissing = True) |
The Spring.aop.auto configuration must be present in the application's environment, and its value is true or the Spring.aop.auto configuration does not exist in the environment (Matchifmissing is true) |
@ConditionalOnResource (resources= "Mybatis.xml") |
Mybatis.xml file must exist in class load path |
@ConditionalOnSingleCandidate (Platformtransactionmanager.class) |
A Platformtransactionmanager instance of this type must exist in spring's current or parent container, and only one instance |
@ConditionalOnWebApplication |
Must be in the Web app before it takes effect |
iv. activation mechanism of springboot conditional annotations
If you want to know the activation mechanism of Springboot condition annotations, you can refer to the original article;
This article was reproduced from: https://www.jianshu.com/p/c4df7be75d6e