preface

Spring Boot is an epoch-making product in the Spring family. It develops from but is superior to the Spring Framework, which is mainly reflected in its three most important features. More important of these three features is Spring Boot’s AutoConfiguration. More “smart” than automatic, the framework seems “smarter”. Therefore, it has become the logical infrastructure to build microservices, firmly in the number one position.

Life is about making choices. The same is true of programming. Any decision can be a double-edged sword. Automatic configuration of Spring Boot solves many of the pain points of using the Spring Framework, making development efficiency exponentially higher. . It is because it is so intelligent that if something goes wrong, it will make the programmer black in the eyes and have no way to start.

In spite of the flaws, Spring Boot is moving forward in a big way

I just received a request the other day to use @AutoConfigureBefore to control the configuration order, but it didn’t work. In this article, we will discuss the correct position to use @AutoConfigureBefore, @AutoConfigureAfter, and @AutoConfigureOrder to control the automatic configuration execution sequence.

Tip: The automatic configuration of Spring Boot is driven by the @enableAutoConfiguration annotation, which is enabled by default. You can also through the spring. The boot. Enableautoconfiguration = false to shut it down, back to the spring Framework. Obviously, that is not the subject of this article


The body of the

This article will talk about the focus of Spring Boot automatic configuration + sequence control, automatic configuration everyone is familiar with, so “first” is to know this question: configuration class execution why control order?


Why do configuration classes need order?

We already know that the Spring container initializes beans out of Order, and we can’t take it for granted that the @order annotation controls their execution Order. In general, for ordinary beans in the container, we only need to care about dependencies, not the absolute order, and Spring does a good job of managing dependencies.

It is also a Bean, but for a Configuration class, the order of execution is required and guaranteed in certain scenarios. For example, A typical case of either A or B: if A already exists in the container, do not put B in it. In this case, the “judgment” of A must be placed before THAT of B, otherwise it may cause problems in the program.

How does the configuration order work in traditional Spring and Spring Boot?


Spring controls the configuration execution sequence

In the traditional Spring Framework, an @Configuration annotation represents a Configuration class. When there are multiple @Configurations, the order in which they are executed is manually specified by the user, like this:

The order of the / / manual control Config1 Config2 ApplicationContext context = new AnnotationConfigApplicationContext (Config1. Class, Config2.class);Copy the code

Of course, you might doubt said: even in traditional Spirng, I also never own use AnnotationConfigApplicationContext to display the load Configuration, are using the @ the Configuration defined Configuration after class, click the Run a business. Yes, that’s because you’re using Spring in a Web environment, and the IoC container is driven by a Web container (such as Tomcat, etc.), which Spring encapsulates so well that it’s almost oblivious to the user.

This part of the content, I will not go into the details here, after all, this article is not focused on that. There are two general ways in which @Configuration can be loaded into containers:

  1. Manually. buildApplicationContextIs passed in manually by the builder, and the order can be manually controlled
  2. Automatically. be@ComponentScanScan in automatically. Can’t control the sequence

Most of the time we do this automatically, so there is no sense of configuration order under Spring. This is really need-driven, because in traditional Spring we don’t have this need, so it’s logical not to feel this way. On the other hand, although we can’t control the order of beans, we can interfere with them by controlling dependencies, promoting priorities, “indirectly” controlling the order of execution… Of course, this is the content of the following article, please pay attention to.


Spring Boot controls the configuration execution sequence

Compared with Spring, it is a black box. It will dynamically judge whether automatic configuration classes are loaded or not and the loading order according to the current situation in the container. Therefore, it can be said that Spring Boot automatic configuration has strong requirements on the order. Driven by demand, Spring Boot provides @AutoConfigureBefore, @AutoConfigureAfter, and @AutoConfigureOrder (hereinafter referred to as the “Three Annotations”) to help us solve this problem.

Note that the three annotations are provided by Spring Boot, not the Spring Framework. The first two are available in 1.0.0, and @AutoConfigureOrder is new in 1.3.0 to indicate absolute order (the smaller the number, the higher the priority). In addition, these annotations are not mutually exclusive and can be annotated on the same @Configuration auto-configuration class.


Spring Boot provides an example of the built-in control configuration sequence

