设计模式8:代理模式-动态代理

上一篇:设计模式8:代理模式-静态代理

如何理解“动态”这两个字?

“动态”的含义是代码生成代理类,一个代理类可以代理多个接口

动态区别于死板,静态代理中一个代理类只能代理一个接口,其他不同的接口,就需要再手写不同的代理类,这就很死板

动态代理类似于在安卓里面,我们常说的动态申请权限,其实就是用java或kotlin代码申请权限,而不是在AndroidManifest.xml文件里面写死一次可以申请一个或多个权限

上一篇:中,StationProxyStarProxy都是我们手写的代理类。动态代理可以自动生成代理类。

动态代理简单的代码实例

动态代理需要jdk中提供的两个类InvocationHandlerProxy,重写InvocationHandler接口实现代理方法,Proxy负责生成代理对象。
上篇文章中“明星代理”的例子,用动态代理实现如下:

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);
    }
}

运行结果:

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

一个InvocationHandler代理多个接口

动态代理的核心优势就在于,一个代理类,可以代理多个接口。如下,演示的是一个代理handler,同时代理两个接口InterfaceA和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();
    }
}

代码执行结果:

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

动态代理大揭秘,带你彻底弄清楚动态代理!

有动态代理,为什么还要用Cglib代理?

动态代理只能把代理对象,赋值给接口,如上面的例子。不能把代理对象直接赋值一个普通类。而Cglib代理可以做到。具体怎么做的,下篇文章再讲。

猜你喜欢

转载自blog.csdn.net/zhangjin1120/article/details/132654735