代理模式

在学习Spring Aop时,使用了动态代理,所以学习了代理模式,静态代理,动态代理,Cglib动态代理,整理blog记录自己的学习笔记

静态代理

1.定义

为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。通过代理对象访问目标对象,防止直接访问目标对象造成系统复杂性提升.

 

2.原理

 

Subject : 接口,为RealSubject和ProxySubject提供一致性的接口

RealSubject : 目标访问类,实际的主体,实现Subject接口的类

ProxySubject : 代理类,处理Client的请求,只有当代理类无法回复请求时,才会调用目标访问类

Client : 请求者

 

3.适用场景

Virtual Proxy : 对于一些占用系统资源较多或者加载时间较长的对象,可以给这些对象提供一个虚拟代理。在真实对象创建成功之前虚拟代理扮演真实对象的替身,而当真实对象创建之后,虚拟代理将用户的请求转发给真实对象。

Remote Proxy : 远程代理使得客户端可以访问远程主机上的对象,远程代理可以把网络的细节隐藏起来,使得客户端不必考虑网络的存在,客户端完全可以认为调用的远程代理对象在本地,而不是在远程

Cache Proxy : 某一个操作的结果提供临时的缓存存储空间,以便在后续使用中能够共享这些结果,从而可以避免某些方法的重复执行,优化系统性能。 

Access Proxy : 可以在调用RealSubject时做访问限制,通过代理过滤不可以访问的对象 

 

4.实现

Printable.java

public interface Printable {
    void setPrintName(String name);

    String getPrintName();

    void print(String str);
}  

Printer.java

public class Printer implements Printable {
    private String name;

    public Printer() {
        heavyJob("正在生成Printer的实例");
    }

    public Printer(String name) {
        this.name = name;
        heavyJob("正在生成(Printer)" + name + "的实例");
    }


    @Override
    public void setPrintName(String name) {
        this.name = name;
    }

    @Override
    public String getPrintName() {
        return this.name;
    }

    @Override
    public void print(String str) {
        System.out.println("==" + name + "==");
        System.out.println(str);
    }

    public void heavyJob(String msg) {
        System.out.println(msg);
        for (int i = 0; i < 5; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.print(".");
        }
        System.out.println("over");
    }
}  

PrintProxy.java

public class PrintProxy implements Printable {
    private String name;
    private Printer real;

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

    @Override
    public synchronized void setPrintName(String name) {
        if (real != null) {
            real.setPrintName(name);
        }
        this.name = name;
    }

    @Override
    public String getPrintName() {
        return this.name;
    }

    @Override
    public void print(String str) {
        realize();
        real.print(str);
    }

    public synchronized void realize() {
        if (real == null) {
            real = new Printer(name);
        }
    }
}  

Main.java

public class Main {
    public static void main(String[] args) {
        Printable p = new PrintProxy("kristin");
        System.out.println("name: " + p.getPrintName());
        p.setPrintName("kkk");
        System.out.println("new name: " + p.getPrintName());
        p.print("hello world");
    }
}

  

Printable相当于Subject

Printer相当于RealSubject

PrinterProxy相当于ProxySubject

Main相当于Client

 

5.优缺点

优点:

协调调用者与被调用者,降低耦合度

作为客户端对象与目标对象的中介,可以有效地保护目标对象

缺点:

在客户端与目标对象之间增加了代理对象,处理请求的速度可能会变慢

如果代理的实现复杂,可能会增加系统实现的复杂性

如果想要为多个类进行代理,需要创建多个代理类,维护难度加大 

JDK动态代理

1.定义

代理类在程序运行时被创建,并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的.

 

2.原理

在java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过这个类和这个接口可以生成JDK动态代理类和动态代理对象。

 

3.实现

UserDao.java

public interface UserDao {
    void add();
}

UserDaoImpl.java

public class UserDaoImpl implements UserDao {
    @Override
    public void add() {
        System.out.println("------------add------------");
    }
}

MyInvocationHandler.java

public class MyInvocationHandler implements InvocationHandler {
    private Object target;

    public void setProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("-------------before-------------");
        Object result = method.invoke(target, args);
        System.out.println("-------------after-------------");
        return result;
    }

}

MyProxy.java

public class MyProxy {
    public static void main(String[] args) {
        UserDao user = new UserDaoImpl();
        MyInvocationHandler handler = new MyInvocationHandler();
        handler.setProxy(user);
//        UserDao userDao = (UserDao) Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(), handler);
        UserDao userDao = (UserDao) Proxy.newProxyInstance(UserDao.class.getClassLoader(), new Class[]{UserDao.class}, handler);
        userDao.add();
    }
}

Output

-------------before-------------
------------add------------
-------------after-------------

  

4.应用 

如果想对代理类的所有方法都加上日志,可以通过动态代理可以对代理类的所有方法进行统一的处理,而不用一一更改每一个方法. 

Cglib动态代理

1.定义

 cglib是针对类来实现代理的,它的原理是对指定的目标类生成一个类,并覆盖其中方法实现增强

2.原理

代理类将委托类作为自己的父类并为其中的非final委托方法创建两个方法,一个是与委托方法签名相同的方法,它在方法中会通过super调用委托方法;另一个是代理类独有的方法。在代理方法中,它会判断是否存在实现了MethodInterceptor接口的对象,若存在则将调用intercept方法对委托方法进行代理.

3.应用

UserDao.java

public interface UserDao {
    void add();
}  

 

UserDaoImpl.java

public class UserDaoImpl implements UserDao {
    public void add() {
        System.out.println("the method is running");
    }
}

 

Interceptor.java

public class Interceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("-------------------before------------------");
        proxy.invokeSuper(obj, args);
        System.out.println("--------------------after-------------------");
        return null;
    }
}

 

Main.java

public class Main {
    @org.junit.jupiter.api.Test
    public void test() {
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:\\code");
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserDaoImpl.class);
        enhancer.setCallback(new Interceptor());
        UserDao userDao = (UserDao) enhancer.create();
        userDao.add();
    }
}

 

Output

CGLIB debugging enabled, writing to 'E:\code'
-------------------before------------------
the method is running
--------------------after-------------------

  

  

  

  

 

posted @ 2018-05-11 15:34  KristinLee  阅读(169)  评论(0编辑  收藏  举报
jQuery火箭图标返回顶部代码