欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

从头开始写项目(Q):通过扩展Convertor玩到ResponseBodyAdvice

程序员文章站 2024-03-22 00:02:22
...

要求:RestFul风格:统一返回对象格式,统一异常对象处理。

类似于一个Controller返回一个Object,然后统一封装成我们自定义的对象AppResponse。

我一开始的思路如下图:

从头开始写项目(Q):通过扩展Convertor玩到ResponseBodyAdvice

结果老大对拓展类型转换器产生浓厚的兴趣(典型的自己给自己挖坑)。

直接上用法,再解释原理。

第一步,依赖,我直接贴全部了:

	<properties>
		<spring.data.jpa.version>2.0.5.RELEASE</spring.data.jpa.version>
		<hibernate.validator.version>6.0.8.Final</hibernate.validator.version>
		<junit.jupiter.version>5.1.0</junit.jupiter.version>
		<junit.platform.version>1.1.0</junit.platform.version>
		<org.springframework.version>5.0.4.RELEASE</org.springframework.version>
		<jackson.version>2.9.4</jackson.version>
		<servlet.version>3.0.1</servlet.version>
		<mysql.connector.version>6.0.6</mysql.connector.version>
		<hibernate.version>5.2.13.Final</hibernate.version>
		<HikariCP.version>2.7.8</HikariCP.version>
		<logback.version>1.2.3</logback.version>
		<common.lang3.version>3.0</common.lang3.version>
		<aspectjweaver.version>1.8.8</aspectjweaver.version>
		<shiro.core.version>1.2.2</shiro.core.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${org.springframework.version}</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${org.springframework.version}</version>
		</dependency>

		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-core</artifactId>
			<version>${jackson.version}</version>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>${jackson.version}</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>${servlet.version}</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-jpa</artifactId>
			<version>${spring.data.jpa.version}</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>${mysql.connector.version}</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>${hibernate.version}</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-entitymanager</artifactId>
			<version>${hibernate.version}</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-ehcache</artifactId>
			<version>${hibernate.version}</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-validator</artifactId>
			<version>${hibernate.validator.version}</version>
		</dependency>
		<!-- <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> 
			<version>3.4</version> </dependency> -->
		<dependency>
			<groupId>com.zaxxer</groupId>
			<artifactId>HikariCP</artifactId>
			<version>${HikariCP.version}</version>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>${logback.version}</version>
		</dependency>
		<dependency>
			<groupId>org.junit.jupiter</groupId>
			<artifactId>junit-jupiter-api</artifactId>
			<version>${junit.jupiter.version}</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.junit.platform</groupId>
			<artifactId>junit-platform-runner</artifactId>
			<version>${junit.platform.version}</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.junit.jupiter</groupId>
			<artifactId>junit-jupiter-engine</artifactId>
			<version>${junit.jupiter.version}</version>
		</dependency>

		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>${common.lang3.version}</version>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>${aspectjweaver.version}</version>
		</dependency>
<dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>${shiro.core.version}</version>
    </dependency>
	</dependencies>
	<build>
		<finalName>demo</finalName>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.1</version>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

第二步:创建你自定义的类型转换器:

import java.io.IOException;
import java.lang.reflect.Type;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;

import com.kushou.demo.common.AppResponse;
import com.kushou.demo.common.ExceptionInfo;

@Component
public class AppResponseMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
	private static final Logger LOGGER = LoggerFactory.getLogger(AppResponseMappingJackson2HttpMessageConverter.class);

	@Override
	protected void writeInternal(Object object, @Nullable Type type, HttpOutputMessage outputMessage)
			throws IOException, HttpMessageNotWritableException {

		// 做数据处理
		if (object == null) {
			//继续原有的方法
			super.writeInternal(object, type, outputMessage);
		}
		AppResponse appResponse = new AppResponse<>();
		appResponse.setData(object);
		appResponse.setStatus(1);
		ExceptionInfo exceptionInfo = new ExceptionInfo();
		appResponse.setExceptionInfo(exceptionInfo);
		//继续原有的方法
		super.writeInternal(appResponse, type, outputMessage);
	}

}

第三步:把你自定义的类型转换器添加到springMVC的配置文件中:

