欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-06-17 23:09:47
目录hmily与feign冲突报错 nullpointerexception解决方法java.lang.nullpointerexception出现的几种原因及解决出现的原因hmily与feign冲突...

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)

推荐使用第二种。

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