Springboot sentiment Edify-@Conditional and @autoconfigureafter annotation analysis

Source: Internet
Author: User

To undertake the previous text springboot sentiment edify [email protected] annotation analysis, this article will be on the basis of the previous article @AutoConfigureAfter and explain @Conditional the role of annotation and analysis

[Email protected]

According to the word, it is the meaning of the condition. We can look at the internal source code before the analysis.

@Target({ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Conditional {    /**     * All {@link Condition}s that must {@linkplain Condition#matches match}     * in order for the component to be registered.     */    Class<? extends Condition>[] value();}

It acts on a class, method, and the specified value must be an implementation class of Org.springframework.context.annotation.Condition for the condition to be judged.
The annotations that are expanded on this basis include,,, and @ConditionalBean @ConditionalOnWebApplication @ConditionalOnClass @ConditionalOnMissingBean so on.

@Conditional annotations are parsed into the portal

Then we would like to know how the annotations are parsed. In fact, in the preceding ConfigurationClassParser class, the following code is executed before the real Doprocessconfigurationclass () method is executed

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {        // 条件判断,不满足则直接返回,不进行后续的解析        if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {            return;        }        ....        // Recursively process the configuration class and its superclass hierarchy.        SourceClass sourceClass = asSourceClass(configClass);        do {            sourceClass = doProcessConfigurationClass(configClass, sourceClass);        }        while (sourceClass != null);        this.configurationClasses.put(configClass, configClass);    }

That is, the above ConditionEvaluator#shouldSkip() method is executed, and the true annotation parsing is performed only if the condition is met @Configuration .

Conditionevaluator#shouldskip ()

Don't say much nonsense, directly on the source

    Metadata is the annotated class element, and a return value of TRUE indicates that the condition does not meet the public boolean shouldskip (@Nullable annotatedtypemetadata metadata, which should be ignored, @Nulla BLE configurationphase phase) {//1. Determine if the class contains @conditional annotations, otherwise return directly if (metadata = = NULL | |!metadata.isannota        Ted (Conditional.class.getName ())) {return false; } if (phase = = null) {if (metadata instanceof annotationmetadata && Configur Ationclassutils.isconfigurationcandidate ((annotationmetadata) metadata) {return Shouldskip (metadata, Conf            Igurationphase.parse_configuration);        } return Shouldskip (metadata, Configurationphase.register_bean); }//2. Gets all the value collections on the class that contain @conditional annotations (which recursively look for annotations) list<condition> conditions = new Arraylist<> (        ); For (string[] conditionclasses:getconditionclasses (metadata)) {for (String conditionclass:conditionclasses ) {Condition Condition = getcondition (CondiTionclass, This.context.getClassLoader ());            Conditions.add (condition);                }}//3. Sort by order annotationawareordercomparator.sort (conditions);            4. Condition unified Call to the matches () method in the collection, once return false and the required phase is consistent, the condition does not satisfy for (Condition condition:conditions) {            Configurationphase requiredphase = null; if (condition instanceof configurationcondition) {requiredphase = ((configurationcondition) condition). Get            Configurationphase (); } if ((Requiredphase = = NULL | | requiredphase = = phase) &&!condition.matches (This.context, metadata))            {return true;    }} return false; }

The specific code explanation has been given in accordance with the comments, in fact, it is very simple, the reader can understand a little reading. So additional annotations such as @ConditionalOnMissingBean readers can read the code analysis on their own, the author does not expand here

[Email protected]

@AutoConfigureBeforeIn contrast, the meaning of the representation is that it is automatically injected before or after the class is loaded. First look at its internal source code

@Retention(RetentionPolicy.RUNTIME)@Target({ ElementType.TYPE })@Documentedpublic @interface AutoConfigureAfter {    /**     * The auto-configure classes that should have already been applied.     * @return the classes     */    Class<?>[] value() default {};    /**     * The names of the auto-configure classes that should have already been applied.     * @return the class names     * @since 1.2.2     */    String[] name() default {};}

Used only on classes, internal properties name indicate Beandefinition's class full path, and internal properties value indicate beandefinition classes. So how is it parsed, and also based on the previous ConfigurationClassParser#parse() method, as follows

    public void parse(Set<BeanDefinitionHolder> configCandidates) {        this.deferredImportSelectors = new LinkedList<>();        // 解析@Configuration注解        ....        // 解析DeferredImportSelector接口类,表面上也就是延迟解析的意思        processDeferredImportSelectors();    }

The author only focuses on the processdeferredimportselectors () method, which can be used to detect @AutoConfigureAfter traces of such annotations.

Configurationclassparser#processdeferredimportselectors ()

Read the source directly

    private void Processdeferredimportselectors () {//1. Processimport () method to get the Deferredimportselector interface set, no direct return        list<deferredimportselectorholder> deferredimports = this.deferredimportselectors;        This.deferredimportselectors = null;        if (deferredimports = = null) {return;        }//2. Sort Deferredimports.sort (Deferred_import_comparator); 3. Traverse the Deferredimportselector interface collection, get the Group collection class, default to Defaultdeferredimportselectorgroup Map<object,        deferredimportselectorgrouping> groupings = new linkedhashmap<> ();        Map<annotationmetadata, configurationclass> configurationclasses = new hashmap<> ();            for (Deferredimportselectorholder deferredimport:deferredimports) {//notice this ..... class<?            Extends group> Group = Deferredimport.getimportselector (). Getimportgroup ();             deferredimportselectorgrouping grouping = groupings.computeifabsent (       (group = null? group:deferredimport), Key-New deferredimportselectorgrouping (Creategro            Up (group));            Grouping.add (Deferredimport); Configurationclasses.put (Deferredimport.getconfigurationclass (). GetMetaData (), Deferredimport.getconfig        Urationclass ()); }//4.            Traversing the group collection, the function is to call the Processimport () method for parsing @import for (deferredimportselectorgrouping grouping:groupings.values ()) { Grouping.getimports (). ForEach (entry, {configurationclass ConfigurationClass = Configuration                Classes.get (Entry.getmetadata ());                            try {processimports (ConfigurationClass, Assourceclass (ConfigurationClass),                Assourceclasses (Entry.getimportclassname ()), false);                } catch (Beandefinitionstoreexception ex) {throw ex; } catch (Throwable ex) {throw nEW beandefinitionstoreexception ("Failed to process import candidates for configuration class [                "+ Configurationclass.getmetadata (). GetClassName () +"] ", ex);        }            }); }    }

The author and reader here only need to pay attention to deferredImport.getImportSelector().getImportGroup() this method, here as an AutoConfigurationImportSelector.class example

Autoconfigurationimportselector

First look at its getimportgroup () method

public Class<? extends Group> getImportGroup() {        return AutoConfigurationGroup.class;    }

Then observe the AutoConfigurationGroup selectimports () method of this class

        public Iterable<Entry> selectImports() {            return sortAutoConfigurations().stream()                    .map((importClassName) -> new Entry(this.entries.get(importClassName),                            importClassName))                    .collect(Collectors.toList());        }

The key is here, just in the sortautoconfigurations () method, which sorts the imported class classes through the Autoconfigurationsorter class, as to how to sort we keep looking down.

Autoconfigurationsorter

Sorting method Getinpriorityorder (), let's look at the source code

    public List<String> getInPriorityOrder(Collection<String> classNames) {        AutoConfigurationClasses classes = new AutoConfigurationClasses(                this.metadataReaderFactory, this.autoConfigurationMetadata, classNames);        List<String> orderedClassNames = new ArrayList<>(classNames);        // Initially sort alphabetically.首先根据ASCII来进行排序        Collections.sort(orderedClassNames);        // Then sort by order,再根据Order来进行排序        orderedClassNames.sort((o1, o2) -> {            int i1 = classes.get(o1).getOrder();            int i2 = classes.get(o2).getOrder();            return Integer.compare(i1, i2);        });        // Then respect @AutoConfigureBefore @AutoConfigureAfter        orderedClassNames = sortByAnnotation(classes, orderedClassNames);        return orderedClassNames;    }

It can be concluded that the most critical sort from the sortbyannotation () method, specifically not looked at, is nothing more than according to Before/after, to the importclassname to sort out an ordered set.

Finally go back to the last paragraph of the Configurationclassparser#processdeferredimportselectors () method, which will have an ordered set traversal operation processImports() Method, If the corresponding class class does not exist, it will be an error, also satisfies the meaning of autoconfigurebefore/autoconfigureafter .

Summary

For @Conditional and @AutoConfigureAfter specific analysis can be seen above, this article is also a supplement to the previous article. Readers are expected to read this article and be sure to read the preceding article to understand the meaning of the code above. At the same time, because these two annotations are conditional, it is very important for the springboot to use the two annotations to match the dependent deployment to build different conditions. WebMvcAutoConfigurationEnd With class

@Configuration@ConditionalOnWebApplication(type = Type.SERVLET)@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,        ValidationAutoConfiguration.class })public class WebMvcAutoConfiguration {}

Springboot sentiment edify [email protected] and @autoconfigureafter annotation parsing

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.