To help you understand, I’ve listed a Spring Boot in its own use as an example. Take the most familiar WebMvc auto-configuration scenario as an example:

@Configuration(proxyBeanMethods = false) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10) @AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class }) public class WebMvcAutoConfiguration { ... } @Configuration(proxyBeanMethods = false) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) @AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class) public class DispatcherServletAutoConfiguration { . } @Configuration(proxyBeanMethods = false) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) public class ServletWebServerFactoryAutoConfiguration { ... }Copy the code

These are the core WebMVC configurations, and they are in order:

  • WebMvcAutoConfigurationTo be loaded:DispatcherServletAutoConfiguration, TaskExecutionAutoConfiguration, ValidationAutoConfigurationAll three of these guys are initialized
  • DispatcherServletAutoConfigurationTo be loaded:ServletWebServerFactoryAutoConfigurationInitialization is complete
  • ServletWebServerFactoryAutoConfigurationTo be loaded:@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)Highest priority, which means it has no other dependencies,You want to be the first one initialized
    • When multiple configurations are in the highest order and have no previous relationship with each other, the order is also variable. But if there are dependencies between each other (such as Benley’sDispatcherServletAutoConfigurationandServletWebServerFactoryAutoConfiguration), then go in relative order

After WebMvcAutoConfiguration is loaded, there are actually many configurations that will be attempted after it, such as:

@AutoConfigureAfter(WebMvcAutoConfiguration.class)
class FreeMarkerServletWebConfiguration extends AbstractFreeMarkerConfiguration { ... }

@AutoConfigureAfter(WebMvcAutoConfiguration.class)
public class GroovyTemplateAutoConfiguration { ... }

@AutoConfigureAfter({ WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class })
public class ThymeleafAutoConfiguration { ... }

@AutoConfigureAfter(WebMvcAutoConfiguration.class)
public class LifecycleMvcEndpointAutoConfiguration { ... }Copy the code

This is easy to understand: if it’s not a Web environment, there’s no point in loading some template engine.


Three misunderstandings in the use of annotations (important)

In my experience, too many people misuse these three annotations. They try to use them, but they don’t work, so it’s easy to trigger a wave of “swearing”. In fact, this is the biggest motivation for me to write this article: to correct your wrong use and tell you the correct posture.


Incorrect Usage Examples

A lot of people I see use three big notes this way: I’m using “dummy code” for simulation

@configuration public class B_ParentConfig {B_ParentConfig() {system.out.println (" Config class ParentConfig constructor is executed..." ); }} @configuration public class A_SonConfig {A_SonConfig() {system.out.println (" Config class SonConfig constructor is executed..." ); }} @configuration public class C_DemoConfig {public C_DemoConfig(){system.out.println (" I am automatically scanned Configuration, initialization....") ); } } @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args).close(); }}Copy the code

The name tells me what I want to achieve: ParentConfig first, SonConfig second. (DemoConfig is a reference configuration and can be used as a log reference)

Start the application, console print:

The config class SonConfig constructor is executed... The config class ParentConfig constructor is executed... I am automatically scanned configuration, initialized....Copy the code

Son is loaded in preference to Parent, which is obviously not the case. So I see a lot of people doing this:

@AutoConfigureBefore(A_SonConfig.class) @Configuration public class B_ParentConfig { B_ParentConfig() { System.out.println(" Config class ParentConfig constructor executed..." ); }}Copy the code

Controlled by @autoConfigurebefore, this configuration is performed before A_SonConfig. Semantically, there seems to be no problem. Start the application again:

The config class SonConfig constructor is executed... The config class ParentConfig constructor is executed... I am automatically scanned configuration, initialized....Copy the code

What a fuck. See? I’m not lying to you. I’m being rude



It didn’t work? Programs don’t lie,@AutoConfigureBeforeYou are using the wrong posture, I will give you the correct posture.


The three main notes use the correct posture

In the above case, in order to achieve the desired effect, only the following two steps are needed for correct posture:

  1. theA_SonConfigandB_ParentConfigMove to the ApplicationScanning can’tIn the package, remember: must be and cannot scan the package
  2. Added configuration to current projectMETA-INF/spring.factories, the content is (the order of Son and Parent in the configuration has no effect on the result) :
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.fsx.autoconfig.A_SonConfig,com.fsx.autoconfig.B_Paren tConfigCopy the code

