Spring笔记-@Order注解和Ordered接口解析

Spring笔记-@Order注解和Ordered接口解析

目录

@Order注解和Ordered接口

1.OrderUtils

2.Ordered接口

3.OrderComparator

4.AnnotationAwareOrderComparator

5.Bean注册顺序

Spring的Orderd接口及@Order,@Primary,@Priority三个注解介绍

1.如何发现Orderd接口及@Order、@Primary、@Priority

2.Orderd、@Order、@Priority、@Primary

3.测试

@Order注解和Ordered接口

Order注解用于排序

public @interface Order {     /**      * The order value.      * <p>Default is {@link Ordered#LOWEST_PRECEDENCE}.      * @see Ordered#getOrder()      */     int value() default Ordered.LOWEST_PRECEDENCE; } 1.OrderUtils

Spring提供了OrderUtils来获取Class的Order注解排序信息

扩展:Priority注解为javax扩展注解,功能与Order相同

public class OrderUtilsTests {     @Test     public void getSimpleOrder() {         assertEquals(Integer.valueOf(50), OrderUtils.getOrder(SimpleOrder.class, null));     }     @Test     public void getPriorityOrder() {         assertEquals(Integer.valueOf(55), OrderUtils.getOrder(SimplePriority.class, null));     }     @Order(50)     private static class SimpleOrder {}     @Priority(55)     private static class SimplePriority {} } 2.Ordered接口

对象排序的另一种实现

public interface Ordered {     int getOrder(); } 3.OrderComparator

使用OrderComparator来比较2个对象的排序顺序

public final class OrderComparatorTests {     private final OrderComparator comparator = new OrderComparator();     @Test     public void compareOrderedInstancesBefore() {         assertEquals(-1, this.comparator.compare(                 new StubOrdered(100), new StubOrdered(2000)));     }     @Test     public void compareOrderedInstancesSame() {         assertEquals(0, this.comparator.compare(                 new StubOrdered(100), new StubOrdered(100)));     }     @Test     public void compareOrderedInstancesAfter() {         assertEquals(1, this.comparator.compare(                 new StubOrdered(982300), new StubOrdered(100)));     }     private static final class StubOrdered implements Ordered {         private final int order;         public StubOrdered(int order) {             this.order = order;         }         @Override         public int getOrder() {             return this.order;         }     } }

其内部比较逻辑

return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;

i1比i2小则返回-1

i1比i2大则返回1

i1等于i2则返回0

4.AnnotationAwareOrderComparator

AnnotationAwareOrderComparator继承自OrderComparator

其可以同时处理对象实现Ordered接口或@Order注解

其提供了静态方法sort,可以对List进行排序

public class AnnotationAwareOrderComparator extends OrderComparator { }

测试代码

public class AnnotationAwareOrderComparatorTests {     @Test     public void sortInstances() {         List<Object> list = new ArrayList<>();         list.add(new B());         list.add(new A());         AnnotationAwareOrderComparator.sort(list);         assertTrue(list.get(0) instanceof A);         assertTrue(list.get(1) instanceof B);     }     @Order(1)     private static class A {     }     @Order(2)     private static class B {     } } 5.Bean注册顺序

Demo2Config的对象将会先于Demo1Config初始化注册

注意点:其构造函数的初始化并不生效

@Configuration @Order(2) public class Demo1Config {     public Demo1Config()     {         System.out.println("Demo1Config");     }     @Bean     public Demo1Service demo1Service(){         System.out.println("demo1config 加载了");         return new Demo1Service();     } } @Configuration @Order(1) public class Demo2Config {     public Demo2Config()     {         System.out.println("Demo2Config");     }     @Bean     public Demo2Service demo2Service(){         System.out.println("demo2config 加载了");         return new Demo2Service();     } } public class Main {     public static void main(String[] args) {         AnnotationConfigApplicationContext context =                 new AnnotationConfigApplicationContext("core.annotation.order2");     } }

输出的结果信息:

Demo1Config

Demo2Config

demo2config 加载了

demo1config 加载了

Spring的Orderd接口及@Order,@Primary,@Priority三个注解介绍

今天要来说一下Orderd接口以及@Order、@Primary、@Priority注解这几个东西,原本只是想介绍一下@Order,但是这几个有一定的关联,因此这里一起进行介绍。这几个接口是用来排序,本文主要介绍用法,具体的比如Spring什么时候对他们排序啊,后面在介绍Spring的处理过程的时候再介绍,还有怎么排序的这些比较好理解的也不介绍了。

1.如何发现Orderd接口及@Order、@Primary、@Priority

在前面文章说过要通过一些常用的注解以及在学习过程中不断的发现,因此这里我还是按我学习的思路介绍一下我是如何发现他们的。如果没有一个发现以及理解的过程有时候可能会很难记住,就比如我之前专门了解了Spring相关的注解,并且去学习用法,但是不理解稍微一不用就忘记了。

