ControllerAdvice的作用范围:
ControllerAdvice 提供了多种指定Advice规则的定义方式,默认什么都不写,则是Advice所有Controller,当然你也可以通过下列的方式指定规则
(1)、指定包
匹配org.my.pkg包及其子包下的所有Controller @ControllerAdvice(basePackages="org.my.pkg") 当然也可以用数组的形式指定,如: @ControllerAdvice(basePackages={"org.my.pkg", "org.my.other.pkg"}),
(2)、指定注解
也可以通过指定注解来匹配,比如我自定了一个 @CustomAnnotation 注解,我想匹配所有被这个注解修饰的 Controller, 可以这么写:@ControllerAdvice(annotations={CustomAnnotation.class})
如果我们想让接口不被@ControllerAdvice注解的拦截器拦截,可以通过指定包的方式解决,即将接口放在指定的包范围之外。另外@ControllerAdvice不拦截@RequestParam请求。
一、源码解析
这是spring 4.2新加的两个接口
1、RequestBodyAdvice
需要注解@ControllerAdvice和实现RequestBodyAdvice 接口,并且这个拦截只会针对@RequestBody注解的生效 。
RequestBodyAdvice:对@RquestBody 进行增强处理,比如所有请求的数据都加密之后放在 body 中,在到达 controller 的方法之前,需要先进行解密,那么就可以通过 RequestBodyAdvice 来进行统一的解密处理,无需在 controller 方法中去做这些通用的操作。
注意:RequestBodyAdvice由于是对@RequestBody进行增强处理,拦截不到无@RequestBody的方法。对@RequestParam无法进行增强处理,当上传文件时,请求可以被拦截的(代码如下所示,确切的说有时可以拦截,有时不能拦截,不太稳定)。
@PostMapping("/importExcelDrug") public Result importInfo(@RequestParam("file") MultipartFile file, HttpServletResponse response) {...}
如我们在RequestBodyAdvice中将用户信息存入SessionCache中,这样就可以在所有的请求中获取到用户信息。代码如下:
@Component @ControllerAdvice({"com.xxxx.controller"}) @Slf4j public class MyRequestBodyHandler implements RequestBodyAdvice { @Autowired private LoginServiceClient loginServiceClient; @Override public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) { return true; } @Override public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException { return inputMessage; } @Override public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) { String token = inputMessage.getHeaders().getFirst("token"); //获取登录用户信息 UserDTO loginUser = loginServiceClient.getLoginUserByToken(); if (loginUser == null) { log.error("获取登录用户信息为空,toekn:{}", token); } else { SessionCache.put(loginUser); } return body; } @Override public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) { return body; } }
源码解析
public interface RequestBodyAdvice { boolean supports(MethodParameter var1, Type var2, Class<? extends HttpMessageConverter<?>> var3); HttpInputMessage beforeBodyRead(HttpInputMessage var1, MethodParameter var2, Type var3, Class<? extends HttpMessageConverter<?>> var4)
throws IOException; Object afterBodyRead(Object var1, HttpInputMessage var2, MethodParameter var3, Type var4, Class<? extends HttpMessageConverter<?>> var5); @Nullable Object handleEmptyBody(@Nullable Object var1, HttpInputMessage var2, MethodParameter var3, Type var4,
Class<? extends HttpMessageConverter<?>> var5); }
查看一下谁调用了这个接口的这些方法,可以看到AbstractMessageConverterMethodArgumentResolver的readWithMessageConverters()方法调用了这个接口的方法。
@Nullable protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType)
throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException { boolean noContentType = false; MediaType contentType; try { contentType = inputMessage.getHeaders().getContentType(); } catch (InvalidMediaTypeException var16) { throw new HttpMediaTypeNotSupportedException(var16.getMessage()); } if (contentType == null) { noContentType = true; contentType = MediaType.APPLICATION_OCTET_STREAM; } Class<?> contextClass = parameter.getContainingClass(); Class<T> targetClass = targetType instanceof Class ? (Class)targetType : null; if (targetClass == null) { ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter); targetClass = resolvableType.resolve(); } HttpMethod httpMethod = inputMessage instanceof HttpRequest ? ((HttpRequest)inputMessage).getMethod() : null; Object body = NO_VALUE; AbstractMessageConverterMethodArgumentResolver.EmptyBodyCheckingHttpInputMessage message; try { label94: { message = new AbstractMessageConverterMethodArgumentResolver.EmptyBodyCheckingHttpInputMessage(inputMessage); Iterator var11 = this.messageConverters.iterator(); HttpMessageConverter converter; Class converterType; GenericHttpMessageConverter genericConverter; while(true) { if (!var11.hasNext()) { break label94; } converter = (HttpMessageConverter)var11.next(); converterType = converter.getClass(); genericConverter = converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter)converter : null; if (genericConverter != null) { if (genericConverter.canRead(targetType, contextClass, contentType)) { break; } } else if (targetClass != null && converter.canRead(targetClass, contentType)) { break; } } if (message.hasBody()) { HttpInputMessage msgToUse = this.getAdvice().beforeBodyRead(message, parameter, targetType, converterType); body = genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
converter.read(targetClass, msgToUse); body = this.getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType); } else { body = this.getAdvice().handleEmptyBody((Object)null, message, parameter, targetType, converterType); } } } catch (IOException var17) { throw new HttpMessageNotReadableException("I/O error while reading input message", var17, inputMessage); } if (body != NO_VALUE) { LogFormatUtils.traceDebug(this.logger, (traceOn) -> { String formatted = LogFormatUtils.formatValue(body, !traceOn); return "Read \"" + contentType + "\" to [" + formatted + "]"; }); return body; } else if (httpMethod != null && SUPPORTED_METHODS.contains(httpMethod) && (!noContentType || message.hasBody())) { throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes); } else { return null; } }
可以看到这接口的方法,主要是在HttpMessageConverter处理request body的前后做一些处理和body为空的时候做处理。
从这个可以看出,我们可以在使用这些HandlerMethodArgumentResolver的时候,我们能对request body进行前处理和解析后处理。
2、ResponseBodyAdvice
拦截不到无@ResponseBody的方法
public interface ResponseBodyAdvice<T> { boolean supports(MethodParameter var1, Class<? extends HttpMessageConverter<?>> var2); @Nullable T beforeBodyWrite(@Nullable T var1, MethodParameter var2, MediaType var3, Class<? extends HttpMessageConverter<?>> var4,
ServerHttpRequest var5, ServerHttpResponse var6); }
此可以对@ResponseBody的返回结果在输出到响应之前做处理。
通过泛型,指定需要被“拦截”的响应体对象类型。该接口的实现会在 Controller
方法返回数据,并且匹配到了 HttpMessageConverter
之后,HttpMessageConverter
进行序列化之前执行。可以通过覆写 beforeBodyWrite
来统一的对响应体进行修改。
二、RequestBodyAdvice的使用
首先一个实现类实现RequestBodyAdvice,后在类上加上注解@ControllerAdvice,这俩个缺一不可。比如有些请求的请求体已经做加密处理,可以在此将请求体解密。
核心的方法就是 supports
,该方法返回的boolean值,决定了是要执行 beforeBodyRead
方法。
而我们主要的逻辑就是在beforeBodyRead
方法中,对客户端的请求体进行解密。
注意:不用加@Component注解
//@Component @ControllerAdvice public class RequestBodyDecrypt implements RequestBodyAdvice { @Reference private EquipmentService equipmentService; @Override public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) { return true; // 必须为true才会执行beforeBodyRead和afterBodyRead方法 } @Override public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type,
Class<? extends HttpMessageConverter<?>> aClass) throws IOException { String equipmentNo = httpInputMessage.getHeaders().getFirst("equipmentNo"); // 从请求头中获取equipmentNo,getFirst()方法根据请求头的名称获取值 String privateKey = null; List<EquipmentDTO> mapList = equipmentService.getByEquipmentNo(equipmentNo); if (mapList.size() > 0) { EquipmentDTO equipmentDTO = mapList.get(0); privateKey = equipmentDTO.getProdPriKey(); } // 提取数据 InputStream is = httpInputMessage.getBody(); // 从HTTPInputMessage中获取请求体,得到字节输入流 byte[] data = new byte[is.available()]; is.read(data); String dataStr = new String(data, StandardCharsets.UTF_8); JSONObject json = JSONObject.parseObject(dataStr); String decrypt = null; try { decrypt = RSAUtils.decryptByPrivateKey(json.getString("applyData"), privateKey); // 私钥解密后的请求体 } catch (Exception e) { throw new RuntimeException("数据错误"); }
// 将解密后的请求体封装到HttpInputMessage中返回 return new DecodedHttpInputMessage(httpInputMessage.getHeaders(), new ByteArrayInputStream(decrypt.getBytes(StandardCharsets.UTF_8))); } @Override public Object afterBodyRead(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type,
Class<? extends HttpMessageConverter<?>> aClass) { return body; } @Override public Object handleEmptyBody(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type,
Class<? extends HttpMessageConverter<?>> aClass) { return body; } static class DecodedHttpInputMessage implements HttpInputMessage { HttpHeaders headers; InputStream body; public DecodedHttpInputMessage(HttpHeaders headers, InputStream body) { this.headers = headers; this.body = body; } @Override public InputStream getBody() throws IOException { return body; } @Override public HttpHeaders getHeaders() { return headers; } } }
decryptByPrivateKey:
public static String decryptByPrivateKey(String encryptData, String priKey) throws NoSuchAlgorithmException,
InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, IOException { byte[] sourceBytes = Base64.getDecoder().decode(encryptData); byte[] keyBytes = Base64.getDecoder().decode(priKey); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); Key priK = keyFactory.generatePrivate(pkcs8KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, priK); int inputLen = sourceBytes.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] cache; int i = 0; // 对数据分段解密 while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_DECRYPT_BLOCK) { cache = cipher.doFinal(sourceBytes, offSet, MAX_DECRYPT_BLOCK); } else { cache = cipher.doFinal(sourceBytes, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); i++; offSet = i * MAX_DECRYPT_BLOCK; } String decryptedData = out.toString("UTF-8"); out.close(); return decryptedData; }
三、ResponseBodyAdvice的使用
首先一个实现类实现ResponseBodyAdvice,后在类上加上注解@ControllerAdvice,
@ControllerAdvice public class MyResponseBodyAdvice implements ResponseBodyAdvice<Result> { /** * 加密串一 */ private static String md5_keyone; /** * 加密串二 */ private static String md5_keytwo; @PostConstruct public void init() throws Exception { md5_keyone = Utils.PT.getProps("md5_keyone"); md5_keytwo = Utils.PT.getProps("md5_keytwo"); } /** * 判断支持的类型 * * @param returnType * @param converterType * @return * @see org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice#supports(org.springframework.core.MethodParameter, * java.lang.Class) */ @Override public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { return returnType.getMethod().getReturnType().isAssignableFrom(Result.class); } /** * 对于结果进行加密 * * @param body * @param returnType * @param selectedContentType * @param selectedConverterType * @param request * @param response * @return * @see org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice#beforeBodyWrite(java.lang.Object, * org.springframework.core.MethodParameter, * org.springframework.http.MediaType, java.lang.Class, * org.springframework.http.server.ServerHttpRequest, * org.springframework.http.server.ServerHttpResponse) */ @Override public Result beforeBodyWrite(Result body, MethodParameter returnType,org.springframework.http.MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,ServerHttpResponse response) { String jsonString = JSON.toJSONString(body.getData()); System.out.println(jsonString); // 第一次加密 String data_encode_one = MD5.md5(md5_keyone + jsonString); // 第二次加密 String data_encode_two = MD5.md5(data_encode_one + md5_keytwo); body.setToken(data_encode_two); return body; } }
四、为什么说要加上@ControllerAdvice注解,且实现RequestBodyAdvice或ResponseBodyAdvice接口
现在来分析为什么需要实现RequestBodyAdvice接口的同时要加上ControllerAdvice注解。
1、为什么要实现RequestBodyAdvice或ResponseBodyAdvice接口?
简单来说,要想执行afterBodyRead方法,必须实现ResponseBodyAdvice接口。
RequestResponseBodyAdviceChain的afterBodyRead方法:调用getMatchingAdvice方法,获取RequestBodyAdvice类型的advice
其中:class RequestResponseBodyAdviceChain implements RequestBodyAdvice, ResponseBodyAdvice<Object>
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
Class<? extends HttpMessageConverter<?>> converterType) { Iterator var6 = this.getMatchingAdvice(parameter, RequestBodyAdvice.class).iterator(); while(var6.hasNext()) { RequestBodyAdvice advice = (RequestBodyAdvice)var6.next(); // 此advice就是我们定义的类 if (advice.supports(parameter, targetType, converterType)) { //如果supports方法的返回值为true,则执行RequestBodyAdvice的afterBodyRead方法 body = advice.afterBodyRead(body, inputMessage, parameter, targetType, converterType); } } return body; }
getMatchAdvice:获取RequestBodyAdvice类型的advice(此advice是我们定义的),如果不是RequestBodyAdvice类型就不会加到结果集,所以这就是我们实现RequestBodyAdvice的原因
private <A> List<A> getMatchingAdvice(MethodParameter parameter, Class<? extends A> adviceType) { List<Object> availableAdvice = this.getAdvice(adviceType);//获取RequestBodyAdvice类型的advice(此advice是我们定义实现RequestBodyAdvice接口的类) if (CollectionUtils.isEmpty(availableAdvice)) { return Collections.emptyList(); } else { List<A> result = new ArrayList(availableAdvice.size()); Iterator var5 = availableAdvice.iterator(); while(true) { Object advice; while(true) { if (!var5.hasNext()) { return result; } advice = var5.next(); if (!(advice instanceof ControllerAdviceBean)) { break; } ControllerAdviceBean adviceBean = (ControllerAdviceBean)advice; if (adviceBean.isApplicableToBeanType(parameter.getContainingClass())) { advice = adviceBean.resolveBean(); // 返回的是我们定义的Advice,即根据Bean的名称从BeanFactory中获取Bean对象 break; } } // 判断这个类是否是RequestBodyAdvice类型,如果不是就不会加到结果集,所以这就是我们实现RequestBodyAdvice的原因 if (adviceType.isAssignableFrom(advice.getClass())) { result.add(advice); } } } }
getAdvice方法:
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); } }
resolveBean方法:this.beanOrName是string类型的,从beanFactory中再拿到对应的bean对象。
public Object resolveBean() { if (this.resolvedBean == null) { Object resolvedBean = this.obtainBeanFactory().getBean((String)this.beanOrName); // obtainBeanFactory()返回BeanFactory对象 if (!this.isSingleton) { return resolvedBean; } this.resolvedBean = resolvedBean; } return this.resolvedBean; }
2、为什么要加上@ControllerAdvice注解?
简单说,只有加上@ControllerAdvice,才能找到ControllerAdviceBean。
HandlerAdapter字面上的意思就是处理适配器,它的作用用一句话概括就是调用具体的方法对用户发来的请求来进行处理。当handlerMapping获取到执行请求的controller时,DispatcherServlte会根据controller对应的controller类型来调用相应的HandlerAdapter来进行处理。
RequestMappingHandlerAdapter
就比较复杂了,可以说,该类是整个SpringMVC中最复杂的类了,却也是目前SpringMVC中使用到的频率最高的类。目前在SpringMVC的使用过程中,对请求的处理主要就是依赖RequestMappingHandlerMapping
和RequestMappingHandlerAdapter
类的配合使用。下面重点介绍下RequestMappingHandlerAdapter
类
RequestMappingHandlerAdapter初始化流程:
RequestMappingHandlerAdapter
实现了InitializingBean
接口,Spring容器会自动调用其afterPropertiesSet
方法。
public void afterPropertiesSet() { this.initControllerAdviceCache(); // 获取ControllerAdviceBean的集合 List handlers; if (this.argumentResolvers == null) { handlers = this.getDefaultArgumentResolvers(); this.argumentResolvers = (new HandlerMethodArgumentResolverComposite()).addResolvers(handlers); } if (this.initBinderArgumentResolvers == null) { handlers = this.getDefaultInitBinderArgumentResolvers(); this.initBinderArgumentResolvers = (new HandlerMethodArgumentResolverComposite()).addResolvers(handlers); } if (this.returnValueHandlers == null) { handlers = this.getDefaultReturnValueHandlers(); this.returnValueHandlers = (new HandlerMethodReturnValueHandlerComposite()).addHandlers(handlers); } }
argumentResolvers
:用于给处理器方法设置参数initBinderArgumentResolvers
:用于给注释了@InitBinder
方法设置参数returnValueHandlers
:用于对处理器返回值进行相应处理
(1) 获取@ControllerAdvice注解的类封装为ControllerAdviceBean的集合,遍历ControllerAdviceBean集合
提取没有@RequestMapping注解标注的,但有@ModelAttribute注解标注的方法
提取@InitBinder注解标注的方法
提取实现了RequestBodyAdvice或ResponseBodyAdvice接口的类
(2) 没有设置argumentResolvers则获取默认的HandlerMethodArgumentResolver
(3) 没有设置initBinderArgumentResolvers则获取默认的处理参数绑定的HandlerMethodArgumentResolver
(4) 没有设置returnValueHandlers则获取默认的HandlerMethodReturnValueHandler
RequestMappingHandlerAdapter的getDefaultReturnValueHandlers方法:初始化了RequestResponseBodyMethodProcessor
private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() { List<HandlerMethodReturnValueHandler> handlers = new ArrayList(20); handlers.add(new ModelAndViewMethodReturnValueHandler()); handlers.add(new ModelMethodProcessor()); handlers.add(new ViewMethodReturnValueHandler()); handlers.add(new ResponseBodyEmitterReturnValueHandler(this.getMessageConverters(), this.reactiveAdapterRegistry,
this.taskExecutor, this.contentNegotiationManager)); handlers.add(new StreamingResponseBodyReturnValueHandler()); handlers.add(new HttpEntityMethodProcessor(this.getMessageConverters(), this.contentNegotiationManager, this.requestResponseBodyAdvice)); handlers.add(new HttpHeadersReturnValueHandler()); handlers.add(new CallableMethodReturnValueHandler()); handlers.add(new DeferredResultMethodReturnValueHandler()); handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory)); handlers.add(new ServletModelAttributeMethodProcessor(false)); handlers.add(new RequestResponseBodyMethodProcessor(this.getMessageConverters(), this.contentNegotiationManager,
this.requestResponseBodyAdvice)); handlers.add(new ViewNameMethodReturnValueHandler()); handlers.add(new MapMethodProcessor()); if (this.getCustomReturnValueHandlers() != null) { handlers.addAll(this.getCustomReturnValueHandlers()); } if (!CollectionUtils.isEmpty(this.getModelAndViewResolvers())) { handlers.add(new ModelAndViewResolverMethodReturnValueHandler(this.getModelAndViewResolvers())); } else { handlers.add(new ServletModelAttributeMethodProcessor(true)); } return handlers; }
requestResponseBodyAdvice
:用来保存实现了RequestBodyAdvice
或ResponseBodyAdvice
接口的类
RequestMappingHandlerAdapter类的initControllerAdviceCache方法:初始化List集合requestResponseBodyAdvice
private void initControllerAdviceCache() { if (this.getApplicationContext() != null) {
// 获取有@ControllerAdvice注解的Bean的集合 List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(this.getApplicationContext()); List<Object> requestResponseBodyAdviceBeans = new ArrayList(); Iterator var3 = adviceBeans.iterator(); while(var3.hasNext()) { // 遍历集合 ControllerAdviceBean adviceBean = (ControllerAdviceBean)var3.next(); 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); } Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS); if (!binderMethods.isEmpty()) { this.initBinderAdviceCache.put(adviceBean, binderMethods); } if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) { requestResponseBodyAdviceBeans.add(adviceBean); // 将ControllerAdviceBean放入List集合中 } } if (!requestResponseBodyAdviceBeans.isEmpty()) {
// 将存有ControllerAdviceBean的集合存入requestResponseBodyAdvice集合中 this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans); } if (this.logger.isDebugEnabled()) { int modelSize = this.modelAttributeAdviceCache.size(); int binderSize = this.initBinderAdviceCache.size(); int reqCount = this.getBodyAdviceCount(RequestBodyAdvice.class); int resCount = this.getBodyAdviceCount(ResponseBodyAdvice.class); if (modelSize == 0 && binderSize == 0 && reqCount == 0 && resCount == 0) { this.logger.debug("ControllerAdvice beans: none"); } else { this.logger.debug("ControllerAdvice beans: " + modelSize + " @ModelAttribute, " + binderSize + "
@InitBinder, " + reqCount + " RequestBodyAdvice, " + resCount + " ResponseBodyAdvice"); } } } }
ControllerAdviceBean(有@ControllerAdvice注解的Bean)的findAnnotatedBeans方法:获得所有的ControllerAdvice类,之后封装为ControllerAdviceBean
public static List<ControllerAdviceBean> findAnnotatedBeans(ApplicationContext context) { ListableBeanFactory beanFactory = context; if (context instanceof ConfigurableApplicationContext) { beanFactory = ((ConfigurableApplicationContext)context).getBeanFactory(); } List<ControllerAdviceBean> adviceBeans = new ArrayList(); String[] var3 = BeanFactoryUtils.beanNamesForTypeIncludingAncestors((ListableBeanFactory)beanFactory, Object.class); int var4 = var3.length; for(int var5 = 0; var5 < var4; ++var5) { String name = var3[var5]; if (!ScopedProxyUtils.isScopedTarget(name)) { ControllerAdvice controllerAdvice = (ControllerAdvice)((ListableBeanFactory)beanFactory).findAnnotationOnBean(name,
ControllerAdvice.class); // 从application中找到ControllerAdvice注解 if (controllerAdvice != null) {
// 将有@ControllerAdvice注解的Bean添加到List集合中并返回 adviceBeans.add(new ControllerAdviceBean(name, (BeanFactory)beanFactory, controllerAdvice)); } } } OrderComparator.sort(adviceBeans); return adviceBeans; }
会从applicationContext中获取有ControllerAdvice注解的bean,