<mvc:annotation-driven>
		<mvc:message-converters register-defaults="true">
			<bean class="com.demo.extension.AppResponseMappingJackson2HttpMessageConverter"></bean>
		</mvc:message-converters>
	</mvc:annotation-driven>

ok,然后写一个简单的controller测试一下:

@RequestMapping(value = "/getAllUser.action", method = { RequestMethod.GET, RequestMethod.POST })
	public Paging<User> getAllUser(HttpServletRequest request) {
		// 分页
		List<User> users;
		int count;
		users = userService.getAllUser();
		count = userService.getAllUserCount();
		LOGGER.info("获取所有用户信息成功");
		if (users == null) {
			return null;
		}
		Paging<User> paging = new Paging<>();
		paging.setData(users);
		paging.setTotal(count);
		return paging;
	}

我这里用的是@RestController,如果Class上标注的是@Controller注意添加@ResponseBody。

看一下结果:

{
	"status": 1,
	"data": {
		"total": 5,
		"data": [{
			"id": 1,
			"username": "loren",
			"password": "123456",
			"phone": null
		}, {
			"id": 2,
			"username": "loren2",
			"password": "e10adc3949ba59abbe56e057f20f883e",
			"phone": null
		}, {
			"id": 3,
			"username": "loren3",
			"password": "25f9e794323b453885f5181f1b624d0b",
			"phone": null
		}, {
			"id": 4,
			"username": "loren4",
			"password": "e10adc3949ba59abbe56e057f20f883e",
			"phone": null
		}],
		"empty": false
	},
	"exceptionInfo": {
		"code": null,
		"message": null
	}
}

似乎完成了返回对象的包装,然而这样做其实有一个问题,那就是如果我的controller返回值是null,就会有问题。看过源码的就会知道这个问题,不过等下再解释,先解决问题。

其实再spring源码RequestResponseBodyMethodProcessor的handleReturnValue这个方法里有这么一句话:

// Try even with null return value. ResponseBodyAdvice could get involved.

你可以用ResponseBodyAdvice来处理controller方法返回值为null的情况。而这个ResponseBodyAdvice方法更加简单。

第一步:自定义一个advice实现ResponseBodyAdvice:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;


@ControllerAdvice
public class MyResponseBodyAdvice implements ResponseBodyAdvice<Object>{
	private static final Logger LOGGER = LoggerFactory.getLogger(MyResponseBodyAdvice.class);
	
	@Override
	public boolean supports(MethodParameter returnType, Class converterType) {
		return true;
	}

	@Override
	public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
			Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
		LOGGER.info("+++++++++++++++++++AppResponseHandler++++++++++++++++++++++");
		if (body == null) {
			return "";
		}
		return body;
	}

}

没了,根本不需要第二步。如果我还有其他比如异常要处理,再定义一个advice实现ResponseBodyAdvice就可以了。这里注意一下advice的执行顺序,就是你的package下advice类的排列顺序,其实就是字符串的顺序。

好了,按上述做法基本就可以完成功能。其实我之前对类型转换器做扩展完全没有必要,所有的封装都可以放到advice中完成,不过我是通过扩展类型转换器发现advice的,所以接下来就跟着源码简单走一遍我的思路:

第一步:RequestResponseBodyMethodProcessor的handleReturnValue方法:

@Override
	public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
			throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

		mavContainer.setRequestHandled(true);
		ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
		ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

		// Try even with null return value. ResponseBodyAdvice could get involved.
		writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
	}

看到调用了AbstractMessageConverterMethodProcessor的writeWithMessageConverters()方法:

if (selectedMediaType != null) {
			selectedMediaType = selectedMediaType.removeQualityValue();
			for (HttpMessageConverter<?> converter : this.messageConverters) {
				GenericHttpMessageConverter genericConverter =
						(converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);
				if (genericConverter != null ?
						((GenericHttpMessageConverter) converter).canWrite(declaredType, valueType, selectedMediaType) :
						converter.canWrite(valueType, selectedMediaType)) {
					outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType,
							(Class<? extends HttpMessageConverter<?>>) converter.getClass(),
							inputMessage, outputMessage);//这里通过advice给outputValue重新赋值了
					if (outputValue != null) {//如果返回为null,直接return掉了
						addContentDispositionHeader(inputMessage, outputMessage);
						if (genericConverter != null) {//重写Converter方法的write方法调用的writeInternal()方法即可
							genericConverter.write(outputValue, declaredType, selectedMediaType, outputMessage);
						}
						else {
							((HttpMessageConverter) converter).write(outputValue, selectedMediaType, outputMessage);
						}
						if (logger.isDebugEnabled()) {
							logger.debug("Written [" + outputValue + "] as \"" + selectedMediaType +
									"\" using [" + converter + "]");
						}
					}
					return;
				}
			}
		}

