Spring筆記-@Order注解和Ordered接口解析
@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注解排序信息
擴(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接口
對象排序的另一種實(shí)現(xiàn)
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;
? ? ? ? }
? ? }
?
}其內(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í)處理對象實(shí)現(xiàn)Ordered接口或@Order注解
其提供了靜態(tài)方法sort,可以對List進(jìn)行排序
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初始化注冊
注意點(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三個注解介紹
今天要來說一下Orderd接口以及@Order、@Primary、@Priority注解這幾個東西,原本只是想介紹一下@Order,但是這幾個有一定的關(guān)聯(lián),因此這里一起進(jìn)行介紹。這幾個接口是用來排序,本文主要介紹用法,具體的比如Spring什么時(shí)候?qū)λ麄兣判虬?,后面在介紹Spring的處理過程的時(shí)候再介紹,還有怎么排序的這些比較好理解的也不介紹了。
1.如何發(fā)現(xiàn)Orderd接口及@Order、@Primary、@Priority
在前面文章說過要通過一些常用的注解以及在學(xué)習(xí)過程中不斷的發(fā)現(xiàn),因此這里我還是按我學(xué)習(xí)的思路介紹一下我是如何發(fā)現(xiàn)他們的。如果沒有一個發(fā)現(xiàn)以及理解的過程有時(shí)候可能會很難記住,就比如我之前專門了解了Spring相關(guān)的注解,并且去學(xué)習(xí)用法,但是不理解稍微一不用就忘記了。
首先自己創(chuàng)建一個測試類,創(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)用了無參構(gòu)造函數(shù),里面有個創(chuàng)建AnnotatedBeanDefinitionReader的步驟,Spring用BeanDefinition表示一個Bean,因此這個類也很容易理解就是與讀取注解Bean有關(guān)的類。
?? ?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è)施類添加到 DefaultListableBeanFactory中。進(jìn)入這個方法中。
?? ?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)建條件判斷者,后面用來進(jìn)行條件注解的判斷,關(guān)聯(lián)@Conditional注解,@Conditional注解內(nèi)傳入的用于判斷的類要實(shí)現(xiàn)Condition接口的match方法
?? ??? ?this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
?? ??? ?// 將那些處理注解的基礎(chǔ)設(shè)施類添加到 DefaultListableBeanFactory中
?? ??? ?AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
?? ?}方法中有個判斷AnnotationAwareOrderComparator是否存在步驟,這個類從字面意思可以看出就是個比較器。
?? ?public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
?? ??? ??? ?BeanDefinitionRegistry registry, @Nullable Object source) {
?? ??? ?// 判斷BeanFactory是不是DefaultListableBeanFactory類型,如果不是需要進(jìn)行轉(zhuǎn)換
?? ??? ?DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
?? ??? ?if (beanFactory != null) {
?? ??? ??? ?// beanFactory的依賴關(guān)系比較器,如果沒有AnnotationAwareOrderComparator這個比較器,就傳入全局默認(rèn)靜態(tài)不可變的order比較器
?? ??? ??? ?if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
?? ??? ??? ??? ?beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
?? ??? ??? ?}查看這個類的介紹可以看到這個類是OrderComparator的派生,OrderComparator是用來對Orderd或者@Order等內(nèi)部的值進(jìn)行比較,內(nèi)部源碼我們不做介紹,就是獲取值然后進(jìn)行數(shù)值的比較。這個類支持Ordered、@Order、@Priority,這些是我們今天要介紹的主要內(nèi)容了,@Primary初始看起來沒有關(guān)聯(lián),后面我們再介紹為什么會有他。
/**
?* {@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接口,實(shí)現(xiàn)Oderd接口的話要實(shí)現(xiàn)int getOrder();這個方法,返回一個整數(shù)值,值越小優(yōu)先級越高。
- ②@Order里面存儲了一個值,默認(rèn)為Integer的最大值,同樣值越小優(yōu)先級越高。要注意@Order只能控制組件的加載順序,不能控制注入的優(yōu)先級。但是能控制List 里面存放的XXX的順序,原因是當(dāng)通過構(gòu)造函數(shù)或者方法參數(shù)注入進(jìn)某個List時(shí),Spring的DefaultListableBeanFactory類會在注入時(shí)調(diào)用AnnotationAwareOrderComparator.sort(listA)幫我們?nèi)ネ瓿筛鶕?jù)@Order或者Ordered接口序值排序。@Order更加適用于集合注入的排序。
- ③@Priority與@Order類似,@Order是Spring提供的注解,@Priority是JSR 250標(biāo)準(zhǔn),同樣是值越小優(yōu)先級越高。但是兩者還是有一定卻別,@Priority能夠控制組件的加載順序,因此@Priority側(cè)重于單個注入的優(yōu)先級排序。此外@Priority優(yōu)先級比@Order更高,兩者共存時(shí)優(yōu)先加載@Priority。
- ④@Primary是優(yōu)先級最高的,如果同時(shí)有@Primary以及其他幾個的話,@Primary注解的Bean會優(yōu)先加載。
這個優(yōu)先級可以在Spring源碼中的DefaultListableBeanFactory類看出,從下面的代碼可以看到優(yōu)先確定Primary的,然后在根據(jù)權(quán)重來確定,Order與Priority只是不同規(guī)范定義的兩種注解,兩者效果是類似的。這里再額外說一下@Qualifier注解,如果beanName和@Qualifier一致,那么這個優(yōu)先級更高,有興趣的可以自己去源碼探索一下,后面文章也會詳細(xì)介紹@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.測試
測試函數(shù)如下所示,只有簡單的兩行,創(chuàng)建Spring上下文獲取bean,調(diào)用s()方法。具體的實(shí)現(xiàn)看OrderTest類。
?? ?@Test
?? ?public void test4() {
?? ??? ?ApplicationContext applicationContext = new AnnotationConfigApplicationContext(OrderTest.class);
?? ??? ?((OrderTest)applicationContext.getBean("orderTest")).test.s();
?? ?}①使用兩個@Order注解
如下所示,我們分別給Test1和Test2t設(shè)置@Order為3和2,執(zhí)行后拋出異常,原因是@Order不能控制注入的優(yōu)先級。
@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優(yōu)先級更高,因此可以控制注入的優(yōu)先級,所以 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)先級越高,但是由于@Priority優(yōu)先級更高,所以注入了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注解同時(shí)存在時(shí),值越小優(yōu)先級越高,因此優(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控制集合注入
修改要注入的為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();
?? ?}執(zhí)行結(jié)果如下所示,可以看到@Order值小的,優(yōu)先級更高,在集合的前邊。
2
Process finished with exit code 0
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解Java?List中五種常見實(shí)現(xiàn)類的使用
Java中提供了非常多的使用的List實(shí)現(xiàn)類,本文將重點(diǎn)介紹一下常見的五種實(shí)現(xiàn)類以及他們的應(yīng)用場景,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-10-10
spring mvc 讀取xml文件數(shù)據(jù)庫配置參數(shù)的方法
下面小編就為大家?guī)硪黄猻pring mvc 讀取xml文件數(shù)據(jù)庫配置參數(shù)的方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-10-10
maven打包web項(xiàng)目時(shí)同時(shí)打包為war和jar文件的方法
本篇文章主要介紹了maven打包web項(xiàng)目時(shí)同時(shí)打包為war和jar文件的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10
Idea開發(fā)工具之SpringBoot整合JSP的過程
最近在學(xué)習(xí)SpringBoot,看到SpringBoot整合jsp,順帶記錄一下。本文通過圖文實(shí)例相結(jié)合給大家講解SpringBoot整合JSP的過程,感興趣的朋友一起看看吧2021-09-09
java基于netty NIO的簡單聊天室的實(shí)現(xiàn)
這篇文章主要介紹了java基于netty NIO的簡單聊天室的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
Maven在Java8下如何忽略Javadoc的編譯錯誤詳解
這篇文章主要給大家介紹了關(guān)于Maven在Java8下如何忽略Javadoc的編譯錯誤的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-08-08

