从代理模式到Spring AOP

Posted float123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从代理模式到Spring AOP相关的知识,希望对你有一定的参考价值。

什么是代理模式

           假如我喜欢上隔壁班的翠花,但是我没胆量向她送花,这时候我需要一个铁杆哥们帮我做这件事, 很明显这哥们是个代理,是去执行任务的,但是花实际上是我“送”的,代理和我一样会送花这个动作,直接上代码。

  1 public interface IProcess {
  2     void SendFlower();
  3 }

 

  1 public class Studnet1 implements IProcess {
  2 
  3     @Override
  4     public void SendFlower() {
  5         System.out.println("my name is Studnet1 , the flower is for you ");
  6     }
  7 }
  8 
  9 
 10 
 11 
 12 
 13 public class ProxyStudent implements IProcess {
 14 
 15     private IProcess targetObj;
 16 
 17     public ProxyStudent(IProcess targetObj) {
 18         this.targetObj = targetObj;
 19     }
 20 
 21     @Override
 22     public void SendFlower() {
 23         System.out.println("check it before send");
 24         targetObj.SendFlower();
 25         System.out.println("check it after send");
 26     }
 27 }
 28 

 

  1 public class ProcessFactory {
  2     public static IProcess getProcess(){
  3         return  new Studnet1();
  4     }
  5 }
  6 

 

  1 public class Main {
  2 
  3     public static void main(String[] args) {
  4         IProcess ProxyObj = ProcessFactory.getProcess();
  5         ProxyObj.SendFlower();
  6     }
  7 }

        运行结果:

  1 check it before send
  2 my name is Studnet1 , the flower is for you
  3 check it after send

        很开心,终于把花送出去了,可以见到调用代理者的SendFlower方法,实际上是我的SendFlower 方法,打到我需要送花的目的,同时这铁哥们人缘非常好,其他的同学也需要他来帮忙 , Student2, Student3 , Student4 也需要这铁哥们,

并且他们的要求不只是送花,还可能邀请看电影….等等,那么ProcessFatory 也要改写,另外假如我不止想送花这个动作,需要添加方法到接口上,那么其他类相应的也要改动。

  1 public class ProcessFactory {
  2     public static IProcess getProcess(){
  3         return  new Studnet1();
  4     }
  5 
  6     public static IHold getHold(){
  7         return  new Studnet2();
  8     }
  9 
 10     public static IMovie getMovier(){
 11         return  new Studnet3();
 12     }
 13 
 14     .....
 15 
 16 }

        显然这样的每次一个新的一个需求都需要创建一个对象,很不合理,于是就出现了动态代理。

 

