代理模式

故事扮演 提交于 2020-04-29 16:52:23

需求场景

我们引用了开源jar包,需要扩展。我们又不能直接改jar包,违反了开闭原则。通常我们使用代理模式,在中间加一层。软件行业有句话:”如果解决不了,就加一层“。

静态代理

步骤

  1. 第三方jar包中的目标类(即被代理类);
  2. 我们创建一个代理类,和目标类实现同样的接口,在内部调用目标类。
  3. 在代码中使用。
/**
 * 第三方jar包中的:目标类接口
 *
 * @author lsh by 2020/4/29
 */
public interface DoSthService {
    void doSth();
}
/**
 * 第三方jar包中的:目标类实现类
 *
 * @author lsh by 2020/4/29
 */
public class DoSthServiceImpl implements DoSthService {
    @Override
    public void doSth() {
        System.out.println("被代理类 do sth");
    }
}
/**
 * 静态代理类
 *
 * @author lsh by 2020/4/29
 */
public class DoSthServiceImplProxy implements DoSthService {
    @Override
    public void doSth() {
        // 加前置逻辑
        System.out.println("before...");
        // 委托给被代理类执行
        // 这里也可以构造器注入
        DoSthService service = new DoSthServiceImpl();
        service.doSth();
        // 加后置逻辑
        System.out.println("after...");
    }
}
// 代码中直接使用代理类即可
DoSthServiceImplProxy proxy = new DoSthServiceImplProxy();
proxy.doSth();

缺点

如果这个接口有很多方法,每个方法都要重写,很麻烦。

动态代理

JDK动态代理

步骤

  1. 创建一个实现了InvocationHandler接口的类,这个类中写清楚前后处理逻辑;
  2. 业务代码中用Proxy.newProxyInstance方法创建代理类;
/**
 * 增强类:只有增强逻辑,没有任何目标类相关信息,完全解耦
 * 
 * @author lsh by 2020/4/29
 */
public class JDKDynamicProxyEnhance implements InvocationHandler {
    /**
     * 这是一个Object类,只有运行时才知道传入的具体目标类
     */
    private Object object;

    public JDKDynamicProxyEnhance(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("jdk proxy...before...");
        // 编写代码时,这里无需知道被代理的方法名,运行时动态传入
        Object invoke = method.invoke(object, args);
        System.out.println("jdk proxy...after...");
        return invoke;
    }
}

// 业务代码中需要三个参数:
// 1.创建第三方jar包中目标类的对象,这里可以是任何类的对象
// 2. 根据这个对象创建实现了InvocationHandler接口的增强类,
DoSthService service = new DoSthServiceImpl();
JDKDynamicProxyEnhance enhance = new JDKDynamicProxyEnhance(service);
DoSthService proxy = (DoSthService) Proxy.newProxyInstance(service.getClass().getClassLoader(), new Class[]{DoSthService.class},
        enhance);
// 3. 业务中使用
proxy.doSth();

总结

从上面的代码中可以看到,动态代理定义增强类的时候,无需知道这个增强器是增强哪个类。就像我们生产了一个发动机,但是不知道以后会用在什么车上一样。只有用到的时候才会组装成整体。这里也是一样,只有用到的时候才告诉增强器要增强的类,然后用Proxy.newProxyInstance组装焊接成一个整体Proxy。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!