Proxy schema definition

What is the proxy pattern? Definition of proxy mode: the proxy mode provides a proxy object to an object, and the proxy object controls the reference to the original object. Generally speaking, the agency model is a common intermediary in our life.

For example, if I want to buy a second-hand car, I can find the source of the car by myself, do quality inspection and a series of transfer procedures, but it is really a waste of my time and energy. Why do I have to go through all this extra work when I just want to buy a car? So I bought a car through an intermediary company. They would find a car source for me and help me with the transfer process. I was just responsible for choosing the car I liked and then paying for it. It is shown as follows:

Why use proxy mode?

  • Mediation isolation: In some cases, a client class may not want or be able to directly reference a delegate object, while a proxy object may act as an intermediary between the client and the delegate, characterized by the fact that the proxy and the delegate classes implement the same interface.
  • Open and close principle, add functionality: In addition to acting as an intermediary between the client class and the delegate class, we can also extend the functionality of the delegate class by adding additional functionality to the proxy class. In this way, we only need to modify the proxy class without modifying the delegate class, in accordance with the open and close principle of code design. The proxy class is responsible for pre-processing messages for the delegate class, filtering messages, forwarding messages to the delegate class, and post-processing the returned results. The proxy class itself does not actually implement the service, but rather provides specific services by calling the related methods of the delegate class. The real business functions are still implemented by delegate classes, but some common services can be added before and after the implementation of business functions. For example, if we want to add caching and logging to the project, we can use the proxy class to do so without opening the wrapped delegate class.

How many proxy modes are there

1. Static proxy

Step 1: Create the service class interface

package main.java.proxy;
/**
 * @Auther: dan gao
 * @Description:
 * @Date: 22:40 2018/1/9 0009
 */
public interface BuyHouse {
    void buyHosue();
}
Copy the code

Step 2: Implement the service interface

import main.java.proxy.BuyHouse; /** * @Auther: dan gao * @Description: * @Date: 22:42 2018/1/9 0009 */ public class BuyHouseImpl implements BuyHouse { @Override public void buyHosue() { System.out.println(" I want to buy a house "); }}Copy the code

Step 3: Create the proxy class

package main.java.proxy.impl; import main.java.proxy.BuyHouse; /** * @Auther: dan gao * @Description: * @Date: 22:43 2018/1/9 0009 */ public class BuyHouseProxy implements BuyHouse { private BuyHouse buyHouse; public BuyHouseProxy(final BuyHouse buyHouse) { this.buyHouse = buyHouse; } @override public void buyHosue() {system.out.println (); buyHouse.buyHosue(); System.out.println(" house after decoration "); }}Copy the code

Step 4: Write the test class

import main.java.proxy.impl.BuyHouseImpl; import main.java.proxy.impl.BuyHouseProxy; /** * @Auther: dan gao * @Description: * @Date: 22:43 2018/1/9 0009 */ public class ProxyTest { public static void main(String[] args) { BuyHouse buyHouse = new BuyHouseImpl(); buyHouse.buyHosue(); BuyHouseProxy buyHouseProxy = new BuyHouseProxy(buyHouse); buyHouseProxy.buyHosue(); }}Copy the code

Static proxy summary

Advantages: It can extend the function of the target object in accordance with the open and close principle.

Cons: We have to create proxy classes for each service, which is too much work to manage. Also, if the interface changes, the proxy class must be modified accordingly

2. Dynamic proxy

In dynamic proxy we no longer need to manually create the proxy class, we just need to write a dynamic processor. The actual proxy objects are created dynamically for us by the JDK runtime.

Step 1: Write a dynamic processor

package main.java.proxy.impl; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * @Auther: dan gao * @Description: * @Date: 20:34 2018/1/12 0012 */ public class DynamicProxyHandler implements InvocationHandler { private Object object; public DynamicProxyHandler(final Object object) { this.object = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {system.out.println (" prepare before buying a house "); Object result = method.invoke(object, args); System.out.println(" house after decoration "); return result; }}Copy the code

Step 2: Write the test class

package main.java.proxy.test;

import main.java.proxy.BuyHouse;
import main.java.proxy.impl.BuyHouseImpl;
import main.java.proxy.impl.DynamicProxyHandler;

import java.lang.reflect.Proxy;

/**
 * @Auther: dan gao
 * @Description:
 * @Date: 20:38 2018/1/12 0012
 */
public class DynamicProxyTest {
    public static void main(String[] args) {
        BuyHouse buyHouse = new BuyHouseImpl();
        BuyHouse proxyBuyHouse = (BuyHouse) Proxy.newProxyInstance(BuyHouse.class.getClassLoader(), new
                Class[]{BuyHouse.class}, new DynamicProxyHandler(buyHouse));
        proxyBuyHouse.buyHosue();
    }
}
Copy the code

Note that the proxy.newProxyInstance () method takes three arguments:

  • ClassLoader: specifies the ClassLoader used by the current target object. The method for obtaining the loader is fixed
  • Class
    [] interfaces: Specifies the type of the interface implemented by the target object, using generics to confirm the type
  • InvocationHandler: Specifies the dynamic handler that fires the event handler method when executing the target object’s method

Dynamic proxy summary

While dynamic proxies significantly reduce our development tasks compared to static proxies, they also reduce the dependence on business interfaces and reduce coupling. There is one small regret, however, that it has never been able to escape the shackles of interface proxy-only support because it was designed to do so. Recall the inheritance diagram for dynamically generated Proxy classes that are destined to have a common parent class called Proxy. Java’s inheritance mechanism prevents these dynamic proxy classes from implementing dynamic proxies to classes because multiple inheritance is inherently unworkable in Java. There are many reasons why one can deny the need for a class proxy, but there are also some reasons why supporting a class dynamic proxy would be better. The division of interfaces and classes was not obvious until Java became so detailed. If you look at methods only in terms of how they are declared and whether they are defined, there is a hybrid called abstract class. Implementing dynamic proxies for abstract classes also has inherent value. In addition, there are legacy classes that will never be used for dynamic proxies because they do not implement any interfaces. Such a variety, have to say is a small regret. However, imperfect is not the same as not great, greatness is an essence, Java dynamic proxy is an example.

3. Additional agent

JDK implementation of dynamic proxies requires implementation classes to define business methods through interfaces. For classes without interfaces, how to implement dynamic proxies requires CGLib. 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. But because you inherit, you can’t delegate final modified classes. Both JDK dynamic proxies and CGLib dynamic proxies are the basis for implementing Spring AOP.

Step 1: Create the CGLIB proxy class

package dan.proxy.impl; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * @Auther: dan gao * @Description: * @Date: 20:38 2018/1/16 0016 */ public class CglibProxy implements MethodInterceptor { private Object target; public Object getInstance(final Object target) { this.target = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.target.getClass()); enhancer.setCallback(this); return enhancer.create(); } public Object intercept(Object object, Method method, Object[] args, Throws Throwable {system.out.println (" prepare before buying a house "); Object result = methodProxy.invoke(object, args); System.out.println(" house after decoration "); return result; }}Copy the code

Step 2: Create the test class

package dan.proxy.test; import dan.proxy.BuyHouse; import dan.proxy.impl.BuyHouseImpl; import dan.proxy.impl.CglibProxy; /** * @Auther: dan gao * @Description: * @Date: 20:52 2018/1/16 0016 */ public class CglibProxyTest { public static void main(String[] args){ BuyHouse buyHouse = new BuyHouseImpl(); CglibProxy cglibProxy = new CglibProxy(); BuyHouseImpl buyHouseCglibProxy = (BuyHouseImpl) cglibProxy.getInstance(buyHouse); buyHouseCglibProxy.buyHosue(); }}Copy the code

CGLIB agent summary

Dynamic proxy objects created by CGLIB perform better than dynamic proxy objects created by JDK, but CGLIB takes much longer to create proxy objects. So for singleton objects, where you don’t need to create objects frequently, using CGLIB is more appropriate than using JDK. And because CGLib uses the dynamic subclass method, it cannot proxy the final modification method.