Detail the three proxy modes in Java!

Keywords: Java JDK Spring Programming

Author: Cen Yu
https://www.cnblogs.com/cenyu/p/6289209.html

proxy pattern

Proxy is a design pattern that provides additional access to the target object; that is, it accesses the target object through the proxy object. The advantage of this is that you can enhance additional functional operations, that is, extend the capabilities of the target object, on the basis of its implementation.

Here's a programming idea: don't modify code or methods that others have written at will. If you need to make changes, you can extend the method by proxy.

Let's take an example to illustrate the role of an agent: Suppose we want to invite a star, then we don't connect directly to the star, but to contact the star's broker to achieve the same purpose. A star is a target. He just has to be responsible for the programme in the activity, and other trivial things are handed over to his agent (broker). This is an example of agent thought in reality.

Chart as follows:

The key points of the proxy mode are: the proxy object and the target object. The proxy object is an extension of the target object and calls the target object.

1.1. Static Proxy

When a static proxy is in use, it needs to define an interface or a parent class. The proxy object implements the same interface with the proxy object or inherits the same parent class.

The following are examples to illustrate:

Simulate the save action and define an interface to save the action: IUserDao.java. Then the target object implements the interface method UserDao.java. If you use the static proxy method, you need to implement the IUserDao interface in the proxy object (UserDaoProxy.java). Call the target object by calling the proxy object's method.

It is important to note that the proxy object implements the same interface as the target object and then invokes the method of the target object by calling the same method.

Code example:

Interface: IUserDao.java

/**  
* Interface  
*/  
public interface IUserDao {  
   void save();  
}

Target object: UserDao.java

/**  
* Interface implementation  
* Target object  
*/  
public class UserDao implements IUserDao {  
   public void save() {  
       System.out.println("----Saved data!----");  
   }  
}

Proxy object: UserDaoProxy.java

/**  
* Proxy object, static proxy  
*/  
public class UserDaoProxy implements IUserDao{  
   //Receive Save Target Object  
   private IUserDao target;  
   public UserDaoProxy(IUserDao target){  
       this.target=target;  
   }  
  
   public void save() {  
       System.out.println("Start Transaction...");  
       target.save();//Method of executing target object  
       System.out.println("Submit Transaction...");  
   }  
}

Test class: App.java

/**  
* Test Class  
*/  
public class App {  
   public static void main(String\[\] args) {  
       //Target object  
       UserDao target = new UserDao();  
  
       //Proxy object, pass target object to proxy object, establish proxy relationship  
       UserDaoProxy proxy = new UserDaoProxy(target);  
  
       proxy.save();//The proxy method is executed  
   }  
}

Static proxy summary:

1. It is possible to extend the target function without modifying the function of the target object.

2. Disadvantages:

Because the proxy object needs the same interface as the target object, there are many proxy classes and too many classes. At the same time, once the interface adds methods, both the target object and the proxy object need to be maintained.

How to resolve the drawbacks of static proxy? The answer is to use dynamic proxy.

1.2. Dynamic proxy

Dynamic agents have the following characteristics:

1. Proxy object, no need to implement interface

2. Proxy object generation is to dynamically build proxy objects in memory using JDK's API (we need to specify the type of interface to create the proxy object/target object implementation)

3. Dynamic proxy is also called: JDK proxy, interface proxy

API for Proxy Object Generation in JDK

Package in which the proxy class resides: java.lang.reflect.Proxy

The JDK implementation proxy only needs to use the newProxyInstance method, but it requires three parameters, which are written in full:

static Object newProxyInstance(ClassLoader loader,   
            Class\[\] interfaces,InvocationHandler h )

Note that this method is static in the Proxy class and receives three parameters in turn:

  1. ClassLoader loader:: Specifies that the current target object uses a class loader, and the method for obtaining the loader is fixed

  2. Class[] interfaces,: The type of interface implemented by the target object, using a generic way to confirm the type

  3. InvocationHandler h: Event handling, which triggers the method of the event handler when executing the method of the target object, passing in the method currently executing the target object as a parameter

Code example:

Interface class IUserDao.java and interface implementation class, the target object UserDao is the same without modification. On this basis, add a proxy factory class (ProxyFactory.java), write the proxy class here, and then in the test class (code that needs to use the proxy), establish the relationship between the target object and the proxy object, and then substitute the method with the same name in the proxy object. Click. Here There is a dynamic proxy mode code war.

ProxyFactory class: ProxyFactory.java

/**  
* Create Dynamic Proxy Object  
* Dynamic agents do not need to implement interfaces, but they need to specify interface types  
*/  
public class ProxyFactory{  
  
   //Maintain a target object  
   private Object target;  
   public ProxyFactory(Object target){  
       this.target=target;  
   }  
  