关于advice的调用顺序,我们跟一下给outputValue赋值的RequestResponseBodyAdviceChain.beforeBodyWrite()方法:

@Override
	@Nullable
	public Object beforeBodyWrite(@Nullable Object body, MethodParameter returnType, MediaType contentType,
			Class<? extends HttpMessageConverter<?>> converterType,
			ServerHttpRequest request, ServerHttpResponse response) {

		return processBody(body, returnType, contentType, converterType, request, response);
	}

调用processBody()方法:

@SuppressWarnings("unchecked")
	@Nullable
	private <T> Object processBody(@Nullable Object body, MethodParameter returnType, MediaType contentType,
			Class<? extends HttpMessageConverter<?>> converterType,
			ServerHttpRequest request, ServerHttpResponse response) {

		for (ResponseBodyAdvice<?> advice : getMatchingAdvice(returnType, ResponseBodyAdvice.class)) {//遍历getMatchingAdvice()方法
			if (advice.supports(returnType, converterType)) {
				body = ((ResponseBodyAdvice<T>) advice).beforeBodyWrite((T) body, returnType,
						contentType, converterType, request, response);
			}
		}
		return body;
	}

我们发现遍历getMatchingAdvice()方法:

@SuppressWarnings("unchecked")
	private <A> List<A> getMatchingAdvice(MethodParameter parameter, Class<? extends A> adviceType) {
		List<Object> availableAdvice = getAdvice(adviceType);//这里获取advice集合
		if (CollectionUtils.isEmpty(availableAdvice)) {
			return Collections.emptyList();
		}
		List<A> result = new ArrayList<>(availableAdvice.size());
		for (Object advice : availableAdvice) {
			if (advice instanceof ControllerAdviceBean) {
				ControllerAdviceBean adviceBean = (ControllerAdviceBean) advice;
				if (!adviceBean.isApplicableToBeanType(parameter.getContainingClass())) {
					continue;
				}
				advice = adviceBean.resolveBean();
			}
			if (adviceType.isAssignableFrom(advice.getClass())) {
				result.add((A) advice);
			}
		}
		return result;
	}

这里通过getAdvice()获取advice集合:

private List<Object> getAdvice(Class<?> adviceType) {
		if (RequestBodyAdvice.class == adviceType) {
			return this.requestBodyAdvice;//自己的成员变量
		}
		else if (ResponseBodyAdvice.class == adviceType) {
			return this.responseBodyAdvice;
		}
		else {
			throw new IllegalArgumentException("Unexpected adviceType: " + adviceType);
		}
	}

显然这里是通过自己的成员变量来获取,说明在初始化服务的时候就加载了advice集合。

看一下构造器:

/**
	 * Create an instance from a list of objects that are either of type
	 * {@code ControllerAdviceBean} or {@code RequestBodyAdvice}.
	 */
	public RequestResponseBodyAdviceChain(@Nullable List<Object> requestResponseBodyAdvice) {
		if (requestResponseBodyAdvice != null) {
			for (Object advice : requestResponseBodyAdvice) {
				Class<?> beanType = (advice instanceof ControllerAdviceBean ?
						((ControllerAdviceBean) advice).getBeanType() : advice.getClass());
				if (beanType != null) {
					if (RequestBodyAdvice.class.isAssignableFrom(beanType)) {
						this.requestBodyAdvice.add(advice);
					}
					else if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
						this.responseBodyAdvice.add(advice);
					}
				}
			}
		}
	}

通过debug发现参数List<Object> requestResponseBodyAdvice已经排序过了,继续找RequestResponseBodyAdviceChain在AbstractMessageConverterMethodArgumentResolver的构造器里被构造:

