AOP introduction: dynamic agent
Before introducing AOP, let's introduce the knowledge of dynamic agent
Let's give you a simple example. Now we have the following user interface and its implementation class (for convenience, only the corresponding statements are printed in the implementation class)
package com.zy.service; public interface userService { public void selectUser(); public void insertUser(); }
package com.zy.service; public class userServiceImpl implements userService { @Override public void selectUser() { System.out.println("Find users"); } @Override public void insertUser() { System.out.println("Insert user"); } }
Now we want to add two functions to these two methods: add the recording time function before execution and add the * * recording log * * function after execution. How do we implement it?
Mode 1:
Most people may want to add these two new functions directly to both methods, as shown below
public class userServiceImpl implements userService { @Override public void selectUser() { System.out.println("Execution time:" + new Date()); System.out.println("Find users"); System.out.println("Print log information"); } @Override public void insertUser() { System.out.println("Execution time:" + new Date()); System.out.println("Insert user"); System.out.println("Print log information"); } }
However, this changes the original code, and the original business processing code and the newly added irrelevant business code are integrated and repeated, which leads to a lot of clutter. Moreover, if we modify the irrelevant business code, we need to modify it in each function, how should we optimize it?
Mode 2:
We extract the code independent of the business separately, encapsulate it into a tool class and call it in the business code, as shown below.
public class otherService { public static void getTime() { System.out.println("Execution time:" + new Date()); } public static void getLog() { System.out.println("Print log information"); } }
@Override public void selectUser() { otherService.getTime(); System.out.println("Find users"); otherService.getLog(); } @Override public void insertUser() { otherService.getTime(); System.out.println("Insert user"); otherService.getLog(); }
This solves some problems, but we can also find that the business code is still the caller's non business code, and the coupling is still too high, which leads to our dynamic agent~
With the emergence of dynamic proxy mechanism, Java developers do not need to write proxy classes manually. As long as they simply specify a group of interfaces and delegate class objects, they can dynamically obtain proxy classes. Proxy classes are responsible for dispatching all method calls to delegate objects for reflection and execution. In the process of dispatching and execution, developers can also adjust delegate class objects and their functions as needed It is a very flexible and flexible agent framework.
The basic process is as follows. The proxy class creates the proxy class object through the business interface, and finally returns the proxy class object.
Mode 3:
We then use the JDK's own dynamic agent to solve the above requirements
First, we create a UserService proxy class to implement the InvocationHandler interface
package com.zy.service; public class UserProxy implements InvocationHandler { private Object target;//Proxy interface (target object) public UserProxy(Object target) { this.target = target; } /** * Add functions to the original method and return the proxy class object * @param proxy Proxy class object * @param method Original method * @param args Parameters in the original method * @return Proxy class object */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { otherService.getTime();//Print time Object invoke = method.invoke(target, args); otherService.getLog();//Print log return invoke; } public void setTarget(Object target) { this.target = target; } }
Next, specify a ClassLoader object and a set of interface s for the Proxy class to create a dynamic Proxy class
public void test() { //First create the target object UserServiceImpl target = new UserServiceImpl(); //Create InvocationHandler object UserProxy proxy = new UserProxy(target); //Creating a Proxy using Proxy UserService userService = (UserService) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), proxy); //Test proxy class object userService.insertUser(); }
give the result as follows
In this way, we did not modify the original business code, but achieved the function of adding new functions.
Dynamic agency
Through the above example, we can find that the dynamic agent has the following functions
- You can add functions without changing the source code of the target class.
- Can reduce code duplication.
- Allows programmers to focus on business logic code.
- The code can be decoupled to separate business functions from non business functions.