@order 注解用法

@order注解是spring-core包下的一个注解,@Order的作用是定义Spring IOC容器中Bean的执行顺序的优先级(这里的顺序也可以理解为存放到容器中的先后顺序)。开发过程当中有时候经常会出现配置依赖关系,例如注入A对象使用了@ConditionalOnBean(B.class),意思是要求容器当中必须存在B.class的实例的时候,才会进行注入A。这时候我们就必须保证B对象在注入A对象前进行注入。

一、观察@order源码

(1)源码当中有三个元注解:

  • @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}): 使用范围接口、类、枚举、注解、方法、字段
  • @Retention(RetentionPolicy.RUNTIME): @Retention是用来修饰注解的生命周期的,RetentionPolicy.RUNTIME代表的是不仅被保存到class文件中,jvm加载class文件之后,仍然存在;一直有效!
  • @Documented: @Documented和@Deprecated注解长得有点像,@Deprecated是用来标注某个类或者方法不建议再继续使用,@Documented只能用在注解上,如果一个注解@B,被@Documented标注,那么被@B修饰的类,生成Javadoc文档时,会显示@B。

(2)属性:

@order当中只有一个value属性,而且还是int类型,值越低优先级越高。

这里spring给了一个接口,接口有两个参数,一个代表最大一个是最小。默认值是Ordered.LOWEST_PRECEDENCE,表示最低优先级(输给任何其他指定的顺序值)。

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Documented
public @interface Order {
    int value() default 2147483647;
}

官网注释:https://github.com/spring-projects/spring-framework/blob/main/spring-core/src/main/java/org/springframework/core/annotation/Order.java

二、@order实战

(1)自定义两个配置类

我们要求Config2先进行加载,然后通过@order来排序测试一下

@Configuration
public class Config1 {

    public Config1() {
        System.out.println("Config1构建了");
    }
}

@Configuration
public class Config2 {

    public Config2() {
        System.out.println("Config2构建了");
    }
}

(2)启动项目测试:默认是先创建的Config1后创建的Config2

(3)既然order可以控制加载顺序,那我们来试验一下,然后让Config2 先加载

@Configuration
@Order(2)
public class Config1 {

    public Config1() {
        System.out.println("Config1构建了");
    }
}

@Configuration
@Order(1)
public class Config2 {

    public Config2() {
        System.out.println("Config2构建了");
    }
}

但是好像没什么卵用

(4)分析原因

目前这两个是在同包情况下不起作用。

在这里插入图片描述
于是进行分开了

在这里插入图片描述

分开之后竟然生效了

(5)于是我又改成了Config1放到最上面,这样进行测试,结果又失效了

假如对这块不理解的,看一下上个图片config1所在的位置!这里说的放到上面是文件所在的位置!

在这里插入图片描述

(6)于是我又放在了同包下,将Config2命名为A开头的,这样他就放到了最上面,于是这样同样也生效了。

在这里插入图片描述

期间我还尝试着将@Configuration都改为使用@Component,结果仍然不变。

得出结论:设置Config2@order值就算是小于Config1@order值同样也是Config1先加载。也可以理解为Order压根没作用,
加载顺序跟类的命名和存放位置有关!

假如Config1Config2两个类在一个包下,假如要求是Config2先加载:

  • 在同一个包:如果同包情况下可以重新命名Config2,只要在Config1上面就行。
  • 不在同一个包:或者拆开不同包也可以,但是Config2所在的包也必须比Config1所呆的包上面。

三、@order失效原因

https://docs.spring.io/spring-framework/docs/5.3.28/reference/html/core.html#spring-core

最关键的一句话:您可以在目标类级别和@Bean方法上声明@Order注释,可能针对的是单个bean定义(如果多个定义使用同一个bean类)。@Order值可能会影响注入点的优先级(注意他说的可能,说明还有不可控因素),但请注意,它们不会影响单例启动顺序,这是由依赖关系和@DependsOn声明确定的正交关注。

下面我继续在带有@Bean注解的类当中添加@Order看看什么效果:

首先我把config1和config2的@Configuration注解都给去掉了,然后又新增了两个配置类,默认是A先执行的,B后执行的。

在这里插入图片描述

接下来再来看一个案例,在Spring当中加载和注入是分两步来完成的,@Order控制不了加载的顺序。所谓的加载就是通过构造器创建对象。而注入就是指的注入属性,包含@Bean修饰的方法也是。

在这里插入图片描述

然后我又把order注解加在了@Bean方法上,是没有效果的

注意@order用在类上代表的是当前类实例注入的顺序级别,假如要用在@Bean修饰的方法上,代表的是@Bean创建的实例的注入顺序级别,而并不是代表的当前类的。

在这里插入图片描述

四、@DependsOn控制加载顺序

@DependsOn可以控制加载的顺序

在这里插入图片描述

五、springboot提供的注解

springboot提供了如下三个注解可以控制顺序:

  • @AutoConfigureAfter:当前配置类在指定配置类之后执行
  • @AutoConfigureBefore:当前配置类在指定配置类之前执行
  • @AutoConfigureOrder:指定优先级,数值越小,优先级越高。

(1)首先将代码改回原来的样子

在这里插入图片描述

(2)在Config2使用@AutoConfigureBefore(Config1.class),代表的是在config1加载前进行加载

@Configuration
public class Config1 {

    public Config1() {
        System.out.println("Config1构建了");
    }
}

@Configuration
@AutoConfigureBefore(Config1.class)
public class Config2 {

    public Config2() {
        System.out.println("Config2构建了");
    }
}

(3)输出结果,显然还是没生效

可能有时候走了狗屎运给你一种错觉还真的配置成功了。实际上这种方式是不可行的,以上三个注解只有针对自动配置类才会生效。

在autoconfigure包下就有spring.factories,这个文件配置了自动配置类,springboot会读取这个文件的,我们也可以在自己项目上定义spring.factories,这样我们的配置类对于@AutoConfigureAfter注解就可以生效了。

在这里插入图片描述

(4)自定义spring.factories

第一行是固定的,后面的就是全类名,虽然只有Config2使用了注解,但是需求是和Config1进行排序,所以这两个都得加。

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.gzl.cn.springbootcache.config.Config2,\
com.gzl.cn.springbootcache.config.Config1

(5)测试,成功解决

六、排序源码分析

针对于@AutoConfigure那三个注解原理:其实关键的代码还是在AutoConfigurationImportSelector中,将自动配置类从spring.factories加载出来之后会根据条件排序(只有自动配置类!),在selectImports()方法中最后一行代码如下:

在这里插入图片描述

紧接着会走到这个地方,实际上是分了三步排序:

  1. 先按照文件名字母排序
  2. 按照@AutoConfigureOrder进行排序
  3. 按照 @AutoConfigureBefore和@AutoConfigureAfter排序

在这里插入图片描述

从上面配置的顺序可以知道,最终决定权还是在@AutoConfigureAfter、@AutoConfigureBefore这两个注解。

当我们不设置spring.factories的时候,这里面压根都没有这两个类!

在这里插入图片描述

七、@AutoConfigureOrder

这种也是可以的!当然前提也是需要配置spring.factories

@Configuration
@AutoConfigureOrder(2)
public class Config1 {

    public Config1() {
        System.out.println("Config1构建了");
    }
}

@Configuration
@AutoConfigureOrder(1)
public class Config2 {

    public Config2() {
        System.out.println("Config2构建了");
    }
}
  • 43
    点赞
  • 109
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

怪 咖@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值