This is the first day of my participation in the August More Text challenge
concept
Provide a proxy for other objects to control access to that object.
The implementation of proxy mode in Java can be roughly divided into three types: static proxy, dynamic proxy, CGlib proxy.
1. Static proxy
Static proxies, the proxy class and the proxied class (the target object) need to implement the same interface to ensure that external calls know which interface it is. The proxy class maintains the target object and executes its methods in the methods. The disadvantage is that you need to build a proxy class for each target object, and if there are more target objects, there are more proxy classes.
Key points:
- The proxy class needs to implement the same interface as the target object;
Interface, the interface that the proxy class and the proxied class need to implement together
public interface DemoService {
void run(a);
}
Copy the code
The proxied class, also known as the target class
public class DemoServiceImpl implements DemoService{
@Override
public void run(a) {
System.out.println("Methods to execute the target object.");
try {
Thread.sleep(100);
} catch(InterruptedException e) { e.printStackTrace(); }}}Copy the code
The proxy class, an implementation of the proxy DemoServiceImpl, performs the business logic
/** * proxy class, maintain target object, execute business logic and call target object method */
public class DemoServiceProxy implements DemoService {
// Maintain the target object
private DemoService service;
DemoServiceProxy(DemoService service) {
this.service = service;
}
@Override
public void run(a) {
System.out.println("Proxy class object method execution;" );
long startTime = System.currentTimeMillis();
// Execute the target method
service.run();
// Record time
long endTime = System.currentTimeMillis();
System.out.println("Method execution is complete. Time:" + (endTime - startTime) + "ms"); }}Copy the code
The client of the call
/** * Call Demo's client class */
public class DemoClient {
public static void main(String[] args) {
// Target object
DemoService service = new DemoServiceImpl();
// proxy object, pass the target object to proxy object, establish proxy relationship
DemoService serviceProxy = new DemoServiceProxy(service);
// Execute methodserviceProxy.run(); }}Copy the code
Benefits: The target object only needs to focus on the core logic, leaving the business logic to the proxy class, such as input printing, time consumption, and exception handling.
Disadvantages: The proxy class needs to implement all the methods of the interface.
2. Dynamic proxy
2.1 JDK built-in implementation
Dynamic Proxy, Proxy class A newInstance method provided by Proxy in the Jdk that generates a Proxy object for an object. This method takes three parameters: the class loader of the proxy object, the interface of the proxied class, and the proxy object handler. The proxy object handler overrides the Invoke method to implement the InvocationHandler interface. The proxied class implements the interface. The disadvantage is that the target object needs to have an interface.
Key points:
- The proxy interception implements the InvocationHandler interface and overrides the Invoke method;
- The invoke method takes three parameters
- Proxy Proxy object instance
- Object obj = method.invoke(target); Object obj = method.invoke(target);
- Args method Specifies the parameters required to execute the method
- The target object is maintained in proxy interception
- Get the proxy object with Proxy#newProxyInstance:
- Class loaders for target objects: target.getClass().getClassloader ();
- The target object’s interface: target.getClass().getinterfaces ();
- A subclass object that implements InvocationHandler;
Proxy factories and proxy implementations
/** * gets the factory class of the proxy object */
public class DemoProxyFactory {
// Target object. The proxyed class
private Object target;
public DemoProxyFactory(Object target) {
this.target = target;
}
public Object getProxyInstance(a) {
InvocationHandler handler = new DemoServiceHandler();
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),handler);
}
class DemoServiceHandler implements InvocationHandler {
/** * Proxy execution method *@paramProxy Indicates the instance of the proxy object@paramMethod The method that the runtime calls, that is, the method that the target object needs to execute@paramArgs method Specifies the parameters required to execute the method *@return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("The proxy object method executes. proxy.class="+proxy.getClass().getCanonicalName());
long startTime = System.currentTimeMillis();
// Execute the target object
Object obj = method.invoke(target);
// Record time
long endTime = System.currentTimeMillis();
System.out.println("Method execution is complete. Time:" + (endTime - startTime) + "ms");
returnobj; }}}Copy the code
Client call
public class DemoClient {
public static void main(String[] args) {
DemoService service = new DemoServiceImpl(); // Target object
DemoProxyFactory factory = new DemoProxyFactory(service); // Build the proxy factory
DemoService serviceProxy = (DemoService)factory.getProxyInstance(); // Get the proxy class from the proxy factoryserviceProxy.run(); }}Copy the code
2.2 Implementation of CGlib agent
CGlib proxies are designed to address dynamic proxies, also known as subclass proxies. By implementing the MethodInterceptor interface, it dynamically builds a subclass of the target object in memory, that is, the proxy object, to extend it. The Enhancer tool class is used to construct the object subclass dynamically, mainly setting the parent class, setting the callback function, and creating the subclass.
Key points:
- Cglib introduced package;
- Implement cglib package interface MethodInterceptor, rewrite intercept method;
- The Intercept method takes four parameters:
- Object O: proxy class instance generated by cglib
- Object obj = method.invoke(target) or methodProxy.invokesuper (target)
- Object[] objects: A list of parameters for the target method
- MethodProxy Proxy: Proxy reference to a method by a generated proxy class
- Maintain the target object target
- Create the subclass proxy instance using the Enhancer utility class
- Set the parent class;
- Set the callback object, which is a subclass instance that implements the MethodInterceptor interface;
- Create a subclass proxy object
Additional cglib dependencies need to be introduced
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.10</version>
</dependency>
Copy the code
The target class
public class DemoCglibService {
public void run(a) {
System.out.println("Methods to execute the target object.");
try {
Thread.sleep(100);
} catch(InterruptedException e) { e.printStackTrace(); }}}Copy the code
Method interceptor implementation,
public class DemoCglibInterceptor implements MethodInterceptor {
private Object target;
public DemoCglibInterceptor(Object target) {
this.target = target;
}
public Object getProxyInstance(a) {
/ / tools
Enhancer enhancer = new Enhancer();
// Set the parent class
enhancer.setSuperclass(target.getClass());
// Set the callback function. CallBack to the current object (because the current object is the implementation of callBack
enhancer.setCallback(this);
return enhancer.create(); // Create a subclass proxy object
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Proxy object method execution.");
long startTime = System.currentTimeMillis();
// Execute the target object
Object obj = method.invoke(target);
// Record time
long endTime = System.currentTimeMillis();
System.out.println("Method execution is complete. Time:" + (endTime - startTime) + "ms");
returnobj; }}Copy the code
Gets the factory class for the subclass proxy
/** * agent factory */
public class DemoProxyFactory {
/** * get subclass proxy object instance *@paramTarget Target object *@paramCallback implements a subclass of MethodInterceptor *@return* /
public static Object getProxyInstance(Object target, Callback callback) {
/ / tools
Enhancer enhancer = new Enhancer();
// Set the parent class
enhancer.setSuperclass(target.getClass());
// Set the callback function.
enhancer.setCallback(callback);
return enhancer.create(); // Create a subclass proxy object}}Copy the code
Client call
public class DemoClient {
public static void main(String[] args) {
System.out.println("Method one: Get a proxy object using a method that intercepts it.");
DemoCglibService service = new DemoCglibService();
DemoCglibInterceptor cglibInterceptor = new DemoCglibInterceptor(service);
DemoCglibService serviceProxy = (DemoCglibService) cglibInterceptor.getProxyInstance();
serviceProxy.run();
System.out.println("\n");
System.out.println("Method two: Use the proxy factory to get subclass proxy objects."); DemoCglibService serviceProxy2 = (DemoCglibService) DemoProxyFactory.getProxyInstance(service,cglibInterceptor); serviceProxy2.run(); }}Copy the code
Note: If you use the Spring framework, you don’t need to import the cglib package because the Spring core package already includes cglib functionality, so you can just import spring-core-.jar. (Maven’s delivery dependency)