Write in front
springboot
Following 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@Component
That'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 A
Loading needs to be waitedBean B
It 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
@Configuration
In 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
@Order
Can this label be controlled in the loading order?
Strictly speaking, not all beans can pass@Order
This marker controls sequence. Because@Order
This annotation has no effect on ordinary methods or classes.
That@Order
Which 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@Order
Annotations 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,
@Aspect
Tagged class - control
ApplicationListener
Implement the loading order of classes - control
CommandLineRunner
Implement 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
@DependsOn
Annotations 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.
@DependsOn
Use:
- Directly or indirectly marked with
@Component
above the annotated class; - Directly or indirectly marked with
@Bean
above the annotation method; - use
@DependsOn
Annotation to the class level is only valid when using component-scanning method, if with@DependsOn
The 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@Bean
In 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:
- accomplish
Ordered/PriorityOrdered
Interface, rewrite the order method - use
@Order/@Priority
annotation,@Order
Annotations can be used at the method level, and@Priority
Annotations 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, injectIBean
For list, we need to test whether the order of beans in this list is as defined@Order
Consistent 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@AutoConfigureOrder
How 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,@AutoConfigureOrder
Can changeIn-house
@Configuration
order.
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!