从代理模式到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这两个东西的。
参考文章:
以上是关于从代理模式到Spring AOP的主要内容,如果未能解决你的问题,请参考以下文章