JAVA dynamic proxy
proxy mode
The agent pattern is a commonly used Java design pattern. Its characteristic is that the agent class and the delegate class have the same interface. The agent class is mainly responsible for preprocessing messages for the delegate class, filtering messages, forwarding messages to the delegate class, and processing messages afterwards. There is usually an association between a proxy class and a delegate class. An object of a proxy class is associated with an object of a delegate class. The object of the proxy class itself does not actually implement the service, but by calling the relevant methods of the object of the delegate class. Provide specific services.
According to the creation period of the agent, the agent class can be divided into two types.
Static proxy: Created by programmers or automatically generated by a specific tool and then compiled. Before the program is run, the .class file of the proxy class already exists.
Dynamic proxy: Dynamically created using the reflection mechanism when the program is running.
First take a look at the static proxy:
1.Count.java
Copy the code code as follows:
package net.battier.dao;
/**
* Define an account interface
*
* @author Administrator
*
*/
public interface Count {
// View account method
public void queryCount();
//Modify account method
public void updateCount();
}
2. CountImpl.java
Copy the code code as follows:
package net.battier.dao.impl;
import net.battier.dao.Count;
/**
* Delegate class (including business logic)
*
* @author Administrator
*
*/
public class CountImpl implements Count {
@Override
public void queryCount() {
System.out.println("View account method...");
}
@Override
public void updateCount() {
System.out.println("Modify account method...");
}
}
CountProxy.java
package net.battier.dao.impl;
import net.battier.dao.Count;
/**
* This is a proxy class (enhanced CountImpl implementation class)
*
* @author 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
Copy the code code as follows:
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();
}
}
Observing the code, you can find that each proxy class can only serve one interface. In this way, too many proxies will inevitably be generated during program development. Moreover, all proxy operations are the same except for the method they call. Then the code must be repeated at this time. The best way to solve this problem is to use a proxy class to complete all proxy functions. In this case, a dynamic proxy must be used to complete it.
Let’s take a look at the dynamic proxy:
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;
}
Parameter description:
Object proxy: refers to the object being proxied.
Method method: the method to be called
Object[] args: parameters required when calling the method
You can think of a subclass of the InvocationHandler interface as the final operation class of a proxy, replacing ProxySubject.
Proxy class:
The Proxy class is a class that specializes in proxy operations. This class can be used to dynamically generate implementation classes 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 loader: class loader
Class<?>[] interfaces: get all interfaces
InvocationHandler h: Get the subclass instance of the InvocationHandler interface
Ps: class loader
An instance of the ClassLoader class is required in the newProxyInstance() method in the Proxy class. ClassLoader actually corresponds to the class loader. There are three main class loaders in Java;
Booststrap ClassLoader: This loader is written in C++ and cannot be seen in general development;
Extension ClassLoader: used to load extension classes, generally corresponding to classes in the jre/lib/ext directory;
AppClassLoader: (default) loads the class specified by classpath, which is the most commonly used loader.
dynamic proxy
In contrast to the static proxy class, there is the dynamic proxy class. The bytecode of the dynamic proxy class is dynamically generated by the Java reflection mechanism when the program is running, without the need for programmers to manually write its source code. Dynamic proxy classes not only simplify programming work, but also improve the scalability of software systems, because the Java reflection mechanism can generate any type of dynamic proxy class. The Proxy class and InvocationHandler interface in the java.lang.reflect package provide the ability to generate dynamic proxy classes.
Dynamic proxy example:
1.BookFacade.java
Copy the code code as follows:
package net.battier.dao;
public interface BookFacade {
public void addBook();
}
2.BookFacadeImpl.java
Copy the code code as follows:
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;
/**
* JDK dynamic proxy 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 the interface (this is a flaw, cglib makes up for this flaw)
}
@Override
/**
* Call method
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result=null;
System.out.println("Thing begins");
//execution method
result=method.invoke(target, args);
System.out.println("End of things");
return result;
}
}
3. TestProxy.java
Copy the code code as follows:
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's dynamic proxy relies on interface implementation. If some classes do not implement the interface, the JDK proxy cannot be used, so cglib dynamic proxy must be used.
Cglib dynamic proxy
JDK's dynamic proxy mechanism can only proxy classes that implement interfaces. Classes that cannot implement interfaces cannot implement JDK's dynamic proxy. cglib implements proxy for classes. Its principle is to generate a subclass for the specified target class. , and override the methods to achieve enhancement, but because inheritance is used, the final-modified class cannot be proxied.
Example
1.BookFacadeCglib.java
Copy the code code as follows:
package net.battier.dao;
public interface BookFacade {
public void addBook();
}
2.BookCadeImpl1.java
Copy the code code as follows:
package net.battier.dao.impl;
/**
* This is an implementation class that does not implement the interface
*
* @author student
*
*/
public class BookFacadeImpl1 {
public void addBook() {
System.out.println("Common method to add books...");
}
}
3.BookFacadeProxy.java
Copy the code code as follows:
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;
/**
* Use cglib dynamic proxy
*
* @author student
*
*/
public class BookFacadeCglib implements MethodInterceptor {
private Object target;
/**
* Create proxy object
*
* @param target
* @return
*/
public Object getInstance(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
// callback method
enhancer.setCallback(this);
//Create proxy object
return enhancer.create();
}
@Override
// callback method
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("Thing begins");
proxy.invokeSuper(obj, args);
System.out.println("End of things");
return null;
}
}
4. TestCglib.java
Copy the code code as follows:
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();
}
}