• Approaching autumn recruitment, preparing for summer internship, I wish you every day progress hundred million little!Day18
  • This article summarizes the proxy design pattern, which will be updated daily


  • The most intuitive explanation of the proxy pattern is that, through the proxy, the prosteed object is “enhanced”! (that is, extending the functionality of the proxied object)

  • The proxy mode is divided into static proxy and dynamic proxy: the dynamic proxy proxy class is dynamically generated, the static proxy class is our pre-written logic.

  • Dynamic proxies can be implemented in Java in two ways:

    • JDK dynamic proxy
    • CGLIB dynamic proxy

Static proxy

Static proxy role analysis:

  • Abstract roles: Typically implemented using interfaces or abstract classes.
  • Real role: The role being represented.
  • Proxy role: Proxy for the real role. After proxy for the real role, it usually performs some subsidiary operations.
  • Caller: Uses the proxy role to perform some operations.

Let’s take tenants renting houses as an example, involving the objects are: tenants, agents, landlords. (The landlord is the agent and the intermediary is the agent)

The tenant rents the landlord’s house through the intermediary, and the agent agent needs to find the tenant to rent and obtain the intermediary fees.

Code implementation:

Rent.java is an abstract role

// Abstract role: rent a house
public interface Rent {
   public void rent(a);
}
Copy the code

Host. Java is a real role

// Real character: landlord, landlord wants to rent the house
public class Host implements Rent{
   public void rent(a) {
       System.out.println("House for Rent"); }}Copy the code

Proxy. Java is the Proxy role

// Proxy role: intermediary
public class Proxy implements Rent {

   private Host host;
   public Proxy(a) {}public Proxy(Host host) {
       this.host = host;
  }

   / / rent
   public void rent(a){
       seeHouse();
       host.rent();
       fare();
  }
   / / the checking
   public void seeHouse(a){
       System.out.println("Show the tenant a house.");
  }
   // A broker fee is charged
   public void fare(a){
       System.out.println("Collect a broker's fee"); }}Copy the code

The Client. Java caller is the Client

// Client class, usually customers to find agent!
public class Client {
   public static void main(String[] args) {
       // The landlord wants to rent a house
       Host host = new Host();
       // The agent helps the landlord
       Proxy proxy = new Proxy(host);

       // You go to an agent!proxy.rent(); }}Copy the code

Disadvantages of static proxies:

  • Proxy classes need to be created manually, and if more objects need to be proxy, more and more proxy classes will be created.

To solve this problem, there is a dynamic proxy!


Dynamic proxy

When it comes to dynamic proxy, there are two ways to implement dynamic proxy:

Let’s start with the common UserService interface and the UserServiceImpl implementation class:

/ * * *@author csp
 * @dateThe 2021-06-03 * /
public interface UserService {

    /** * login */
    void login(a);

    /** * log out */
    void logout(a);
}
Copy the code
/ * * *@author csp
 * @dateThe 2021-06-03 * /
public class UserServiceImpl implements UserService{
    @Override
    public void login(a) {
        System.out.println("User login...");
    }

    @Override
    public void logout(a) {
        System.out.println("User push login..."); }}Copy the code

JDK dynamic proxy

The code is as follows:

/ * * *@author csp
 * @dateThe 2021-06-03 * /
public class JDKProxyFactory implements InvocationHandler {

    // Target object (proxy object)
    private Object target;

    public JDKProxyFactory(Object target) {
        super(a);this.target = target;
    }

    /** * Create the proxy object **@return* /
    public Object createProxy(a) {
        // 1. Get the class loader for the target object
        ClassLoader classLoader = target.getClass().getClassLoader();
        // 2. Get the implementation interface of the target objectClass<? >[] interfaces = target.getClass().getInterfaces();// 3. The third argument requires an object that implements the invocationHandler interface
        Object newProxyInstance = Proxy.newProxyInstance(classLoader, interfaces, this);

        return newProxyInstance;
    }


    /** * actually implements the proxy enhancement method **@paramProxy Proxy object. * is generally not used@paramMethod Method that needs to be enhanced *@paramParameter * in the args method@return* /
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("JDK dynamic Proxy: logic verification before login/logout......");
        Object invoke = method.invoke(target, args);
        System.out.println("JDK dynamic proxy: Log printing after login/logout......");
        return invoke;
    }

    public static void main(String[] args) {
        // 1. Create objects
        UserServiceImpl userService = new UserServiceImpl();
        // 2. Create proxy objects
        JDKProxyFactory jdkProxyFactory = new JDKProxyFactory(userService);
        // 3. Call the enhanced method of the proxy object to get the enhanced object
        UserService userServiceProxy = (UserService) jdkProxyFactory.createProxy();
        userServiceProxy.login();
        System.out.println("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ="); userServiceProxy.logout(); }}Copy the code

The following output is displayed:

JDK dynamic proxy: logic verification before login/logout...... User login... JDK dynamic proxy: Logs are printed after login/logout...... = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = the JDK dynamic proxy: login/logout logic check before... Users roll out login... JDK dynamic proxy: Logs are printed after login/logout......Copy the code

\

CGLIB dynamic proxy

The code is as follows:

/ * * *@author csp
 * @dateThe 2021-06-03 * /
public class CglibProxyFactory implements MethodInterceptor {

    // Target object (proxy object)
    private Object target;

    // Pass the target object using the constructor
    public CglibProxyFactory(Object target) {
        super(a);this.target = target;
    }

    /** * Create the proxy object **@return* /
    public Object createProxy(a) {
        // create Enhancer
        Enhancer enhancer = new Enhancer();
        // 2. Pass the target object's class
        enhancer.setSuperclass(target.getClass());
        3. Set the callback operation
        enhancer.setCallback(this);

        return enhancer.create();
    }

    /** * actually implements the proxy enhancement method *@paramO Proxy object *@paramMethod Specifies the method to be enhanced@paramObjects to enhance method parameters *@paramMethodProxy The proxy for the method to be enhanced@return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("Cglib dynamic Proxy: Logic verification before login/logout......");
        Object invoke = method.invoke(target, objects);
        System.out.println("Cglib dynamic Proxy: Log printing after login/logout......");

        return invoke;
    }

    public static void main(String[] args) {
        // 1. Create objects
        UserServiceImpl userService = new UserServiceImpl();
        // 2. Create proxy objects
        CglibProxyFactory cglibProxyFactory = new CglibProxyFactory(userService);
        // 3. Call the enhanced method of the proxy object to get the enhanced object
        UserService userServiceProxy = (UserService) cglibProxyFactory.createProxy();
        userServiceProxy.login();
        System.out.println("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ="); userServiceProxy.logout(); }}Copy the code

The test results are as follows:

Cglib dynamic proxy: Verify logic before login and logout...... User login... Cglib dynamic proxy: Logs generated after login and logout are printed...... = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = additional dynamic proxy: login/logout logic check before... Users roll out login... Cglib dynamic proxy: Logs generated after login and logout are printed......Copy the code

3, summarize

JDK dynamic proxy and CGLIB dynamic proxy?

  • CGLib inherits the propped object’s interface and overwrites its methods.
  • JDK dynamic proxies can only generate proxies for classes that implement interfaces. CGLib does not have this limitation. However, CGLib cannot delegate final classes, private methods, and static methods because of its inheritance implementation.
  • The JDK dynamic proxy is a built-in JDK, CGLib dynamic proxy needs to introduce a third partyjarThe package.
  • (4) In the call proxy method, JDK dynamic proxy is passedReflection mechanismThe call to CGLib is passedFastClass mechanismDirect call. A simple way to understand FastClass is to use oneindexThe subscript is used as an input parameter to locate and call the method directly.

In terms of performance, before JDK1.7, CGLib was faster than JDK in terms of execution efficiency due to the use of FastClass mechanism, but with the continuous optimization of JDK dynamic proxy, JDK dynamic proxy has been significantly faster than CGLib since JDK1.7.

Why do JDK dynamic proxies only generate proxies for classes that implement interfaces?

The root cause is that classes generated by dynamic proxies in the JDK already inherit Proxy classes, so classes can no longer be proxied by inheritance.


Summary of the interview question is also quite time-consuming, the article will be updated from time to time, sometimes more than a day to update a few, if you help to review and consolidate the knowledge point, please also support three, the follow-up will be a hundred million points of update!