Fast understanding of Java’s three proxy patterns through code

Time:2019-9-6

proxy pattern

Proxy is a design pattern that provides additional access to the target object, that is, through the proxy object to access the target object. The advantage of this method is that on the basis of the realization of the target object, additional functional operations can be enhanced, that is, the functions of the target object can be extended.

Here we use the idea of programming: don’t modify the code or method that others have written at will. If you need to modify it, you can extend the method by proxy.

UML diagrams are shown as follows:

proxy pattern

Static proxy

When using static proxies, you need to define interfaces or parent classes. The proxy object implements the same interface with the proxy object or inherits the same parent class.

Code example:


interface Source{ void method();}
class OldClass implements Source{
@Override
public void method() {
}
}
class Proxy implements Source{
private Source source = new OldClass();
void doSomething(){}
@Override
public void method() {
new Class1().Func1();
source.method();
new Class2().Func2();
doSomething();
}
public static void main(String[] args) {
Proxy proxy = new Proxy();
proxy.method();
}
}

Deficiencies of static proxy:

Because the proxy object needs the same interface or parent class as the target object, there will be many proxy classes and too many classes. At the same time, once the method is added to the interface, both the target object and the proxy object are maintained.

Dynamic Agent

The dynamic proxy class in JDK only needs to use the java.lang.reflect.Proxy.newProxyInstance method, which needs to receive three parameters. The complete writing is:

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )

Note that this method is static in the Proxy class, and the three parameters received are in turn:

  • ClassLoader loader: Specifies that the current target object uses a class loader, and the method of obtaining the loader is fixed
  • Class <?>[] interfaces: The interface type implemented by the target object is confirmed by generic method, and the method of obtaining the interface type is fixed.
  • Invocation Handler; Event handling, when executing the method of the target object, triggers the method of the event handler, and passes in the current method of executing the target object as a parameter.

Code example:

/**
* Interface
*/
interface IUserDao {
void save();
}
/**
* Interface实现
* Target object
*/
class UserDao implements IUserDao {
public void save() {
System.out.println ("----------------------------------------------");
}
}
/**
* Creating dynamic proxy objects
* Dynamic agents do not need to implement interfaces, but they need to specify interface types
*/
class ProxyFactory {
// Maintaining a target object
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
// Generating proxy objects for target objects
public Object getProxyInstance() {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
(proxy, method, args) -> {
System. out. println ("Start a transaction");
// Executing target object method
Object returnValue = method.invoke(target, args);
System. out. println ("commit transaction");
return returnValue;
});
}
}
/**
* Test class
*/
class App {
public static void main(String[] args) {
// Target object
IUserDao target = new UserDao();
// System.out.println(target.getClass());
// To target objects, create proxy objects
IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
// System.out.println(proxy.getClass());
// Proxy Object Execution Method
proxy.save();
}
}

Note: Proxy objects do not need to implement interfaces, but the target objects must implement interfaces, otherwise dynamic proxy cannot be used.

Cglib Agent

Both static proxy and dynamic proxy modes require the target object to implement the 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 by means of the subclass of the target object. This method is called Cglib proxy.

Cglib proxy, also known as subclass proxy, constructs a subclass object in memory to extend the function of the target object. Cglib is a powerful high-performance code generation package that can extend Java classes and implement Java interfaces at runtime. It is widely used by many AOP frameworks to provide interception (interception) of methods, such as Spring AOP, which is well known.

The bottom layer of Cglib package is to convert bytecode and generate new classes by using a small and fast bytecode processing framework ASM. The Cglib subclass proxy needs to pay attention to:

1. We need to introduce Cglib’s jar file, but Spring’s core package already includes Cglib functions, so we can directly introduce spring-core-xxx.jar. (Spring 3.2 includes Cglib only after)

2. The proxy class cannot be final, otherwise an error will be reported.

3. If the method of the target object is final/static, it will not be intercepted, that is, it will not execute additional business methods of the target object.

Code example:

public class test {
public static void main(String[] args) {
// Target object
UserDao target = new UserDao();
// Proxy object
UserDao proxy = (UserDao) new ProxyFactory(target).getProxyInstance();
// Method of executing proxy objects
proxy.save();
}
}
/**
* Target object, no interface implemented
*/
class UserDao {
public void save() {
System.out.println ("------------------------------------");
}
}
/**
* Cglib Subclass Agent Factory
* Dynamic construction of a subclass object in memory for UserDao
*/
class ProxyFactory implements MethodInterceptor {
// Maintaining 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 class
Enhancer en = new Enhancer();
// 2. Setting parent class
en.setSuperclass(target.getClass());
// 3. Setting 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 a transaction...");
// Method of executing target object
Object returnValue = method.invoke(target, args);
System. out. println ("Submit a transaction...");
return returnValue;
}
}

The above is the whole content of this article. I hope it will be helpful to everyone’s study, and I hope you will support developpaer more.