ROP的服務類經過@ServiceMethodBean進行註解,服務方法經過@ServiceMethod標註,ROP在啓動時自動掃描Spring容器中的Bean,將服務方法寫到服務註冊表中.
最近發現了一個問題,是因爲Java泛型的橋方法和合成方法引發的,下面舉例說明:
java
package com.rop.session; ide
/** ui
* 其中T是登陸請求的類,而R是註銷請求的類 spa
* @author : chenxh debug
* @date: 13-10-16 blog
*/ 圖片
import com.rop.RopRequest; get
import org.slf4j.Logger; it
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定義了兩個抽象方法,須要子類實現,以便實現登陸認證.
子類實現以下:
@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中定義的方法,然後兩個方法是爲了實現泛型具化JAVA自動生產的方法,稱爲橋方法,可參見這篇文章的說明:
http://jiangshuiy.iteye.com/blog/1339105
後兩個方法也有和前兩個方法同樣的@ServiceMethod註解,所以在ROP掃描時,就能夠掃描到橋方法,而把真正的方法覆蓋了.
JAVA的Method反射類中擁有判斷是不是橋方法的方法:
Method#isBridge()
前兩個方法返回的是false,然後兩個方法返回的是true.
另外,橋方法也是合成方法(Synthetic),Method反射類中擁有判斷是不是橋方法的方法:
Method#isSynthetic()
關於合成方法,亦請參考http://jiangshuiy.iteye.com/blog/1339105
爲了不ROP掃描到這些雜攻雜八的方法,所以ROP掃描程序作了如下的調整:
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;
}
}
);
}
}
...
}