Small knowledge, big challenge! This paper is participating in theEssentials for programmers”Creative activities
First, what is the agency model
A Proxy Pattern provides a Proxy for an object, which controls references to the original object. The proxy object acts as an intermediary between the client and the target object.
The proxy pattern is one of the common structural design patterns. When there is a problem in accessing some objects directly, it can be accessed indirectly through a proxy object. In order to ensure the transparency of the client, the real object accessed and the proxy object need to implement the same interface. The agent pattern belongs to the structural design pattern and is one of the 23 design patterns of GOF.
The proxy mode can be divided into static proxy and dynamic proxy, and dynamic proxy is divided into JDK dynamic proxy and CGLIB proxy.
The proxy mode contains the following roles:
- Subject (Abstract Topic Role) Abstract topic roles declare the common interface of real and proxy topics, so that proxy topics can be used anywhere the real topic is used. The client needs to program against abstract topic roles.
- Proxy (Proxy topic role) Proxy topic roles contain internal references to real topics and can manipulate real topic objects at any time. Provide an interface in the proxy subject role that is identical to the real subject role so that the real subject can be replaced at any time. The proxy topic role also controls the use of real topics, is responsible for creating and deleting real topic objects as needed, and restricts the use of real topic objects. Proxy roles typically require additional operations to be performed before or after a client invokes the referenced real topic operation, rather than simply calling the operations in the real topic object.
- RealSubject (RealSubject role) RealSubject roles define real objects represented by proxy roles and implement real business operations in RealSubject roles. Clients can indirectly invoke methods defined in RealSubject roles through proxy roles.
Advantages of the proxy model
-
The proxy pattern separates the proxy object from the actual target object being invoked.
-
The coupling degree of the system is reduced to a certain extent, and the expansibility is good.
-
It can protect the target object.
-
You can enhance the functionality of the target object.
Disadvantages of the proxy model
-
The proxy pattern increases the number of classes in the system design.
-
Adding a proxy object to both the client and the target object slows down request processing.
JDK dynamic proxy
In Java dynamic Proxy mechanism, there are two important classes or interfaces, one is InvocationHandler(Interface), the other is Proxy(Class), this one Class and Interface is necessary to implement our dynamic Proxy.
InvocationHandler
Every dynamic proxy class must implement the InvocationHandler interface, and each instance of the proxy class is associated with a handler. When we call a method from the proxy object, The call to this method is then forwarded to the Invoke method of the InvocationHandler interface.
The InvocationHandler interface’s only method is the invoke method:
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
Copy the code
This method takes three parameters, which are represented as follows:
- Proxy: Represents the final proxy object dynamically generated by the JDK
- Method: Refers to the method object of a method that we want to call the real object
- Args: refers to arguments accepted when a method of a real object is called
Proxy
The Proxy class is used to dynamically create a Proxy object class. It provides many methods, but the one we use most is newProxyInstance:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler) throws IllegalArgumentException
Copy the code
This method returns a dynamic proxy object that takes three parameters. Let’s look at what these parameters mean:
- Loader: The ClassLoader object that defines which ClassLoader loads the generated proxy object, the ClassLoader of the proxy class.
- Interfaces: an array of Interface objects that represent the set of interfaces I am going to provide to the object I want to proide. If I provide interfaces to it, the proxy object claims to implement that Interface (polymorphic) so that I can call methods in that set of interfaces.
- Handler: The InvocationHandler object, which represents the InvocationHandler object to which the dynamic proxy object is associated when calling a method.
So what we call a DynamicProxy is a class that is generated at runtime, you have to give it a set of interfaces to generate it, and then the class claims that it implements those interfaces. DynamicProxy is just a Proxy, it doesn’t do any real work, you have to provide a handler to take over the actual work when creating its instance.
JDK dynamic proxy instance
Creating an interface Class
public interface HelloInterface {
void sayHello(a);
}
Copy the code
Create a proxied class to implement the interface
/** * Proxy class */
public class HelloImpl implements HelloInterface{
@Override
public void sayHello(a) {
System.out.println("hello"); }}Copy the code
Create the InvocationHandler implementation class
/** * Each time you generate a dynamic proxy class object, you need to specify a call handler object that implements the InvocationHandler interface */
public class ProxyHandler implements InvocationHandler{
private Object subject; // This is the real object we want to proide, i.e. the class that actually performs the business logic
public ProxyHandler(Object subject) {// Pass the proxied object through the constructor
this.subject = subject;
}
/** * When a proxy object calls a method of the real object, it automatically jumps to the invoke method of the handler object associated with the proxy object to invoke */
@Override
public Object invoke(Object obj, Method method, Object[] objs)
throws Throwable {
Object result = null;
System.out.println("There are a few things you can do before calling the actual method.");
System.out.println("The method currently called is." + method.getName());
result = method.invoke(subject, objs);// You need to specify the propped object and the parameters passed in
System.out.println(method.getName() + "The return value of the method is + result);
System.out.println("There's something you can do after calling the actual method.");
System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -");
return result;// returns the value returned after the method is executed}}Copy the code
test
public class Mytest {
public static void main(String[] args) {
// Step 1: Create the proxied object
HelloImpl hello = new HelloImpl();
// Step 2: Create a handler and pass in the real object
ProxyHandler handler = new ProxyHandler(hello);
// Step 3: Create a proxy object and pass in the class loader, interface, and handler
HelloInterface helloProxy = (HelloInterface) Proxy.newProxyInstance(
HelloInterface.class.getClassLoader(),
new Class[]{HelloInterface.class}, handler);
// Step 4: Call the methodhelloProxy.sayHello(); }}Copy the code
The results of
There are a few things you can do before calling the actual method the method currently called is sayHello Hello sayHello returns null there are a few things you can do after calling the actual method ------------------------Copy the code
JDK dynamic proxy steps
JDK dynamic proxies are divided into the following steps:
- Get a reference to the proxied object and get all its interfaces by reflection.
- Use the JDK Proxy class to create a new class that implements all the interfaces implemented by the Proxy class.
- Dynamically generate Java code, the newly added business logic method by a certain logic code to call.
- Compile the newly generated Java code. Class.
- Reload the newly generated Class file into the JVM to run.
So the core of JDK dynamic proxies is to regenerate proxy classes by overriding methods in the interface implemented by the propped object. What if the propped object doesn’t implement the interface? This is where the CGLIB dynamic proxy comes in.
CGLIB dynamic proxy
JDK dynamic proxies are implemented by overriding methods in the promenade’s interface. CGLIB is implemented by inheriting methods from the promenade. Just as JDK dynamic proxies implement the specified interface, CGLIB also requires that the promenade implement the MethodInterceptor interface. Rewrite its only method intercept.
CGLib uses very low-level bytecode technology to create a subclass of a class and use method interception techniques in the subclass to intercept all calls to the methods of the parent class, weaving into crosscutting logic. (Using the ASM open source package, load in the class file of the proxy object class, and modify its bytecode generation subclass to deal with it)
Note: Because CGLIB overrides its methods by inheriting from the target class, final and private methods cannot be overridden, that is, cannot be propped.
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2</version>
</dependency>
Copy the code
Additional core classes
1, the.net. Sf. Additional. Proxy. Enhancer: main enhancement class, through the bytecode technology created dynamically authorize subclass instances of a class;
Enhancer is probably the most commonly used class in CGLIB, similar to the Proxy class introduced in Java1.3 dynamic proxies. Unlike a Proxy, Enhancer can Proxy both ordinary classes and interfaces. Enhancer Creates a subclass of the propped Object and intercepts all method calls (including toString and hashCode methods inherited from Object). Enhancer cannot intercept final methods, such as the object.getClass () method, due to Java final method semantics. For the same reason, Enhancer cannot broker the fianl class. This is why Hibernate cannot persist final classes.
2,.net. Sf. Additional. Proxy. MethodInterceptor: interceptor interface, commonly used method to implement intercept method, realize the intercept processing;
public java.lang.Object intercept(java.lang.Object obj, java.lang.reflect.Method method, java.lang.Object[] args, MethodProxy proxy) throws java.lang.Throwable{}
Copy the code
- Obj: dynamically generated proxy object
- Method: the actual method called
- Args: Call method entry parameter
- Net. Sf. Additional. Proxy. MethodProxy: Java proxy class Method class, can realize the delegate class object Method calls; MethodProxy. InvokeSuper (proxy, args); It can be called multiple times within an intercepting method.
CGLib proxy instance
Create the proxied class
public class SayHello {
public void say(a){
System.out.println("hello"); }}Copy the code
Creating a proxy class
/** * Proxy class */
public class ProxyCglib implements MethodInterceptor{
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz){
// Set the class to subclass
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
// Create subclass instances dynamically using bytecode technology
return enhancer.create();
}
// Implement the MethodInterceptor interface method
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("There are a few things you can do before calling the actual method.");
// Call a method in the parent class through the proxy class
Object result = proxy.invokeSuper(obj, args);
System.out.println("There's something you can do after calling the actual method.");
returnresult; }}Copy the code
test
public class Mytest {
public static void main(String[] args) {
ProxyCglib proxy = new ProxyCglib();
// Create a proxy class by subclassing itSayHello proxyImp = (SayHello)proxy.getProxy(SayHello.class); proxyImp.say(); }}Copy the code
The results of
You can do a couple of things before you call the actual method hello can do a couple of things after you call the actual methodCopy the code
CGLIB dynamic proxy implementation analysis
The CGLib dynamic proxy uses the FastClass mechanism, which generates a FastClass for both the proxy class and the proxied class. This FastClass assigns an index(int) to the proxy class or the proxied class’s methods. With this index as an input parameter, FastClass can directly locate the method to be called, eliminating reflection calls, so calls are more efficient than JDK dynamic proxies using reflection calls.
However, the JDK dynamic proxy generates only one file, whereas CGLIB generates three files, so the process of generating proxy objects is more complicated.
JDK and CGLib dynamic proxy comparison
The JDK dynamic proxy implements the interface implemented by the proxied object, and CGLib inherits the proxied object. Both JDK and CGLib generate bytecodes at runtime. JDK writes Class bytecodes directly. CGLib uses the ASM framework to write Class bytecodes.
JDK calls proxy methods through reflection. CGLib calls methods directly through FastClass. CGLib is more efficient.
Principle difference:
Java dynamic proxies use reflection to generate an anonymous class that implements the proxy interface and InvokeHandler is invoked to handle it before invoking the specific method. The core is to implement the InvocationHandler interface, using the invoke() method for section-oriented processing, invoking the corresponding notification.
The cglib dynamic proxy uses the ASM open source package to load the class file of the proxy object class and modify its bytecode generation subclass to deal with it. The core is to implement the MethodInterceptor interface, using the Intercept () method for section-oriented processing, call the corresponding notification.
The JDK’s dynamic proxy implementation of AOP is used by default if the target object implements an interface
You can force CGLIB to implement AOP if the target object implements an interface
3. If the target object does not implement an interface, the CGLIB library must be used, and Spring will automatically convert between JDK dynamic proxies and CGLIB
Performance differences:
1. CGLib uses ASM bytecode generation framework at the bottom and uses bytecode technology to generate proxy classes, which is more efficient than Java reflection before JDK6. The only caveat is that CGLib cannot proxy methods that are declared final, because CGLib’s principle is to dynamically subclass the proxied class.
2, in jdk6 has, jdk7, jdk8 gradually the JDK dynamic proxy after optimization, the call number is less, the JDK efficiency is higher than the additional agency efficiency, only when a large number of calls, jdk6 has and jdk7 than additional agent efficiency is lower, but by jdk8, The JDK agent is more efficient than the CGLIB agent.
Limitations:
The JDK dynamic proxy mechanism can only proxy classes that implement the interface, and classes that do not implement the interface cannot implement JDK dynamic proxy.
2. Cglib implements proxying for classes. Its principle is to generate a subclass of the specified target class and override the method enhancements.
type | mechanism | The callback method | Applicable scenario | The efficiency of |
---|---|---|---|---|
JDK dynamic proxy | In the delegate mechanism, both the proxy class and the target class implement the same interface. InvocationHandler holds the target class, and the proxy class delegates InvocationHandler to call the target class’s original methods | reflection | The target class is the interface class | The efficiency bottleneck is slightly slower in reflection calls |
CGLIB dynamic proxy | Inheritance mechanism, the proxy class inherits the target class and overwrites the target method, using the callback function MethodInterceptor to call the parent class method to execute the original logic | Called through the FastClass method index | Non-interface classes, non-final classes, non-final methods | The first call is slower than the JDK approach because it generates multiple Class objects. Multiple calls because method indexing is faster than reflection, if there are too many methods, switch case too many its efficiency needs to be tested |
The essential difference between static proxy and dynamic proxy
- A static proxy can only be manually performed. If a new method is added to the proxy class, the proxy class must be added at the same time, which violates the open/close principle.
- Dynamic proxy adopts the method of dynamically generating code at run time, which removes the limitation of extending the proxied class and follows the open and closed principle.
- If the dynamic proxy wants to extend the enhanced logic of the target class, combined with the policy mode, it only needs to add the policy class to complete, without modifying the code of the proxy class.