大话设计模式:动态代理模式

由于静态代理带来扩展性差,可维护性差等缺点,所以就有了动态代理模式。

下面介绍一下JDK的动态代理:

动态代理有两个重要的类:

1. Proxy类:

provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.

它是所有动态代理类的父类,同时提供一个静态方法来创建代理类的实例,方法名叫:newProxyInstance

2. InvocationHandler接口:

Processes a method invocation on a proxy instance and returns the result.  This method will be invoked on an invocation handler when a method is invoked on a proxy instance that it is associated with.

其中只有一个方法invoke,大致是:在代理类的实例中调用真实方法,并返回结果。

有三个参数:

1. proxy:代理对象的实例

2. method: 通过它可以调用真实方法

3. args:传过来的参数

动态代理的简单应用:

1. 创建实现InvocationHandler接口的代理类:

/**
 * description 实现InvocationHandler接口的动态代理类
 *
 * @author 70KG
 * @date 2018/8/2
 */
public class ProxyClassBeans implements InvocationHandler {

    /**
     * 被代理的对象
     **/
    private Object tar;

    /**
     * 利用反射来调用目标方法
     **/
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        doBefore();
        Object invoke = method.invoke(tar, args);
        doAfter();
        return invoke;
    }

    /** 绑定该类实现的所有接口,取得代理类 **/
    public Object getProxyInstance() {
        return Proxy.newProxyInstance(tar.getClass().getClassLoader(), tar.getClass().getInterfaces(), this);
    }

    // ===================动态代理类中的增强方法========================

    public void doBefore() {
        System.out.println("在国外寻找优质的货源。");
    }

    public void doAfter() {
        System.out.println("精包装安全邮寄回国内。");
    }

    // ===========================get/set=============================


    public Object getTar() {
        return tar;
    }

    public void setTar(Object tar) {
        this.tar = tar;
    }
}

2. 接口

/**
 * description
 *
 * @author 70KG
 * @date 2018/8/1
 */
public interface IBusinessA {

    /**
     * Description: 卖包的业务接口
     * Author:70KG
     * Param [brand] 品牌
     * Return void
     * Date 2018/8/1 9:46
     */
    void saleBag(String brand);

}
/**
 * description
 *
 * @author 70KG
 * @date 2018/8/1
 */
public interface IBusinessB {

    /**
     * Description: 卖手表的业务接口
     * Author:70KG
     * Param [brand] 品牌
     * Return void
     * Date 2018/8/1 9:48
     */
    void saleWatch(String brand);

}

3. 实现规定接口的被代理类

/**
 * description
 *
 * @author 70KG
 * @date 2018/8/1
 */
public class CompanyA implements IBusinessA {

    @Override
    public void saleBag(String brand) {
        System.out.println("从国外A公司买到一款" + brand + "牌的包。");
    }

}
/**
 * description
 *
 * @author 70KG
 * @date 2018/8/1
 */
public class CompanyB implements IBusinessB {

    @Override
    public void saleWatch(String brand) {
        System.out.println("从国外B公司买到一款" + brand + "牌的手表。");
    }

}

4. 测试方法:

/**
 * description
 *
 * @author 70KG
 * @date 2018/8/2
 */
public class MainTest {

    public static void main(String[] args) {
        ProxyClassBeans proxyClassBeans = new ProxyClassBeans();

        IBusinessA companyA = new CompanyA();
        proxyClassBeans.setTar(companyA);
        IBusinessA instance1 = (IBusinessA) proxyClassBeans.getProxyInstance();
        instance1.saleBag("Gucci");

        System.out.println("=================================");

        IBusinessB companyB = new CompanyB();
        proxyClassBeans.setTar(companyB);
        IBusinessB instance2 = (IBusinessB) proxyClassBeans.getProxyInstance();
        instance2.saleWatch("Tissot");
    }

}

5. 运行结果:

在国外寻找优质的货源。
从国外A公司买到一款Gucci牌的包。
精包装安全邮寄回国内。
=================================
在国外寻找优质的货源。
从国外B公司买到一款Tissot牌的手表。
精包装安全邮寄回国内。

6. JDK的动态代理只能代理接口,不能代理具体的类,通过JDK生成的代理类:public final class $Proxy0 extends Proxy implements YourInterface {},Java只支持单继承,所以不能代理具体类了。

相比静态代理,当业务扩展或者参数变动的时候,我们不需要改动代理类,只需要生成相应的代理实例,并传入接口需要的参数就好了,这样扩展性和维护性大大提高。

动态代理源码的简单分析:

debug跟进生成的代理类

这个代理类的名字很特殊,跟一下源码

跟进 Class<?> cl = getProxyClass0(loader, intfs);

跟进get方法

跟进apply方法

动态代理的源码大概就这么多了。

原文地址:https://www.cnblogs.com/zhangjianbing/p/9406576.html