通过代理模式可以在不修改原对象代码的基础上,对业务逻辑与功能性逻辑进行解耦,对源对象的功能进行修改或者增强(日志、权限控制)。

定义以及目的


  • 定义:代理模式(Proxy Pattern)即为某一个对象提供一个代理对象,由代理对象来接管被代理对象的各个方法的访问。

    通俗说,房东想要出租房屋,出租房屋需要:找租客—>看房—>租客不应定满意,循环上一过程—>办各种手续—>签合同。而房东的意图很简单,就是把房屋出租,所以都是累赘的步骤,这个时候就有了房屋中介,代理房东,去找租客、看房、办手续、最后签订三方合同,成功把房屋出租出去。在这个过程中,房屋中介就承担了代理的作用,帮助房东完成多余步骤,达到出租房屋的根本目的。

代理模式,就是在不改变主体方法的情况下,对主体方法的增强(日志、记录等操作)

  • UML类图

image.png

  • Subject(共同接口):客户端使用的现有接口
  • RealSubject(真实对象):真实对象的类
  • ProxySubject(代理对象):代理类

按照代理类的创建时期,代理类可分为两种:

  • 静态代理类:由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
  • 动态代理类:在程序运行时,运用反射机制动态创建而成

Java中可以通过三种方式创建代理对象:

  • 静态代理
  • 基于JDK(接口)的动态代理
  • 基于CGLIB(父类)的动态代理

    静态代理

    需要手工编写代理类代码,经过编译后执行。编写代理类,实现目标类的接口或直接继承目标类,完成逻辑的修改。 ```java public interface Subject { public void dosomething(); }

public class RealSubject implements Subject { @Override public void dosomething() { System.out.println(“dosomething….”); } }

public class SubjectProxy implements Subject{

  1. public Subject subject;
  2. public SubjectProxy(Subject subject){
  3. this.subject = subject;
  4. }
  5. @Override
  6. public void dosomething() {
  7. dosomethingBefore();
  8. subject.dosomething();
  9. dosomethingAfter();
  10. }
  11. private void dosomethingAfter() {
  12. System.out.println("dosomthing-before....");
  13. }
  14. private void dosomethingBefore() {
  15. System.out.println("dosomthing-after....");
  16. }

}

  1. public static void main(String[] args) {
  2. Subject subject = new SubjectProxy(new RealSubject());
  3. subject.dosomething();
  4. }

———调用结果 dosomthing-after…. dosomething…. dosomthing-before….

  1. 静态代理虽然简单,但是缺点也很明显:在需求接口和实现类很多的情况下,要为每个需求都建立一个工厂类(例如为需求增加日志需求,需要为所有service都添加代理类吗?),在接口或者父类发生变动的时候,代理类也需要进行改变。
  2. <a name="SiwDN"></a>
  3. ## 动态代理
  4. 动态代理是在内存中生成代理对象的一种技术(代理类的字节码将在运行时生成并载入当前的ClassLoader),也就是整个代理过程在内存中进行,不需要像静态代理那样需要去手写代理类代码,也不存在代理类编译过程,动态代理合理的避免了静态代理的那种方式,不用事先为要代理的类而构建好代理类。而是在运行时通过反射机制创建。尽管动态代理需要利用到反射机制和动态生成字节码,导致其性能会比静态代理稍差一些,但是相对于它的有点,这点劣势可以忽略不计。一般动态代理使用JDK或者CGLIB实现静态代理。<br />动态代理模式通过使用反射,可以在运行期决定加载哪个类,避免了一个类对应一个代理的问题;同时,通过统一的invoke方法,统一了代理类对原函数的处理过程,使用动态代理很大程度上减少了重复的代码,降低了维护的复杂性和成本。
  5. <a name="PGoVt"></a>
  6. ### 基于JDK(接口)的动态代理
  7. Jdk的动态代理是基于接口的。现在想要为RealSubject这个类创建一个动态代理对象,Jdk主要会做一下工作:
  8. 1. 获取RealSubject上的所有接口列表
  9. 1. 确定要生成的代理类的类名,默认为:com.sun.proxy.$ProxyXXXX
  10. 1. 根据需要实现的接口信息,在代码中动态创建该Proxy类的字节码;
  11. 1. 将对应的字节码转换为对于的class对象;
  12. 1. 创建InvocationHandler实例handler,用来处理Proxy所有方法的调用;
  13. 1. Proxyclass对象以创建的handler对象为参数,实例化一个proxy对象;
  14. Jdk通过java.lang.reflect.Proxy包来支持动态代理,在Java中要创建一个代理对象,必须调用Proxy类的静态方法newProxyInstance,该方法的原型如下:
  15. ```java
  16. - ClassLoader loader : 表示类加载器,对于不同来源(系统库或网络等)的类需要不同的类加载器来加载,这是Java安全模型的一部分。可以使用null来使用默认的加载器;不过一般使用被代理类的加载器
  17. - Class<?>[] interfaces : 表示接口或对象的数组,指被代理对象和真实对象都必须共有的父类或者接口;
  18. - InvocationHandler handler : 表示调用处理器,它必须是实现了InvocationHandler接口的对象,其作用是定义代理对象中需要执行的具体操作。
  19. Object Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler) throws IllegalArgumentException

