[apache/dubbo]注解加载服务配置,部分服务正常部分事务失效,Dubbo代理类跳过了Spring CGLib的代理

2024-07-31 466 views
8

测试版本:(注:2.8.4的版本一样存在)

<dubbo.version>2.5.5</dubbo.version>
其他依赖版本:
<spring.version>4.3.10.RELEASE</spring.version>
<aspectj.version>1.7.4</aspectj.version>
<zookeeper.version>3.4.6</zookeeper.version>

问题简述: 同样写法下,用注解配置的服务,部分类会走SpringCGLib代理,而部分却跳过了代理,导致事务失效。 我认真比对了所有的写法,都一模一样,却出现了两种效果

备用解决方案: 出问题的类改用xml配置,一切正常,问题应该出在 Dubbo的注解扫描

项目说明: 使用了DBUtils,如下配置事务

     <\!--事务管理器配置-->
     <bean id="dataSourceProxy" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
         <constructor-arg name="targetDataSource" ref="ds"/>
     </bean>
     <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSourceProxy"/>
    <property name="nestedTransactionAllowed" value="true"/>
    </bean>
    <\!--Spring JDBC和DBUtils-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <constructor-arg name="dataSource" ref="dataSourceProxy"/>
    </bean>
    <bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
    <constructor-arg name="ds" ref="dataSourceProxy"/>
    </bean>
    <\!--事务注解支持-->
    <tx:annotation-driven transaction-manager="txManager"
                        proxy-target-class="true"/>

问题信息重现: 代码写法(简化中间内容):

正常的如下:

public interface OrderCreateService {
    ...
}

@Service
@com.alibaba.dubbo.config.annotation.Service(version = "1.0.0", interfaceName = "com.temsoft.oms.order.service.OrderCreateService")
public class OrderCreateServiceImpl implements OrderCreateService {
    ...
}

同样写法,错误的如下:

public interface OrdersMngService {
    ...
}
@Service
@com.alibaba.dubbo.config.annotation.Service(version = "1.0.0", interfaceName = "com.temsoft.oms.order.service.OrdersMngService")
public class OrdersMngServiceImpl implements OrdersMngService {
    ...
}

Spring配置(spring 的扫描,我全部都用include-filter 和 use-default-filters="false", 确定没有扫描两次):

<!--注解方式加载-->
<dubbo:annotation />
<!-- 扫描注解Bean -->
<context:component-scan base-package="com.temsoft.oms" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>

说明:在测试过程中发现,错误的类(OrdersMngService)在Jrebel重载时也会是重载的Spring CGLib代理的类,但是Dubbo调用的依旧跳过了该代理。

错误说明方式:服务端按简述方式编写,消费端直接调用,目标函数直接报异常,传出调用栈,栈信息如下:

错误调用栈:

java.lang.NullPointerException
    at com.temsoft.oms.order.service.impl.OrdersMngServiceImpl.updateOrderGoods(OrdersMngServiceImpl.java:80)
    at com.temsoft.oms.order.service.impl.OrdersMngServiceImpl.updateOrderGoods(OrdersMngServiceImpl.java:74)
    at com.alibaba.dubbo.common.bytecode.Wrapper21.invokeMethod(Wrapper21.java)
    at com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory$1.doInvoke(JavassistProxyFactory.java:46)
    at com.alibaba.dubbo.rpc.proxy.AbstractProxyInvoker.invoke(AbstractProxyInvoker.java:72)
    at com.alibaba.dubbo.rpc.protocol.InvokerWrapper.invoke(InvokerWrapper.java:53)
    at com.alibaba.dubbo.rpc.filter.ExceptionFilter.invoke(ExceptionFilter.java:64)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69)
    at com.alibaba.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:75)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69)
    at com.alibaba.dubbo.rpc.filter.TimeoutFilter.invoke(TimeoutFilter.java:42)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69)
    at com.alibaba.dubbo.rpc.protocol.dubbo.filter.TraceFilter.invoke(TraceFilter.java:78)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69)
    at com.alibaba.dubbo.rpc.filter.ContextFilter.invoke(ContextFilter.java:61)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69)
    at com.alibaba.dubbo.rpc.filter.GenericFilter.invoke(GenericFilter.java:132)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69)
    at com.alibaba.dubbo.rpc.filter.ClassLoaderFilter.invoke(ClassLoaderFilter.java:38)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69)
    at com.alibaba.dubbo.rpc.filter.EchoFilter.invoke(EchoFilter.java:38)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69)
    at com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol$1.reply(DubboProtocol.java:102)
    at com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.handleRequest(HeaderExchangeHandler.java:98)
    at com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.received(HeaderExchangeHandler.java:170)
    at com.alibaba.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:52)
    at com.alibaba.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:81)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:748)

