Feign反序列化错误
起因:在导出excel的时候, 发现有的字段不能正常输出。

其中对应的字段是 cPremium和cPopularizeFee,但是按照这样的命名却读不到数据。debug发现数据源的字段数据变成了cpremium和cpopularizeFee,好神奇啊。。为啥嘞?
在反复的测试中,总结下,通过feign后key的转换关系如下:
- aaAAAAA->aaAAAAA
- aAA->aaa
- aA->aa
- A->a
最后总结 :变量的前两个字母要么全部大写,要么全部小写。
参考:
https://blog.csdn.net/john1337/article/details/105077234
https://blog.csdn.net/u011742227/article/details/42425065/?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-5&spm=1001.2101.3001.4242
麻烦的spring-security
为了设计而设计的spring-security, 把用户验证大致分为两步:校验用户是否存在->校验密码
。
@Override
public void configure(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(authenticationProvider1());
}
@Bean
public DaoAuthenticationProvider authenticationProvider1() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setHideUserNotFoundExceptions(false);
provider.setUserDetailsService(loginUserService);
provider.setPasswordEncoder(passwordEncoder());
return provider;
}
第一个坑:loginUserService校验用户是否存在,不存在的话会抛UsernameNotFoundException
异常,如果存在就进行下一步密码的校验。但是实际情况是第一步抛了异常,第二步还是会走,解决方法是在第二步进行特殊的判断:
//这一行是可以抛出 UsernameNotFoundException关键 否则永远会屏蔽 loginUserService中抛出的此异常
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
//这一行是可以抛出 UsernameNotFoundException关键 否则永远会屏蔽 loginUserService中抛出的此异常
if ("userNotFoundPassword".equals(encodedPassword)) {
return true;
}
}
第二个坑:UsernameNotFoundException
异常抛了,但是我们密码校验需要修改,加一个参数,但是org.springframework.security.crypto.password.PasswordEncoder#matches
方法是写死的2个参数,一个新的,一个旧的做密码对比。最终解决方法是在这个类里,注入了HttpServletRequest
,然后用它来获取新加的参数。感觉还是用org.springframework.web.servlet.HandlerInterceptor
的老方法,拦截器来处理比较清晰明了,用security
,要配置更多,写更多的类,学习成本比较高,有问题还比较难解决。
循环依赖报错
项目启动时报错:
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'orderServiceImpl': Bean with name 'orderServiceImpl' has been injected into other beans [weChatNotifyServiceImpl] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.
应该是bean循环引用的问题 weChatNotifyServiceImpl
中 引入了 orderServiceImpl
然后orderServiceImpl
中也引入了 weChatNotifyServiceImpl
。
说好的不是spring bean
依赖注入的时候不会出现循环引用的问题了吗?
- 通过2级缓存,避免了普通
bean
循环引用。 - 通过3级缓存,避免
Aop
中代理类循环引用问题。
原来在因为开启了@EnableAsync
异步调用,bean注入时和aop一样会生成新的代理类,此时如果出现循环引用还是或出现问题。
解决方案: 加@Lazy注解

加入日志的traceId
-
项目日志中添加
实现很简单在拦截器中,利用MDC添加到日志:
public static void addLogTraceId(HttpServletRequest request) {
String ipAddress = getIpAddress(request);
String uuid = ParamUtil.toString(UUID.randomUUID()).replaceAll("-", "");
MDC.put("requestId", "[TraceID:" + uuid + ",IP:" + ipAddress + "]");
}
然后添加日志配置:
logging:
pattern:
console: '[%d{yyyy-MM-dd HH:mm:ss.SSS} %5p %t] [%c{1}] %M:%L - %X{requestId} %m%n'
file: '[%d{yyyy-MM-dd HH:mm:ss.SSS} %5p %t] [%c{1}] %M:%L - %X{requestId} %m%n'
日志中就会这样打印:
[2022-02-10 15:00:30.009 DEBUG pool-6-thread-1] [c.b.b.d.o.O.selectSynList] debug:159 - [TraceID:6f62d621ea82443c890d45bb5924e8a2,IP:] ==> Parameters: 2022-02-10 14:50:
- 异步线程保持一致
//相关的异步方法比较少,所以简单实现
String logId = MDC.get("requestId");
executorService.execute(() -> orderService.orderPush(requestJsonStr, logId));
executorService.shutdown();
-
微服务保持一致
思路是放到header
里,然后下游的服务从header
中取就可以了。
- 上游添加利用
feign
的拦截器去批量添加:
@Component
public class FeignConfiguration implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
requestTemplate.header("request-id", MDC.get("requestId"));
}
}
- 下游获取,在拦截器中添加到
MDC
:
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) {
String requestId = httpServletRequest.getHeader("request-id");
addLogTraceId(requestId);
return true;
}
当然了还有spring cloud sleuth+zipkin
的方案,可以在网页直观的查看,请求的调用链路,以及访问时间。还有基于javaagent
的skywalking
,0入侵代码。
网友评论