【问题标题】:I am having trouble in using jdk dynamic proxy我在使用 jdk 动态代理时遇到问题
【发布时间】:2020-05-25 11:54:02
【问题描述】:

之前用spring aop和cglib,现在换一个简单的例子。发现执行方法sayHello1()和sayHello2()都输出“before”和“after” 天啊,好难,你懂什么吗我在说什么?我现在快疯了。 T.T

public interface HelloWorld {
    void sayHello1(String say);
    void sayHello2(String say);
}
public static class HelloWorldImpl implements HelloWorld {
    @Override
    public void sayHello1(String say) { System.out.println(say); }
    @Override
    public void sayHello2(String say) { System.out.println(say); }
}
public static class Invocation implements InvocationHandler {
    private final Object target;

    public Invocation(Object target) { this.target = target; }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before..."); // TODO method before
        Object object = method.invoke(target, args);
        System.out.println("after..."); // TODO method after
        return object;
    }
}
public static void main(String[] args) {
    HelloWorld helloWorld = (HelloWorld) Proxy.newProxyInstance(
        ClassLoader.getSystemClassLoader(),
        new Class[] { HelloWorld.class },
        new Invocation(new HelloWorldImpl())
    );
    helloWorld.sayHello1("Hello World1 ...");
    helloWorld.sayHello2("Hello World2 ...");
}

【问题讨论】:

  • 不,我想没有人会明白你在说什么。暂时不要发疯,而是慢慢呼吸,然后花一些时间编辑您的问题,并将其变成可以分析、复制、粘贴、编译和运行的东西。它被称为MCVE,可能会为您提供所需的帮助。所以坚持下去,但通过使其可重现来帮助您的助手首先了解您的问题。这就是开发人员所做的。
  • 现在我换了一个简单的例子,但问题似乎是[关闭]。 : (
  • 是的,我和其他人投票结束了这个问题,因为它需要更多细节。在您再回答一个问题后,我可以重新打开它:您究竟为InvocationHandlerProxy 导入了哪些类?来自包java.lang.reflect 的那些还是来自org.springframework.cglib.proxy 的类似的?顺便说一句,我用两种变体测试了你的代码,无论哪种方式都可以正常工作。因此,除了将导入添加到您的类定义之外,请回答最重要的问题:您的问题是什么?你没有提到这一点。它对我来说很好用!
  • 一个相关的问题是:如果你说你以前使用过 Spring AOP,你为什么要尝试实现某种基于代理的 AOP 方案?你想在 Spring 框架之外使用它吗?那么为什么不直接使用 AspectJ 呢?它不需要代理,比 Spring AOP 更强大、更高效。或者这个示例代码只是一个实验,以了解如何更好地使用动态代理背后的基本原理?
  • 好吧,我认为你是否使用嵌入在 Spring 中的 CGLIB 代理类并不重要,因为它们的存在只是为了将代理功能反向移植到旧的 Java 版本中。所以我只是假设你使用 JRE 类并且会投票重新打开这个问题。

标签: java aop aspectj dynamic-proxy invocationhandler


【解决方案1】:

你的意思是你想要这样的东西?

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  System.out.println("Instrumenting " + method);
  Object result;
  switch (method.getName()) {
    case "sayHello1":
      System.out.println("before A");
      result = method.invoke(target, args);
      System.out.println("after A");
      break;
    case "sayHello2":
      System.out.println("before B");
      // Let's change the argument just for fun
      args[0] = "changed argument";
      result = method.invoke(target, args);
      System.out.println("after B");
      break;
    default:
      result = method.invoke(target, args);
  }
  return result;
}

这将产生以下控制台日志:

Instrumenting public abstract void de.scrum_master.spring.q62001911.HelloWorld.sayHello1(java.lang.String)
before A
Hello World1 ...
after A
Instrumenting public abstract void de.scrum_master.spring.q62001911.HelloWorld.sayHello2(java.lang.String)
before B
changed argument
after B

当然,您可以打印更多信息或通过参数类型区分具有相同名称的重载方法。尝试类似

method.getParameterTypes();
method.getParameterCount();
method.getReturnType();

这很乏味吗?是的,它是,但仍然很简单。单调乏味是 AspectJ 或 Spring AOP 及其优雅的切入点 + 建议模型如此易于使用的原因,因为它们已经完成了工作并且向您隐藏了内部的复杂性。

【讨论】:

    猜你喜欢
    • 2020-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-23
    • 2021-11-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多