解决Hmily与Feign冲突报错 NullPointerException

解决Hmily与Feign冲突报错 NullPointerException在项目中使用了Hmily保证分布式事务的一致性,由于Hmily会注册一个HmilyFeignInterceptor,并且feign会将其添加到SynchronousMethodHandler中的requestInterceptors,当feign客户端执行HmilyFeignInterceptor中apply方法publicvoidapply(finalRequestTemplaterequestTemplate){Transmiter.getInstance

大家好,又见面了,我是你们的朋友全栈君。

在项目中使用了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;
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/144064.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • java打印数组_Java中打印数组内容的方式有哪些?

    java打印数组_Java中打印数组内容的方式有哪些?下面是几种常见的打印方式。方法一:使用循环打印。publicclassDemo{publicstaticvoidmain(String[]args){String[]infos=newString[]{“Java”,”Android”,”C/C++”,”Kotlin”};StringBufferstrBuffer=newStringBuffer();for(…

  • 闰年的判断方法_判断是不是闰年的条件

    闰年的判断方法_判断是不是闰年的条件①、普通年能被4整除且不能被100整除的为闰年.②、世纪年能被400整除的是闰年③、对于数值很大的年份,这年如果能整除3200,并且能整除172800则是闰年.如172800年是闰年,86400年不是

  • 图像处理中经常用的一幅图片Lena.jpg

    图像处理中经常用的一幅图片Lena.jpg在数字图像处理中,Lena(Lenna)是一张被广泛使用的标准图片,特别在图像压缩的算法研究中。(为什么用这幅图,是因为这图的各个频段的能量都很丰富:即有低频(光滑的皮肤),也有高频(帽子上的羽毛),很适合来验证各种算法)然而,这张图片背后的故事是颇有意思的,很多人都抱有学究都是呆子的看法,然而Lena对此就是一个有力的驳斥。lena(lenna)是一张于1972年11月…

  • IDEA设置背景为自定义照片「建议收藏」

    IDEA设置背景为自定义照片「建议收藏」一分钟教你把女朋友的照片设置成IDEA的背景图片【建议收藏】1.为什么写这篇文章?2.操作方法2.1.步骤12.2.步骤22.3.快捷操作一2.4.快捷操作二1.为什么写这篇文章?事情是这样的,在2021年6月10日早上我在CSDN上发布了文章《你真的懂Java怎么输出HelloWorld吗?》。这篇文章就如同标题一样,讲的是Java输出HelloWorld时源码的实现原理,本身再正常不过的一篇文章,但没想到的是。。十几天过去了,我却收到如下的评论??!!大家居然对我的IDEA背

  • 【小白视角】大数据基础实践(五) MapReduce编程基础操作

    【小白视角】大数据基础实践(五) MapReduce编程基础操作目录1.MapReduce简介1.1起源1.2模型简介1.3MRv1体系结构1.4YARN1.4.1YARN体系结构1.4.2YARN工作流程2.MapReduce工作流程3.JavaApi要点4.实验过程最后1.MapReduce简介1.1起源在函数式语言里,map表示对一个列表(List)中的每个元素做计算,reduce表示对一个列表中的每个元素做迭代计算。它们具体的计算是通过传入的函数来实现的,map和reduce提供的是计算的框架。在MapReduce

  • decltype 使用

    decltype 使用功能decltype可以将给定的表达式或变量的类型推导出来,包含引用和指针。一般用于复杂表达式作为返回值的类型推导。可以用于补足c++11的auto缺陷.编译阶段的事情,不会任何执行,表达式也不会执行。类型规则规则一:声明类型,类型包含引用就有引用,没有引用也不会自行添加。规则二:返回值则根据返回值类型确定最终类型。规则三:表达式根据默认和重载得到的最终类型。不建议特别复杂的表达式。声明类型分析案例一intmain()..

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号