有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java我在使用jdk动态代理时遇到问题

在使用SpringAOP和cglib之前,现在我替换了一个简单的示例。我发现执行方法sayHello1()和sayHello2()都会输出“之前”和“之后”哦,天哪,这很难,你明白我在说什么吗?我现在快发疯了。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 ...");
}

共 (1) 个答案

  1. # 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及其优雅的切入点+建议模型更易于使用的原因,因为它们已经完成了工作,并且向您隐藏了内部的复杂性