解決Hmily與Feign沖突報(bào)錯(cuò) NullPointerException的問(wèn)題
Hmily與Feign沖突報(bào)錯(cuò) NullPointerException
在項(xiàng)目中使用了Hmily保證分布式事務(wù)的一致性,由于Hmily會(huì)注冊(cè)一個(gè) HmilyFeignInterceptor ,并且feign會(huì)將其添加到 SynchronousMethodHandler 中的 requestInterceptors ,當(dāng)feign客戶端執(zhí)行 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 異常。
解決方法
定義一個(gè)后置處理器,將沒(méi)有被 @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 {
// 對(duì)所有含有 @FeignClient 的bean進(jìn)行處理
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對(duì)feign的攔截器 HmilyFeignInterceptor
*/
for (Map.Entry<Method, InvocationHandlerFactory.MethodHandler> entry : dispatch.entrySet()) {
/**
* 沒(méi)有添加 @Hmily 注解的方法不需要被 Hmily 攔截處理,
* 否則會(huì)因?yàn)榧虞d的 HmilyTransactionContext 為 null 導(dǎo)致 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出現(xiàn)的幾種原因及解決
出現(xiàn)的原因
1、字符串變量未初始化
2、接口類型的對(duì)象沒(méi)有用具體的類初始化,比如:
Map map // 會(huì)報(bào)錯(cuò) Map map = new Map(); //則不會(huì)報(bào)錯(cuò)了
3、當(dāng)一個(gè)對(duì)象的值為空時(shí),你沒(méi)有判斷為空的情況。
4、字符串與文字的比較,文字可以是一個(gè)字符串或Enum的元素,如下會(huì)出現(xiàn)異常
String str = null;
if(str.equals(“Test”)){undefined
//這里的代碼將不會(huì)被觸發(fā),因?yàn)闀?huì)拋出java.lang.NullPointerException異常。
}
5、優(yōu)先使用String.valueOf()方法代替toString()
當(dāng)程序代碼需要對(duì)象的字符串表示形式時(shí),請(qǐng)避免使用該對(duì)象的toString方法。如果你的對(duì)象的引用等于null,NullPointerException則會(huì)拋出,使用靜態(tài)String.valueOf方法,該方法不會(huì)拋出任何異常并打印"null"
6、class被聲明了類型, 默認(rèn) class = null; 這樣在調(diào)用class中方法的時(shí)候系統(tǒng)只能給你個(gè)空指針異常, 給其實(shí)例化就好了:class = new Class();
7、返回null,方法的返回值不要定義成為一般的類型,而是用數(shù)組。這樣如果想要返回null的時(shí)候就能避免許多不必要的NullPointerException
我加粗的兩個(gè)是比較常見(jiàn)的,容易忽略的錯(cuò)誤,
大部分都是字符串比較的時(shí)候由于str=null,那么使用str.equals(“Test”)就會(huì)拋出異常
null不能和字符串進(jìn)行比較
解決的辦法有兩種:
- 就是在比較之前判斷字符串是否為空
- 當(dāng)傳入的參數(shù)str是空值的時(shí)候,程序就會(huì)異常,正確的是應(yīng)該把字符串放在前面
"Test".equals(str)
推薦使用第二種。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java編程中靜態(tài)內(nèi)部類與同步類的寫法示例
這篇文章主要介紹了Java編程中靜態(tài)內(nèi)部類與同步類的寫法示例,用于構(gòu)建靜態(tài)對(duì)象以及實(shí)現(xiàn)線程同步等,需要的朋友可以參考下2015-09-09
查看Java所支持的語(yǔ)言及相應(yīng)的版本信息
Java語(yǔ)言作為第一種支持國(guó)際化的語(yǔ)言,在Internet從一開(kāi)始就具有其他語(yǔ)言無(wú)與倫比的國(guó)際化的本質(zhì)特性,查看Java所支持的語(yǔ)言及相應(yīng)的版本信息可以采用以下代碼進(jìn)行查詢2014-01-01
Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(27)
下面小編就為大家?guī)?lái)一篇Java基礎(chǔ)的幾道練習(xí)題(分享)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧,希望可以幫到你2021-07-07
Java8 Optional優(yōu)雅空值判斷的示例代碼
這篇文章主要介紹了Java8 Optional優(yōu)雅空值判斷的相關(guān)知識(shí),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-05-05
關(guān)于spring data jpa一級(jí)緩存的問(wèn)題
這篇文章主要介紹了關(guān)于spring data jpa一級(jí)緩存的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11
解決java junit單元測(cè)試@Test報(bào)錯(cuò)的問(wèn)題
今天小編就為大家分享一篇解決java junit單元測(cè)試@Test報(bào)錯(cuò)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-11-11
spring中FactoryBean中的getObject()方法實(shí)例解析
這篇文章主要介紹了spring中FactoryBean中的getObject()方法實(shí)例解析,分享了相關(guān)代碼示例,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-02-02

