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

本文详细介绍了Spring中用于Bean排序的@Order、@Priority、@Primary注解及Ordered接口的用法。通过源码分析展示了它们在Bean加载和依赖注入中的作用,以及如何影响Bean的加载顺序和优先级选择。并通过测试案例说明了各种情况下的实际效果。

今天要来说一下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
<think>好的,我需要帮助用户理解Ordered接口的优先级排序方式。首先,根据用户提供的引用,特别是引用[2]和引用[3],可以看到Ordered接口中数值越小优先级越高,数值越大优先级越低。用户可能想知道具体的实现方法以及应用场景。 我需要先整理引用中的关键点:Ordered接口通过getOrder()方法返回一个整数来确定优先级,这个数值可以是负数,Integer.MAX_VALUE代表最低优先级。然后要说明如何使用,比如通过注解或者实现接口。接着可能需要解释为什么这样设计,比如在Spring中的应用,比如动态广播接收者和静态接收者的处理顺序,引用[4]中的例子。 用户可能还想知道如何在实际代码中应用,比如示例代码中的StubOrdered类。需要确保回答结构清晰,分点说明排序规则、实现方式、应用场景。同时生成相关的问题,比如如何设置不同优先级,或者在不同框架中的应用差异。 要避免使用Markdown,用自然的中文分段,确保LaTeX公式正确,比如在提到数值时用$符号包裹。最后检查是否符合系统级指令,如引用标识的位置是否正确,相关问题的生成是否合理。</think>在Java中,`Ordered`接口通过整数值定义优先级排序规则,具体实现方式如下: ### 一、优先级排序规则 1. **数值越小,优先级越高** 例如:`@Order(1)`的优先级高于`@Order(2)`,因为$1 < 2$[^2][^3]。 2. **数值可为负数** 负数值允许定义比默认值更高的优先级,例如`@Order(-1)`会优先于`@Order(0)`。 3. **特殊值定义** - 最高优先级:`Integer.MIN_VALUE`(理论最小值) - 最低优先级:`Integer.MAX_VALUE`(理论最大值) ### 二、实现方式 1. **通过注解定义** 使用`@Order(数值)`直接标注类或方法: ```java @Order(30) public class HighPriorityService { ... } ``` 2. **实现`Ordered`接口** 自定义类实现`getOrder()`方法返回优先级数值: ```java public class StubOrdered implements Ordered { private final int order; public StubOrdered(int order) { this.order = order; } @Override public int getOrder() { return this.order; } } ``` 引用来源:[^1] ### 三、应用场景 1. **Spring框架中的组件加载顺序** 例如:多个`BeanPostProcessor`的执行顺序由`Ordered`控制,数值小的先执行。 2. **广播接收器处理顺序** 在Android系统中,动态广播接收器(通过代码注册)默认优先级高于静态接收器(通过清单文件注册),具体可通过`priority`属性调整[^4]。 ### 四、示例对比 | 实现方式 | 优先级数值 | 实际优先级 | |----------------|-----------|------------| | `@Order(10)` | 10 | 较低 | | `@Order(-5)` | -5 | 较高 | | `Integer.MAX_VALUE` | 2147483647 | 最低 | ---
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值