Java dynamic proxy of JDK with cglib details

  • 2020-04-01 02:15:51
  • OfStack

Dynamic proxy for JAVA

The proxy pattern
The proxy pattern is a commonly used Java design pattern. It is characterized by the fact that the proxy class has the same interface with the delegate class. The proxy class is mainly responsible for preprocessing messages, filtering messages, forwarding messages to the delegate class, and processing messages afterwards for the delegate class. There is usually an association between the proxy class and the delegate class. The object of a proxy class is associated with the object of a delegate class. The object of the proxy class does not really implement the service itself, but provides a specific service by calling the relevant methods of the object of the delegate class.
Proxy classes can be divided into two categories by the time they are created.

Static proxy: The source code is automatically generated and compiled by a programmer or by a specific tool. The.class file for the proxy class exists before the program runs.

Dynamic agent: Created dynamically while the program is running using reflection.  

First look at the static proxy:
1, the Count. Java


package net.battier.dao;  

  
public interface Count {  
    //Check account method & NBSP;
    public void queryCount();  

    //Modifying account methods & NBSP;
    public void updateCount();  

}  

2, CountImpl. Java

package net.battier.dao.impl;  

import net.battier.dao.Count;  

  
public class CountImpl implements Count {  

    @Override  
    public void queryCount() {  
        System.out.println(" View account method ...");  

    }  

    @Override  
    public void updateCount() {  
        System.out.println(" Account modification method ...");  

    }  

}  

CountProxy.java  
package net.battier.dao.impl;  

import net.battier.dao.Count;  

  
public class CountProxy implements Count {  
    private CountImpl countImpl;  

      
    public CountProxy(CountImpl countImpl) {  
        this.countImpl = countImpl;  
    }  

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

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

    }  

}  

3, TestCount. Java

package net.battier.test;  

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

  
public class TestCount {  
    public static void main(String[] args) {  
        CountImpl countImpl = new CountImpl();  
        CountProxy countProxy = new CountProxy(countImpl);  
        countProxy.updateCount();  
        countProxy.queryCount();  

    }  
}  

If you look at the code, you can see that each proxy class can only serve one interface, so there are bound to be too many proxies in the program development, and all the proxy operations are the same except that the methods are not the same, so the code must be duplicated. The best way to solve this problem is to use a single proxy class to do all of the proxy functionality, so you must use dynamic proxies to do this.

Take a look at dynamic proxies:
The JDK dynamic proxy contains a class and an interface:
InvocationHandler interface:
Public interface InvocationHandler {
Public Object invoke(Object proxy,Method Method,Object[] args) throwthrowable;
}
Parameter description:
Object proxy: refers to the Object being represented.
Method Method: the Method to call
Object[] args: the parameter required when a method is called

Subclasses of the InvocationHandler interface can be thought of as the final action class of a proxy, replacing the ProxySubject.

The Proxy class:
Proxy class is an operation class specially designed to complete Proxy, which can dynamically generate an 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
Parameter description:
ClassLoader: a ClassLoader
Class< ? > [] interfaces: get all the interfaces
InvocationHandler h: gets a subclass instance of the InvocationHandler interface

Ps: class loader
In the newProxyInstance () method of the Proxy class, an instance of the ClassLoader class is needed. Classloaders actually correspond to classloaders. In Java, there are mainly three kinds of loaders.
Booststrap ClassLoader: this loader is written in C++.
Extendsion ClassLoader: used to load extended classes, usually corresponding to classes in the jre\lib\ext directory;
AppClassLoader :(default) to load classes specified by the classpath is the most commonly used type of loader.

A dynamic proxy
The contrast with the static proxy class is the dynamic proxy class, whose bytecode is generated dynamically by the Java reflection mechanism while the program is running, without the programmer having to manually write its source code. Dynamic proxy classes not only simplify programming, but also improve the scalability of software systems, because Java reflection can generate any type of dynamic proxy class. The Proxy class and the InvocationHandler interface in the java.lang.reflect package provide the ability to generate dynamic Proxy classes.

Example dynamic proxy:
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(" Add book method... ");  
    }  

}  

BookFacadeProxy.java  

package net.battier.proxy;  

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

  
public class BookFacadeProxy implements InvocationHandler {  
    private Object target;  
      
    public Object bind(Object target) {  
        this.target = target;  
        //Getting the agent object & NBSP;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),  
                target.getClass().getInterfaces(), this);   //To bind the interface (which is a bug that cglib compensates for)& NBSP;
    }  

    @Override  
      
    public Object invoke(Object proxy, Method method, Object[] args)  
            throws Throwable {  
        Object result=null;  
        System.out.println(" Things start ");  
        //Execution method & NBSP;
        result=method.invoke(target, args);  
        System.out.println(" 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, JDK dynamic proxies rely on interface implementations, and if some classes do not implement interfaces and cannot use JDK proxies, then cglib dynamic proxies are used.

Cglib dynamic proxy
The JDK dynamic proxy mechanism can only proxy class implements an interface, and can't implement the interface cannot achieve the JDK dynamic proxy class, additional class to implement for the agent, his principle is to specify the target class to generate a subclass, and override the method, but because the inheritance, so can't class of final modification agent.

The sample
1, BookFacadeCglib. Java


package net.battier.dao;  

public interface BookFacade {  
    public void addBook();  
}  

2, BookCadeImpl1. Java

package net.battier.dao.impl;  

  
public class BookFacadeImpl1 {  
    public void addBook() {  
        System.out.println(" A common way to add 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;  

  
public class BookFacadeCglib implements MethodInterceptor {  
    private Object target;  

      
    public Object getInstance(Object target) {  
        this.target = target;  
        Enhancer enhancer = new Enhancer();  
        enhancer.setSuperclass(this.target.getClass());  
        //Callback method & NBSP;
        enhancer.setCallback(this);  
        //Create a proxy object & NBSP;
        return enhancer.create();  
    }  

    @Override  
    //Callback method & NBSP;
    public Object intercept(Object obj, Method method, Object[] args,  
            MethodProxy proxy) throws Throwable {  
        System.out.println(" Things start ");  
        proxy.invokeSuper(obj, args);  
        System.out.println(" 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();  
    }  
}  


Related articles: