最近在做一個(gè)分布式的web系統(tǒng)秘蛇,用的boot+dubbo传于,中間碰到不少坑讹躯,最近碰到的坑可是坑了我三四天菩彬,把坑都給大家捎帶分享一下,希望能少走彎路潮梯。
1. 坑一:與jpa的不兼容
如果你想寫這樣的jpasql
@Query("select g.userIdentity from GroupMembers g where g.userId=?1 and g.groupId=?2")
int selectIndentity(Integer userId,Integer groupId);
恭喜你骗灶,你可以成功的運(yùn)行它。但是如果你想要這樣
@Transactional
@Modifying
@Query("update GroupMembers g set g.userIdentity=1 where g.userId=?1 and g.groupId=?2")
int updateIdentity(Integer userId,Integer groupId);
那么秉馏,對(duì)不起耙旦!你不可以。如果這樣做萝究,你會(huì)發(fā)現(xiàn)你注冊(cè)不了服務(wù)免都,消費(fèi)者也相應(yīng)的得到nullpointexception異常,這一點(diǎn)你可以在dubbo-admin中清晰的看到--沒有提供服務(wù)帆竹。但是單獨(dú)一個(gè)模塊跑起來是沒有問題的琴昆,測試也沒有問題的,就是注冊(cè)不進(jìn)去~~
想知道為啥的請(qǐng)看第二點(diǎn)~
2. 坑二:service層加事務(wù)報(bào)空指針
截圖我不發(fā)了馆揉,我可不想把事發(fā)場景還原业舍,畢竟花了我?guī)滋斓木皖^皮營養(yǎng)。
之所以說這個(gè)bug費(fèi)時(shí)費(fèi)力升酣,是因?yàn)檫@個(gè)項(xiàng)目可以運(yùn)行舷暮,測試全都通過,但是就是注冊(cè)不進(jìn)去dubbo噩茄,配置和別的模塊一模一樣也無動(dòng)于衷下面!就是注冊(cè)不進(jìn)去dubbo,就是注冊(cè)不進(jìn)去dubbo,就是注冊(cè)不進(jìn)去dubbo.
為什么呢?為什么呢绩聘?
如果給service層加事務(wù)沥割,同樣服務(wù)也注冊(cè)不進(jìn)dubbo,那web層的調(diào)用當(dāng)然也是返回空指針凿菩。那原因是為什么呢机杜?
我們看一下dubbo的@Service這個(gè)注解源碼:
package com.alibaba.dubbo.config.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface Service {
Class<?> interfaceClass() default void.class;
String interfaceName() default "";
String version() default "";
String group() default "";
String path() default "";
boolean export() default false;
String token() default "";
boolean deprecated() default false;
boolean dynamic() default false;
String accesslog() default "";
int executes() default 0;
boolean register() default false;
int weight() default 0;
String document() default "";
int delay() default 0;
String local() default "";
String stub() default "";
String cluster() default "";
String proxy() default "";
int connections() default 0;
int callbacks() default 0;
String onconnect() default "";
String ondisconnect() default "";
String owner() default "";
String layer() default "";
int retries() default 0;
String loadbalance() default "";
boolean async() default false;
int actives() default 0;
boolean sent() default false;
String mock() default "";
String validation() default "";
int timeout() default 0;
String cache() default "";
String[] filter() default {};
String[] listener() default {};
String[] parameters() default {};
String application() default "";
String module() default "";
String provider() default "";
String[] protocol() default {};
String monitor() default "";
String[] registry() default {};
}
發(fā)現(xiàn)它不支持被子類繼承,所以dubbo掃描的時(shí)候不能夠掃到被注解的服務(wù)衅谷。
解決方案:修改Service源碼
怎么修改呢椒拗。我們找到Service這個(gè)注解類,位于com.alibaba.dubbo.config.annotation;
1. 給它添加一個(gè)注解@Inherited
@Inherited
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
2. 重編譯生成class文件
這個(gè)不用說了吧 javac Service.java
.
然后把class覆蓋上去。
3. maven項(xiàng)目扔到服務(wù)器又變了啊
所以蚀苛,我們需要把這個(gè)單獨(dú)作為jar包放到項(xiàng)目中在验。然后maven引用本地jar,而不是從倉庫中獲取堵未。
<dependency>
<groupId>com.xxx</groupId>
<!--自定義-->
<artifactId>xxxx</artifactId>
<!--自定義-->
<version>1.0</version>
<!--自定義-->
<scope>system</scope>
<!--system腋舌,類似provided,需要顯式提供依賴的jar以后渗蟹,Maven就不會(huì)在Repository中查找它-->
<systemPath>${pom.basedir}/src/main/webapp/WEB-INF/lib/xxx-xxx.jar</systemPath>
<!--項(xiàng)目根目錄下的lib文件夾下-->
</dependency>
4. 修改后遺癥
如果你真的像我上面所講的修改了dubbo的Service類块饺,那你注冊(cè)的時(shí)候會(huì)發(fā)現(xiàn)一個(gè)問題,也是找不到服務(wù)拙徽,但是這次不一樣了刨沦,你如果在dubbo-admin上看就很清楚诗宣。
天吶膘怕,服務(wù)名是springProxy,所以我們修改了源碼后必須要手動(dòng)生命Service名稱召庞。@Service(interfaceName="com.xx.xxx.service.xxx")
坑一坑二的總結(jié)
個(gè)人認(rèn)為坑一坑二是同一個(gè)問題岛心,jpa出了問題后因?yàn)闀r(shí)間關(guān)系我還是盡快選擇了mybatis替代的方案,所以解決了坑二后并沒有去試坑一是否能解決篮灼。不過想想忘古,jpa的修改必須要@Modifying 和事務(wù),在原生的dubbo的@Service注解下都是不認(rèn)識(shí)的诅诱,可能會(huì)有用髓堪。試過的小伙伴可以在評(píng)論分享下你的成果,謝謝娘荡!
3. 坑三:service層緩存報(bào)異常
我忘了是什么錯(cuò)了干旁,沒有及時(shí)記錄下來,當(dāng)時(shí)在網(wǎng)上查炮沐,前輩說的是因?yàn)榧恿藃edis后service接口不符合dubbo規(guī)范争群,也就是dubbo不能識(shí)別這個(gè)接口,所以我最終把cache的實(shí)現(xiàn)放在了controller里大年。