A, the opening

What is a Java proxy? Java’s proxy is that the client class no longer deals directly with the delegate class, but is accessed through an intermediate layer, which is the proxy. For example, when we want to add some extra processing to a method in a class, we can create a proxy class for that class. This class not only contains the method functions of the original class, but also adds additional processing functions to the original class.

Why do you do that? Because there are advantages to adding agents:

  • You can hide the implementation of the delegate class.
  • Decoupling can be achieved between the client and the delegate class, allowing additional operations to be added without modifying the delegate code (The decoupling,flexible,Extensibility is strong).

Static proxy

A static proxy is a class that is created manually at compile time. That is, the relationship between the proxy class and the delegate class exists before the program runs. It is suitable for situations where there are few and certain proxy analogies. If the delegate class has many methods, it will be uncomfortable to write a bunch of proxy methods in the delegate class.

Implementation steps

  1. Defines the interface and its implementation class.
  2. Define a proxy object for the interface and inject an instance of the interface into the proxy object.
  3. The real implementation class is then invoked through the proxy object.

Code case

Public interface IHelloService {String sayHello(String message); Public class HelloService implements IHelloService{public String sayHello(String message) { System.out.println("I am static proxy,"+word); return "I am static proxy,"+word; Public Class StaticProxyHello implements IHelloService{private IHelloService helloService = new HelloService(); public String sayHello(String message) { beforeProcess(); String result = helloService.sayHello(message); afterProcess(); return result; } private void beforeProcess(){system.out.println (" I am delegating the method to be executed before the class method handles..." ); } private void afterProcess(){system.out.println (){system.out.println (); ); Public static void main(String[] args) {StaticProxyHello Proxy = new StaticProxyHello(); Proxy. sayHello(" I am a static proxy..." ); }}Copy the code

The following information is displayed:

I'm delegating to the class method to handle the method that was executed before... I am a static proxy... I'm delegating the method to execute after the class handles it...Copy the code

Static proxy is simply a proxy pattern. The proxy pattern is basically an interface, a delegate class, and a proxy class. The proxy class holds instances of the delegate class, and the proxy class executes instance methods of the concrete class. The point of a proxy class is to enhance the delegate class and add some extra processing logic.

Java dynamic proxy

The proxy class is created when the program is running. The proxy method is called dynamic proxy. Compared with static proxy, dynamic proxy has the advantage of uniformly treating the methods in the proxy class without modifying the methods in each proxy class. In Java dynamic Proxy involves two main classes, Java. Lang. Reflect. InvocationHandler and Java lang. Reflect. The Proxy, you need to create a Proxy class to implement the InvocationHandler interface, There is only one method invoke in this interface, and all method calls we make to the delegate class become invoke method calls. This allows us to add some specific logic to the Invoke method for processing.

Implementation steps

Public interface IHelloService {String sayHello(String message); Public class HelloService implements IHelloService {@override public String sayHello(String message) { System.out.println(" execute sayHello method....") ); Return "message content:" + message; }} / / proxy class public class HelloProxyInvocationHandler implements InvocationHandler {private Object obj. public HelloProxyInvocationHandler(Object obj) { this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { beforeProcess(); Object result = method.invoke(obj, args); afterProcess(); return result; } private void beforeProcess() {system.out.println (" Adds additional operations performed before method calls..." ); } private void afterProcess() {system.out.println (" Add extra operation after method call..." ); }} / / testing dynamic proxy class public class MainProxy {public static void main (String [] args) {HelloProxyInvocationHandler proxyInvocationHandler = new HelloProxyInvocationHandler(new HelloService()); IHelloService helloProxy = (IHelloService) Proxy.newProxyInstance(HelloService.class.getClassLoader(), new Class<? >[]{IHelloService.class}, proxyInvocationHandler); SayHello (" I am JDK dynamic proxy "); }}Copy the code

The result after execution is printed:

Add additional operations performed before method calls... The sayHello method.... is executed Additional operations performed after method calls...Copy the code

In the test dynamic Proxy class above, we call the newProxyInstance method of the Proxy class to get an instance of the Proxy class. This proxy class implements the interface we specify and distributes method calls to the specified invocation handler.

We first get an instance of the proxy class through the newProxyInstance method, and then we call the method of the proxy class through this instance. All method invocations of the proxy class call invoke method, where we call the corresponding method of the delegate class and add our own processing logic.

The most important feature of Java dynamic proxy is that the dynamically generated proxy class and the delegate class implement the same interface. Java dynamic proxies are actually implemented internally by reflection, which is a known object that dynamically calls its methods at runtime and can add some of its own logic to the invocation.

CGlib dynamic proxy

JDK dynamic proxies rely on interfaces, and when we have classes but no interfaces, we need a tripartite framework called CGlib to implement dynamic proxies. The CGLIB proxy is implemented for classes by generating a subclass of the specified delegate class and overriding the business methods to implement the proxy. But because you inherit, you can’t delegate final modified classes. Final modified classes are not inheritable.

Implementation steps

Maven depends on:

<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId>Copy the code

The code implementation is as follows:

Public HelloService {public String sayHello(String message) {system.out.println (" target sayHello executes....") ); Return "message content:" + message; Public class HelloInterceptor implements MethodInterceptor {/** * is used to generate Cglib dynamic proxy class tool methods * @param Public Object initCglib(Class target) {Enhancer Enhancer = new Enhancer(); // Specify the desired class for the proxy class, i.e., the parent class enhancer.setsuperclass (target); // Set the method interceptor CallBack reference, which will be called for all method calls on the proxy class, and which will need to implement the intercept() method to intercept enhancer.setcallback (this); // Get the dynamic proxy class object and return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { beforeProcess(); Object result = methodProxy.invokeSuper(o, args); afterProcess(); return result; } private void beforeProcess() {system.out.println (" Adds additional operations performed before method calls..." ); } private void afterProcess() {system.out.println (" Add extra operation after method call..." ); Public class MainCglib {public static void main(String[] args) {HelloInterceptor interceptor = new HelloInterceptor(); HelloService helloService = (HelloService) interceptor.initCglib(HelloService.class); SayHello (" I am the dynamic proxy implemented by Cglib "); }}Copy the code

The result after execution is printed:

Add additional operations performed before method calls... The target object sayHello executes.... Additional operations performed after method calls...Copy the code

For classes that need to be propped, it simply generates a subclass dynamically to override non-final methods while binding hooks to call back custom interceptors.

conclusion

Static proxies are relatively easy to understand, requiring the delegate class and the proxy class to implement the same interface, then calling the real implementation class from the proxy class, and the static proxy relationship is determined at compile time. Dynamic proxy relationships are determined at run time. Static proxies are simple to implement and are suitable for situations where there are fewer and more defined proxy classes, whereas dynamic proxies give us more flexibility.

The proxy classes used by JDK dynamic proxies are actually created by the JVM when the program calls the proxy class object. The JVM dynamically creates a proxy class file based on the passed business implementation class object and method name, which is executed by the bytecode engine, and then makes method calls through the proxy class object.

Both static and dynamic proxies are implemented based on interfaces, and for those that do not provide an interface but only an implementation class, CGLIB dynamic proxies are the only choice.

What are the differences between Cglib and JDK dynamic proxies?

  1. JDK dynamic proxies are implemented based on Java reflection, which requires business classes that implement the interface to generate proxy objects in this way.
  2. CGLIB dynamic proxy is implemented based on the ASM framework by generating subclasses of business classes.

Advantages and disadvantages of static proxy, JDK dynamic proxy, CGlib dynamic proxy?

Static proxy: both the proxy object and the real object implement the same interface. The proxy object points to an instance of the real object, exposing the proxy object and calling the real object.

  • Advantages: The service logic of real objects can be protected to improve security.
  • Disadvantages: Different interfaces must have different proxy class implementation, can be very redundant

JDK dynamic proxy: To solve the static proxy, generate a large number of proxy classes caused by the redundancy; JDK dynamic proxies only need to implement the InvocationHandler interface and override the Invoke method to complete the implementation of the proxy. JDK proxies use reflection to generate proxy class proxyxx.class bytecode and generate objects. JDK dynamic proxies can only Proxy interfaces because Proxy classes themselves already inherit from proxies, and Java does not allow multiple inheritance.

  • Advantages: Solve the problem of redundant proxy implementation classes in static proxy.
  • Disadvantages: JDK dynamic proxy is based on interface design implementation, if there is no interface, will throw exceptions.

CGLIB dynamic proxy: The JDK dynamic proxy can only be designed based on the interface, and there is no interface, JDK approach can not solve the problem; CGLib uses very low-level bytecode technology. Its principle is to create a subclass of a class by bytecode technology, and use method interception technology in the subclass to intercept all the calls of the parent class method, and then weave the crosscutting logic to achieve dynamic proxy. Implement the MethodInterceptor interface, rewrite the intercept method, through the Enhancer class callback method to implement.

However, CGLib takes a lot more time to create proxy objects than the JDK, so for singleton objects that don’t need to be created frequently, CGLib is more appropriate than the JDK approach. At the same time, because CGLib is subclassed dynamically, there is no proxy for final methods.

  • Advantages: Dynamic proxy can be realized without interface, and bytecode enhancement technology, performance is also good.
  • Disadvantages: The technical implementation is relatively difficult to understand.

Write in the last

Dynamic proxy is very common in Java development, has a wide range of applications in logging, monitoring, transactions, and at the same time in most of the mainstream framework of the core components are also indispensable to use, master its key points, whether development or reading other framework source code, is a must. I hope this article will be helpful. Like to add attention, continue to update the follow-up!!