解决Hmily与Feign冲突报错 NullPointerException的问题
目录
- Hmily与Feign冲突报错 NullPointerException
- 解决方法
- java.lang.NullPointerException出现的几种原因及解决
- 出现的原因
Hmily与Feign冲突报错 NullPointerException
在项目中使用了Hmily保证分布式事务的一致性,由于Hmily会注册一个 HmilyFeignInterceptor ,并且feign会将其添加到 SynchronousMethodHandler 中的 requestInterceptors ,当feign客户端执行 HmilyFeignInterceptor 中apply方法
public void apply(final RequestTemplate requestTemplate) { Transmiter.getInstance().transmit((x$0, xva$1) -> { requestTemplate.header(x$0, new String[]{xva$1}); }, HmilyTransactionContextLocal.getInstance().get()); }
由于获取到的 HmilyTransactionContext 为 null ,所以抛出 NullPointerException 异常。
解决方法
定义一个后置处理器,将没有被 @Hmily 注解的方法,移除 HmilyFeignInterceptor 。
package com.jz.shop.cart.service; import com.jz.shop.commons.utils.text.StringUtils; import feign.InvocationHandlerFactory; import feign.ReflectiveFeign; import feign.RequestInterceptor; import lombok.extern.slf4j.Slf4j; import org.dromara.hmily.annotation.Hmily; import org.dromara.hmily.springcloud.feign.HmilyFeignInterceptor; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.stereotype.Component; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RestController; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.List; import java.util.Map; /** * @author:JZ * @date:2020/6/1 */ @Slf4j @Component public class ShopFeignPostProcessor implements BeanPostProcessor { public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { // 对所有含有 @FeignClient 的bean进行处理 if (StringUtils.isNotNull(AnnotationUtils.findAnnotation(bean.getClass(), FeignClient.class))) { // 排除含有 @Controller 和 @RestController 注解的bean if (StringUtils.isNotNull(AnnotationUtils.findAnnotation(bean.getClass(), Controller.class)) || StringUtils.isNotNull(AnnotationUtils.findAnnotation(bean.getClass(), RestController.class))) { return bean; } try { // 获取代理类中的 FeignInvocationHandler Field h = bean.getClass().getSuperclass().getDeclaredField("h"); boolean hAccessible = h.isAccessible(); h.setAccessible(true); Object feignInvocationHandler = h.get(bean); /** * 获取 FeignInvocationHandler 中 dispatch 字段的 Map<Method, MethodHandler> dispatch 属性。 * dispatch中包含feign代理的方法 和 SynchronousMethodHandler */ Field dispatchField = feignInvocationHandler.getClass().getDeclaredField("dispatch"); boolean dispatchAccessible = dispatchField.isAccessible(); dispatchField.setAccessible(true); Map<Method, InvocationHandlerFactory.MethodHandler> dispatch = (Map<Method, InvocationHandlerFactory.MethodHandler>) dispatchField.get(feignInvocationHandler); /** * SynchronousMethodHandler 中的 List<RequestInterceptor> requestInterceptors 字段 * 加载了Hmily对feign的拦截器 HmilyFeignInterceptor */ for (Map.Entry<Method, InvocationHandlerFactory.MethodHandler> entry : dispatch.entrySet()) { /** * 没有添加 @Hmily 注解的方法不需要被 Hmily 拦截处理, * 否则会因为加载的 HmilyTransactionContext 为 null 导致 NullPointerException */ if (StringUtils.isNull(AnnotationUtils.findAnnotation(entry.getKey(), Hmily.class))) { Field riField = entry.getValue().getClass().getDeclaredField("requestInterceptors"); boolean riAccessible = riField.isAccessible(); riField.setAccessible(true); List<RequestInterceptor> requestInterceptors = (List<RequestInterceptor>) riField.get(entry.getValue()); for (RequestInterceptor interceptor : requestInterceptors) { if (interceptor instanceof HmilyFeignInterceptor) { requestInterceptors.remove(interceptor); break; } } riField.setAccessible(riAccessible); log.info("{}.{} 方法移除 HmilyFeignInterceptor", beanName, entry.getKey().getName()); } } dispatchField.setAccessible(dispatchAccessible); h.setAccessible(hAccessible); } catch (Exception e) { log.warn("{} exception", beanName); e.printStackTrace(); } } return bean; } }
java.lang.NullPointerException出现的几种原因及解决
出现的原因
1、字符串变量未初始化
2、接口类型的对象没有用具体的类初始化,比如:
Map map // 会报错 Map map = new Map(); //则不会报错了
3、当一个对象的值为空时,你没有判断为空的情况。
4、字符串与文字的比较,文字可以是一个字符串或Enum的元素,如下会出现异常
String str = null; if(str.equals(“Test”)){undefined //这里的代码将不会被触发,因为会抛出java.lang.NullPointerException异常。 }
5、优先使用String.valueOf()方法代替toString()
当程序代码需要对象的字符串表示形式时,请避免使用该对象的toString方法。如果你的对象的引用等于null,NullPointerException则会抛出,使用静态String.valueOf方法,该方法不会抛出任何异常并打印"null"
6、class被声明了类型, 默认 class = null; 这样在调用class中方法的时候系统只能给你个空指针异常, 给其实例化就好了:class = new Class();
7、返回null,方法的返回值不要定义成为一般的类型,而是用数组。这样如果想要返回null的时候就能避免许多不必要的NullPointerException
我加粗的两个是比较常见的,容易忽略的错误,
大部分都是字符串比较的时候由于str=null,那么使用str.equals(“Test”)就会抛出异常
null不能和字符串进行比较
解决的办法有两种:
- 就是在比较之前判断字符串是否为空
- 当传入的参数str是空值的时候,程序就会异常,正确的是应该把字符串放在前面
"Test".equals(str)
推荐使用第二种。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。