正常调用栈:

java.lang.NullPointerException
    at com.temsoft.oms.order.service.impl.OrderCreateServiceImpl.update(OrderCreateServiceImpl.java:914)
    at com.temsoft.oms.order.service.impl.OrderCreateServiceImpl$$FastClassBySpringCGLIB$$be6e0d2.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
    at com.temsoft.oms.order.service.impl.OrderCreateServiceImpl$$EnhancerBySpringCGLIB$$cda42b2.update(<generated>)
    at com.alibaba.dubbo.common.bytecode.Wrapper18.invokeMethod(Wrapper18.java)
    at com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory$1.doInvoke(JavassistProxyFactory.java:46)
    at com.alibaba.dubbo.rpc.proxy.AbstractProxyInvoker.invoke(AbstractProxyInvoker.java:72)
    at com.alibaba.dubbo.rpc.protocol.InvokerWrapper.invoke(InvokerWrapper.java:53)
    at com.alibaba.dubbo.rpc.filter.ExceptionFilter.invoke(ExceptionFilter.java:64)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69)
    at com.alibaba.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:75)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69)
    at com.alibaba.dubbo.rpc.filter.TimeoutFilter.invoke(TimeoutFilter.java:42)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69)
    at com.alibaba.dubbo.rpc.protocol.dubbo.filter.TraceFilter.invoke(TraceFilter.java:78)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69)
    at com.alibaba.dubbo.rpc.filter.ContextFilter.invoke(ContextFilter.java:61)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69)
    at com.alibaba.dubbo.rpc.filter.GenericFilter.invoke(GenericFilter.java:132)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69)
    at com.alibaba.dubbo.rpc.filter.ClassLoaderFilter.invoke(ClassLoaderFilter.java:38)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69)
    at com.alibaba.dubbo.rpc.filter.EchoFilter.invoke(EchoFilter.java:38)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:69)
    at com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol$1.reply(DubboProtocol.java:102)
    at com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.handleRequest(HeaderExchangeHandler.java:98)
    at com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.received(HeaderExchangeHandler.java:170)
    at com.alibaba.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:52)
    at com.alibaba.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:81)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:748)

回答

1

@service不要同时注解dubbo的和spring的。可以看示例项目https://gitee.com/lei0719/spring-boot-starter-dubbo-example

6

@halober 我觉得同时配置dubbo和spring的service注解应该是没有问题的。 这里的问题或许出在BeanPostProcessor执行的顺序上

6

transactional和dubbo service注解一同dubbo service应该是无法正常暴露才对呀,奇怪你这里竟然成功暴露了(OrderCreateService)

6

指定了 interfaceName 或者interfaceClass,是可以暴露的。

8

@halober 不好意思最近比较忙 刚测试了一下,改为只用Dubbo的注解,配置改为以下配置

问题依旧存在
6

吧这一行去掉,

dubbo自己有处理这个注解的扫描,具体看这个类,AnnotationBean

6

