溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Spring的@Order注解和Ordered接口怎么應(yīng)用

發(fā)布時(shí)間:2022-08-18 09:19:53 來(lái)源:億速云 閱讀:197 作者:iii 欄目:開(kāi)發(fā)技術(shù)

這篇“Spring的@Order注解和Ordered接口怎么應(yīng)用”文章的知識(shí)點(diǎn)大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價(jià)值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來(lái)看看這篇“Spring的@Order注解和Ordered接口怎么應(yīng)用”文章吧。

@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來(lái)獲取Class的Order注解排序信息

擴(kuò)展:Priority注解為javax擴(kuò)展注解,功能與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接口

對(duì)象排序的另一種實(shí)現(xiàn)

public interface Ordered {
    int getOrder();
}

3.OrderComparator

使用OrderComparator來(lái)比較2個(gè)對(duì)象的排序順序

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;
        }
    }
 
}

其內(nèi)部比較邏輯

return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;
  • i1比i2小則返回-1

  • i1比i2大則返回1

  • i1等于i2則返回0

4.AnnotationAwareOrderComparator

AnnotationAwareOrderComparator繼承自O(shè)rderComparator

其可以同時(shí)處理對(duì)象實(shí)現(xiàn)Ordered接口或@Order注解

其提供了靜態(tài)方法sort,可以對(duì)List進(jìn)行排序

public class AnnotationAwareOrderComparator extends OrderComparator {
}

測(cè)試代碼

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注冊(cè)順序

Demo2Config的對(duì)象將會(huì)先于Demo1Config初始化注冊(cè)

注意點(diǎn):其構(gòu)造函數(shù)的初始化并不生效

@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");
    }
 
}

輸出的結(jié)果信息:

Demo1Config

Demo2Config

demo2config 加載了

demo1config 加載了

Spring的Orderd接口及@Order,@Primary,@Priority三個(gè)注解介紹

1.如何發(fā)現(xiàn)Orderd接口及@Order、@Primary、@Priority

在前面文章說(shuō)過(guò)要通過(guò)一些常用的注解以及在學(xué)習(xí)過(guò)程中不斷的發(fā)現(xiàn),因此這里我還是按我學(xué)習(xí)的思路介紹一下我是如何發(fā)現(xiàn)他們的。如果沒(méi)有一個(gè)發(fā)現(xiàn)以及理解的過(guò)程有時(shí)候可能會(huì)很難記住,就比如我之前專(zhuān)門(mén)了解了Spring相關(guān)的注解,并且去學(xué)習(xí)用法,但是不理解稍微一不用就忘記了。

首先自己創(chuàng)建一個(gè)測(cè)試類(lèi),創(chuàng)建AnnotationConfigApplicationContext實(shí)例。

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

進(jìn)入AnnotationConfigApplicationContext構(gòu)造函數(shù)可以發(fā)現(xiàn)調(diào)用了無(wú)參構(gòu)造函數(shù),里面有個(gè)創(chuàng)建AnnotatedBeanDefinitionReader的步驟,Spring用BeanDefinition表示一個(gè)Bean,因此這個(gè)類(lèi)也很容易理解就是與讀取注解Bean有關(guān)的類(lèi)。

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

繼續(xù)進(jìn)入可以看到AnnotatedBeanDefinitionReader的構(gòu)造函數(shù),最后一行表示將那些處理注解的基礎(chǔ)設(shè)施類(lèi)添加到 DefaultListableBeanFactory中。進(jìn)入這個(gè)方法中。

    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;
        // 創(chuàng)建條件判斷者,后面用來(lái)進(jìn)行條件注解的判斷,關(guān)聯(lián)@Conditional注解,@Conditional注解內(nèi)傳入的用于判斷的類(lèi)要實(shí)現(xiàn)Condition接口的match方法
        this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);

        // 將那些處理注解的基礎(chǔ)設(shè)施類(lèi)添加到 DefaultListableBeanFactory中
        AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    }

方法中有個(gè)判斷AnnotationAwareOrderComparator是否存在步驟,這個(gè)類(lèi)從字面意思可以看出就是個(gè)比較器。

    public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
            BeanDefinitionRegistry registry, @Nullable Object source) {

        // 判斷BeanFactory是不是DefaultListableBeanFactory類(lèi)型,如果不是需要進(jìn)行轉(zhuǎn)換
        DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
        if (beanFactory != null) {
            // beanFactory的依賴(lài)關(guān)系比較器,如果沒(méi)有AnnotationAwareOrderComparator這個(gè)比較器,就傳入全局默認(rèn)靜態(tài)不可變的order比較器
            if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
                beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
            }

查看這個(gè)類(lèi)的介紹可以看到這個(gè)類(lèi)是OrderComparator的派生,OrderComparator是用來(lái)對(duì)Orderd或者@Order等內(nèi)部的值進(jìn)行比較,內(nèi)部源碼我們不做介紹,就是獲取值然后進(jìn)行數(shù)值的比較。這個(gè)類(lèi)支持Ordered、@Order、@Priority,這些是我們今天要介紹的主要內(nèi)容了,@Primary初始看起來(lái)沒(méi)有關(guān)聯(lián),后面我們?cè)俳榻B為什么會(huì)有他。

