什么是代理模式

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

  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. Eclipse无法正常创建android工程解决方法!

    我最近升级了安卓的SDK,升级后发现无法在Eclipse中创建android工程了,创建的工程完毕后,没有自动生成这个工程的activity和对应的布局文件,上网搜索一番,最后终于解决了.可能是升级后 ...

  2. [Flex] 组件Tree系列 —— 支持CheckBox组件

    主程序mxml: <?xml version="1.0" encoding="utf-8"?> <!--功能描述:支持CheckBox--&g ...

  3. [ActionScript 3.0] 结合FMS实现简单视频录制

    首先在本机上安装Flash Media Server,简称FMS,在测试过程中window防火墙开启可能有影响,可先关闭防火墙,FMS安装好后检查相关服务有没有启动,若没有,可启动任务管理器,点击服务 ...

  4. JMessage Android 端开发详解

    目前越来越多的应用会需要集成即时通讯功能,这里就为大家详细讲一下如何通过集成 JMessage 来为你的 App 增加即时通讯功能. 首先,一个最基础的 IM 应用会需要有哪些功能? 用户注册 / 登 ...

  5. The input file was not found

    错误位置: File file= new File("/report/_test/test.xls");Workbook wb1 = jxl.Workbook.getWorkboo ...

  6. 关于前后台DOM树应用

    Dom对象是在程序开发中很实用而且经常会应用到的技术,通过Dom对象可以传递具有树结构的对象,有利用前台页面的诸如树的显示和相应值的处理,本文从两个方面全面解析Dom对象的应用,一是从后台得到完整的D ...

  7. CSS的nth-of-type和nth-child的区别

    <!--源代码--><!DOCTYPE html> <html lang="en"> <head> <meta charset ...

  8. vue中vueRouter使用

    首先需要安装依赖:

  9. 如何打开java监控

    直接在cmd中输入 1.jconsole 2.jvisualvm

  10. Ubuntu18.04安装thunderbird并设置中文

    Ubuntu18.04安装thunderbird并设置中文 安装thunderbird sudo apt-get install thunderbird 安装中文包 sudo apt-get inst ...