您的位置:首页 > 运维架构

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

2017-05-26 14:14 417 查看
导致这个问题的主要原因有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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