This article mainly introduces: general proxy mode (namely static proxy), Java dynamic proxy, CGLib dynamic proxy.
Model background
In some cases, for some reason, a system module does not want or cannot directly access another module. For example, under the existing project, there is already an interface, but it only provides services. In subsequent development, it was found that some other modules needed to call it, but this interface needed to be modified. However, the form of interface modification is different depending on the user (maybe module A needs to add log interception to the call, and module B needs to verify the permission of the call). At this point we can introduce a third-tier proxy class to do this.
The proxy pattern should be a relatively simple design pattern with a wide range of applications.
Definitions & Concepts
Provides a proxy for an object that controls references to the original object.
The proxy pattern is an object structured pattern.
The principle of
The proxy pattern is done by introducing a new proxy object into the system. The only thing to note is that in standard design patterns, proxied objects need to have an implementation of the interface. And this way of doing it is called static proxy.
elements
- Abstract Subject Role (Subject)
- Declare the common interface of real and proxy roles, so that real and proxy roles comply with the Rule of Substitution, and proxy roles can be used wherever real roles are used. The client primarily uses this abstraction to program.
- Proxy Subject Role (Proxy)
- Internal contains references to real roles to manipulate real objects. There is an interface that is the same as the real character and can be used to replace the real character.
- RealSubject roles (RealSubject)
- The real proxied object.
UML
implementation
Think of theme characters
public interface Subject {
void request(a);
}
Copy the code
Real Theme character
public class RealSubject implements Subject {
@Override
public void request(a) {
System.out.println("subject is working..."); }}Copy the code
The agent role
public class Proxy implements Subject {
// The actual subject of the reference
private Subject subject;
public Proxy(Subject subject) {
this.subject = subject;
}
// pre-code reinforcement
public void preRequest(a) {
System.out.println("prepare...");
}
@Override
public void request(a) {
preRequest();
subject.request();
postRequest();
}
// code after enhancement
public void postRequest(a) {
System.out.println("finish..."); }}Copy the code
The client
Subject s = new Proxy(new RealSubject());
s.request();
Copy the code
Decorative pattern distinction
The proxy mode mainly adds new responsibilities to the real character, such as permission control, buffering, etc., which are not in the same domain as the original responsibilities of the real character. Its main purpose is to control external access to objects.
The decoration pattern is an extension of the original responsibilities, which belong to the same domain. Its main purpose is to extend functionality for objects.
The advantages and disadvantages
advantages
- Coordinate the caller and the called, and decouple the system to a certain extent, in accordance with Demeter’s law.
- For new requirements, just add the proxy class and do not modify the source code. In line with the open and close principle.
disadvantages
- A proxy class was added to add complexity to the system.
- A static proxy, a real object, needs to have a static proxy class corresponding to it.
extension
Some other things about the proxy model
Type of proxy mode
Proxy patterns fall into many categories (just take a look) :
- Remote agent
- Proxy between different processes (address Spaces). Processes can be distributed on different hosts and communicate through network RPCS.
- Virtual agent
- To create an object that consumes a lot of resources, you can create a smaller proxy object first. The specific object can be created when necessary.
- Protection agency
- Controlling access to an object can give permissions to different levels of users.
- Buffer agent
- Provide temporary caching for a target operation so that more clients can share the result.
- Intelligent reference proxy
- Records the number of times an object is called, etc.
Java dynamic proxy
The disadvantage of static proxy classes mentioned above: for every entity class that needs to be propped, you need to write a proxy class. This will undoubtedly greatly increase the complexity of the system.
Think about it: by proxy, we could totally spin off the RealSubject! Just like trying on clothes in the mall, each person wearing clothes is a kind of agent, but people are people, clothes are clothes, this clothes can be worn by many people, we do not need to make a clothes for each person, and then try on. ** We strip out the functionality of the proxy class, form a template, and then dynamically create the proxy class for it by passing in entity objects. ** Instead of creating proxy classes for each of these entities, we only need to implement a single proxy template that satisfies many different entity objects.
Java has a mechanism for dynamically creating proxy classes while the system is running. The reflection mechanism used typically proxies all classes under an interface, since it can only proxy interfaces.
implementation
The idea is to implement a proxy class and then, when used, pass in objects like this proxy class and create proxy objects dynamically through reflection.
public class JavaProxy implements InvocationHandler {
private Subject subject;
public JavaProxy(Subject subject) {
this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("invoke java proxy");
if ("request".equals(method.getName())) {
System.out.println("invoke request method");
return method.invoke(subject, args);
} else {
System.out.println("Other methods called");
returnmethod.invoke(subject, args); }}}Copy the code
The client
//JDK dynamic proxy
Subject real = new RealSubject();
// Pass in entities
JavaProxy proxy = new JavaProxy(real);
// Create a proxy object
Subject proxyClass = (Subject) java.lang.reflect.Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Subject.class}, proxy);
proxyClass.request();
Copy the code
The principle of
Two key Java classes are involved:
-
java.lang.reflect.Proxy
- Used to generate proxy classes and objects
-
java.lang.reflect.InvocationHandler
- The implementation logic of the agent.
disadvantages
- Requires the original entity object (
RealSubject
The interface must be implemented.
Matters needing attention
- Java dynamic proxy can only proxy interfaces. To proxy classes, you need to use third-party libraries such as CLIGB.
CGLIB dynamic proxy
CGLIB is a Java bytecode generation tool that dynamically generates a subclass of the propped class from the original class.
implementation
You also need to implement an abstract proxy layer first.
public class ProxyInterceptor implements MethodInterceptor {
private Object object;
public ProxyInterceptor(Object object) {
this.object = object;
}
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("invoke cglib proxy");
if ("request".equals(method.getName())) {
System.out.println("invoke request method [cglib]");
methodProxy.invokeSuper(o, args);
} else {
System.out.println("Other methods called");
methodProxy.invokeSuper(o, args);
}
return null; }}Copy the code
A proxied class with no interface
public class CGLibRealSubject {
public void request(a) {
System.out.println("cglib subject is working..."); }}Copy the code
Client use
//CGLIB dynamic proxy
ProxyInterceptor interceptor = new ProxyInterceptor(new CGLibRealSubject());
CGLibRealSubject cgLibRealSubject = (CGLibRealSubject) Enhancer.create(CGLibRealSubject.class,interceptor);
cgLibRealSubject.request();
Copy the code
The attached
Related code: github.com/zhaohaoren/…
If there are code and article problems, also please correct! Thank you!