前言
在使用註解式dubbo開發的過程中,忽然發現Service上只要有@transactional註解或者是配置的事務切面時,該Service不能被dubbo發佈。
問題詳情
dubbo的配置:
- <span style="white-space:pre"> </span><!-- 定義註冊中心,採用zookeeper -->
- <dubbo:registry protocol="zookeeper" address="127.0.0.1:2181"/>
- <!-- 定義協議爲dubbo,在端口20880上暴露服務 -->
- <dubbo:protocol name="dubbo" port="20880"/>
- <dubbo:annotation package="com.rondo"/>
<span style="white-space:pre"> </span><!-- 定義註冊中心,採用zookeeper -->
<dubbo:registry protocol="zookeeper" address="127.0.0.1:2181"/>
<!-- 定義協議爲dubbo,在端口20880上暴露服務 -->
<dubbo:protocol name="dubbo" port="20880"/>
<dubbo:annotation package="com.rondo"/>
事務的配置:
- <span style="white-space:pre"> </span><!-- 註解方式配置事務 -->
- <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource"/>
- </bean>
- <span style="white-space:pre"> </span><tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>
<span style="white-space:pre"> </span><!-- 註解方式配置事務 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<span style="white-space:pre"> </span><tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>
- @Component
- @Service//這個service註解是dubbo的
- @Transactional
- public class UserServiceImpl implements UserService {
- @Autowired
- private UserMapper userMapper;
- @Override
- public Mapper<User> getMapper() {
- return userMapper;
- }
- }
@Component
@Service//這個service註解是dubbo的
@Transactional
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public Mapper<User> getMapper() {
return userMapper;
}
}
這種情況下,UserService不能被dubbo發佈。
解決思路
這個問題簡直~~,後來發現,在使用事務的時候,配置文件中使用了cglib的方式(proxy-target-class="true")爲service生成代理,而當dubbo掃描註解的時候,這個被代理的UserService並沒有dubbo的@service註解,因爲dubbo定義這個註解的時候,沒有允許子類集成父類的註解。
cglib生成代理的方式恰好是生成該類的子類,那麼問題顯而易見了,就是這個代理上缺少了@Service,怎麼解決這個問題呢?------------修改dubbo源碼是個好辦法,讓@service可以被子類繼承。
解決方法
1.https://github.com/alibaba/dubbo上有dubbo的源碼,找到dubbo-config/dubbo-config-api/src/main/java/com/alibaba/dubbo/config/annotation/Service.java,複製裏面所有內容。
2.新建一個txt文件並修改名稱爲“Service.java”,打開粘貼所有內容,並添加註解@Inherited,別忘了導入Inherited的包,如圖:
3.javac Service.java將該java文件編譯爲class,具體步驟就不用說了吧。。。
4.使用解壓軟件打開dubbo-x.x.x.jar,找到包com.alibaba.dubbo.config.annotation下的Service.class,用自己編譯的替換掉原有的。
效果
做完上面這些,我覺得問題肯定解決了,於是重新啓動了一下工程,結果消費端調用UserService中的方法的時候還是會報沒有provider!word 天~,這怎麼可能!於是我啓動了dubbo-admin(關於這個玩意如果有疑問自己網上下載個dubbo-admin.war,你就明白了),在查看發佈的接口的時候發現悲劇了
我原本要發佈的UserService,竟然是SpringProxy。發現dubbo的@Service註解中有一個屬性“interfaceName”,這下問題得到徹底解決,將UserServiceImpl中的@Service註解修改爲@Service(interfaceName="com.rondo.business.service.UserService"),即指定了接口名稱,效果如圖:
然後,在消費端調用了一下,調用成功,而且事務也是有效的。