InvocationHandler之于Proxy,就如Runnable之于Thread。InvocationHandler接口中只有一个方法invoke,它的作用就跟Runnable中的run方法类似,定义了代理对象在执行真实对象的方法时所希望执行的动作。其原型如下:

  1. - Object proxy : 表示执行这个方法的代理对象;
  2. - Method method : 表示真实对象实际需要执行的方法
  3. - Object[] args : 表示真实对象实际执行方法时所需的参数
  4. Object invoke(Object proxy, Method method, Object[] args) throws Throwable

  在实际的编程中,需要优先定义一个实现InvocationHandler接口的调用处理器对象,然后将它作为创建代理类实例的参数。(抑或在调用newProxyInstance方法时使用匿名内部类。)这样就得到了代理对象。
真实对象本身的实例化在调用处理器对象内部完成,实例化时需要的参数也应该及时传入调用处理器对象中。这样一来就完成了代理对象对真实对象的包装,而代理对象需要执行的额外操作也在invoke方法中处理。

CGLIB动态代理

Jdk的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用jdk代理,这就要用到CGLIB代理了。CGLIB是针对类来实现的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
CGLIB创建某个类A的动态代理类的模式是:

  1. 查找A上的所有非final的public类型的方法定义
  2. 将这些方法的定义转换成字节码
  3. 将组成的字节码转换成相应的代理的class对象
  4. 实现MethodInterceptor接口,用来处理对代理类上所有方法的请求(这个接口和Jdk动态代理InvocationHandler的功能和角色是一样的) ```java public class RealSubjectCglib { public String operate(){
    1. return "RealSubjectCglib";
    } }

public class ProxyCglib implements MethodInterceptor { private Object target;

  1. public Object getInstance(Object target)
  2. {
  3. this.target = target;
  4. //Cglib中的加强器,用来创建动态代理
  5. Enhancer enhancer = new Enhancer();
  6. //设置要创建动态代理的类
  7. enhancer.setSuperclass(this.target.getClass());
  8. //设置回调,这里相当于是对于代理类上所有方法的调用,都会调用Callback,而Callback则需要实现intercept()方法进行拦截
  9. enhancer.setCallback(this);
  10. Object obj = enhancer.create();
  11. return obj;
  12. }
  13. @Override
  14. public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable
  15. {
  16. System.out.print("I'm Proxy, I'm invoking...");
  17. Object object = proxy.invokeSuper(obj, args);
  18. System.out.println(object);
  19. return object;
  20. }

}

ProxyCglib proxy = new ProxyCglib(); RealSubjectCglib cglib = (RealSubjectCglib)proxy.getInstance(new RealSubjectCglib()); cglib.operate();

```