spring中关于Order的那点事

写在前面

本文阅读源码版本为spring5.3.1

为啥要用Order

spring是一个大量使用策略设计模式的框架,这意味着有很多相同接口的实现类,如果不手动指定顺序的话,那么使用时肯定会有问题。而Order给我们提供了一种编码设置顺序的可能。

关于Order

spring中提供了多种方式来设置优先级,有Ordered,PriorityOrdered接口,有Order注解,除此之外,spring4.1以后,还可以使用Priority注解。下面我将针对这几种用法从源码的角度来进行分析。

Ordered,PriorityOrdered接口
public interface Ordered {
	/**
	 * 最高优先值
	 */
	int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;

	/**
	 * 最低优先值
	 */
	int LOWEST_PRECEDENCE = Integer.MAX_VALUE;

	int getOrder();
}

PriorityOrdered继承了Ordered,但并未提供任何方法,这是一个标记了优先级的接口,和Ordered相比,PriorityOrdered就是高人一等,spring中提供了比较器OrderComparator,可以通过构建一个OrderComparator,调用其compare方法,不过OrderComparator提供了一个静态sort方法,我们无需自己构建OrderComparator了,排序的结果按照order值从小到大排序。

demo

public class OrderDemo{
	private final OrderComparator comparator = new OrderComparator();

	@Test
    void comparePriorityOrderedInstanceToStandardOrderedInstanceWithSamePriority() {
        assertThatPriorityOrderedAlwaysWins(new StubPriorityOrdered(100), new StubOrdered(100));
    }

    @Test
    void comparePriorityOrderedInstanceToStandardOrderedInstanceWithLowerPriority() {
        assertThatPriorityOrderedAlwaysWins(new StubPriorityOrdered(100), new StubOrdered(200));
    }
	
	@Test
    void compareOrderedInstancesBefore() {
        assertThat(this.comparator.compare(new StubOrdered(100), new StubOrdered(2000))).isEqualTo(-1);
    }

    @Test
    void compareOrderedInstancesNullFirst() {
        assertThat(this.comparator.compare(null, new StubOrdered(100))).isEqualTo(1);
    }

    @Test
    void compareOrderedInstancesNullLast() {
        assertThat(this.comparator.compare(new StubOrdered(100), null)).isEqualTo(-1);
    }

	@Test
    void test1() {
        assertThat(this.comparator.compare(new Object (), new StubOrdered(2000))).isEqualTo(1);
    }

	 private static class StubOrdered implements Ordered {
        private final int order;

        StubOrdered(int order) {
            this.order = order;
        }

        @Override
        public int getOrder() {
            return this.order;
        }
    }

    private static class StubPriorityOrdered implements PriorityOrdered {

        private final int order;

        StubPriorityOrdered(int order) {
            this.order = order;
        }

        @Override
        public int getOrder() {
            return this.order;
        }
    }
}
小结
  1. PriorityOrdered优先级比Ordered高,与设置的order值无关。
  2. 若两个对象都实现了Ordered或PriorityOrdered接口,那么设置的order值越小,优先值越高。
  3. 若没有实现Ordered或PriorityOrdered接口,默认是最低的优先级。
OrderComparator#compare解读

在看compare之前,我觉得将OrderSourceProvider这个函数式接口放在前面讲解一下,阅读源码时会更清晰一点。

	@FunctionalInterface
	public interface OrderSourceProvider {

		/**
		 * 对给定对象校验并返回一个新的对象
		 */
		@Nullable
		Object getOrderSource(Object obj);
	}

demo

public class OrderDemo{
	private final OrderComparator comparator = new OrderComparator();

	private static class TestSourceProvider implements OrderComparator.OrderSourceProvider {

		private final Object target;

		private final Object orderSource;

		TestSourceProvider(Object target, Object orderSource) {
			this.target = target;
			this.orderSource = orderSource;
		}

		@Override
		public Object getOrderSource(Object obj) {
			if (target.equals(obj)) {
				return orderSource;
			}
			return null;
		}
	}

	@Test
	void compareWithSourceProviderArray() {
		Comparator<Object> customComparator = this.comparator.withSourceProvider(
				new TestSourceProvider(5L, new Object[] {new StubOrdered(10), new StubOrdered(-25)}));
		assertThat(customComparator.compare(5L, new Object())).isEqualTo(-1);
	}

	@Test
	void compareWithSourceProviderArrayNoMatch() {
		Comparator<Object> customComparator = this.comparator.withSourceProvider(
				new TestSourceProvider(5L, new Object[] {new Object(), new Object()}));
		assertThat(customComparator.compare(new Object(), 5L)).isEqualTo(0);
	}

	@Test
	void compareWithSourceProviderEmpty() {
		Comparator<Object> customComparator = this.comparator.withSourceProvider(
				new TestSourceProvider(50L, new Object()));
		assertThat(customComparator.compare(new Object(), 5L)).isEqualTo(0);
	}
}

