解決Hmily與Feign沖突報錯 NullPointerException的問題
Hmily與Feign沖突報錯 NullPointerException
在項目中使用了Hmily保證分布式事務的一致性,由于Hmily會注冊一個 HmilyFeignInterceptor ,并且feign會將其添加到 SynchronousMethodHandler 中的 requestInterceptors ,當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 異常。
解決方法
定義一個后置處理器,將沒有被 @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出現(xiàn)的幾種原因及解決
出現(xiàn)的原因
1、字符串變量未初始化
2、接口類型的對象沒有用具體的類初始化,比如:
Map map // 會報錯 Map map = new Map(); //則不會報錯了
3、當一個對象的值為空時,你沒有判斷為空的情況。
4、字符串與文字的比較,文字可以是一個字符串或Enum的元素,如下會出現(xiàn)異常
String str = null; if(str.equals(“Test”)){undefined //這里的代碼將不會被觸發(fā),因為會拋出java.lang.NullPointerException異常。 }
5、優(yōu)先使用String.valueOf()方法代替toString()
當程序代碼需要對象的字符串表示形式時,請避免使用該對象的toString方法。如果你的對象的引用等于null,NullPointerException則會拋出,使用靜態(tài)String.valueOf方法,該方法不會拋出任何異常并打印"null"
6、class被聲明了類型, 默認 class = null; 這樣在調(diào)用class中方法的時候系統(tǒng)只能給你個空指針異常, 給其實例化就好了:class = new Class();
7、返回null,方法的返回值不要定義成為一般的類型,而是用數(shù)組。這樣如果想要返回null的時候就能避免許多不必要的NullPointerException
我加粗的兩個是比較常見的,容易忽略的錯誤,
大部分都是字符串比較的時候由于str=null,那么使用str.equals(“Test”)就會拋出異常
null不能和字符串進行比較
解決的辦法有兩種:
- 就是在比較之前判斷字符串是否為空
- 當傳入的參數(shù)str是空值的時候,程序就會異常,正確的是應該把字符串放在前面
"Test".equals(str)
推薦使用第二種。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Java編程中靜態(tài)內(nèi)部類與同步類的寫法示例
這篇文章主要介紹了Java編程中靜態(tài)內(nèi)部類與同步類的寫法示例,用于構(gòu)建靜態(tài)對象以及實現(xiàn)線程同步等,需要的朋友可以參考下2015-09-09Java8 Optional優(yōu)雅空值判斷的示例代碼
這篇文章主要介紹了Java8 Optional優(yōu)雅空值判斷的相關知識,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-05-05spring中FactoryBean中的getObject()方法實例解析
這篇文章主要介紹了spring中FactoryBean中的getObject()方法實例解析,分享了相關代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下2018-02-02