重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
@order
注解是spring-core
包下的一个注解,@Order
的作用是定义Spring IOC容器中Bean的执行顺序的优先级(这里的顺序也可以理解为存放到容器中的先后顺序)。开发过程当中有时候经常会出现配置依赖关系,例如注入A对象使用了@ConditionalOnBean(B.class)
,意思是要求容器当中必须存在B.class
的实例的时候,才会进行注入A
。这时候我们就必须保证B对象在注入A
对象前进行注入。
(1)源码当中有三个元注解:
(2)属性:
@order当中只要一个value属性,而且还是int类型,值越低优先级越高,默认值是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)但是分开也是将Config2放到了上面的包当中,于是我又改成了Config1放到最上面,这样进行测试,结果又失效了
(6)于是我又放在了同包下,将Config2命名为A开头的,这样他就放到了最上面,于是这样同样也生效了。
期间我还尝试着将@Configuration都改为使用@Component,结果仍然不变。
得出结论:
@order
指定加载顺序还跟类的命名和存放位置有关!假如有Config1
和Config2
两个类在一个包下,要求是Config2
先加载:
Config2
的@order值
就算是小于Config1
的@order值
同样也是Config1
先加载。这样才能保证@Order生效!
三、@order失效原因https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-constructor-injection
最关键的一句话:您可以在目标类级别和@Bean方法上声明@Order注释,可能针对的是单个bean定义(如果多个定义使用同一个bean类)。@Order值可能会影响注入点的优先级,但请注意,它们不会影响单例启动顺序
,这是由依赖关系和@DependsOn声明确定的正交关注。
我理解的注入点的优先级应该是指的存放容器的先后顺序,也就是他并不会影响启动顺序。
四、解决排序问题我们不可能每次遇到这种问题又是改名又是换包的,所以,springboot提供了如下三个注解可以控制顺序:
(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()方法中最后一行代码如下:
紧接着会走到这个地方,实际上是分了三步排序:
从上面配置的顺序可以知道,最终决定权还是在@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构建了");
}
}
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