如何使用javassist / CGLib

时间:2015-07-24 09:03:11

标签: java proxy javassist cglib

我有第三方API调用,它返回以下对象:

public class A {
  protected void common() {
     System.out.println("common is called in A");
  }

  public void test1() {
    common();
    System.out.println("test1 is called in A");
  }
  public void test2() {
    common();
    System.out.println("test2 is called in A");
  }
}

但是我想像下面的ModifiedA节目一样修改它的行为:

public class ModifiedA extends A {
  @Override
  protected void common() {
     super.common();
     System.out.println("common is called in ModifiedA");
  }
}

所以我想做的是:

A a = 3rdPartyAPI_call();

//
// Now I'd like to get a ModifiedA which has changed common() behavior.
//

如何使用javassist / CGLIB来实现这个目标?

一种简单的方法可能就是这样:

public class ModifiedA extends A {
  private A a;
  public ModifiedA(final A a) {
     this.a = a;
  }
  //
  // Override every public method in A
  //

  @Override
  protected void common() {
     super.common();
     System.out.println("common is called in ModifiedA");
  }
}

但由于A的定义来自第三方并且非常复杂并且可能会发生变化,所以我想使用代理来实现这一目标吗?

感谢您的评论。

2 个答案:

答案 0 :(得分:2)

您可以使用CGLib实现委托者模式,而无需覆盖所有方法。根据样式,有几种不同的方法可以实现这一点,但这里有一个类似于你的例子。

您可以使用cglib Enhancer包装实例:

public static <T> T wrapInstance(final T original) {
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(original.getClass());
    enhancer.setCallback(new MethodInterceptor() {
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            Object returnValue = proxy.invoke(original, args);
            if (method.getName().equals("common")) {
                System.out.println("common is called");
            }
            return returnValue;
        }
    });
    return (T) enhancer.create();
}

答案 1 :(得分:0)

eclps帖子将满足您的要求并且有效。我想为eclps代码添加更多代码。

添加为常用方法提供索引零的过滤器,并将所有方法保留为One。 MethodInterceptor回调只会拦截常用方法,并且所有方法都使用NoOp intercetor(它将调用超类apis)。这样每次方法调用都不会进行过滤。

public static <T> T wrapInstance(final T original) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(original.getClass());
        enhancer.setCallbackFilter(new CallbackFilter() {
            @Override
            public int accept(Method method) {
                if (method.getName().equals("common")) {
                    return 0;
                }
                return 1;
            }
        });
        enhancer.setCallbacks(new Callback[]{new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                // only common method will intercept this call back.
                return proxy.invoke(this, args);
            }
        }, NoOp.INSTANCE});
        return (T) enhancer.create();
    }