Springboot Series (11) The underlying implementation of conditional annotations

Source: Internet
Author: User
Tags abstract aop stringbuffer
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

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.