Detailed explanation of design mode agent mode

Introduction to agent mode

The agent mode provides an additional access to the target object, that is, through the agent object to access the target object, which can provide additional functional operations and expand the function of the target object without modifying the original target object.

There are three types of agent patterns:

  • Static proxy
  • Dynamic proxy
  • Cglib agent

Static agent (not recommended)

introduce

It is required that the target object and the proxy object implement the same interface and call the methods of the proxy object when calling, so as to achieve the enhanced effect

Advantage:

You can enhance the function of the target object method without modifying the target object (this method is not recommended because it can be implemented in all proxy modes)

Disadvantages:

① Redundancy. If the target object and the proxy object implement the same interface, too many proxy classes will be generated.

② Not easy to maintain. When interface methods are added, both the target object and the proxy object need to be modified.

code implementation

Scenario: the manufacturer produces goods, but does not have enough energy and manpower to sell them. At this time, an agent is needed to help him sell them, but the agent needs to extract 20% of the profits.

Common interface

public interface IProducer {
    void sale(float money);
}

Represented object

public class Producer implements IProducer {
    @Override
    public void sale(float money) {
        System.out.println("Sold products, obtained by the manufacturer" + money + "element");
    }
}

Surrogate object

public class ProxyProducer implements IProducer{

    private IProducer producer;

    public ProxyProducer(IProducer producer) {
        this.producer = producer;
    }

    @Override
    public void sale(float money) {
        producer.sale(money * 0.8f);
    }
}

Test class

public class Client {
    @Test
    public void test(){
        IProducer producer = new Producer();
        ProxyProducer proxyProducer = new ProxyProducer(producer);
        proxyProducer.sale(1000f);
    }
}

Operation result

The manufacturer gets 800.0 yuan when selling products

Dynamic proxy

introduce

Dynamic proxy, also known as JDK proxy and interface proxy, requires the target object to implement the interface. Otherwise, dynamic proxy cannot be used to build proxy objects in memory dynamically by using the JDK API (java.lang.reflect.Proxy).

Difference between static agent and dynamic agent:

  • The static agent is implemented at compile time. The compiled agent class is an actual class file
  • The dynamic agent is generated dynamically at run time. There is no actual class file after compilation. Instead, it dynamically generates class bytecode at run time and loads it into the JVM

code implementation

In the case of static proxy, we only need to modify the code of the proxy object, and the proxy object does not need to implement the public interface.

public class ProxyProducer {
    /**
     * Maintain a target object
     */
    private Object target;

    public ProxyProducer(Object target) {
        this.target = target;
    }

    public Object getProxyInstance() {
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    /**
                     * Any interface method that executes the proxied object will pass through here
                     * @param proxy References to proxy objects
                     * @param method Currently implemented method
                     * @param args Parameters of the current execution method
                     * @return Has the same return value as the proxied object
                     * @throws Throwable
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //Some methods are implemented in the agent process
                        float money = (float) args[0] * 0.8f;
                        //Reflection mechanism calls method of target object
                        Object invoke = method.invoke(target, money);
                        return invoke;
                    }
                });
    }
}

Cglib agent

introduce

Cglib proxy is also called subclass proxy. The target object does not need to implement any interface. It is to build a subclass object in memory to extend the function of the target object.

Cglib is a powerful and high-performance code generation package. It can extend Java classes and implement Java interfaces during runtime. It is widely used by many AOP frameworks, such as Spring AOP, to implement method interception.

The underlying Cglib package uses the bytecode processing framework ASM to transform bytecode and generate new classes.

Which agent mode is chosen in AOP programming?

  • The target object needs to implement the interface with JDK proxy
  • The target object does not need to implement the interface. Cglib proxy is used

code implementation

Before use, you need to import the relevant jar package, which can be downloaded from the maven warehouse

Proxy object, no need to implement interface

public class Producer {
    public void sale(float money) {
        System.out.println("Sold products, obtained by the manufacturer" + money + "element");
    }
}

Surrogate object

public class ProxyProducer implements MethodInterceptor {
    /**
     * Maintain a target object
     */
    private Object target;

    public ProxyProducer(Object target) {
        this.target = target;
    }

    /**
     * Generate proxy objects for target objects
     */
    public Object getProxyInstance(){
        //Create a tool class
        Enhancer enhancer = new Enhancer();
        //Setting parent class
        enhancer.setSuperclass(target.getClass());
        //Set callback function
        enhancer.setCallback(this);
        //Create a subclass object (proxy object)
        return enhancer.create();
    }

    /**
     * All methods of the proxy object will be blocked
     * @param obj Enhanced object
     * @param method Methods of proxied objects
     * @param args Parameters of the represented object method
     * @param methodProxy Surrogate object
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("obj: " + obj.getClass());
        Object returnValue = null;
        float money = (float) args[0] * 0.8f;
        if("sale".equals(method.getName())){
            returnValue = method.invoke(target, money);
        }
        return returnValue;
    }
}

Test class

public class Client {
    @Test
    public void test() {
        Producer producer = new Producer();
        Producer proxyInstance = (Producer) new ProxyProducer(producer).getProxyInstance();
        proxyInstance.sale(1000f);
    }
}

Tags: JDK Java jvm Spring

Posted on Fri, 17 Apr 2020 01:56:10 -0700 by mudi