/**
	 * Constructor with converters and {@code Request~} and {@code ResponseBodyAdvice}.
	 * @since 4.2
	 */
	public AbstractMessageConverterMethodArgumentResolver(List<HttpMessageConverter<?>> converters,
			@Nullable List<Object> requestResponseBodyAdvice) {

		Assert.notEmpty(converters, "'messageConverters' must not be empty");
		this.messageConverters = converters;
		this.allSupportedMediaTypes = getAllSupportedMediaTypes(converters);
		this.advice = new RequestResponseBodyAdviceChain(requestResponseBodyAdvice);//这里被构造
	}

发现AbstractMessageConverterMethodArgumentResolver的子类RequestPartMethodArgumentResolver调用了它的构造器:

public class RequestPartMethodArgumentResolver extends AbstractMessageConverterMethodArgumentResolver {

	/**
	 * Basic constructor with converters only.
	 */
	public RequestPartMethodArgumentResolver(List<HttpMessageConverter<?>> messageConverters) {
		super(messageConverters);
	}

	/**
	 * Constructor with converters and {@code Request~} and
	 * {@code ResponseBodyAdvice}.
	 */
	public RequestPartMethodArgumentResolver(List<HttpMessageConverter<?>> messageConverters,
			List<Object> requestResponseBodyAdvice) {

		super(messageConverters, requestResponseBodyAdvice);
	}

然后RequestPartMethodArgumentResolver在RequestMappingHandlerAdapter中被创建:

private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
		List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();

		// Annotation-based argument resolution
		resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
		resolvers.add(new RequestParamMapMethodArgumentResolver());
		resolvers.add(new PathVariableMethodArgumentResolver());
		resolvers.add(new PathVariableMapMethodArgumentResolver());
		resolvers.add(new MatrixVariableMethodArgumentResolver());
		resolvers.add(new MatrixVariableMapMethodArgumentResolver());
		resolvers.add(new ServletModelAttributeMethodProcessor(false));
		resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
		resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));//创建
		resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));

看到这个this.requestResponseBodyAdvice,想到要么是RequestMappingHandlerAdapter在哪里被创建,要么是set进来的。

然而它的构造器是这样的:

public RequestMappingHandlerAdapter() {
		StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
		stringHttpMessageConverter.setWriteAcceptCharset(false);  // see SPR-7316

		this.messageConverters = new ArrayList<>(4);
		this.messageConverters.add(new ByteArrayHttpMessageConverter());
		this.messageConverters.add(stringHttpMessageConverter);
		this.messageConverters.add(new SourceHttpMessageConverter<>());
		this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
	}

明显没有advice,那么去set方法看在WebMvcConfigurationSupport.requestMappingHandlerAdapter()方法被设置值:

/**
	 * Returns a {@link RequestMappingHandlerAdapter} for processing requests
	 * through annotated controller methods. Consider overriding one of these
	 * other more fine-grained methods:
	 * <ul>
	 * <li>{@link #addArgumentResolvers} for adding custom argument resolvers.
	 * <li>{@link #addReturnValueHandlers} for adding custom return value handlers.
	 * <li>{@link #configureMessageConverters} for adding custom message converters.
	 * </ul>
	 */
	@Bean
	public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
		RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
		adapter.setContentNegotiationManager(mvcContentNegotiationManager());
		adapter.setMessageConverters(getMessageConverters());
		adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer());
		adapter.setCustomArgumentResolvers(getArgumentResolvers());
		adapter.setCustomReturnValueHandlers(getReturnValueHandlers());

		if (jackson2Present) {
			adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
			adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
		}

		AsyncSupportConfigurer configurer = new AsyncSupportConfigurer();
		configureAsyncSupport(configurer);
		if (configurer.getTaskExecutor() != null) {
			adapter.setTaskExecutor(configurer.getTaskExecutor());
		}
		if (configurer.getTimeout() != null) {
			adapter.setAsyncRequestTimeout(configurer.getTimeout());
		}
		adapter.setCallableInterceptors(configurer.getCallableInterceptors());
		adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());

		return adapter;
	}

