When querying the loading Order of beans on the Internet, I have seen a large number of articles that use the @order annotation to control the loading Order of beans. I don’t know if the students who wrote these blogs have actually verified it. This paper hopes to point out these incorrect use gestures. Let readers know the specific application scenarios of @Order

The SpringBoot tutorial debunks the incorrect Bean loading sequence using posture

I. Environment construction

Create a Maven project with the following POM file (the project code is available at the end of this article)

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.7</version>
    <relativePath/> <! -- lookup parent from update -->
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
    <java.version>1.8</java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </pluginManagement>
</build>
<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>
Copy the code

II. Wrong posture

Below we’ll look at two incorrect positions for typical annotations, @Order and @AutoConfigureOrder

I. @Order

Err. case1: Add the Order annotation to the class

A common misconception is that by adding this Order annotation to a class, you can specify the initialization Order between beans. The smaller the Order value, the higher the priority. Let’s actually test this

We create two DemoBeans specifying different Order orders

@Order(4)
@Component
public class BaseDemo1 {
    private String name = "base demo 1";

    public BaseDemo1(a) { System.out.println(name); }}@Order(3)
@Component
public class BaseDemo2 {
    private String name = "base demo 2";

    public BaseDemo2(a) { System.out.println(name); }}Copy the code

BaseDemo2 should be initialized first if orDE values are smaller than orde values

Err. Case2: Add @Order to the Bean declaration method in the configuration class

In addition to the automatic scanning above, there is another way for beans to use the @bean annotation. Let’s demonstrate the error case of specifying the loading order of beans in a configuration class

Also, let’s create two new test beans

public class BaseDemo3 {
    private String name = "base demo 3";

    public BaseDemo3(a) { System.out.println(name); }}public class BaseDemo4 {
    private String name = "base demo 4";

    public BaseDemo4(a) { System.out.println(name); }}Copy the code

Next, define the bean in the configuration class

@Configuration
public class ErrorDemoAutoConf {
    @Order(2)
    @Bean
    public BaseDemo3 baseDemo3(a) {
        return new BaseDemo3();
    }

    @Order(1)
    @Bean
    public BaseDemo4 baseDemo4(a) {
        return newBaseDemo4(); }}Copy the code

Similarly, if the @ORDER annotation is valid, BaseDemo4 should be initialized first

As you can see from the actual test output above, the @Order annotation does not work either. If you are interested, you can try reversing the Order of the two methods in the configuration class above and find that BaseDemo4 loads first

The Err. case3: @order annotation decorates the configuration class

It is also a common mistake to assume that the @order annotation is used to specify the loading Order of configuration classes, but is this really the case?

We create two configuration classes for the tests

@Order(1)
@Configuration
public class AConf {
    public AConf(a) {
        System.out.println("AConf init!"); }}@Order(0)
@Configuration
public class BConf {
    public BConf(a) {
        System.out.println("BConf init"); }}Copy the code

If the @Order annotation works, the BConf configuration class will initialize first, so let’s test it

As you can see from the above results, BConf is not loaded first; The configuration class is also a bean. It does not work in this case, and it does not work in this case

In fact, the @order is placed on the configuration class, and the Bean defined in this configuration class takes precedence over that defined in another configuration class.

Again, to test this case, we define three beans and two Confs

public class Demo1 {
    private String name = "conf demo bean 1";

    public Demo1(a) { System.out.println(name); }}public class Demo2 {
    private String name = "conf demo bean 2";

    public Demo2(a) { System.out.println(name); }}public class Demo3 {
    private String name = "conf demo bean 3";

    public Demo3(a) { System.out.println(name); }}Copy the code

Then we put Demo1, Demo3 in one configuration, and Demo2 in another

@Order(2)
@Configuration
public class AConf1 {
    @Bean
    public Demo1 demo1(a) {
        return new Demo1();
    }

    @Bean
    public Demo3 demo3(a) {
        return newDemo3(); }}@Order(1)
@Configuration
public class BConf1 {

    @Bean
    public Demo2 demo2(a) {
        return newDemo2(); }}Copy the code

If the @order annotation actually controls the loading Order of the beans in the configuration class, then the beans in BConf1 should be loaded first, that is, Demo2 will take precedence over Demo1 and Demo3

The output above is not what we expected, so the @order annotation is wrong to determine the Order in which to configure the classes

2. @AutoConfigureOrder

From the naming point of view, this annotation is used to specify the order of the configuration classes. However, this annotation is often used incorrectly, and most of the errors are caused by not really understanding its usage scenarios

Let’s demonstrate the use of the wrong case

Create two new configuration classes within the project, using annotations directly

@Configuration
@AutoConfigureOrder(1)
public class AConf2 {
    public AConf2(a) {
        System.out.println("A Conf2 init!"); }}@Configuration
@AutoConfigureOrder(-1)
public class BConf2 {
    public BConf2(a) {
        System.out.println("B conf2 init!"); }}Copy the code

When the annotation is in effect, the BConf is loaded in priority

The output is different from what we expected; Does this annotation apply to the order of beans in the configuration class, rather than to the configuration class itself?

Similarly, let’s design a case to verify

public class DemoA {
    private String name = "conf demo bean A";

    public DemoA(a) { System.out.println(name); }}public class DemoB {
    private String name = "conf demo bean B";

    public DemoB(a) { System.out.println(name); }}public class DemoC {
    private String name = "conf demo bean C";

    public DemoC(a) { System.out.println(name); }}Copy the code

Corresponding configuration class

