解决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)

推荐使用第二种。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • java.lang.NullPointerException异常问题解决方案

    java.lang.NullPointerException异常原因是因为创建了一个引用类型的变量却没有指向任何对象而又去通过这个引用类型变量加点的形式去访问非静态的方法及属性. 给出三种情况, 第一种情况,在启动类中定义了引用类型变量,赋值为空: /** * 引用类型变量没有指向对象所引起的空指针异常 * @author Superhero * @version 2018年12月16日上午10:32:43 */ //图书类 class Books { private String name;

  • java静态工具类注入service出现NullPointerException异常处理

    目录 一般我们在controller层调用service时,只需要使用@Autowired注解即可,例如如下代码我们经常看到: @RestController @RequestMapping("business") public class BizResourceController { @Autowired private BusinessService businessService; @RequestMapping(path = "/queryYearList"

  • 详解Java中NullPointerException异常的原因详解以及解决方法

    NullPointerException是当您尝试使用指向内存中空位置的引用(null)时发生的异常,就好像它引用了一个对象一样. 当我们声明引用变量(即对象)时,实际上是在创建指向对象的指针.考虑以下代码,您可以在其中声明基本类型的整型变量x: int x; x = 10; 在此示例中,变量x是一个整型变量,Java将为您初始化为0.当您在第二行中将其分配给10时,值10将被写入x指向的内存中. 但是,当您尝试声明引用类型时会发生不同的事情.请使用以下代码: Integer num; num

  • 解决Hmily与Feign冲突报错 NullPointerException的问题

    目录 Hmily与Feign冲突报错 NullPointerException 解决方法 java.lang.NullPointerException出现的几种原因及解决 出现的原因 Hmily与Feign冲突报错 NullPointerException 在项目中使用了Hmily保证分布式事务的一致性,由于Hmily会注册一个 HmilyFeignInterceptor ,并且feign会将其添加到 SynchronousMethodHandler 中的 requestInterceptors

  • springboot启动feign项目报错:Service id not legal hostnam的解决

    目录 springboot启动feign项目报错:Service id not legal hostnam 在feign项目中,定义接口调用服务 启动时报出异常信息 度娘后发现问题所在 配置文件服务名做同样修改 Service id not legal hostname (pin_user) 错误信息 出现原因 解决方案 springboot启动feign项目报错:Service id not legal hostnam 在feign项目中,定义接口调用服务 @FeignClient(name=

  • 解决IDEA配置tomcat启动报错问题

    在配置servlet不同路径时遇上以下两个错误: java.lang.NoSuchMethodError: javax.servlet.ServletContext.getVirtualServerName()Ljava/lang/String:  java.lang.ClassNotFoundException: org.apache.jsp.index_jsp: 对于第一个问题,我上网查阅了很多资料后发现,可能是tomcat版本冲突导致,catalina log如下: 19-Feb-2018

  • .Net解决引用程序集没有强名称报错

    目录 一.什么是强名称 为什么要使用强名称签名 二.如何设置强名称 1.应用程序有源代码 1.生成公钥 2.设置签名公钥 2.应用程序没有源代码 1.打开SDK命令提示窗口 2.创建一个新的随机密钥对 3.反编译目标程序集 4.重新编译,附带强命名参数 5.验证签名信息 6.重新引用 一.什么是强名称 强名称是一个由程序集的标识组成并通过公钥和数字签名(针对该程序集生成)加强的名称,其中的标识包括程序集的简单文本名称.版本号和区域性信息. 由于程序集清单包含构成程序集实现的所有文件的文件散列,因

  • 三个思路解决laravel上传文件报错:413 Request Entity Too Large问题

    最近一个项目当中,要求上传图片,并且限制图片大小,虽然在laravel当中已经添加了相关的表单验证来阻止文件过大的上传,然而当提交表单时,还没轮到laravel处理,nginx就先报错了.当你仔细看报错页面时,你会发现有nginx版本信息,经过分析,这报错是因为nginx的默认上传文件大小配置client_max_body_size只有2MB, 基于nginx验证比laravel验证要早,想要友好报错而不是直接显示413 Request Entity Too Large,那么就有三个思路去解决.

  • 解决maven启动Spring项目报错的问题

    第一个问题 java.lang.ClassCastException: org.springframework.web.SpringServletContainerInitializer cannot be cast to javax.servlet.ServletContainerInitializer 出现原因主要是 javax.servlet-api 在运行时将spring容器当成了servlet容器出现类型转换错误. 解决方法: 在pom.xml文件中修改 javax.servlet-a

  • 解决iview打包时UglifyJs报错的问题

    使用npm run dev时运行是ok的,但是npm run build打包时iview报错, 如下: 原因是iview中使用了es6语法,然而uglifyJs是不支持的,打开我们的build/webpack.prod.conf.js文件,可以看到 // UglifyJs do not support ES6+, you can also use babel-minify for better treeshaking: https://github.com/babel/minify new we

  • 解决java junit单元测试@Test报错的问题

    在我们在myeclips里使用junit测试工具时有时会遇到错误,这是什么原因呢? 导致问题的原因通常有下面几个: (1)没有导入jar包 (2)导入jar包版本太低 (3)注意@Test要写在方法上面 如果不是几种问题,那便试试下面的解决方案: 1.在项目上点击右键,出现下图内容,选择properties 2.出现如下对话框,点击java build path,再选择add Library 3.之后如下图操作 4.选择junit4,点击finish,配置完毕. 以上这篇解决java junit

  • 解决安装python3.7.4报错Can''t connect to HTTPS URL because the SSL module is not available

    简述 从官网下载了Python3.7.4,直接编译安装后,使用pip3出现了报错信息: Can't connect to HTTPS URL because the SSL module is not available 错误原因 在Python3.7之后的版本,依赖的openssl,必须要是1.1或者1.0.2之后的版本,或者安装了2.6.4之后的libressl. image.png 而本地的openssl依然是1.0.1e的. [root@localhost ~]# openssl ver

  • 解决使用export_graphviz可视化树报错的问题

    在使用可视化树的过程中,报错了.说是'dot.exe'not found in path 原代码: # import tools needed for visualization from sklearn.tree import export_graphviz import pydot #Pull out one tree from the forest tree = rf.estimators_[5] # Export the image to a dot file export_graphv

随机推荐