Let’s start the application again and print the output:

I am automatically scanned configuration, initialized.... The config class ParentConfig constructor is executed... The config class SonConfig constructor is executed...Copy the code

Perfect. As expected, Parent finally completes the initialization before Son, which means our @AutoConfigureBefore annotation is in effect.


Use details to note

For this use of posture, although very correct, is not completely without “side effects”, there are the following details usually need to pay attention to:

  • If you don’t have to@AutoConfigureBeforeThis annotation simply relies on the order in the Spring. factories to control the actual load order. The answer is yesCan not beI can’t control it
  • There is one small detail in the example: I output it on purpose every timeI am automatically scanned configuration, initialized....This sentence can be found scanned into the configuration routines that are before it (see error example), while passingspring.factoriesThe way in is behind it (see correct posture)
  • The conclusion can be derived from this small detail:Spring BootThe automatic configuration is all throughspring.factories, which has the lowest priority (execution time is the last); What comes in through the scan is usually your own custom configuration classes, so it’s the highest priority,It must be loaded before auto-configuration
    • The lesson here is: if you specify the name of the package to scan, don’t scan the packageorg.springframeworkTo prevent this from happening, Spring Boot is fault-tolerant. It has a class that detects this case in case you misconfigure it, seeComponentScanPackageCheckDefault implementation)
  • Try not to have auto-configuration classes both scanned and placedspring.factoriesOtherwise, the latter will overwrite the former, which is easy to cause puzzling errors

In summary, the correct use of the three annotations is: please use them in your autoconfiguration (usually when you customize your starter), not in @Configuration in your business project, because that would be useless.

Analysis of the three major annotation opportunity

In order to better assist understanding, strengthen memory, this article will be the three annotation analysis time brief ramble, know it is the time to analyze, naturally very good explanation why you write is invalid.

Parsing the three annotations are to AutoConfigurationSorter to ordering, processing, is similar to the AnnotationAwareOrderComparator to parse sorting @ Order annotation. The core code is as follows:

Class AutoConfigurationSorter {// Unique method for external calls: List<String> getInPriorityOrder(Collection<String> classNames) {... // Sort collections.sort (orderedClassNames); OrderedClassNames = sortByAnnotation(classes, orderedClassNames); // orderedClassNames = sortByAnnotation(classes, orderedClassNames); return orderedClassNames; }... }Copy the code

This collator is used in two places:

  • AutoConfigurationImportSelectorThe Spring auto-configuration handler is used to load all auto-configuration classes. It implementsDeferredImportSelectorInterface: This also explains why auto-configuration is the last thing to be done
  • AutoConfigurations: indicates that the @Configuration class is automatically configured.

This sort of “parsing/sorting” process is still relatively complex, this article points out, the general idea can be. You can simply remember the conclusion: @AutoConfigureBefore, @AutoConfigureAfter, and @AutoConfigureOrder only apply to autoconfiguration classes, not custom @Configuration classes.


conclusion

@AutoConfigureBefore, @AutoConfigureAfter, @AutoConfigureOrder The main purpose of this article is to help you standardize the use of these “common notes”, to avoid some mistakes, correct use posture, to avoid making mistakes.

I see a lot of articles, production procedures are used wrong (estimated have no effect of their own do not know, or just happened to be behind the implementation of XXX and thought it was effective), I hope this article can help you. This article reprinted from: www.yourbatman.cn/x2y/3aa2234…

Welcome to my blog, where there are many fine collections

  • This article is reprinted with a credit (must be accompanied by a link, not only the text) : Antetokounmpo blog.

Feel helpful to you, help me like, share! Your support is my inexhaustible creative power! . In addition, the author recently a period of time output as follows boutique content, looking forward to your attention.

  • Spring Boot2.0 by Hand
  • Spring Security- JWT-OAUTH2
  • RBAC Authority Management System for Actual Combat Front-end and Back-end Separation
  • “Actual SpringCloud Micro-service from Bronze to King”
  • VUE Series