去掉后还是一样。。。 老神奇了,就那几个特定的服务类出问题,都不变 这样,抽时间我把代码整理出来一份发到github吧,由于是公司的项目,所以我还得把实现代码去掉,时间会长一点 1 2

7

+1,最后是怎么解决的?

7

看代码呗,是不是用错注解了?

6

@duqicauc 事务问题可能是其他地方配置的问题,可以按我测试的方式试一下看是不是这个问题,如果是,备用解决方法前面说过

@chickenlj 实在不好意思,最近太忙没时间处理,我正在弄公司项目,clone出一个可以放出来的版本,但是代码量挺多的,我尽快完成 刚试了2.5.7 问题依旧存在,可能是spring BeanPostProcessor 执行过程中出的问题 今天下班挺早的,我继续改改公司的项目代码:smile:

1

@kisChang 出问题的类xml是怎么配置的,能贴出来吗?

5
遇到同样的问题,某些Service事务一直失效,跟进去对比发现无事务的服务调用字节码处理直接略过了spring事务相关的aop。 看到你的备用方案改成xml配置解决。 给你点个赞!

看到有人在追问xml配置怎么加,我顺便贴一下(spring-boot): doubb-provider.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://code.alibabatech.com/schema/dubbo         http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    <!-- 声明需要暴露的服务接口 -->
    <dubbo:service interface="接口"
                   ref="spring bean" protocol="dubbo" timeout="3000" retries="0" version="版本"/>
</beans>

App.java增加注解(启动入口)

@ImportResource({"classpath:dubbo-provider.xml"})

@wallaceyoung

5

问题遇到+1,解决方案已试两个,1、改xml配置。 2,、新增中间一层接口实现类调用

1

@chickenlj
1、2.5.9 解决了,需要增加包扫描,之前只使用了<dubbo:annotation 配置

2、但是 2.6.0 问题依旧存在 打印日志如,发布的服务接口为SpringProxy ,之前的版本也有此问题,由于不想每次注解中指定接口名称,于是修改了如下: //修复 代理类发布的服务接口为 SpringProxy Class clazz = bean.getClass(); if (org.springframework.aop.support.AopUtils.isAopProxy(bean)) { clazz = org.springframework.aop.support.AopUtils.getTargetClass(bean); } serviceConfig.setInterface(clazz.getInterfaces()[0]); [com.alibaba.dubbo.registry.integration.RegistryProtocol]- [DUBBO] subscribe url: provider://192.168.2.77:20880/org.springframework.aop.SpringProxy?anyhost=true&application=dubbo-rss-provider&category=configurators&check=false&default.delay=-1&default.retries=0&default.timeout=60000&delay=-1&dubbo=2.6.0&generic=false&interface=org.springframework.aop.SpringProxy&methods=*&pid=10752&revision=4.2.5.RELEASE&side=provider×tamp=1521424569991&version=1.0.0, override urls: [empty://192.168.2.77:20880/org.springframework.aop.SpringProxy?anyhost=true&application=dubbo-rss-provider&category=configurators&check=false&default.delay=-1&default.retries=0&default.timeout=60000&delay=-1&dubbo=2.6.0&generic=false&interface=org.springframework.aop.SpringProxy&methods=*&pid=10752&revision=4.2.5.RELEASE&side=provider×tamp=1521424569991&version=1.0.0], dubbo version: 2.6.0, current host: 127.0.0.1 [com.alibaba.dubbo.config.model.ApplicationModel]- [DUBBO] already register the provider service: org.springframework.aop.SpringProxy:1.0.0, dubbo version: 2.6.0, current host: 127.0.0.1
9

我也遇到了同样的问题,在com.alibaba.dubbo.config.spring.AnnotationBean 的204行serviceConfig.setRef(bean);设置ServiceBean 的ref时,部分服务会使用目标对象导致dubbo的服务有事务时没有被增强,改成 serviceConfig.setRef(applicationContext.getBean(beanName,clazz)); 即可

0

related issue #557