SoFunction
Updated on 2025-04-07

How to control the loading order of beans in Java

Write in front

springbootFollowing the principle that agreement is greater than configuration, greatly solving the problem of cumbersome configuration. On this basis, a spi mechanism is provided, usingThe automatic assembly function of a widget can be completed.

In general business scenarios, you may not need to care about how a bean is registered into the spring container. You only need to declare the bean that needs to be registered into the container as@ComponentThat's it, because spring will automatically scan to this bean to complete initialization and load into the spring context container.

However, if the bean is loadingSome beans and beans have dependencies, that isBean ALoading needs to be waitedBean BIt can only be done after the loading is completed; or when you are developing a middleware that needs to be automatically assembled, you will declare your own Configuration class, but you may face several interdependent beans. If it is not controlled, you may report an error of not finding the dependency.

The Spring framework cannot load beans in the order expected by the business logic without explicitly specifying the load order, so the Spring framework is required to provide the ability to allow developers to display the load order of beans.

Several misunderstandings

Before formally talking about how to control the loading order, let me first talk about two misunderstandings:

  • It's marked@ConfigurationIn the class, will @Bean written in the previous class definitely be registered first?

This does not exist. In the era of xml, there is no logic that will be loaded first when written in front of it. Because xml is not loading gradually, but parse all, then dependency analysis and registration are performed. In springboot, the process of XML being parse into an internal object of spring is eliminated, but the loading method has not changed much.

  • use@OrderCan this label be controlled in the loading order?

Strictly speaking, not all beans can pass@OrderThis marker controls sequence. Because@OrderThis annotation has no effect on ordinary methods or classes.

That@OrderWhich beans can be controlled? Official explanation:

java

{@code @Order} defines the sort order for an annotated component. Since Spring 4.0, 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).

At the beginning@OrderAnnotations are used for priority specification of sections; its functionality has been enhanced after 4.0, and when the injection of sets is supported, the order of beans in the set is specified, and it specifically points out that it has no effect on the order between beans of a single instance. Currently, there are 3 points that are used more frequently:

  • Control the loading order of AOP classes, that is,@AspectTagged class
  • controlApplicationListenerImplement the loading order of classes
  • controlCommandLineRunnerImplement the loading order of classes

Please see the following article for details on usage

How to control

@Conditional Conditional Annotation Family

  • @ConditionalOnClass: The configuration class will only take effect when the specified class exists in the classpath.
@Configuration
// The configuration class will only take effect when the specified class exists under the classpath.@ConditionalOnClass(name = "")
public class MyConfiguration {
	// ...
}
  • @ConditionalOnMissingClass: The configuration class will only take effect when the specified class does not exist in the classpath.
  • @ConditionalOnBean: The configuration class will only take effect when the specified bean exists in the container.
  • @ConditionalOnMissingBean: The configuration class will only take effect when the specified bean does not exist in the container.

@DependsOn

@DependsOnAnnotations can be used to control the order in which the bean is created. This annotations are used to declare that the current bean depends on another bean. The dependency bean is ensured by the container to be instantiated before the current bean is instantiated.

@DependsOnUse:

  • Directly or indirectly marked with@Componentabove the annotated class;
  • Directly or indirectly marked with@Beanabove the annotation method;
  • use@DependsOnAnnotation to the class level is only valid when using component-scanning method, if with@DependsOnThe annotated class is used in XML, and the annotation will be ignored.<bean depends-on="..."/>This method will take effect.

Example:

@Configuration
public class BeanOrderConfiguration {
    @Bean
    @DependsOn("beanB")
    public BeanA beanA(){
        ("bean A init");
        return new BeanA();
    }
    @Bean
    public BeanB beanB(){
        ("bean B init");
        return new BeanB();
    }
    @Bean
    @DependsOn({"beanD","beanE"})
    public BeanC beanC(){
        ("bean C init");
        return new BeanC();
    }
    @Bean
    @DependsOn("beanE")
    public BeanD beanD(){
        ("bean D init");
        return new BeanD();
    }
    @Bean
    public BeanE beanE(){
        ("bean E init");
        return new BeanE();
    }
}

The loading order of the above code bean is:

bean B init
bean A init
bean E init
bean D init
bean C init

Parameter injection

exist@BeanIn the annotation method, if a parameter is passed, springboot will automatically look for references of this type in the spring context for this parameter. And initialize the instance of this class first.

With this feature, we can also control the loading order of beans.

