业务层使用@Transactional后Dubbo无法发布服务

问题描述

使用@Transactional来对业务层进行事务管理,并使用@Service注册提供方时,提供方无法注册。

原因分析

在使用Dubbo注解(@Service)发布提供发时,Dubbo会根据配置把所有扫描到的类放入Spring容器中进行匹配,并遍历这个包中每一个Bean对象,判断这个Bean对象是不是想要发布的那个Bean(含有@Service注解的类),如果符合,则将这个Bean对象发布到zookeeper中,如果不符合,则不会发布。

<dubbo:annotation package="com.ruiqin.service.impl" />

在使用@Transactional注解对业务类进行事务管理时,Spring容器会为这个业务类创建一个代理类,Spring容器中只有代理类,业务类并不在容器中。又因为Spring容器默认使用JDK动态代理的方式创建代理对象,所以此代理对象的包名是com.sun.proxy,这就导致了Dubbo在发布服务的时候无法正确的匹配包名,从而没有发布服务。

      public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
            //如果得到的是false就不会发布服务
        if (!isMatchPackage(bean)) {
            return bean;
        }
        
        //获取Bean的字节码对象,并获得其中为Service的注解
        Service service = bean.getClass().getAnnotation(Service.class);
         
         //如果类中存在注解
        if (service != null) {
            ServiceBean<Object> serviceConfig = new ServiceBean<Object>(service);
			//设置Bean对象的引用
            serviceConfig.setRef(bean);
            if (void.class.equals(service.interfaceClass())
                    && "".equals(service.interfaceName())) {
                if (bean.getClass().getInterfaces().length > 0) {
                
                  //设置接口类型,为Bean对象实现的所有接口中的第一个,加上上面的引用设置,相当于把注册方放入XML文件中
                    serviceConfig.setInterface(bean.getClass().getInterfaces()[0]);
                } else {
                    throw new IllegalStateException("Failed to export remote service class " + bean.getClass().getName() + ", cause: The @Service undefined interfaceClass or interfaceName, and the service class unimplemented any interfaces.");
                }
            }
            if (applicationContext != null) {
                serviceConfig.setApplicationContext(applicationContext);
                if (service.registry() != null && service.registry().length > 0) {
                    List<RegistryConfig> registryConfigs = new ArrayList<RegistryConfig>();
                    for (String registryId : service.registry()) {
                        if (registryId != null && registryId.length() > 0) {
                            registryConfigs.add((RegistryConfig) applicationContext.getBean(registryId, RegistryConfig.class));
                        }
                    }
                    serviceConfig.setRegistries(registryConfigs);
                }
                if (service.provider() != null && service.provider().length() > 0) {
                    serviceConfig.setProvider((ProviderConfig) applicationContext.getBean(service.provider(), ProviderConfig.class));
                }
                if (service.monitor() != null && service.monitor().length() > 0) {
                    serviceConfig.setMonitor((MonitorConfig) applicationContext.getBean(service.monitor(), MonitorConfig.class));
                }
                if (service.application() != null && service.application().length() > 0) {
                    serviceConfig.setApplication((ApplicationConfig) applicationContext.getBean(service.application(), ApplicationConfig.class));
                }
                if (service.module() != null && service.module().length() > 0) {
                    serviceConfig.setModule((ModuleConfig) applicationContext.getBean(service.module(), ModuleConfig.class));
                }
                if (service.provider() != null && service.provider().length() > 0) {
                    serviceConfig.setProvider((ProviderConfig) applicationContext.getBean(service.provider(), ProviderConfig.class));
                } else {

                }
                if (service.protocol() != null && service.protocol().length > 0) {
                    List<ProtocolConfig> protocolConfigs = new ArrayList<ProtocolConfig>();
                    for (String protocolId : service.protocol()) {
                        if (protocolId != null && protocolId.length() > 0) {
                            protocolConfigs.add((ProtocolConfig) applicationContext.getBean(protocolId, ProtocolConfig.class));
                        }
                    }
                    serviceConfig.setProtocols(protocolConfigs);
                }
                try {
                    serviceConfig.afterPropertiesSet();
                } catch (RuntimeException e) {
                    throw (RuntimeException) e;
                } catch (Exception e) {
                    throw new IllegalStateException(e.getMessage(), e);
                }
            }
            serviceConfigs.add(serviceConfig);
            serviceConfig.export();
        }
        return bean;
    }

	 private boolean isMatchPackage(Object bean) {
	      if (annotationPackages == null || annotationPackages.length == 0) {
            return true;
        }
        //业务类生成代理对象的包名是 com.sun.proxy 与 要扫描的包名不匹配,所以返回false
        String beanClassName = bean.getClass().getName();
        for (String pkg : annotationPackages) {
            if (beanClassName.startsWith(pkg)) {
                return true;
            }
        }
        return false;
    }

解决方法

方法1.直接在xml中配置

	<bean class="com.ruiqin.service.impl.OrderServiceImpl" id="orderService"/>
    <dubbo:service interface="com.ruiqin.service.OrderService" ref="orderService"/>

方法2.将动态代理类的包名改成我们想要扫描的包名

先强制使用CGLIB的方式进行代理对象的生成。

tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>

因为Dubbo在发布服务时,接口类型为发布对象实现的第一个接口类型

  serviceConfig.setInterface(bean.getClass().getInterfaces()[0]);

所以要再指定一下我们的接口类型,确保我们发布的是正确的接口类型

@Service(interfaceClass = OrderService.class)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值