Design Pattern 8: Proxy Pattern - Dynamic Proxy

Previous article: Design Pattern 8: Proxy Pattern-Static Proxy

How to understand the word "dynamic"?

"Dynamic" means 代码生成代理类,一个代理类可以代理多个接口.

Dynamic is different from 死板static proxy. In static proxy, one proxy class can only proxy one interface. For other different interfaces, different proxy classes need to be written by hand, which is very complicated 死板.

Dynamic proxy is similar to what we often say in Android. In fact, it is to apply for permissions 动态申请权限using java or kotlin code instead of in the AndroidManifest.xml file 写死.一次可以申请一个或多个权限

Previous article: Zhong, StationProxyHe and StarProxyare all our handwritten proxy classes. Dynamic proxy can automatically generate proxy classes.

Simple code example of dynamic proxy

Dynamic proxy requires two classes provided in jdk InvocationHandlerand Proxyrewrites InvocationHandlerthe interface to implement the proxy method and Proxyis responsible for generating proxy objects.
The example of the "star agent" in the previous article is implemented as follows using dynamic agents:

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

interface IStar {
    
    
    void sing(double money);
}

class StarImpl implements IStar {
    
    
    public void sing(double money) {
    
    
        System.out.println("唱歌,收入" + money + "元");
    }
}

class MyInvocationHandler implements InvocationHandler {
    
    
    private Object target;

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

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
        System.out.println("请先预约时间");
        System.out.println("沟通出场费用");
        double money= (double) args[0];
        if (money < 100000) {
    
    
            System.out.println("对不起,出场费10w万以内不受理");
            return null;
        }

        System.out.println("经纪人抽取了"+ money * 0.2 + "代理费用");
        args[0] = money * 0.8;
        Object result = method.invoke(target, args);
        System.out.println("演唱完毕");
        return result;
    }
}

public class DynamicProxyExample {
    
    
    public static void main(String[] args) {
    
    
        //原始对象
        IStar mStar = new StarImpl();
        InvocationHandler handler = new MyInvocationHandler(mStar);

        //代理对象
        IStar proxyHello = (IStar) Proxy.newProxyInstance(
                mStar.getClass().getClassLoader(),
                mStar.getClass().getInterfaces(),
                handler
        );

        proxyHello.sing(200000);
    }
}

operation result:

请先预约时间
沟通出场费用
经纪人抽取了40000.0代理费用
唱歌,收入160000.0元
演唱完毕

An InvocationHandler proxies multiple interfaces

The core advantage of dynamic proxy is that one proxy class can proxy multiple interfaces. As shown below, the demonstration is a proxy handler that simultaneously proxies two interfaces, InterfaceA and InterfaceB:

package dynamic_proxy;

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

interface InterfaceA {
    
    
    void methodA();
}

interface InterfaceB {
    
    
    void methodB();
}

class ClassA implements InterfaceA {
    
    
    public void methodA() {
    
    
        System.out.println("执行methodA");
    }
}

class ClassB implements InterfaceB {
    
    
    public void methodB() {
    
    
        System.out.println("执行methodB");
    }
}

class MyInvocationHandler implements InvocationHandler {
    
    
    private Object target;

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

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
        if (method.getName().equals("methodA")) {
    
    
            System.out.println("调用methodA之前");
            Object result = method.invoke(target, args);
            System.out.println("调用methodA之后");
            return result;
        } else if (method.getName().equals("methodB")) {
    
    
            System.out.println("调用methodB之前");
            Object result = method.invoke(target, args);
            System.out.println("调用methodB之后");
            return result;
        } else {
    
    
            throw new UnsupportedOperationException("Unsupported method: " + method.getName());
        }
    }
}

public class DynamicProxyExample {
    
    
    public static void main(String[] args) {
    
    


        InvocationHandler handlerA = new MyInvocationHandler(new ClassA());

        InterfaceA proxyA = (InterfaceA) Proxy.newProxyInstance(
                handlerA.getClass().getClassLoader(),
                new Class[]{
    
    InterfaceA.class},
                handlerA
        );
        proxyA.methodA();

        InvocationHandler handlerB = new MyInvocationHandler(new ClassB());
        InterfaceB proxyB = (InterfaceB) Proxy.newProxyInstance(
                handlerB.getClass().getClassLoader(),
                new Class[]{
    
    InterfaceB.class},
                handlerB
        );
        proxyB.methodB();
    }
}

Code execution results:

调用methodA之前
执行methodA
调用methodA之后
调用methodB之前
执行methodB
调用methodB之后

Revealing the secrets of dynamic proxies will help you thoroughly understand dynamic proxies!

There is a dynamic proxy, why should we use Cglib proxy?

Dynamic proxy can only assign the proxy object to the interface, as in the above example. The proxy object cannot be directly assigned to a normal class. And the Cglib proxy can do it. How to do it specifically will be discussed in the next article.

Guess you like

Origin blog.csdn.net/zhangjin1120/article/details/132654735