Example:

@Bean
public BeanA beanA(BeanB demoB){
  ("bean A init");
  return new BeanA();
}
@Bean
public BeanB beanB(){
  ("bean B init");
  return new BeanB();
}

As a result, beanB is initialized and loaded before beanA.

It should be noted that springboot will search by type. If multiple instances of this type are registered to the spring context, then you need to add@Qualifier("Bean's name")Let's specify

Take advantage of the extension points in the life cycle of a bean

In the spring system, from container to bean instantiation and initialization, there are life cycles, and many extension points are provided, allowing logical extensions during these steps.

The loading order of these scalable points is controlled by spring itself, and most of them cannot be intervened. This can be used to extend the extension point of spring. Add your own business initialization code to the corresponding extension point. Always achieve sequential control.

Specifically for the analysis of most extensible points in spring containers, I have written an article to introduce them in detail:All extension points in Spring&SpringBoot

Implement Ordered/PriorityOrdered interface/annotation

Spring provides the following methods to control the order of bean loading:

  • accomplishOrdered/PriorityOrderedInterface, rewrite the order method
  • use@Order/@Priorityannotation,@OrderAnnotations can be used at the method level, and@PriorityAnnotations won't work;

againstCustom BeansIn other words, the above methods can all control the bean loading order. Whether it is the way to implement interfaces or use annotations,The smaller the value is, the higher the priority, and when implementing the PriorityOrdered interface or using the @Priority annotation, its loading priority will beAboveImplement the Ordered interface or bean annotated using @Order.

It should be noted that using the above method will only change the order (or priority) of loading the same interface bean into the set (such as List, Set, etc.), but this method will notIt will not affect the initialization order of different beans when Spring application context is started(startup order)。

  • Error case: The following case code cannot specify the configuration order
@Component
@Order(1)
public class BeanA {
    // Definition of BeanA}
@Component
@Order(2)
public class BeanB {
    // Definition of BeanB}
  • Correct use cases:

First, define two beans to implement the same interface and add the @Order annotation.

public interface IBean {
}
@Order(2)
@Component
public class AnoBean1 implements IBean {
    private String name = "ano order bean 1";
    public AnoBean1() {
        (name);
    }
}
@Order(1)
@Component
public class AnoBean2 implements IBean {
    private String name = "ano order bean 2";
    public AnoBean2() {
        (name);
    }
}

Then in a test bean, injectIBeanFor list, we need to test whether the order of beans in this list is as defined@OrderConsistent rules

@Component
public class AnoTestBean {
    public AnoTestBean(List<IBean> anoBeanList) {
        for (IBean bean : anoBeanList) {
            ("in ano testBean: " + ().getName());
        }
    }
}

@AutoConfigureOrder

This annotation is used to specify the loading order of the configuration file. However, in actual testing, it was found that the following use is not effective:

@Configuration
@AutoConfigureOrder(2)
public class BeanOrderConfiguration1 {
    @Bean
    public BeanA beanA(){
        ("bean A init");
        return new BeanA();
    }
}
@Configuration
@AutoConfigureOrder(1)
public class BeanOrderConfiguration2 {
    @Bean
    public BeanB beanB(){
        ("bean B init");
        return new BeanB();
    }
}

No matter how many 2 numbers you fill in, the loading order will not be changed. Then this@AutoConfigureOrderHow is it used?

@AutoConfigureOrder applies to the order of AutoConfig in externally dependent packages, and cannot be used to specify the order within this package. The packages that can be scanned by your project are all internal configurations, while spring introduces external configurations, and spring uses spring's unique spi files:

in other words,@AutoConfigureOrderCan changeIn-house@Configurationorder.

Specific usage method:

@Configuration
@AutoConfigureOrder(10)
public class BeanOrderConfiguration1 {
    @Bean
    public BeanA beanA(){
        ("bean A init");
        return new BeanA();
    }
}
@Configuration
@AutoConfigureOrder(1)
public class BeanOrderConfiguration2 {
    @Bean
    public BeanB beanB(){
        ("bean B init");
        return new BeanB();
    }
}

=\
  .BeanOrderConfiguration1,\
  .BeanOrderConfiguration2

Summarize

In fact, at work, I believe that many people have encountered complex dependency loading beans. It is better to control this uncertainty by spring. In this way, when reading the code, we can easily see the order of dependencies between beans.

This is the end of this article about how to control the loading order of beans in Java. For more related content on Java beans, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!