可能我没有足够的思考,或者答案真的难以捉摸。快速方案(尝试编码。编译)。
考虑遗留接口
public interface LegacyInterfaceNoCodeAvailable{
void logInfo(String message);
}
考虑上面接口的遗留实现
public abstract class LegacyClassNoCodeAvailable implements LegacyInterfaceNoCodeAvailable{
public abstract void executeSomething();
public void rockItOldSchool(){
logInfo("bustin' chops, old-school style");
}
@Override
public void logInfo(String message){
System.out.println(message);
}
}
现在我作为这个雄心勃勃的人进入并为“新”系统编写了一个类但是在“Legacy”框架内运行,因此我必须扩展遗留基类。
public class lass SpankingShiny extends LegacyClassNoCodeAvailable{
public void executeSomething(){
rockItOldSchool();
logInfo("I'm the King around here now");
System.out.println("this new stuff rocks!!");
}
}
一切都很好,就像你期望的那样:
SpankingShiny shiny = new SpankingShiny();
shiny.executeSomething();
以上代码产生(如预期):
bustin' chops, old-school style
I'm the King around here now
this new stuff rocks!!
现在您可以看到,'System.out.println()'忠实地打印所需的输出。但我希望用记录器替换'System.out.println()'。
问题:
我无法让CGLIB代理拦截'logInfo(string)'的方法,并让它通过记录器打印出我想要的消息(顺便说一下,我已经完成了日志记录配置)。该方法调用“显然”没有触及代理。
代码:
public class SpankingShinyProxy implements MethodInterceptor{
private SpankingShiny realShiny;
private final Logger logger = Logger.getLogger(SpankingShinyProxy.class);
public SpankingShinyProxy(SpankingShiny realShiny) {
super();
this.realShiny = realShiny;
}
@Override
public Object intercept(Object proxyObj, Method proxyMethod, Object[] methodParams, MethodProxy methodProxy) throws Throwable {
String methodName = proxyMethod.getName();
if("logInfo".equals(methodName)){
logger.info(methodParams[0]);
}
return proxyMethod.invoke(realShiny, methodParams);
}
public static SpankingShiny createProxy(SpankingShiny realObj){
Enhancer e = new Enhancer();
e.setSuperclass(realObj.getClass());
e.setCallback(new SpankingShinyProxy(realObj));
SpankingShiny proxifiedObj = (SpankingShiny) e.create();
return proxifiedObj;
}
}
主要方法:
public static void main(String... args) {
SpankingShiny shiny = new SpankingShiny();
shiny.executeSomething();
SpankingShiny shinyO = SpankingShinyProxy.createProxy(shiny);
shinyO.executeSomething();
}
以上代码产生(不按预期):
bustin' chops, old-school style
I'm the King around here now
this new stuff rocks!!
bustin' chops, old-school style
I'm the King around here now
this new stuff rocks!!
我哪里会出错?
谢谢!
答案 0 :(得分:1)
嗯,首先,你很幸运,你的代理没有被击中。如果您在intercept
中引用实际代理,则最终会出现无限循环,因为您的反射方法位置将由相同的SpankingShinyProxy
分派。一次又一次。
代理无法正常工作,因为您只需将代理上的方法调用executeSomething
委托给某个未经代理的对象。您不得使用realObj
。所有方法调用必须由您的代理调度,也必须由必须访问代理本身调用的那些方法调用!
将intercept
方法中的最后一行更改为methodProxy.invokeSuper(proxyObj, args)
。然后,使用Enhancer
构建对象。如果SpankingShiny
的构造函数不需要参数,那么如果没有任何参数则调用create
。否则,将通常提供给构造函数的对象提供给create
方法。然后,只使用从create
获得的对象并且你很好。
如果您想了解有关cglib的更多信息,可能需要阅读此博客文章:http://mydailyjava.blogspot.no/2013/11/cglib-missing-manual.html
答案 1 :(得分:0)
我遇到了同样的问题。就我而言,realObj
本身就是一个代理(一个Spring Bean - 一个@Component
)。
所以我要做的就是更改.setSuperClass()
部分:
Enhancer e = new Enhancer();
e.setSuperclass(realObj.getClass());
e.setCallback(new SpankingShinyProxy(realObj));
SpankingShiny proxifiedObj = (SpankingShiny) e.create();
我改变了:
e.setSuperclass(realObj.getClass());
要:
e.setSuperclass(realObj.getClass().getSuperClass());
这很有效,因为如上所述,realObj.getClass()
本身就是一个CGLIB代理,并且该方法返回了一个疯狂名称CGLIB生成的类,例如a.b.c.MyClass$$EnhancerBySpringCGLIB$$1e18666c
。当我添加.getSuperClass()
时,它返回了它应该首先返回的类。