什么是代理模式

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

  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. nowcoder(牛客网)OI测试赛3 解题报告

    昨天因为胡搞了一会儿社团的事情,所以错过(逃过)了nowcoder的测试赛..... 以上,听说还是普及组难度qwq,而且还有很多大佬AK(然而我这么蒻肯定还是觉得有点难度的吧qwq) 不过我还是日常 ...

  2. BZOJ2243 [SDOI2011]染色(LCT)

    传送门 明明是道树剖的题…… 然而我硬生生做成了LCT 虽然的确用LCT只是板子啦(LCT的题哪道不是板子) 就是把颜色打上标记,然后基本就是板子 //minamoto #include<bit ...

  3. Heap堆

    #pragma once#include<iostream>using namespace std;#include<vector> template<class T&g ...

  4. Layout2:StackPanel(补交作业)

    <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" > <Rect ...

  5. 阿里java开发规范学习(附P3C IDEA插件 帮助规范的养成)

    浅析 阿里巴巴 Java 开发规约 (未完成) 更加优秀的页面展现请到浅析 阿里巴巴 Java 开发规约 contents 为什么要学 编程规约 P3C IDEA 插件 why-use 我们知道,一般 ...

  6. animal与@keyframe

    .test1 { width: 90px; height: 60px; -webkit-animation-name: skyset; -webkit-animation-duration: 2000 ...

  7. HTML-JavaScript的DOM操作-非重点部分

    1.DOM的基本概念 DOM是文档对象模型,这种模型为树模型:文档是指标签文档(HTML文档),对象是指文档中每个元素:模型是指抽象划的东西. 2.Windows对象操作 一.属性和方法 属性(值或者 ...

  8. [原创]Redis 持久化说明及配置

    目录 参考链接 介绍 RDB 持久化 优点 缺点 相关配置参数 AOF 持久化 优点 缺点 相关配置参数 参考链接 持久化 Redis命令参考 介绍 Redis 运行时数据保存在内存中, 一旦重启则数 ...

  9. js 的常用方法和对象

    每日分享: 加油!你一定可以!你是最牛逼的!!!-------------------------------------------------------------------------- - ...

  10. springcloud(一)-初识

    springCloud简介 尽管springCloud带有“cloud”字样,但它并不是云计算解决方案,而是在SpringBoot基础上构建的,用于快速构建分布式系统的通用的工具集.从技术架构上降低了 ...