动态代理

        先上代码,新建一个类,

  1 public class StuInvocationHandler<T> implements InvocationHandler {
  2     T target;
  3 
  4     public StuInvocationHandler(T target) {
  5         this.target = target;
  6     }
  7 
  8 
  9     @Override
 10     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 11         System.out.println("this is a proxy method");
 12         System.out.println("check it before sending");
 13         Object result = method.invoke(target, args);
 14         System.out.println("check it after sending ");
 15         return result;
 16     }
 17 }

      调用,输出结果:

  1 public class Main {
  2 
  3     public static void main(String[] args) {
  4         IProcess student1 = ProcessFactory.getProcess();
  5         InvocationHandler handler = new StuInvocationHandler<IProcess>(student1);
  6         IProcess ProxyStudent = (IProcess) Proxy.newProxyInstance(IProcess.class.getClassLoader(), new Class<?>[]{IProcess.class}, handler);
  7         ProxyStudent.SendFlower();
  8 
  9     }
 10 }
  1 this is a proxy method
  2 check it before sending
  3 my name is Studnet1 , the flower is for you
  4 check it after sending

        我们似乎看不到了代理类,实际上StuInvocationHandler就是我们的代理类,这时无论代理谁都可以进行操作,动态代理运用了java一个重要的特性—“反射” 。  我们需要知道两点:

  • 代理类调用方法使用了反射
  • 代理类继承了Proxy , 实现了被代理的接口,对应例子中的 IProcess , 由于java是单继承,所以也就决定了java动态代理只能对接口进行代理。

       在main方法中添加以下代码,

  1  byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", Studnet1.class.getInterfaces());
  2         String path = "E:StuProxy.class";
  3         try(FileOutputStream fos = new FileOutputStream(path)) {
  4             fos.write(classFile);
  5             fos.flush();
  6             System.out.println("代理类class文件写入成功");
  7         } catch (Exception e) {
  8             System.out.println("写文件错误");
  9         }

         在E盘中就会有一个StuProxy.class 文件,这个就是代理类, 我们用反编译工具java decompiler查看源代码,

  1 import com.benjious.IProcess;
  2 import java.lang.reflect.InvocationHandler;
  3 import java.lang.reflect.Method;
  4 import java.lang.reflect.Proxy;
  5 import java.lang.reflect.UndeclaredThrowableException;
  6 
  7 public final class $Proxy0
  8   extends Proxy
  9   implements IProcess
 10 {
 11   private static Method m1;
 12   private static Method m3;
 13   private static Method m2;
 14   private static Method m0;
 15 
 16   public $Proxy0(InvocationHandler paramInvocationHandler)
 17     throws
 18   {
 19     super(paramInvocationHandler);
 20   }
 21 
 22   public final boolean equals(Object paramObject)
 23     throws
 24   {
 25     try
 26     {
 27       return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
 28     }
 29     catch (Error|RuntimeException localError)
 30     {
 31       throw localError;
 32     }
 33     catch (Throwable localThrowable)
 34     {
 35       throw new UndeclaredThrowableException(localThrowable);
 36     }
 37   }
 38 
 39   public final void SendFlower()
 40     throws
 41   {
 42     try
 43     {
 44       this.h.invoke(this, m3, null);
 45       return;
 46     }
 47     catch (Error|RuntimeException localError)
 48     {
 49       throw localError;
 50     }
 51     catch (Throwable localThrowable)
 52     {
 53       throw new UndeclaredThrowableException(localThrowable);
 54     }
 55   }
 56 
 57   public final String toString()
 58     throws
 59   {
 60     try
 61     {
 62       return (String)this.h.invoke(this, m2, null);
 63     }
 64     catch (Error|RuntimeException localError)
 65     {
 66       throw localError;
 67     }
 68     catch (Throwable localThrowable)
 69     {
 70       throw new UndeclaredThrowableException(localThrowable);
 71     }
 72   }
 73 
 74   public final int hashCode()
 75     throws
 76   {
 77     try
 78     {
 79       return ((Integer)this.h.invoke(this, m0, null)).intValue();
 80     }
 81     catch (Error|RuntimeException localError)
 82     {
 83       throw localError;
 84     }
 85     catch (Throwable localThrowable)
 86     {
 87       throw new UndeclaredThrowableException(localThrowable);
 88     }
 89   }
 90 
 91   static
 92   {
 93     try
 94     {
 95       m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
 96       m3 = Class.forName("com.benjious.IProcess").getMethod("SendFlower", new Class[0]);
 97       m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
 98       m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
 99       return;
100     }
101     catch (NoSuchMethodException localNoSuchMethodException)
102     {
103       throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
104     }
105     catch (ClassNotFoundException localClassNotFoundException)
106     {
107       throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
108     }
109   }
110 }
111 

 

动态代理的弊端

         java动态代理只能对接口进行代理。这个在源代码中也可以看到,CGLib可以解决这个问题,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

         再回想一下,调用invoke方法前后我们都是可以进行其他操作的,实际上这就是Spring里的AOP,Spring的AOP实现其实也是用了Proxy和InvocationHandler这两个东西的。

 

 

参考文章:

1.https://www.cnblogs.com/gonjan-blog/p/6685611.html

2.http://www.importnew.com/22015.html

以上是关于从代理模式到Spring AOP的主要内容,如果未能解决你的问题,请参考以下文章

从代理机制到Spring AOP,这篇给你安排的明明白白的

代理模式 - spring aop 抛砖

代理模式 - spring aop 抛砖

Spring的Aop是采用的啥设计模式?

阿里四面:你知道Spring AOP创建Proxy的过程吗?

spring-aop