【问题标题】:CGLIB not able to intercept methods in a superclass/superinterfaceCGLIB 无法拦截超类/超接口中的方法
【发布时间】:2013-11-13 22:59:18
【问题描述】:

可能是我想得不够努力,或者答案真的难以捉摸。快速场景(试用代码。它可以编译)。

考虑一个旧接口

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);
    }
}

现在我以这个雄心勃勃的人的身份进来,为“新”系统编写一个类,但该类在“旧”框架内运行,因此我必须扩展旧基类。

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!!

我哪里会出错?

谢谢!

【问题讨论】:

    标签: java proxy cglib


    【解决方案1】:

    嗯,首先,你很幸运你的代理没有被命中。如果你在intercept 中引用实际的代理,你最终会陷入无限循环,因为你的反射方法incocation 会被同一个SpankingShinyProxy 调度。一次又一次。

    代理不起作用,因为您只是将代理上的方法调用executeSomething 委托给了一些未代理的对象。您不得使用realObj。所有方法调用都必须由您的代理分派,那些由代理调用的方法调用也必须命中代理本身!

    intercept 方法中的最后一行更改为methodProxy.invokeSuper(proxyObj, args)。然后,使用Enhancer 构造您的对象。如果SpankingShiny 的构造函数不需要参数,则在没有任何参数的情况下调用create。否则,将您通常提供给构造函数的对象提供给create 方法。然后,只使用您从create 获得的对象就可以了。

    如果您想了解更多关于 cglib 的信息,您可能需要阅读这篇博文:http://mydailyjava.blogspot.no/2013/11/cglib-missing-manual.html

    【讨论】:

      【解决方案2】:

      我遇到了同样的问题。在我的例子中,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() 时,它返回了它应该首先返回的类。

      【讨论】:

      • 很好的答案!很好地解决了我的问题。对于那些使用 Spring 的人,您可以利用:ClassUtils.getUserClass(type); 在这种情况下,.getSuperClass() 将仅在您处理 CGLIB 代理时使用(这几乎就是您可能正在寻找这个的原因解决方案)。
      猜你喜欢
      • 2020-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-03
      • 1970-01-01
      • 1970-01-01
      • 2012-01-29
      • 1970-01-01
      相关资源
      最近更新 更多