Spring Cloud 中使用Feign解决参数注解无法继承的问题
Spring Cloud 中使用Feign解决参数注解无法继承的问题
在使用Feign的时候,通常先写一个接口类,然后再写实现类,根据官网的例子接下来编写一个简单的Feign的请求例子
@FeignClient("spring-cloud-eureka") public interface FeignDemoApi { @RequestMapping("/testFeign") public String testSpringMvc(@RequestBody User user); }
然后实现类如下
@RestController public class FeignDemoApiImpl implements FeignDemoApi{ @Override public String testSpringMvc(User user) { return user.getName(); } }
然后测试类编写如下
@RequestMapping("/testSpringmvc") public void test6(){ User user =new User(); user.setName("test"); user.setAge(18); feignDemoApi.testSpringMvc(user); }
发现在客户端进行接收的时候发现接收到的User
为null
然后从网上查资料才知道需要在实现类的入参中也加入@RequestBody
注解,这样才能接收到参数。但是不禁有个疑问,我们查看@RequestMapping
和@RequestBody
这两个注解的代码中都没有@Inherited
这个可支持继承的注解,那么@RequestMapping
为什么能发挥作用?而@RequestBody
却不能发挥作用呢?
@RequestMapping 注解
然后经过查资料了解到,SpringMvc在初始化时候会将带有@Controller
初始化进Spring容器中,其实例化的类型为RequestMappingInfo
类,此时在SpringMvc中会加载@Controller
类注解下的所有带有@ RequestMapping
的方法,将其@RequestMapping
中的属性值也加载进来,如果在本类方法上找不到@RequestMapping
注解信息的话,那么就会寻找父类相同方法名的@RequestMapping
的注解。具体在AnnotatedElementUtils
类中的searchWithFindSemantics
方法中有下面的一段。表示在父类中寻找注解。
// Search on interfaces for (Class<?> ifc : clazz.getInterfaces()) { T result = searchWithFindSemantics(ifc, annotationType, annotationName, containerType, processor, visited, metaDepth); if (result != null) { return result; } }
此时就能知道为什么在子类中没有加@RequestMapping
注解,但是却享有父类@RequestMapping
注解的效果了。
@RequestBody 注解
在上面的注解中我们了解到虽然@RequestMapping
不支持继承,但是子类享有同样效果的原因就是在判断的时候如果子类没有就去父类找,但是在测试中我们发现@RequestBody
是没有享受此效果的,所以我猜测在判断是否有注解的时候只是判断本类有没有此注解而没有判断父类。
经过查询资料,发现在SpringMvc中使用RequestResponseBodyMethodProcessor
来进行入参和出参的解析,其中使用supportsParameter
来判断是否有@RequestBody
的注解
@Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(RequestBody.class); }
我们发现事实如我们猜测的一样。
解决方案
我们也可以像@RequestMapping
注解一样进行判断如果本类没有的话,那么就对其父类进行判断。创建一个配置类然后将自定义的ArgumentResolvers
放入到RequestMappingHandlerAdapter
中
@Configuration public class MyWebMvcConfigu implements BeanFactoryAware { private ConfigurableBeanFactory beanFactory; @Autowired private RequestMappingHandlerAdapter requestMappingHandlerAdapter; //判断其父类是否有注解 public static <A extends Annotation> MethodParameter interfaceMethodParameter(MethodParameter parameter, Class<A> annotationType) { if (!parameter.hasParameterAnnotation(annotationType)) { for (Class<?> itf : parameter.getDeclaringClass().getInterfaces()) { try { Method method = itf.getMethod(parameter.getMethod().getName(), parameter.getMethod().getParameterTypes()); MethodParameter itfParameter = new MethodParameter(method, parameter.getParameterIndex()); if (itfParameter.hasParameterAnnotation(annotationType)) { return itfParameter; } } catch (NoSuchMethodException e) { continue; } } } return parameter; } @PostConstruct public void modifyArgumentResolvers() { List<HandlerMethodArgumentResolver> list = new ArrayList<>(requestMappingHandlerAdapter.getArgumentResolvers()); // RequestBody 支持接口注解 list.add(0, new RequestResponseBodyMethodProcessor(requestMappingHandlerAdapter.getMessageConverters()) { @Override public boolean supportsParameter(MethodParameter parameter) { return super.supportsParameter(interfaceMethodParameter(parameter, RequestBody.class)); } @Override // 支持@Valid验证 protected void validateIfApplicable(WebDataBinder binder, MethodParameter methodParam) { super.validateIfApplicable(binder, interfaceMethodParameter(methodParam, Valid.class)); } }); // 修改ArgumentResolvers, 支持接口注解 requestMappingHandlerAdapter.setArgumentResolvers(list); } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = (ConfigurableBeanFactory) beanFactory; } }
然后我们就可以发现再重新调用以后子类没有加入@RequestBody
注解也能够接收到实体类了
参考文章
- Spring Cloud中使用Feign,@RequestBody无法继承问题解决
- [swift]-使用JavaScript解决WKWebView无法发送POST参数问题
- 关于DAO实现类继承JdbcDaoSupport类后,使用注解无法注入DataSource的问题
- Struts2 使用拦截器后参数无法传递问题的解决
- 使用dubbo注解@Service注册服务后使用aop或者申明式事物导致无法注册的问题解决办法
- 解决controller无法使用@value注解读取properties文件的问题
- Spring cloud - 在微服务中使用feign造成unsatisfied dependency 问题及解决
- 解决Spring框架的Dao层改用@Repository注解,无法使用JdbcDaoSupport的问题
- springcloud使用feign实现服务间条用,参数数据太大,无法调用成功解决方法
- 解决Spring框架的Dao层改用@Repository注解,无法使用JdbcDaoSupport的问题
- 解决VIsta iis7中asp无法使用中文参数的问题
- 在参数上使用@Param(“paramName”)注解”解决了传多个参数的问题
- 使用startx无法进入图形界面的问题终于解决
- 安装完vs.2005之后,重新安装iis后无法使用http方式访问asp.net工程的页面的问题的解决方法
- C++学习笔记(9)——使用范围运算符解决继承中的二义性问题
- 解决AJAX中使用UpdatePanel后无法弹出js对话框问题(引)
- 使用ORACLE 10.2G DBMS_CHANGE_NOTIFICATION 解决参数表的CACHE问题
- 请教:使用spring2.0 @AspectJ注解风格进行AOP编程时遇到问题:传递参数到Advice失败。...
- 使用PLSQL Developer时,“ORA-12154: TNS:无法解析指定的连接标识符”问题的一个解决办法
- 如何解决Remoting无法传输存储过程参数的问题