1. JDK dynamic proxy
Java has its own proxy support in the package. This class () is used to dynamically generate proxy classes. You only need to pass in the target interface, the class loader of the target interface and the InvocationHandler to generate proxy classes and proxy objects for the target interface. We call this Java technology: Dynamic proxy
@CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { //... }
It is stipulated in Java that in order to generate an object's proxy object, the object must have an interface, so interfaces must be an interface.
In dynamic proxy technology, no matter what method the user calls the proxy object, the invoke method of the InvocationHandler written by the developer is called (this is equivalent to the method call of the invoke method intercepting the proxy object).
Therefore, the overall process of JDK dynamic proxy is:
- Implement InvocationHandler, used to handle the logic after object intercepting. (The object must be an interface, or the parent class is an interface)
- Use to generate proxy objects.
The following is a specific example of implementing AOP using JDK dynamic code:
1. Target class
public interface UserService { void eat(); }
public class UserServiceImpl implements UserService { @Override public void eat() { ("Eat"); } }
2.Aspect class
public class MyAspect { /** * Pre-Notice */ public void before() { ("Wash your hands first"); } }
3. Weaving process
/** * Factory class that generates proxy objects */ public class MyFactoryBean { private MyFactoryBean() { } public static UserService getInstance() { // target: target class final UserService userService = new UserServiceImpl(); // Aspect: Face-cut final MyAspect myAspect = new MyAspect(); // Weaving: Weaving, that is, the process of generating agents UserService proxyInstance = (UserService) ((), new Class[]{}, (Object proxy, Method method, Object[] args) -> { // Simulated point cut - pointcut if ("eat".equals(())) { (); } return (userService, args); }); return proxyInstance; } }
public static void main(String[] args) { UserService userService = (); // Wash your hands before eating (); }
Think about it, this is actually very similar to the AOP we usually use. Spring defines pre-notifications (@Before), exception notifications (@AfterThrowing), etc. Spring just uses these annotations to select when to call the notification method. In addition, Spring also selects the target class and entry point through point-cut expressions.
2. CGLIB dynamic proxy
CGLIB dynamic proxy needs to introduce third-party libraries, which realize call interception by modifying the way the proxy object generates subclasses. The proxy object does not need to implement an interface, but the proxy class cannot be final, and the proxy method cannot be final.
/** * Factory class that generates proxy objects */ public class MyFactoryBean { private MyFactoryBean() { } public static UserService getInstance() { // target: target class final UserService userService = new UserServiceImpl(); // Aspect: Face-cut final MyAspect myAspect = new MyAspect(); // Weaving: Weaving, that is, the process of generating agents Enhancer enhancer = new Enhancer(); (()); (false); (new MethodInterceptor() { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { // Simulation pointcut-point cut if ("eat".equals(())) { (); } return (o, objects); } }); return (UserService) (); } public static void main(String[] args) { UserService proxyInstance = (); // Wash your hands before eating (); } }
3. Summary
When implementing dynamic proxy in JDK, it is required that the proxy class must be an interface or an inherited interface class, because the proxy class generated by the JDK actually implements the interface proxy by the proxy class and inherits the Proxy class in java (inheriting the Proxy class is to determine whether the class is a proxy class), finds the interface method through reflection, and calls the invoke method of the InvocationHandler to achieve interception.
CGLIB bytecode enhancement is a good complement to JDK dynamic proxy. The last generated proxy class in CGLIB is a class that inherits the proxy class, and implements the proxy by rewriting the non-final method in the proxy class.
Summary as:
- JDK Dynamic Proxy: The proxy class must be an interface or a class that inherits the interface.
- CGLIB bytecode enhancement: The proxy class cannot be final, and the proxy method cannot be final (inheritance limit).
Regarding what proxy methods are used in Spring's AOP, if we do not impose restrictions, we will treat them differently based on whether the class has an interface:
- When a class has an interface, it will use JDK dynamic proxy.
- When a class does not implement an interface, it will use the CGLIB proxy method.
The above is the detailed content of implementing dynamic proxy in two ways of Java. For more information about Java dynamic proxy, please follow my other related articles!