@Configuration
@AutoConfigureOrder(1)
public class AConf3 {
    @Bean
    public DemoA demoA(a) {
        return new DemoA();
    }

    @Bean
    public DemoC demoC(a) {
        return newDemoC(); }}@Configuration
@AutoConfigureOrder(-1)
public class BConf3 {

    @Bean
    public DemoB demoB(a) {
        return newDemoB(); }}Copy the code

If DemoB is loaded later, it indicates that the above view is wrong, and the measured result is as follows

The @autoConfigureOrder annotation does not specify the order in which to configure classes. The essence is misleading not!!

Let’s look at the correct use of @Order and @autoConfigureOrder

III. Instructions for Use

1. @Order

Take a look at the official note for this note

{@code @order} defines the sort Order for an annotated component. annotation-based ordering is supported for many kinds of components in Spring, even for collection injection where the order values of the target components are taken into account (either from their target class or from their {@code @Bean} method). While such order values may influence priorities at injection points, please be aware that they do not influence singleton startup order which is an orthogonal concern determined by dependency relationships and {@code @DependsOn} declarations (influencing a runtime-determined dependency graph).

Initially the Order annotation is used to specify the priority of the aspect; It has been enhanced since 4.0 to support specifying the order of beans in a collection when injected into a collection

In particular, it has no effect on the order between the beans of the instance; This is also true according to our test above

Next we need to look at the scenario where the Order is specified when the collection is injected via the @Order annotation

First we define two beans that implement the same interface and add an @Order annotation

public interface IBean {}@Order(2)
@Component
public class AnoBean1 implements IBean {

    private String name = "ano order bean 1";

    public AnoBean1(a) { System.out.println(name); }}@Order(1)
@Component
public class AnoBean2 implements IBean {

    private String name = "ano order bean 2";

    public AnoBean2(a) { System.out.println(name); }}Copy the code

Then, in a test bean, we inject a list of iBeans. We need to test that the Order of the beans in this list is consistent with the @Order rule we defined

@Component
public class AnoTestBean {

    public AnoTestBean(List<IBean> anoBeanList) {
        for (IBean bean : anoBeanList) {
            System.out.println("in ano testBean: "+ bean.getClass().getName()); }}}Copy the code

As we expect, anoBean2 should come first in the anoBeanList collection

Based on the output above, you can also see that the order in the list is as expected, and AnoOrderBean1 and AnoOrderBean2 have no relation to the loading order and annotations

2. @AutoConfigureOrder

This annotation is used to specify the loading order of configuration files, but it did not work in the previous test. What is the correct posture?

@AutoConfigureOrderApplies to the order of AutoConfig in externally dependent packages and cannot be used to specify the order within this package

To verify the above statement, let’s create two new projects and specify the order of the auto-configuration classes

The configuration of Project 1 is as follows:

@AutoConfigureOrder(1)
@Configuration
@ComponentScan(value = {"com.git.hui.boot.order.addition"})
public class AdditionOrderConf {
    public AdditionOrderConf(a) {
        System.out.println("additionOrderConf init!!!"); }}Copy the code

Note that the auto-configuration classes need to be defined in the/meta-INF/spring.Factories file of the project for them to be loaded correctly

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.git.hui.boot.order.addition.AdditionOrderConf
Copy the code

The configuration of Project 2 is as follows:

@Configuration
@AutoConfigureOrder(-1)
@ComponentScan("com.git.hui.boot.order.addition2")
public class AdditionOrderConf2 {

    public AdditionOrderConf2(a) {
        System.out.println("additionOrderConf2 init!!!"); }}Copy the code

Then we add a configuration inside the project

@AutoConfigureOrder(10)
@Configuration
public class OrderConf {
    public OrderConf(a) {
        System.out.println("inner order conf init!!!"); }}Copy the code

AdditionOrderConf2 correctly precedes AdditionOrderConf1 in the above three configuration classes because the annotation applies to the order of the automatic configuration classes in the external dependency package. And OrderConf don’t receive the influence of annotation, the default environment, the internal configuration of the definition of class will be better than the external dependencies, explains from the following output can also support us (to verify that really like, of course, and should adjust the two external project configuration class order, and observe the load order is changed, we omitted here)

IV. The summary

This article mainly introduces the common incorrect use of @Order and @autoconfigureOrder on the Internet, and gives the correct use case.

Here are a few simple sentences about proper posture

  • @OrderAnnotations do not specify the loading order of beans, which applies to AOP priorities and the order in which beans are injected into the collection
  • @AutoConfigureOrderSpecifies the load order of externally dependent AutoConfig (that is, defined in/META-INF/spring.factoriesConfiguration bean priority in the file), what is the use of this annotation in the current project
  • The same@AutoConfigureBeforeand@AutoConfigureAfterThe scope of application of these two notes and@AutoConfigureOrderThe same

0. Project

  • Project: github.com/liuyueyi/sp…
  • Source code module: – github.com/liuyueyi/sp… – github.com/liuyueyi/sp… – github.com/liuyueyi/sp…

1. An ashy Blog

As far as the letter is not as good, the above content is purely one’s opinion, due to the limited personal ability, it is inevitable that there are omissions and mistakes, if you find bugs or have better suggestions, welcome criticism and correction, don’t hesitate to appreciate

Below a gray personal blog, record all the study and work of the blog, welcome everyone to go to stroll

  • A grey Blog Personal Blog blog.hhui.top
  • A Grey Blog-Spring feature Blog Spring.hhui.top