从代理模式到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

原文地址:https://www.cnblogs.com/Benjious/p/9302016.html

时间: 2024-10-09 06:33:34

从代理模式到Spring AOP的相关文章

代理模式 与 Spring AOP

AOP:在一个服务的流程中插入与业务逻辑无关的系统服务逻辑(例如Logging.Security),这样的逻辑称为Cross-cutting concerns,将Cross-cutting concerns独立出来设计为一个对象,这样的特殊对象称之为Aspect,Aspect-oriented programming着重在Aspect的设计上以及与应用程序的织入(Weave). 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把

CgLib动态代理学习【Spring AOP基础之一】

如果不了解JDK中proxy动态代理机制的可以先查看上篇文章的内容:Java动态代理学习[Spring AOP基础之一] 由于Java动态代理Proxy.newProxyInstance()的时候会发现其参数类型是ClassLoader classLoader, Class<?>[] interface, InvocationHandler handler, 只支持根据接口实现代理类,如果所有代码都是自己掌控,当然没有问题.所有的业务逻辑均抽象出接口,然后所有的业务类实现接口,这样所有的业务类

java动态代理,及spring AOP

介绍:spring 的AOP (Aspect Oriented Programming)是通过java的动态代理来实现的,对于AOP不了解的朋友可以去网上看相关资料,我这里重点说明实现原理即java动态代理 要谈java动态代理就不得不说java的代理模式,我这里只给出代理模式的UML图 如图(1)及动态代理模式的UML类图 如图(2) 说明:图(2)中的红色红色斜体的类或接口是由java类库提供的即 Proxy和InvocationHandler 是java对动态代理的支持 图 (1) 和 图

Java 设计模式(八) Proxy(代理)模式及Spring引申

Proxy 基本概念 代理模式(Proxy pattern)是一种使用率非常高的模式: 为其他对象提供一种代理以控制对这个对象的访问 代理模式也叫作委托模式,它是一项基本设计技巧 Proxy中的角色 Subject(抽象主题类):既可以是抽象类也可以是抽象的接口 RealSubject(具体的主题角色):是被委托角色或者说是被代理角色 Proxy(代理主题角色):是委托类或者代理类: 它负责对真实的角色的应用 把Subject定义的方法限制委托给RealSubject实现 在RealSubjec

Java动态代理学习【Spring AOP基础之一】

Spring AOP使用的其中一个底层技术就是Java的动态代理技术.Java的动态代理技术主要围绕两个类进行的 java.lang.reflect.InvocationHandler java.lang.reflect.Proxy 首先从代码层面说明Java动态代理是如何实现的, 业务逻辑接口: /** * 创建一个人的接口,其中有一个吃的方法 */ public interface Person { public void eat(); } 创建一个实现该业务接口的类: /** * 人接口的

基于代理类实现Spring AOP

目录 ProxyFactoryBean类介绍 基于JDK动态代理的Spring  AOP实现 基于CGLIB代理的Spring  AOP实现 Spring的通知类型 ProxyFactoryBean类 虽然直接使用代理就可以创建代理的实例,但需要自己写创建代理的方法,比如JDK动态代理: 1 ........ 2 //创建代理方法,参数是目标接口的实例 3 public Object createProxy(UserInterface user){ 4 this.user=user; //初始化

Spring AOP详解 、 JDK动态代理、CGLib动态代理

AOP是Aspect Oriented Programing的简称,面向切面编程.AOP适合于那些具有横切逻辑的应用:如性能监测,访问控制,事务管理以及日志记录.AOP将这些分散在各个业务逻辑中的代码通过横向切割的方式抽取到一个独立的模块中. 一.AOP术语 1.连接点(Joinpoint) 程序执行的某个特定位置:如类开始初始化之前.类初始化之后.类某个方法调用前.调用后等:一个类或一段程序代码拥有一些具有边界性质的特定点,这些代码中的特定点就成为“连接点”,Spring仅支持方法的连接点,即

【转载】Spring AOP详解 、 JDK动态代理、CGLib动态代理

原文地址:https://www.cnblogs.com/kukudelaomao/p/5897893.html AOP是Aspect Oriented Programing的简称,面向切面编程.AOP适合于那些具有横切逻辑的应用:如性能监测,访问控制,事务管理以及日志记录.AOP将这些分散在各个业务逻辑中的代码通过横向切割的方式抽取到一个独立的模块中. 一.AOP术语 1.连接点(Joinpoint) 程序执行的某个特定位置:如类开始初始化之前.类初始化之后.类某个方法调用前.调用后等:一个类

Spring AOP 实现原理(三) 使用 使用 CGLIB 生成代理类

CGLIB(Code Generation Library),简单来说,就是一个代码生成类库.它可以在运行时候动态是生成某个类的子类. 此处使用前面定义的 Chinese 类,现在改为直接使用 CGLIB 来生成代理,这个代理类同样可以实现 Spring AOP 代理所达到的效果. 下面先为 CGLIB 提供一个拦截器实现类: public class AroundAdvice implements MethodInterceptor { public Object intercept(Obje