设计模式-动态代理

166 阅读2分钟

代理模式:客户端并不直接访问服务端,而是通过调用代理,来间接调用实际的对象。

有两种实现方式:

  • 静态代理:

    代理类和目标类是确定的;

    在不修改目标对象功能的前提下,对目标功能进行扩展;

  • 动态代理:根据代理对象,动态的创建代理类。本质是通过反射实现的

public interface Person {

    //交作业
    void giveTask();
}
public class Student implements Person {

    private String name;

    public Student(String name) {
        this.name = name;
    }

    @Override
    public void giveTask() {
        System.out.println(String.format("%s交语文作业", name));
    }
}
/**
 * 每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,
 * 当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke方法来进行调用。
 */
public class StuInvocationHandler<T> implements InvocationHandler {

    //invocationHandler持有的被代理对象
    T target;

    public StuInvocationHandler(T target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理执行" + method.getName() + "方法");
        return method.invoke(target, args);
    }

动态代理测试:

@Test
public void dynamicProxy() {
    //创建一个实例对象,这个对象是被代理的对象
    Person linqian = new Student("林浅");

    //创建一个与代理对象相关联的InvocationHandler
    InvocationHandler stuHandler = new StuInvocationHandler<>(linqian);

    //创建一个代理对象stuProxy来代理linqian,代理对象的每个执行方法都会替换执行Invocation中的invoke方法
    Person stuProxy = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, stuHandler);

    // 代理执行交作业方法
    stuProxy.giveTask();
}

静态代理与动态代理的区别

  • 静态代理只能通过手动完成代理操作,如果被代理类增加了新方法,代理类需要同步增加,违背了开闭原则;
  • 动态代理采用在运行时动态生成代码的方式,取消了被代理类的扩展限制,遵循开闭原则;
  • 若动态代理对目标类进行增强逻辑扩展,只需要新增策略便可完成,无需修改代理类代码;