接下来我们来阅读compare源码。

	public int compare(@Nullable Object o1, @Nullable Object o2) {
		return doCompare(o1, o2, null);
	}

	private int doCompare(@Nullable Object o1, @Nullable Object o2, @Nullable OrderSourceProvider sourceProvider) {
		// 这里会判断是否实现了PriorityOrdered接口
		boolean p1 = (o1 instanceof PriorityOrdered);
		boolean p2 = (o2 instanceof PriorityOrdered);
		// 这里会看到根本没有比较order的值,只要实现PriorityOrdered接口,就会排在前面
		if (p1 && !p2) {
			return -1;
		}else if (p2 && !p1) {
			return 1;
		}
		// 获取对象设置的order值
		int i1 = getOrder(o1, sourceProvider);
		int i2 = getOrder(o2, sourceProvider);
		return Integer.compare(i1, i2);
	}
	
	private int getOrder(@Nullable Object obj, @Nullable OrderSourceProvider sourceProvider) {
		Integer order = null;
		if (obj != null && sourceProvider != null) {
			Object orderSource = sourceProvider.getOrderSource(obj);
			if (orderSource != null) {
				// 如果返回的是数组
				if (orderSource.getClass().isArray()) {
					for (Object source : ObjectUtils.toObjectArray(orderSource)) {
						// 只要找到对象设置的order值,就跳出
						order = findOrder(source);
						if (order != null) {
							break;
						}
					}
				}else {
					order = findOrder(orderSource);
				}
			}
		}
		// 如果我们没有提供OrderSourceProvider 
		return (order != null ? order : getOrder(obj));
	}

	protected int getOrder(@Nullable Object obj) {
		if (obj != null) {
			Integer order = findOrder(obj);
			if (order != null) {
				return order;
			}
		}
		// object为null时,返回值最大
		return Ordered.LOWEST_PRECEDENCE;
	}

	protected Integer findOrder(Object obj) {
		// 没有实现Ordered接口将返回null
		return (obj instanceof Ordered ? ((Ordered) obj).getOrder() : null);
	}
@Order与@Priority

spring中提供了对@Order与@Priority支持的比较器AnnotationAwareOrderComparator,该类继承OrderComparator,并覆盖了findOrder方法,我们来一起看下源码。

	protected Integer findOrder(Object obj) {
		Integer order = super.findOrder(obj);
		if (order != null) {
			return order;
		}
		// 调用父类的findOrder方法无法找到设定的order值时
		return findOrderFromAnnotation(obj);
	}
	
	private Integer findOrderFromAnnotation(Object obj) {
		AnnotatedElement element = (obj instanceof AnnotatedElement ? (AnnotatedElement) obj : obj.getClass());
		// 对整个类型层次结构执行完整搜索,包括父类和接口
		MergedAnnotations annotations = MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY);
		// 获取注解中设置的order值
		Integer order = OrderUtils.getOrderFromAnnotations(element, annotations);
		if (order == null && obj instanceof DecoratingProxy) {
			return findOrderFromAnnotation(((DecoratingProxy) obj).getDecoratedClass());
		}
		return order;
	}
	
	static Integer getOrderFromAnnotations(AnnotatedElement element, MergedAnnotations annotations) {
		if (!(element instanceof Class)) {
			return findOrder(annotations);
		}
		// 加入缓存中
		Object cached = orderCache.get(element);
		if (cached != null) {
			return (cached instanceof Integer ? (Integer) cached : null);
		}
		Integer result = findOrder(annotations);
		orderCache.put(element, result != null ? result : NOT_ANNOTATED);
		return result;
	}
	
	// 没有找到Order注解后才去寻找@Priority注解
	private static Integer findOrder(MergedAnnotations annotations) {
		MergedAnnotation<Order> orderAnnotation = annotations.get(Order.class);
		if (orderAnnotation.isPresent()) {
			return orderAnnotation.getInt(MergedAnnotation.VALUE);
		}
		MergedAnnotation<?> priorityAnnotation = annotations.get(JAVAX_PRIORITY_ANNOTATION);
		if (priorityAnnotation.isPresent()) {
			return priorityAnnotation.getInt(MergedAnnotation.VALUE);
		}
		return null;
	}

demo

public class AnnotationAwareOrderComparatorTests {
	@Test
	void sortInstancesWithSubclass() {
		List<Object> list = new ArrayList<>();
		list.add(new B());
		list.add(new C());
		AnnotationAwareOrderComparator.sort(list);
		assertThat(list.get(0) instanceof C).isTrue();
		assertThat(list.get(1) instanceof B).isTrue();
	}

	@Test
	void sortInstancesWithOrderAndPriority() {
		List<Object> list = new ArrayList<>();
		list.add(new B());
		list.add(new A2());
		AnnotationAwareOrderComparator.sort(list);
		assertThat(list.get(0) instanceof A2).isTrue();
		assertThat(list.get(1) instanceof B).isTrue();
	}
	
	@Order(1)
	private static class A {
	}

	@Order(2)
	private static class B {
	}
	
	private static class C extends A {
	}

	@Priority(1)
	private static class A2 {
	}
}
小结

@Order与@Priority注解放置在类,接口或参数上,可以被继承;它们之间是可以互相替换的关系。