首先自己创建一个测试类,创建AnnotationConfigApplicationContext实例。

    @Test     public void test() {         ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

进入AnnotationConfigApplicationContext构造函数可以发现调用了无参构造函数,里面有个创建AnnotatedBeanDefinitionReader的步骤,Spring用BeanDefinition表示一个Bean,因此这个类也很容易理解就是与读取注解Bean有关的类。

    public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) {         super(beanFactory);         this.reader = new AnnotatedBeanDefinitionReader(this);         this.scanner = new ClassPathBeanDefinitionScanner(this);     }

继续进入可以看到AnnotatedBeanDefinitionReader的构造函数,最后一行表示将那些处理注解的基础设施类添加到 DefaultListableBeanFactory中。进入这个方法中。

    public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {         Assert.notNull(registry, "BeanDefinitionRegistry must not be null");         Assert.notNull(environment, "Environment must not be null");         this.registry = registry;         // 创建条件判断者,后面用来进行条件注解的判断,关联@Conditional注解,@Conditional注解内传入的用于判断的类要实现Condition接口的match方法         this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);         // 将那些处理注解的基础设施类添加到 DefaultListableBeanFactory中         AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);     }

方法中有个判断AnnotationAwareOrderComparator是否存在步骤,这个类从字面意思可以看出就是个比较器。

    public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(             BeanDefinitionRegistry registry, @Nullable Object source) {         // 判断BeanFactory是不是DefaultListableBeanFactory类型,如果不是需要进行转换         DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);         if (beanFactory != null) {             // beanFactory的依赖关系比较器,如果没有AnnotationAwareOrderComparator这个比较器,就传入全局默认静态不可变的order比较器             if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {                 beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);             }

查看这个类的介绍可以看到这个类是OrderComparator的派生,OrderComparator是用来对Orderd或者@Order等内部的值进行比较,内部源码我们不做介绍,就是获取值然后进行数值的比较。这个类支持Ordered、@Order、@Priority,这些是我们今天要介绍的主要内容了,@Primary初始看起来没有关联,后面我们再介绍为什么会有他。

/**  * {@code AnnotationAwareOrderComparator} is an extension of  * {@link OrderComparator} that supports Spring's  * {@link org.springframework.core.Ordered} interface as well as the  * {@link Order @Order} and {@link javax.annotation.Priority @Priority}  * annotations, with an order value provided by an {@code Ordered}  * instance overriding a statically defined annotation value (if any).  *  * <p>Consult the Javadoc for {@link OrderComparator} for details on the  * sort semantics for non-ordered objects.  *  * @author Juergen Hoeller  * @author Oliver Gierke  * @author Stephane Nicoll  * @since 2.0.1  * @see org.springframework.core.Ordered  * @see org.springframework.core.annotation.Order  * @see javax.annotation.Priority  */ public class AnnotationAwareOrderComparator extends OrderComparator { 2.Orderd、@Order、@Priority、@Primary

这一个接口和三个注解比较简单,我粗略介绍一下,不做具体的介绍。总的来说都是用来做bean加载的排序。

①orderd接口,实现Oderd接口的话要实现int getOrder();这个方法,返回一个整数值,值越小优先级越高。

②@Order里面存储了一个值,默认为Integer的最大值,同样值越小优先级越高。要注意@Order只能控制组件的加载顺序,不能控制注入的优先级。但是能控制List 里面存放的XXX的顺序,原因是当通过构造函数或者方法参数注入进某个List时,Spring的DefaultListableBeanFactory类会在注入时调用AnnotationAwareOrderComparator.sort(listA)帮我们去完成根据@Order或者Ordered接口序值排序。@Order更加适用于集合注入的排序。

③@Priority与@Order类似,@Order是Spring提供的注解,@Priority是JSR 250标准,同样是值越小优先级越高。但是两者还是有一定却别,@Priority能够控制组件的加载顺序,因此@Priority侧重于单个注入的优先级排序。此外@Priority优先级比@Order更高,两者共存时优先加载@Priority。

④@Primary是优先级最高的,如果同时有@Primary以及其他几个的话,@Primary注解的Bean会优先加载。

这个优先级可以在Spring源码中的DefaultListableBeanFactory类看出,从下面的代码可以看到优先确定Primary的,然后在根据权重来确定,Order与Priority只是不同规范定义的两种注解,两者效果是类似的。这里再额外说一下@Qualifier注解,如果beanName和@Qualifier一致,那么这个优先级更高,有兴趣的可以自己去源码探索一下,后面文章也会详细介绍@Qualifier这个注解。

/**      * Determine the autowire candidate in the given set of beans.      * <p>Looks for {@code @Primary} and {@code @Priority} (in that order).      * @param candidates a Map of candidate names and candidate instances      * that match the required type, as returned by {@link #findAutowireCandidates}      * @param descriptor the target dependency to match against      * @return the name of the autowire candidate, or {@code null} if none found      */     @Nullable     protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {         Class<?> requiredType = descriptor.getDependencyType();         String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);         if (primaryCandidate != null) {             return primaryCandidate;         }         String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);         if (priorityCandidate != null) {             return priorityCandidate;         }         // Fallback         for (Map.Entry<String, Object> entry : candidates.entrySet()) {             String candidateName = entry.getKey();             Object beanInstance = entry.getValue();             if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||                     matchesBeanName(candidateName, descriptor.getDependencyName())) {                 return candidateName;             }         }         return null;     } 3.测试

测试函数如下所示,只有简单的两行,创建Spring上下文获取bean,调用s()方法。具体的实现看OrderTest类。

    @Test     public void test4() {         ApplicationContext applicationContext = new AnnotationConfigApplicationContext(OrderTest.class);         ((OrderTest)applicationContext.getBean("orderTest")).test.s();     }

①使用两个@Order注解

如下所示,我们分别给Test1和Test2t设置@Order为3和2,执行后抛出异常,原因是@Order不能控制注入的优先级。

@Configuration public class OrderTest {     public interface Test {         void s();     }     @Service     @Order(3)     public class Test1 implements Test {         @Override         public void s() {             System.out.println(1);         }     }     @Service     @Order(2)     public class Test2 implements Test {         @Override         public void s() {             System.out.println(2);         }     }     @Autowired     public Test test; }

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'orderTest': Unsatisfied dependency expressed through field 'test'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.huang.config.OrderTest$Test' available: expected single matching bean but found 2: com.huang.config.OrderTest$Test2,com.huang.config.OrderTest$Test1

②使用两个注解以及一个@Primary注解

我们再上面基于给Test1添加@Primary,由于@Primary优先级更高,因此可以控制注入的优先级,所以 Test1的实例被注入了,输出结果为1。

@Configuration public class OrderTest {     public interface Test {         void s();     }     @Service     @Order(3)     @Primary     public class Test1 implements Test {         @Override         public void s() {             System.out.println(1);         }     }     @Service     @Order(2)     public class Test2 implements Test {         @Override         public void s() {             System.out.println(2);         }     }     @Autowired     public Test test; }

1

Process finished with exit code 0

③既有@Order,又有@Priority

既有@Order,又有@Priority时,可以看到虽然@Order的值更小,之前介绍值越小优先级越高,但是由于@Priority优先级更高,所以注入了Test1。

@Configuration public class OrderTest {     public interface Test {         void s();     }     @Service     @Priority(3)     public class Test1 implements Test {         @Override         public void s() {             System.out.println(1);         }     }     @Service     @Order(2)     public class Test2 implements Test {         @Override         public void s() {             System.out.println(2);         }     }     @Autowired     public Test test; }

1

Process finished with exit code 0

④两个@Priority注解

两个@Priority注解同时存在时,值越小优先级越高,因此优先注入的是Test2。

@Configuration public class OrderTest {     public interface Test {         void s();     }     @Service     @Priority(4)     public class Test1 implements Test {         @Override         public void s() {             System.out.println(1);         }     }     @Service     @Priority(3)     public class Test2 implements Test {         @Override         public void s() {             System.out.println(2);         }     }     @Autowired     public Test test; }

2

Process finished with exit code 0

⑤使用@Order控制集合注入

修改要注入的为Test集合

@Configuration public class OrderTest {     public interface Test {         void s();     }     @Service     @Order(2)     public class Test1 implements Test {         @Override         public void s() {             System.out.println(1);         }     }     @Service     @Order(1)     public class Test2 implements Test {         @Override         public void s() {             System.out.println(2);         }     }     @Autowired     public List<Test> testList; }

修改测试代码

    @Test     public void test4() {         ApplicationContext applicationContext = new AnnotationConfigApplicationContext(OrderTest.class);         ((OrderTest)applicationContext.getBean("orderTest")).testList.get(0).s();     }

执行结果如下所示,可以看到@Order值小的,优先级更高,在集合的前边。

2

Process finished with exit code 0

以上为个人经验,希望能给大家一个参考,也希望大家多多支持易知道(ezd.cc)。

推荐阅读

    01- 第一天 spring boot2.3.1 +vue3.0 后台管理系统的研发

    01- 第一天 spring boot2.3.1 +vue3.0 后台管理系统的研发,自己的,后台,后台框架一直想开发一套完全属于自己的后台,但是18年的时候,曾经答

    1.springCloud学习-注册中心eureka

    1.springCloud学习-注册中心eureka,中心,注册表,1.背景 接下来我们学习SpringCloud的注册中心,作为微服务的第一的专题,我们需要将服务注册

    Spring和SpringMVC的区别是什么

    Spring和SpringMVC的区别是什么,框架,项目,本文目录Spring和SpringMVC的区别是什么springboot 和spring的区别java编程语言中,spring boot

    SpringBoot自动配置的实现原理是什么

    SpringBoot自动配置的实现原理是什么,配置,组件,文件,方法,注册,获取,一、什么是springboot自动配置SpringBoot通过@EnableAutoConfiguration注

    SpringBoot启动流程是什么

    SpringBoot启动流程是什么,应用程序,方法,组件,上下文,对象,配置,SpringBoot启动过程简介SpringBoot应用程序的启动过程可以分为以下几个步骤:加

    disorder 是什么意思

    disorder 是什么意思,命令,订单,disorder 是什么意思1. n。混乱;凌乱;不舒服;失衡;疾病2. VT。破坏1.发音:英国。2.用法:1、动词+~  check a