在前面博客的Dubbo的入门案例(Dubbo学习(三):Dubbo快速入门(含负载均衡))中,可以看到通过Dubbo提供的标签配置就可以进行包扫描,扫描到@Service注解的类就可以被发布为服务。
如果在服务提供者类上加入
@Transactional
事务控制注解后,服务就发布不成功了。
原因是事务控制的底层原理是为服务提供者类创建代理对象,而默认情况下Spring是基于JDK动态代理方式创建代理对象,而此代理对象的完整类名为com.sun.proxy.$Proxy42(最后两位数字不是固定的),导致Dubbo在发布服务前进行包匹配时无法完成匹配,进而没有进行服务的发布。
一、问题展示(dubbo-provider工程)
说明: 操作入门案例的服务提供者dubbo-provider工程。
(1)在pom.xml文件中增加maven坐标
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.6</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
(2)在applicationContext-service.xml配置文件中加入数据源、事务管理器、开启事务注解的相关配置
<!--数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="username" value="root" />
<property name="password" value="1234" />
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mytest" />
</bean>
<!-- 事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--开启事务控制的注解支持-->
<tx:annotation-driven transaction-manager="transactionManager"/>
(3)在HelloServiceImpl类上加入spring事务注解:@Transactional
package net.xiaof.service.impl;
import com.alibaba.dubbo.config.annotation.Service;
import net.xiaof.service.HelloService;
import org.springframework.transaction.annotation.Transactional;
/**
* @author zhangxh
* @Description:
* @date 2021-01-02
*
* “@service”注解的类会被发布为服务
*/
@Transactional
@Service //【注意】:此注解非spring注解,为com.alibaba.dubbo.config.annotation.Service
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
return "hello " + name;
}
}
(4)启动服务提供者和服务消费者,并访问
访问:http://localhost:8084/dubbo/hello?name=zhangsan
报如下错: 没有可用的服务提供者
查看dubbo管理控制台发现服务并没有发布,如下:
访问地址:http://localhost:9000/dubbo-admin-2.6.0/
用户:root
密码:root
(5)断点调试查看Dubbo执行过程
在IDEA中使用快捷键“ctrl+shift+R”,搜索类AnnotationBean:
在AnnotationBean类的postProcessAfterInitialization方法上打断点。
Debug方式启动服务提供者应用:
断点调试自行查看(可参考下图):
二、解决方法(dubbo-provider工程)
通过上面的断点调试可以看到,在HelloServiceImpl类上加入事务注解后,Spring会为此类基于JDK动态代理技术创建代理对象,创建的代理对象完整类名为com.sun.proxy.$Proxy35,导致Dubbo在进行包匹配时没有成功(因为我们在发布服务时扫描的包为com.itheima.service),所以后面真正发布服务的代码没有执行。
解决方法操作步骤:
(1)指定使用cglib代理方式为Service类创建代理对象
修改applicationContext-service.xml配置文件,开启事务控制注解支持,必须指定proxy-target-class
属性,值为true。其作用是使用cglib代理方式为Service类创建代理对象。
<!--开启事务控制的注解支持-->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
(2)@Service注解指定接口类型
修改HelloServiceImpl类,在该类上dubbo源的@Service注解中加入interfaceClass属性,值为HelloService.class,作用是指定服务的接口类型
注意:
必须指定interfaceClass属性,否则会导致发布的服务接口为SpringProxy(这是spring的cglib代理默认实现的接口),而不是我们创建的HelloService接口。
package net.xiaof.service.impl;
import com.alibaba.dubbo.config.annotation.Service;
import net.xiaof.service.HelloService;
import org.springframework.transaction.annotation.Transactional;
/**
* @author zhangxh
* @Description:
* @date 2021-01-02
*
* “@service”注解的类会被发布为服务
* 【注意】:@Service注解非spring注解,为com.alibaba.dubbo.config.annotation.Service
*/
@Transactional
@Service(interfaceClass = HelloService.class,protocol = "dubbo")
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
return "hello " + name;
}
}
(3)启动服务提供者和服务消费者,并访问(成功
)
访问:http://localhost:8084/dubbo/hello?name=zhangsan
(4)可查看zookeeper管控台
访问:http://localhost:9000/dubbo-admin-2.6.0/
用户:root
密码:root