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

ROP扫描服务方法因桥方法产生的BUG的解决

2015-08-21 13:53 302 查看
ROP的服务类通过@ServiceMethodBean进行注解,服务方法通过@ServiceMethod标注,ROP在启动时自动扫描Spring容器中的Bean,将服务方法写到服务注册表中.

最近发现了一个问题,是由于Java泛型的桥方法和合成方法引起的,下面举例说明:

Java代码


package com.rop.session;



/**

* 其中T是登录请求的类,而R是注销请求的类

* @author : chenxh

* @date: 13-10-16

*/



import com.rop.RopRequest;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;



import java.util.UUID;



public abstract class AuthenticationService<T extends RopRequest,R extends RopRequest> {

...

public abstract Object logon(T logonRequest);





/**

* 该方法在子类在实现,并打上@ServiceMethod注解,作为注销的服务方法

* @param loginRequest

* @return

*/

public abstract Object logout(R logoutRequest);



}

AuthenticationService定义了两个抽象方法,需要子类实现,以便实现登录认证.

子类实现如下:

Java代码


@ServiceMethodBean

public class AppAuthenticationService extends AuthenticationService<LogonRequest,LogoutRequest> {



public static final String USER_LOGON = "user.logon";

public static final String USER_LOGOUT = "user.logout";



...



@ServiceMethod(method = USER_LOGON, version = "1.0",

needInSession = NeedInSessionType.NO,ignoreSign = IgnoreSignType.YES)

@Override

public Object logon(LogonRequest logonRequest) {

...

}



@ServiceMethod(method = USER_LOGOUT, version = "1.0")

@Override

public Object logout(LogoutRequest logoutRequest) {

...

}

}

AppAuthenticationService类中覆盖了抽象父类中的方法,并且对泛型进行了具化.

但是当ROP扫描服务方法时,服务方法的入参识别发生了错误,错将入参识别为RopRequest,而非
LogonRequest,LogoutRequest.

断点跟踪到注册服务方法时,发现AuthenticationService类居然有2个logon和2个logout方法:



1.logon(LogonRequest r)
2.logout(LogoutRequest r)

3.logon(RopRequest r)
4.logout(RopRequest r)

其中前两个方法是AuthenticationService中定义的方法,而后两个方法是为了实现泛型具化J***A自动生产的方法,称为桥方法,可参见这篇文章的说明:
http://jiangshuiy.iteye.com/blog/1339105

后两个方法也有和前两个方法一样的@ServiceMethod注解,因此在ROP扫描时,就可以扫描到桥方法,而把真正的方法覆盖了.

J***A的Method反射类中拥有判断是否是桥方法的方法:

Java代码


Method#isBridge()

前两个方法返回的是false,而后两个方法返回的是true.

另外,桥方法也是合成方法(Synthetic),Method反射类中拥有判断是否是桥方法的方法:

Java代码


Method#isSynthetic()

关于合成方法,亦请参考http://jiangshuiy.iteye.com/blog/1339105

为了避免ROP扫描到这些杂攻杂八的方法,因此ROP扫描程序做了以下的调整:

Java代码


private void registerFromContext(final ApplicationContext context) throws BeansException {

if (logger.isDebugEnabled()) {

logger.debug("对Spring上下文中的Bean进行扫描,查找ROP服务方法: " + context);

}

String[] beanNames = context.getBeanNamesForType(Object.class);

for (final String beanName : beanNames) {

Class<?> handlerType = context.getType(beanName);



//1只对标注 ServiceMethodBean的Bean进行扫描

if(AnnotationUtils.findAnnotation(handlerType,ServiceMethodBean.class) != null){

ReflectionUtils.doWithMethods(handlerType, new ReflectionUtils.MethodCallback() {

public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {

ReflectionUtils.makeAccessible(method);

... }

},

new ReflectionUtils.MethodFilter() {

public boolean matches(Method method) {



//2不是合成方法,且标注了ServiceMethod的方法!!

return !method.isSynthetic() && AnnotationUtils.findAnnotation(method, ServiceMethod.class) != null;

}

}

);

}

}

...

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: