JDK and cglib dynamic proxy

Posted by philweb on Mon, 08 Jul 2019 05:46:04 +0200

JAVA Dynamic Agent proxy pattern Proxy pattern is a common java design pattern. its characteristic is that proxy class has the same interface with delegate class. proxy class is mainly responsible for pre-processing messages, filtering messages, forwarding messages to delegate class, and post-processing messages for delegate class. There is usually an association between the proxy class and the delegate class. An object of the proxy class is associated with an object of the delegate class. The object of the proxy class does not really realize the service itself, but provides a specific service by calling the related methods of the object of the delegate class. According to the establishment period of agency, there are two types of agency. Static proxy: Programmers create or specific tools automatically generate source code, and then compile it. Before the program runs, the. class file of the proxy class already exists. Dynamic proxy: When the program runs, it is created dynamically by using reflection mechanism.

Let's first look at the static proxy: 1,Count.java

package net.battier.dao;  

/** 
 * Define an account interface 
 *  
 * [@author](https://my.oschina.net/arthor) Administrator 
 *  
 */  
public interface Count {  
    // View Account Method  
    public void queryCount();  

    // Modifying Account Method  
    public void updateCount();  

}  

2,CountImpl.java

package net.battier.dao.impl;  

import net.battier.dao.Count;  

/** 
 * Delegate classes (including business logic) 
 *  
 * [@author](https://my.oschina.net/arthor) Administrator 
 *  
 */  
public class CountImpl implements Count {  

    [@Override](https://my.oschina.net/u/1162528)  
    public void queryCount() {  
        System.out.println("View Account Method...");  

    }  

    [@Override](https://my.oschina.net/u/1162528)  
    public void updateCount() {  
        System.out.println("Modifying Account Method...");  

    }  

}  

,CountProxy.java

package net.battier.dao.impl;  

import net.battier.dao.Count;  

/** 
 * This is a proxy class (enhanced CountImpl implementation class) 
 *  
 * [@author](https://my.oschina.net/arthor) Administrator 
 *  
 */  
public class CountProxy implements Count {  
    private CountImpl countImpl;  

    /** 
     * Override the default constructor 
     *  
     * @param countImpl 
     */  
    public CountProxy(CountImpl countImpl) {  
        this.countImpl = countImpl;  
    }  

    @Override  
    public void queryCount() {  
        System.out.println("Before transaction processing");  
        // Call the method of the delegate class;  
        countImpl.queryCount();  
        System.out.println("After transaction processing");  
    }  

    @Override  
    public void updateCount() {  
        System.out.println("Before transaction processing");  
        // Call the method of the delegate class;  
        countImpl.updateCount();  
        System.out.println("After transaction processing");  

    }  

}  

3,TestCount.java

package net.battier.test;  

import net.battier.dao.impl.CountImpl;  
import net.battier.dao.impl.CountProxy;  

/** 
 *Test Count class 
 *  
 * @author Administrator 
 *  
 */  
public class TestCount {  
    public static void main(String[] args) {  
        CountImpl countImpl = new CountImpl();  
        CountProxy countProxy = new CountProxy(countImpl);  
        countProxy.updateCount();  
        countProxy.queryCount();  

    }  
}  

Looking at the code, we can find that each proxy class can only serve for one interface. In this way, there will inevitably be too many proxies in the development of the program. Moreover, all proxy operations except the method of invocation are different, and other operations are the same, then the code must be duplicated at this time. The best way to solve this problem is to use a proxy class to complete all the proxy functions, then dynamic proxy must be used to complete. Let's look at dynamic proxy again: The JDK dynamic proxy contains a class and an interface: InvocationHandler interface: public interface InvocationHandler { public Object invoke(Object proxy,Method method,Object[] args) throws Throwable; } Description of parameters: Object proxy: Refers to the proxy object. Method method: The method to be invoked Object[] args: The parameters required for method invocation

Subclasses of the InvocationHandler interface can be imagined as the final operation class of an agent, replacing ProxySubject.

Proxy class: Proxy class is a kind of operation class specializing in agent completion, which can dynamically generate implementation class for one or more interfaces. This class provides the following operation methods: public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException Description of parameters: ClassLoader loader: Class loader Class <?>[] interfaces: Get all the interfaces InvocationHandler h: Get a subclass instance of InvocationHandler interface

Ps: Class Loader In the new ProxyInstance () method of Proxy class, we need an instance of ClassLoader class. ClassLoader actually corresponds to class loader. There are three main classloaders in Java. Booststrap Class Loader: This loader is written in C++, which can not be seen in general development. Extendion ClassLoader: Used for loading extended classes, generally corresponding to the classes in the jre lib ext directory; AppClassLoader:(default) Loading classpath-specified classes is the most commonly used type of loader.

Dynamic Agent Comparing with static proxy class, dynamic proxy class's bytecode is generated dynamically by Java reflection mechanism when the program runs, and it does not need programmers to write its source code manually. Dynamic proxy classes not only simplify programming, but also improve the scalability of software systems, because Java reflection mechanism can generate any type of dynamic proxy classes. Proxy classes and InvocationHandler interfaces in the java.lang.reflect package provide the ability to generate dynamic proxy classes.

Dynamic proxy example: 1,BookFacade.java

package net.battier.dao;  

public interface BookFacade {  
    public void addBook();  
}  

2,BookFacadeImpl.java

package net.battier.dao.impl;  

import net.battier.dao.BookFacade;  

public class BookFacadeImpl implements BookFacade {  

    @Override  
    public void addBook() {  
        System.out.println("Adding book methods...");  
    }  

}  

,BookFacadeProxy.java

package net.battier.proxy;  

import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Method;  
import java.lang.reflect.Proxy;  

/** 
 * JDK Dynamic proxy class 
 *  
 * @author student 
 *  
 */  
public class BookFacadeProxy implements InvocationHandler {  
    private Object target;  
    /** 
     * Bind the delegate object and return a proxy class 
     * @param target 
     * @return 
     */  
    public Object bind(Object target) {  
        this.target = target;  
        //Get the proxy object  
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),  
                target.getClass().getInterfaces(), this);   //To bind interfaces (this is a flaw that cglib compensates for)  
    }  

    @Override  
    /** 
     * Call method 
     */  
    public Object invoke(Object proxy, Method method, Object[] args)  
            throws Throwable {  
        Object result=null;  
        System.out.println("Things begin");  
        //Execution method  
        result=method.invoke(target, args);  
        System.out.println("The End of Things");  
        return result;  
    }  

}  

3,TestProxy.java

package net.battier.test;  

import net.battier.dao.BookFacade;  
import net.battier.dao.impl.BookFacadeImpl;  
import net.battier.proxy.BookFacadeProxy;  

public class TestProxy {  

    public static void main(String[] args) {  
        BookFacadeProxy proxy = new BookFacadeProxy();  
        BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());  
        bookProxy.addBook();  
    }  

} 

However, the dynamic proxy of JDK depends on the interface. If some classes do not implement the interface, they can not use the JDK proxy, so we need to use the cglib dynamic proxy.

Cglib Dynamic Agent The dynamic proxy mechanism of JDK can only proxy the class that implements the interface, but the class that can't implement the interface can't realize the dynamic proxy of JDK. cglib is for the class to realize the proxy. Its principle is to generate a subclass of the specified target class and cover the method to enhance it, but because it uses inheritance, it can't implement the dynamic proxy of JDK. The final modified class acts as a proxy. Example 1,BookFacadeCglib.java

package net.battier.dao;  

public interface BookFacade {  
    public void addBook();  
}  

2,BookCadeImpl1.java

package net.battier.dao.impl;  

/** 
 * This is an implementation class that does not implement interfaces. 
 *  
 * @author student 
 *  
 */  
public class BookFacadeImpl1 {  
    public void addBook() {  
        System.out.println("Common Ways to Increase Books...");  
    }  
}  

3,BookFacadeProxy.java

package net.battier.proxy;  

import java.lang.reflect.Method;  

import net.sf.cglib.proxy.Enhancer;  
import net.sf.cglib.proxy.MethodInterceptor;  
import net.sf.cglib.proxy.MethodProxy;  

/** 
 * Using cglib dynamic proxy 
 *  
 * @author student 
 *  
 */  
public class BookFacadeCglib implements MethodInterceptor {  
    private Object target;  

    /** 
     * Creating proxy objects 
     *  
     * @param target 
     * @return 
     */  
    public Object getInstance(Object target) {  
        this.target = target;  
        Enhancer enhancer = new Enhancer();  
        enhancer.setSuperclass(this.target.getClass());  
        // callback  
        enhancer.setCallback(this);  
        // Creating proxy objects  
        return enhancer.create();  
    }  

    @Override  
    // callback  
    public Object intercept(Object obj, Method method, Object[] args,  
            MethodProxy proxy) throws Throwable {  
        System.out.println("Things begin");  
        proxy.invokeSuper(obj, args);  
        System.out.println("The End of Things");  
        return null;  

    }  

}  

4,TestCglib.java

package net.battier.test;  

import net.battier.dao.impl.BookFacadeImpl1;  
import net.battier.proxy.BookFacadeCglib;  

public class TestCglib {  

    public static void main(String[] args) {  
        BookFacadeCglib cglib=new BookFacadeCglib();  
        BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());  
        bookCglib.addBook();  
    }  
}

Topics: Java JDK Programming