-2

Before using spring aop and cglib, Now I replaced a simple example.I found that executing method sayHello1 () and sayHello2 () both output "before" and "after" Oh my god, it's very difficult, Do you understand what I am talking about? I am going crazy now. 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 ...");
}
kriegaex
  • 63,017
  • 15
  • 111
  • 202
Muscidae
  • 99
  • 1
  • 7
  • 1
    No, I think next to nobody will understand what you are talking about. Don't go crazy just yet, rather breathe slowly and then take some time to edit your question and turn it into something that can be analysed, copied, pasted, compiled and run. It is called an [MCVE](https://stackoverflow.com/help/mcve) and will probably get you the help you need. So hang in there, but help your helpers understand your problem first by making it reproducible. That is what developers do. – kriegaex May 25 '20 at 13:48
  • Now I replaced a simple example, But the problem seems to be [closed]. : ( – Muscidae May 26 '20 at 03:21
  • 1
    Yes, me and others voted to close the question because it needed more detail. I can reopen it after you answer one more question: Which classes exactly did you import for `InvocationHandler` and `Proxy`? The ones from package `java.lang.reflect` or the similar ones from `org.springframework.cglib.proxy`? BTW, I tested your code with both variants, it works fine either way. So, in addition to adding the imports to your class definitions, please answer the most important question: What is your problem anyway? You did not mention that. It works just fine for me! – kriegaex May 26 '20 at 04:27
  • 1
    A related question is: Why are you trying to implement some kind of proxy-based AOP scheme if you said you used Spring AOP before? Do you want to use it outside of the Spring framework? Then why not just use AspectJ? It does not need proxies and is much more powerful and efficient than Spring AOP. Or is this sample code just an experiment to understand the basic principles behind how to use dynamic proxies better? – kriegaex May 26 '20 at 04:29
  • Okay, I think it does not matter if you are using the CGLIB proxy classes embedded in Spring because they only exist to backport the proxying functionality into older Java versions. So I am just assuming you use the JRE classes and will vote to re-open the question. – kriegaex May 26 '20 at 04:42
  • Sorry, my English is not very good, please understand, I use Google to translate instructions, so there is a deviation and even the description is unclear. : ( – Muscidae May 26 '20 at 04:59
  • Now, I want to implement different before () and after () for sayHello1 () and sayHello2 () respectively, I don't know how to deal with it. Of course aspectj is a very good choice, but I want to try to use jdk's dynamic proxy. – Muscidae May 26 '20 at 05:03
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/214643/discussion-between-muscidae-and-kriegaex). – Muscidae May 26 '20 at 05:06

1 Answers1

1

You mean you want something like this?

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

That would yield the following console log:

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

Of course you could print further information or differentiate overloaded methods with the same names by parameter types. Try things like

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

Is this tedious? Yeah, it is, but still straightforward. And it being tedious is the reason why AspectJ or Spring AOP with their elegant pointcut + advice model are so much easier to use because they did the work already and hide the inner complexity from you.

kriegaex
  • 63,017
  • 15
  • 111
  • 202