什么是代理模式

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

  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的更多相关文章

  1. Hibernate 延迟加载的代理模式 和 Spring AOP的代理模式

    Hibernate 延迟加载的代理模式 和 Spring AOP的代理模式 主题 概念 Hibernate 延迟加载的代理模式 Spring AOP的代理模式 区别和联系 静态代理和动态代理 概念 代 ...

  2. 代理模式及Spring AOP (一)

    一.代理模式 在不更改源码的前提下,加入新功能,通常需要用到代理设计模式. 代理设计模式分类: 静态代理 动态代理 jdk动态代理 cglib动态代理 其中spring AOP的底层用的是动态代理.其 ...

  3. 代理模式及Spring AOP (二)

    一.Spring AOP   1.1 Spring AOP 底层还是用的动态代理.如果目标对象所对应的类有接口,spring就用jdk生成代理对象: 如果目标对象所对应的类没有接口,spring就用C ...

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

    如果不了解JDK中proxy动态代理机制的可以先查看上篇文章的内容:Java动态代理学习[Spring AOP基础之一] 由于Java动态代理Proxy.newProxyInstance()的时候会发 ...

  5. java代理课程测试 spring AOP代理简单测试

    jjava加强课程测试代码 反射. 代理 .泛型.beanUtils等 项目源码下载:http://download.csdn.net/detail/liangrui1988/6568169 热身运动 ...

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

    Spring AOP使用的其中一个底层技术就是Java的动态代理技术.Java的动态代理技术主要围绕两个类进行的 java.lang.reflect.InvocationHandler java.la ...

  7. 基于代理类实现Spring AOP

    目录 ProxyFactoryBean类介绍 基于JDK动态代理的Spring  AOP实现 基于CGLIB代理的Spring  AOP实现 Spring的通知类型 ProxyFactoryBean类 ...

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

    AOP是Aspect Oriented Programing的简称,面向切面编程.AOP适合于那些具有横切逻辑的应用:如性能监测,访问控制,事务管理以及日志记录.AOP将这些分散在各个业务逻辑中的代码 ...

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

    Spring AOP详解 . JDK动态代理.CGLib动态代理  原文地址:https://www.cnblogs.com/kukudelaomao/p/5897893.html AOP是Aspec ...

随机推荐

  1. idea debug 启动慢出现假死

    断点设置不合理引发应用启动慢问题java idea应用启动很慢|非常慢|超级慢的问题排查! 解决关于应用启动超慢这个问题,其实两年前就已经遇到过,https://blog.csdn.net/li396 ...

  2. Win8.1下安装sql server 2008 r2详解

    我是来斗图的,安装了好多次,有一些配置还是不能烂熟于心啊,所以就想起来了米老师那句话,学习是个反复的过程.写个教程吧,很简单但是很实用. 首先打开"setup.exe"出现以下界面 ...

  3. objectARX加载lisp函数、源码的一种方式

    //感谢高飞鸟highflybird版主的思路以及研究. //先声明非公开函数acedEvaluateLisp extern int acedEvaluateLisp(const ACHAR*,str ...

  4. Access MongoDB Data with Entity Framework 6

    This article shows how to access MongoDB data using an Entity Framework code-first approach. Entity ...

  5. iOS核心动画CALayer和UIView

    UIView和CALayer的关系. 每一个UIview都有一个CALayer实例的图层属性,也就是所谓的backing layer. 实际上这些背后关联的图层才是真正用来在屏幕上显示和做动画,UIV ...

  6. Numpy中扁平化函数ravel()和flatten()的区别

    在Numpy中经常使用到的操作由扁平化操作,Numpy提供了两个函数进行此操作,他们的功能相同,但在内存上有很大的不同. 先来看这两个函数的使用: from numpy import * a = ar ...

  7. [Alpha]Scrum Meeting#2

    github 本次会议项目由PM召开,时间为4月2日晚上10点30分 时长25分钟 任务表格 人员 昨日工作 下一步工作 木鬼 撰写内置问卷(issue#3) 撰写团队贡献分配计划(issue#39) ...

  8. struts2后台向前台传值为空

    今天遇到了一个bug,在后台定义了一个list,然后在前台展示,结果前台接手到的一直是个空,然后找了半天最后才知道是名字名字的问题,这个变量是第一个字母小写,然后第二个字母大写了,然后自动生成的get ...

  9. 基于iTop4412的FM收音机系统设计(一)

    说明:第一版架构为:APP+JNI(NDK)+Driver(linux),优点是开发简单,周期短,也作为自己的毕业设计 现在更新第二版,FM服务完全植入Android系统中,成为系统服务,架构为:AP ...

  10. 【实战分享】安卓app测试的一些记录

    一.app代码未混淆1.使用7zip解压apk文件2.执行命令:dex2jar.bat apk解压后文件夹中的classes.dex文件3.上述命令执行后会在apk文件夹中生成java源码文件clas ...