  //Generate proxy object for target object  
   public Object getProxyInstance(){  
       return Proxy.newProxyInstance(  
               target.getClass().getClassLoader(),  
               target.getClass().getInterfaces(),  
               new InvocationHandler() {  
                   @Override  
                   public Object invoke(Object proxy, Method method, Object\[\] args) throws Throwable {  
                       System.out.println("Start Transaction 2");  
                       //Execute Target Object Method  
                       Object returnValue = method.invoke(target, args);  
                       System.out.println("Commit Transaction 2");  
                       return returnValue;  
                   }  
               }  
       );  
   }  
  
}

Test class: App.java

/**  
* Test Class  
*/  
public class App {  
   public static void main(String\[\] args) {  
       // Target object  
       IUserDao target = new UserDao();  
       // [original type class cn.itcast.b_dynamic.UserDao]  
       System.out.println(target.getClass());  
  
       // Create proxy object for target object  
       IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();  
       // class $Proxy0 dynamically generated proxy object in memory  
       System.out.println(proxy.getClass());  
  
       // Execution Method [Proxy Object]  
       proxy.save();  
   }  
}

Summary:

The proxy object does not need to implement the interface, but the target object must implement the interface, otherwise the dynamic proxy cannot be used

1.3.Cglib Agent

The above static proxy and dynamic proxy modes both require the target object to be the target object of an interface, but sometimes the target object is only a single object and does not implement any interface. At this time, the proxy can be implemented using a subclass of the target object, which is called Cglib proxy. Click Here There is a dynamic proxy mode code war.

Cglib proxy, also known as subclass proxy, is an extension of the function of the target object by building a subclass object in memory.

A limitation of JDK's dynamic proxy is that objects using dynamic proxy must implement one or more interfaces. If you want the proxy to have no classes that implement interfaces, you can use Cglib to implement them.

Cglib is a powerful and high performance code generation package that extends java classes and implements java interfaces at runtime. It is widely used by many AOP frameworks, such as Spring AOP and synaop, to provide interception methods for them.

The bottom level of the Cglib package is to convert byte codes and generate new classes by using a small block byte code processing framework ASM. Direct use of ASM is not encouraged, as it requires that you be familiar with the internal structure of the JVM, including the format and instruction set of class files.

Cglib subclass proxy implementation method:

1. The jar file for cglib needs to be introduced, but the Cglib functionality is already included in Spring's core package, so it is sufficient to introduce pring-core-3.2.5.jar directly.

2. By introducing a feature pack, you can dynamically build subclasses in memory

3. The proxy class cannot be final, otherwise an error is reported

4. If the target object's method is final/static, it will not be intercepted, that is, it will not execute the target object's extra business methods.

Code example:

Target object class: UserDao.java

/**  
* Target object, no interface implemented  
*/  
public class UserDao {  
  
   public void save() {  
       System.out.println("----Saved data!----");  
   }  
}

Cglib Proxy Factory: ProxyFactory.java

/**  
* Cglib Subclass Proxy Factory  
* Dynamically building a subclass object in memory for UserDao  
*/  
public class ProxyFactory implements MethodInterceptor{  
   //Maintain target objects  
   private Object target;  
  
   public ProxyFactory(Object target) {  
       this.target = target;  
   }  
  
   //Create a proxy object for the target object  
   public Object getProxyInstance(){  
       //1. Tool Classes  
       Enhancer en = new Enhancer();  
       //2. Set Parent Class  
       en.setSuperclass(target.getClass());  
       //3. Set callback function  
       en.setCallback(this);  
       //4. Create subclasses (proxy objects)  
       return en.create();  
  
   }  
  
   @Override  
   public Object intercept(Object obj, Method method, Object\[\] args, MethodProxy proxy) throws Throwable {  
       System.out.println("Start Transaction...");  
  
       //Method of executing target object  
       Object returnValue = method.invoke(target, args);  
  
       System.out.println("Submit Transaction...");  
  
       return returnValue;  
   }  
}

Test class:

/**  
* Test Class  
*/  
public class App {  
  
   @Test  
   public void test(){  
       //Target object  
       UserDao target = new UserDao();  
  
       //Proxy Object  
       UserDao proxy = (UserDao)new ProxyFactory(target).getProxyInstance();  
  
       //Method of executing proxy object  
       proxy.save();  
   }  
}

In Spring's AOP programming:

If the target object joining the container has an implementation interface, use the JDK proxy.
If the target object does not implement the interface, use the Cglib proxy.

Recommend going to my blog to read more:

1.Java JVM, Collections, Multithreaded, New Features Series Tutorial

2.Spring MVC, Spring Boot, Spring Cloud series tutorials

3.Maven, Git, Eclipse, Intellij IDEA Series Tools Tutorial

4.Latest Interview Questions for Java, Backend, Architecture, Alibaba, etc.

Life is good. See you tomorrow~

Posted by tlenker09 on Thu, 26 Mar 2020 23:52:48 -0700