使用dubbo注解@Service注册服务后使用aop或者申明式事物导致无法注册的问题解决办法

导致这个问题的主要原因有2个
  • 1:JdkDynamicProxy导致获取到的class路径不正确无法通过包路径检查动态代理后的对象获取到的class都是 com.sun.proxy开头的
         private boolean isMatchPackage(Object bean) {
        if (annotationPackages == null || annotationPackages.length == 0) {
            return true;
        }
        String beanClassName = bean.getClass().getName();
        for (String pkg : annotationPackages) {

            if (beanClassName.startsWith(pkg)) {
                return true;
            }
        }
        return false;
    }
  • 2:cglib代理后由于dubbo的@Service注解头没有标注@Inherited导致无法查找到注解
Service service = bean.getClass().getAnnotation(Service.class);

解决思路:

既然是由于代理对象导致无法获取到注解那么我的思路就是获取到被代理的对象

1:引入spring-aop依赖
2:使用AopUtils来判断是属于哪种代理并分别通过反射获取被代理的对象

public class AopUtils {
    private static final Logger logger = LoggerFactory.getLogger(AopUtils.class);
    public static Object getTarget(Object bean){
        if(org.springframework.aop.support.AopUtils.isCglibProxy(bean)) return getCglibAopObject(bean);
        if(org.springframework.aop.support.AopUtils.isAopProxy(bean)) return getJDKDynamicAopObject(bean);
        return bean;
    }


    private static Object getJDKDynamicAopObject(Object bean){
        Field field = null;
        try {
            field = bean.getClass().getSuperclass().getDeclaredField("h");
            field.setAccessible(true);
            AopProxy aopProxy = null;
                aopProxy = (AopProxy) field.get(bean);
                field.setAccessible(false);


            Field advised = aopProxy.getClass().getDeclaredField("advised");
            advised.setAccessible(true);
            Object target = ((AdvisedSupport)advised.get(aopProxy)).getTargetSource().getTarget();
            advised.setAccessible(false);
            return target;
        } catch (Exception e) {
            logger.error("获取JDK动态代理真实对象出错",e);
            return bean;
        }

    }
    private static Object getCglibAopObject(Object bean){
        Field field = null;
        try {
            field = bean.getClass().getDeclaredField("CGLIB$CALLBACK_0");
            field.setAccessible(true);
            Object dynamicAdvisedInterceptor = field.get(bean);
            field.setAccessible(false);
            Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
            advised.setAccessible(true);
            Object target = ((AdvisedSupport)advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
            advised.setAccessible(false);
            return  target;
        } catch (Exception e) {
            logger.error("获取CGLIB动态代理真实对象出错",e);
            return bean;

        }


    }

}

判断方式改为判断被代理的对象

     Object unWrapBean = AopUtils.getTarget(bean);
        if (! isMatchPackage(unWrapBean)) {
            return bean;
        }
Service service = unWrapBean.getClass().getAnnotation(Service.class);
        if (service != null) {
            ServiceBean<Object> serviceConfig = new ServiceBean<Object>(service);
            if (void.class.equals(service.interfaceClass())
                    && "".equals(service.interfaceName())) {
                if (unWrapBean.getClass().getInterfaces().length > 0) {
                    serviceConfig.setInterface(unWrapBean.getClass().getInterfaces()[0]);
                } else {
                    throw new IllegalStateException("Failed to export remote service class " + unWrapBean.getClass().getName() + ", cause: The @Service undefined interfaceClass or interfaceName, and the service class unimplemented any interfaces.");
                }
            }

这样就可以使被代理的对象也能注册了,使用这种方式有个坏处就是要修改源码

所以我的方法是把AnnotationBean的代码copy过来然后修改然后new自己的类来规避这个问题

 @Bean
    public AnnotationBean annotationBean(@Value("${dubbo.annotation.package}") String packageName) {
        AnnotationBean annotationBean = new AnnotationBean();
        annotationBean.setPackage(packageName);
        return annotationBean;
    }
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值