这里加进来的是JsonViewResponseBodyAdvice();而且只有一个,肯定不对。然后到前面的RequestMappingHandlerAdapter看一下:

	private void initControllerAdviceCache() {
		if (getApplicationContext() == null) {
			return;
		}
		if (logger.isInfoEnabled()) {
			logger.info("Looking for @ControllerAdvice: " + getApplicationContext());
		}

		List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
		AnnotationAwareOrderComparator.sort(adviceBeans);

		List<Object> requestResponseBodyAdviceBeans = new ArrayList<>();

		for (ControllerAdviceBean adviceBean : adviceBeans) {
			Class<?> beanType = adviceBean.getBeanType();
			if (beanType == null) {
				throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);
			}
			Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);
			if (!attrMethods.isEmpty()) {
				this.modelAttributeAdviceCache.put(adviceBean, attrMethods);
				if (logger.isInfoEnabled()) {
					logger.info("Detected @ModelAttribute methods in " + adviceBean);
				}
			}
			Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);
			if (!binderMethods.isEmpty()) {
				this.initBinderAdviceCache.put(adviceBean, binderMethods);
				if (logger.isInfoEnabled()) {
					logger.info("Detected @InitBinder methods in " + adviceBean);
				}
			}
			if (RequestBodyAdvice.class.isAssignableFrom(beanType)) {
				requestResponseBodyAdviceBeans.add(adviceBean);
				if (logger.isInfoEnabled()) {
					logger.info("Detected RequestBodyAdvice bean in " + adviceBean);
				}
			}
			if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
				requestResponseBodyAdviceBeans.add(adviceBean);
				if (logger.isInfoEnabled()) {
					logger.info("Detected ResponseBodyAdvice bean in " + adviceBean);
				}
			}
		}

		if (!requestResponseBodyAdviceBeans.isEmpty()) {
			this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
		}
	}

这里获取了有@ControllerAdvice的bean,并加入到requestResponseBodyAdvice中去了。

既然找到了,那么看一下它到底是怎样排序的。

进入AnnotationAwareOrderComparator.sort(adviceBeans):

/**
	 * Sort the given List with a default AnnotationAwareOrderComparator.
	 * <p>Optimized to skip sorting for lists with size 0 or 1,
	 * in order to avoid unnecessary array extraction.
	 * @param list the List to sort
	 * @see java.util.List#sort(java.util.Comparator)
	 */
	public static void sort(List<?> list) {
		if (list.size() > 1) {
			list.sort(INSTANCE);
		}
	}

原来直接调用了list.sort(compare);

那么只要观察这个compare的compare()方法是怎么实现的就可以了。

在它的父类OrderComparator中:

@Override
	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) {
		boolean p1 = (o1 instanceof PriorityOrdered);
		boolean p2 = (o2 instanceof PriorityOrdered);
		if (p1 && !p2) {//o1是PriorityOrdered类型而p2不是
			return -1;
		}
		else if (p2 && !p1) {//o2是PriorityOrdered类型而o1不是
			return 1;
		}
                //很明显我们自定义的两个advice都实现了ResponseBodyAdvice,所以肯定是同一类型的,所以只会走下面的方法。
		// Direct evaluation instead of Integer.compareTo to avoid unnecessary object creation.
		int i1 = getOrder(o1, sourceProvider);
		int i2 = getOrder(o2, sourceProvider);
		return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;//i1<i2则返回-1 i1>i2则返回1 相等返回0
	}

接下来看这个getOrder()方法,由于这里sourceProvider是null,所以直接进单参数的那个方法中:

protected int getOrder(@Nullable Object obj) {
		if (obj != null) {//我们自定义的对象一般不是null
			Integer order = findOrder(obj);
			if (order != null) {
				return order;//这里基本就看findOrder返回什么了
			}
		}
		return Ordered.LOWEST_PRECEDENCE;//若findOrder返回null,则返回integer的最大值
	}

再看这个findOrder方法:

@Nullable
	protected Integer findOrder(Object obj) {
		return (obj instanceof Ordered ? ((Ordered) obj).getOrder() : null);
	}
再次判断对象是不是Ordered类型,是返回getOrder的值,否返回null。

由此我们有一个注解@Order:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Documented
public @interface Order {

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

}

着这个注解上设置值,越小就会先被执行。

ok结束。