/**
 * {@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

這一個(gè)接口和三個(gè)注解比較簡(jiǎn)單,我粗略介紹一下,不做具體的介紹??偟膩?lái)說(shuō)都是用來(lái)做bean加載的排序。

  • ①orderd接口,實(shí)現(xiàn)Oderd接口的話要實(shí)現(xiàn)int getOrder();這個(gè)方法,返回一個(gè)整數(shù)值,值越小優(yōu)先級(jí)越高。

  • ②@Order里面存儲(chǔ)了一個(gè)值,默認(rèn)為Integer的最大值,同樣值越小優(yōu)先級(jí)越高。要注意@Order只能控制組件的加載順序,不能控制注入的優(yōu)先級(jí)。但是能控制List 里面存放的XXX的順序,原因是當(dāng)通過(guò)構(gòu)造函數(shù)或者方法參數(shù)注入進(jìn)某個(gè)List時(shí),Spring的DefaultListableBeanFactory類(lèi)會(huì)在注入時(shí)調(diào)用AnnotationAwareOrderComparator.sort(listA)幫我們?nèi)ネ瓿筛鶕?jù)@Order或者Ordered接口序值排序。@Order更加適用于集合注入的排序。

  • ③@Priority與@Order類(lèi)似,@Order是Spring提供的注解,@Priority是JSR 250標(biāo)準(zhǔn),同樣是值越小優(yōu)先級(jí)越高。但是兩者還是有一定卻別,@Priority能夠控制組件的加載順序,因此@Priority側(cè)重于單個(gè)注入的優(yōu)先級(jí)排序。此外@Priority優(yōu)先級(jí)比@Order更高,兩者共存時(shí)優(yōu)先加載@Priority。

  • ④@Primary是優(yōu)先級(jí)最高的,如果同時(shí)有@Primary以及其他幾個(gè)的話,@Primary注解的Bean會(huì)優(yōu)先加載。

這個(gè)優(yōu)先級(jí)可以在Spring源碼中的DefaultListableBeanFactory類(lèi)看出,從下面的代碼可以看到優(yōu)先確定Primary的,然后在根據(jù)權(quán)重來(lái)確定,Order與Priority只是不同規(guī)范定義的兩種注解,兩者效果是類(lèi)似的。這里再額外說(shuō)一下@Qualifier注解,如果beanName和@Qualifier一致,那么這個(gè)優(yōu)先級(jí)更高,有興趣的可以自己去源碼探索一下。

/**
     * 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.測(cè)試

測(cè)試函數(shù)如下所示,只有簡(jiǎn)單的兩行,創(chuàng)建Spring上下文獲取bean,調(diào)用s()方法。具體的實(shí)現(xiàn)看OrderTest類(lèi)。

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

①使用兩個(gè)@Order注解

如下所示,我們分別給Test1和Test2t設(shè)置@Order為3和2,執(zhí)行后拋出異常,原因是@Order不能控制注入的優(yōu)先級(jí)。

@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

②使用兩個(gè)注解以及一個(gè)@Primary注解

我們?cè)偕厦婊诮oTest1添加@Primary,由于@Primary優(yōu)先級(jí)更高,因此可以控制注入的優(yōu)先級(jí),所以 Test1的實(shí)例被注入了,輸出結(jié)果為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時(shí),可以看到雖然@Order的值更小,之前介紹值越小優(yōu)先級(jí)越高,但是由于@Priority優(yōu)先級(jí)更高,所以注入了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

④兩個(gè)@Priority注解

兩個(gè)@Priority注解同時(shí)存在時(shí),值越小優(yōu)先級(jí)越高,因此優(yōu)先注入的是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控制集合注入

修改要注入的為T(mén)est集合

@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;
}

修改測(cè)試代碼

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

執(zhí)行結(jié)果如下所示,可以看到@Order值小的,優(yōu)先級(jí)更高,在集合的前邊。

2

Process finished with exit code 0

以上就是關(guān)于“Spring的@Order注解和Ordered接口怎么應(yīng)用”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對(duì)大家有幫助,若想了解更多相關(guān)的知識(shí)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI