23 design modes: agent mode

Catalog

1. Concepts

Definition: Provides a proxy for another object to control outside access to it.

The proxy pattern is interpreted in Wikipedia as a wrapper or proxy object being invoked by the client to access the real service object behind the scenes.The use of a proxy can be simply forwarded to a real object, or it can provide additional logic.In a proxy, you can provide additional functionality, such as caching when the operation on the real object consumes a lot of resources, or checking prerequisites before the operation on the real object is invoked.

As an example, there used to be an ivory tower where local wizards went to learn magic.Over time, more and more local wizards learned magic, eventually filling the day with ivory towers.So two mighty guards came in, who stipulated that only three wizards could go in to study at a time.Thus, the two guards act as agents of the ivory tower, delegating access to the tower and adding access control to it.In short, use the proxy mode, where one class represents the functionality of another.

2. Program examples

2.1 Wizards

public class Wizard {
    private String name;

    public Wizard(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return name;
    }
}

2.2 Tower Interface

public interface Tower {
    public void enter(Wizard wizard);
}

2.3 Ivory Tower Implementation Class

/**
 * Ivory Tower (everyone can enter, no number limit)
 *
 * @author suvue
 */
@Slf4j
public class IvoryTower implements Tower {
    @Override
    public void enter(Wizard wizard) {
        log.info("{}Enter the ivory tower", wizard.toString());
    }
}

2.4 Ivory Tower Proxy Class (equivalent to example gatekeeper)

/**
 * I'm the Ivory Tower agent and only three people are allowed in
 *
 * @author suvue
 */
@Slf4j
public class IvoryTowerProxy implements Tower {
    //Maximum number of people allowed to enter
    private static final int NUMBER_ALLOW = 3;
    private Tower tower;
    private int numWizards;

    //Constructor
    public IvoryTowerProxy(Tower tower) {
        this.tower = tower;
    }

    @Override
    public void enter(Wizard wizard) {
        if (numWizards < NUMBER_ALLOW) {
            tower.enter(wizard);
            numWizards++;
        } else {
            log.error("The ivory tower is full. Please come back later!");
        }
    }
}

2.5 Client Caller

public class Client {
    public static void main(String[] args){
        IvoryTowerProxy towerProxy = new IvoryTowerProxy(new IvoryTower());
        towerProxy.enter(new Wizard("Red Wizard"));
        towerProxy.enter(new Wizard("Wizard Huang"));
        towerProxy.enter(new Wizard("Blue Wizard"));
        towerProxy.enter(new Wizard("Green Wizard"));
        towerProxy.enter(new Wizard("White Wizard"));
    }
}

2.6 Results Printing

The Red Wizard enters the Ivory Tower
 Wizard Yellow enters the ivory tower
 The blue wizard enters the ivory tower
 The ivory tower is full. Please come back later!
The ivory tower is full. Please come back later!

2.7. Summary

In the program, this is the implementation of the static proxy, which generates a proxy class for each actual object and treats it as an internal property.But there are many more ivory towers in the world?What should I do when current limits are needed?Do you need two guards for each ivory tower?This is the disadvantage of static proxies, which can lead to a rapid increase in the number of classes and a lot of duplication of proxy class code, in which each ivory tower needs two guards of the same duties.

	Let's change the idea that if the tribal chiefs had a decree that all the ivory towers could only be accessed at a time
	Three people study, so don't you need to recruit guards?This is the implementation of our dynamic proxy.

3.jdk Dynamic Proxy Mode

Concepts: In short, a proxy class with the same functions is merged into one proxy class, which reduces many proxy classes with duplicate functions.

Let's optimize the above example and look directly at the code.

Let's start with an important interface class in jdk

3.1 InvocationHandler interface

package java.lang.reflect;
//A class must implement this interface if it wants to implement proxy functionality
public interface InvocationHandler {
    //Implement the function of this method
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;

}

3.2 Proxy Class

package java.lang.reflect;
//Provides static methods for creating dynamic proxy classes and instances, and it is also the parent of all proxy classes created by these methods
public class Proxy implements java.io.Serializable {
//The following method returns a proxy class that implements InvocationHandler
@CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
       //...
    }
}

3.3 Program Example

package cn.suvue.discipline.practice.designpattern.proxy.jdk;

import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * jdk Dynamic Proxy Class
 *
 * @author suvue
 * @date 2020/1/14
 */
@Slf4j
public class JdkProxyHandler implements InvocationHandler {

    private static final int NUMBER_ALLOW = 3;
    private int numWizards = 0;
    private Object target;

    //Note: The object Type of the parameter passed by the construction method here
    public JdkProxyHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (numWizards < NUMBER_ALLOW) {
            method.invoke(target, args);
            numWizards++;
        } else {
            log.error("The ivory tower is full. Please come back later!");
        }
        return null;
    }
}

Client Caller

public class Client {
    public static void main(String[] args){
        Tower target = new IvoryTower();
        Tower proxyInstance = (Tower)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                new JdkProxyHandler(target));
        proxyInstance.enter(new Wizard("White Wizard"));
        proxyInstance.enter(new Wizard("dark wizards"));
        proxyInstance.enter(new Wizard("Red Wizard"));
        proxyInstance.enter(new Wizard("Blue Wizard"));
        proxyInstance.enter(new Wizard("Green Wizard"));
    }
}

The dynamic proxy is used, which was originally used to control access rights for the object's dental towers, but is now available for castles, farms, and schools because it uses a reflection mechanism that determines the parameter type only at runtime.This is really impressive and of course convenient.

This pattern is also used in the spring framework, so you can see the class JdkDynamicAopProxy.

Note: However, the dynamic proxy of JDK is implemented through the proxy interface, if the object does not implement the interface, then there is nothing to do.

4.CGLIB Dynamic Proxy Mode

4.1 Program Example

package cn.suvue.discipline.practice.designpattern.proxy.cglib;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * cglib Dynamic Proxy
 *
 * @author suvue
 * @date 2020/1/14
 */
@Slf4j
public class CglibInterceptor implements MethodInterceptor {
    private static final int NUMBER_ALLOW = 3;
    private int numWizards = 0;


    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        if (numWizards < NUMBER_ALLOW) {
            methodProxy.invokeSuper(o, objects);
            numWizards++;
        } else {
            log.error("The ivory tower is full. Please come back later!");
        }
        return null;
    }
}

Client Caller

public class Client {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(IvoryTower.class);
        enhancer.setCallback(new CglibInterceptor());
        Tower tower = (Tower) enhancer.create();
        tower.enter(new Wizard("White Wizard"));
        tower.enter(new Wizard("dark wizards"));
        tower.enter(new Wizard("Red Wizard"));
        tower.enter(new Wizard("Blue Wizard"));
        tower.enter(new Wizard("Green Wizard"));
    }
}

As you can see, CGLIB acts as a dynamic proxy by dynamically generating subclasses of the target class and setting interception logic in the subclasses.Therefore, the method of the target class cannot be modified by final.

39 original articles published, acclaimed 13, visited 2280
Private letter follow

Tags: JDK Java Lombok Spring

Posted on Tue, 14 Jan 2020 17:07:13 -0800 by thewitt