应用

spring源码中有很多地方都显式的调用AnnotationAwareOrderComparator的sort方法,也有一些地方调用的OrderComparator的sort方法,大家自己可以找找看。

我这里发现了一点有意思的地方,我们如果定义多个ControllerAdvice的bean,分别通过实现Ordered,PriorityOrdered接口来定义执行时的顺序,会发现上面我们总结的 PriorityOrdered优先级就是比Ordered高 这一点不成立,其实只是spring将ControllerAdvice相关信息封装了一下欺骗了我们。我看的源码的版本是5.3.1,低于5.2版本的不会发生这样的事情。这里我们就来看看5.2版本前后源码有哪些变化,导致了这个现象的发生。

这里就拿RequestMappingHandlerAdapter初始化去寻找ControllerAdvice注解的代码来举例

	private void initControllerAdviceCache() {
		if (getApplicationContext() == null) {
			return;
		}

		List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
		// 5.2版本前使用下面注释的这行代码,5.2之后这行代码就去掉了,而是在上面findAnnotatedBeans
		// 方法中使用OrderComparator.sort(adviceBeans)
		//AnnotationAwareOrderComparator.sort(adviceBeans);
		...
	}

我们知道OrderComparator适用范围是比AnnotationAwareOrderComparator要窄一点的,它不支持注解,那么上面这样的改动是不是就意味着我们定义ControllerAdvice时,就不能使用@Order与@Pri-ority呢?其实它是支持的,ControllerAdviceBean#findAnnotatedBeans方法中会将我们定义的Con-trollerAdvice类包装成ControllerAdviceBean,而ControllerAdviceBean是实现了Ordered接口的,那么OrderComparator#sort方法要想支持使用注解,ControllerAdviceBean的getOrder方法中就必须干点啥,分析了挺多,我们还是看源码实现吧。

	// 5.2版本后
	public int getOrder() {
		if (this.order == null) {
			String beanName = null;
			Object resolvedBean = null;
			// 这里根据beanName获取bean
			if (this.beanFactory != null && this.beanOrName instanceof String) {
				beanName = (String) this.beanOrName;
				String targetBeanName = ScopedProxyUtils.getTargetBeanName(beanName);
				boolean isScopedProxy = this.beanFactory.containsBean(targetBeanName);
				if (!isScopedProxy && !ScopedProxyUtils.isScopedTarget(beanName)) {
					resolvedBean = resolveBean();
				}
			}else {
				resolvedBean = resolveBean();
			}
			// 这里只判断了是否实现了Ordered接口,并没有对实现PriorityOrdered作特殊处理
			// 这里优先判断是否实现了Ordered接口,如果同时使用注解的话将被忽略
			if (resolvedBean instanceof Ordered) {
				this.order = ((Ordered) resolvedBean).getOrder();
			}else {
				if (beanName != null && this.beanFactory instanceof ConfigurableBeanFactory) {
					ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) this.beanFactory;
					try {
						BeanDefinition bd = cbf.getMergedBeanDefinition(beanName);
						if (bd instanceof RootBeanDefinition) {
							Method factoryMethod = ((RootBeanDefinition) bd).getResolvedFactoryMethod();
							if (factoryMethod != null) {
								// 这里将会从注解@Order与@Priority中获取order值
								this.order = OrderUtils.getOrder(factoryMethod);
							}
						}
					}catch (NoSuchBeanDefinitionException ex) {
						// ignore -> probably a manually registered singleton
					}
				}
				if (this.order == null) {
					if (this.beanType != null) {
						this.order = OrderUtils.getOrder(this.beanType, Ordered.LOWEST_PRECEDENCE);
					}
					else {
						this.order = Ordered.LOWEST_PRECEDENCE;
					}
				}
			}
		}
		return this.order;
	}

源码分析后,我们来看一段测试demo

public class ControllerAdviceBeanTests {
	@ControllerAdvice
	@Order(100)
	@Priority(200)
	static class OrderedControllerAdvice implements Ordered {

		@Override
		public int getOrder() {
			return 42;
		}
	}

	@ControllerAdvice
	// Order和@Priority由于Order的实现应该被忽略
	@Order(100)
	@Priority(200)
	static class PriorityOrderedControllerAdvice implements PriorityOrdered {

		@Override
		public int getOrder() {
			return 55;
		}
	}

	@Configuration(proxyBeanMethods = false)
	static class Config {
		@Bean
		OrderedControllerAdvice orderedControllerAdvice() {
			return new OrderedControllerAdvice();
		}

		@Bean
		PriorityOrderedControllerAdvice priorityOrderedControllerAdvice() {
			return new PriorityOrderedControllerAdvice();
		}
	}

	@Test
	@SuppressWarnings({"rawtypes", "unchecked"})
	public void findAnnotatedBeansSortsBeans() {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
		List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(context);
		// 输出顺序并不是 55 42,而是42,55
		for (ControllerAdviceBean adviceBean : adviceBeans) {
			System.out.println (adviceBean.getOrder ());
		}
	}
}

知其然,知其所以然,学才不倦

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值