从代理模式到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
从代理模式到Spring AOP的更多相关文章
- Hibernate 延迟加载的代理模式 和 Spring AOP的代理模式
Hibernate 延迟加载的代理模式 和 Spring AOP的代理模式 主题 概念 Hibernate 延迟加载的代理模式 Spring AOP的代理模式 区别和联系 静态代理和动态代理 概念 代 ...
- 代理模式及Spring AOP (一)
一.代理模式 在不更改源码的前提下,加入新功能,通常需要用到代理设计模式. 代理设计模式分类: 静态代理 动态代理 jdk动态代理 cglib动态代理 其中spring AOP的底层用的是动态代理.其 ...
- 代理模式及Spring AOP (二)
一.Spring AOP 1.1 Spring AOP 底层还是用的动态代理.如果目标对象所对应的类有接口,spring就用jdk生成代理对象: 如果目标对象所对应的类没有接口,spring就用C ...
- CgLib动态代理学习【Spring AOP基础之一】
如果不了解JDK中proxy动态代理机制的可以先查看上篇文章的内容:Java动态代理学习[Spring AOP基础之一] 由于Java动态代理Proxy.newProxyInstance()的时候会发 ...
- java代理课程测试 spring AOP代理简单测试
jjava加强课程测试代码 反射. 代理 .泛型.beanUtils等 项目源码下载:http://download.csdn.net/detail/liangrui1988/6568169 热身运动 ...
- Java动态代理学习【Spring AOP基础之一】
Spring AOP使用的其中一个底层技术就是Java的动态代理技术.Java的动态代理技术主要围绕两个类进行的 java.lang.reflect.InvocationHandler java.la ...
- 基于代理类实现Spring AOP
目录 ProxyFactoryBean类介绍 基于JDK动态代理的Spring AOP实现 基于CGLIB代理的Spring AOP实现 Spring的通知类型 ProxyFactoryBean类 ...
- Spring AOP详解 、 JDK动态代理、CGLib动态代理
AOP是Aspect Oriented Programing的简称,面向切面编程.AOP适合于那些具有横切逻辑的应用:如性能监测,访问控制,事务管理以及日志记录.AOP将这些分散在各个业务逻辑中的代码 ...
- 【转载】Spring AOP详解 、 JDK动态代理、CGLib动态代理
Spring AOP详解 . JDK动态代理.CGLib动态代理 原文地址:https://www.cnblogs.com/kukudelaomao/p/5897893.html AOP是Aspec ...
随机推荐
- UWA发布 | 2017 Unity手游体检蓝皮书 — ARPG篇
报告目录: 一.ARPG手游总体性能开销分析 二.ARPG手游CPU模块性能开销分析 三.ARPG手游内存模块性能开销分析 四.ARPG手游资源管理分析 五.UWA对于ARPG手游研发团队的建议 一. ...
- nginx的conf文件,两种配置方式,第一种无ssl证书,第二种有ssl证书。
以下为无ssl证书配置的请求转发 server { listen 80; server_name api.******.com; location ~* /union { client_max_bod ...
- [Maven实战-许晓斌]-[第三章] Mave使用入门二(在IDE中的使用) [第四章] 案例的背景介绍
创建maven项目
- php面向对象编程_2
1, 抽象类 ,用abstract关键字来修饰一个类,这个类就是抽象类:如果用abstract关键字来修饰一个方法,这个方法就是抽象方法,如果是抽象方法就不能实现(即抽象方法只能声明,不能定义). 抽 ...
- jquery源码解析:jQuery工具方法Callbacks详解
我们首先来讲下Callbacks是如何使用的:第一个例子 function a(){} function b(){} var cb = $.Callbacks(); cb.add(a); cb.add ...
- spring框架里面的注入?
在Spring框架里面注入可以通过1.setter方法注入:2.构造器注入:3.注入对象 在配置文件中配置如下: 前面两者不能同时注入: 入 如果前两者同时注入将会报错 将注入修改以后,如下图: 修改 ...
- 解决mysql最大允许传输包不足的问题
一.报错提示内容和原因 在执行“数据传输”或者“运行SQL文件”时报错误:Got a packet bigger than 'max_allowed_packet' bytes With,表明当前所传 ...
- 达人篇:5)公差的正态分布与CPK与制程能力(重要)
本章目的:明确公差分布(Tolerance Distribution)也有自己的形状,了解CPK概念. 1.正态分布(常态分布)normal distribution的概念 统计分析常基于这样的假设: ...
- 2019年华南理工大学程序设计竞赛(春季赛) B 修仙时在做什么?有没有空?可以来炼丹吗?(思维建图搜索)
https://ac.nowcoder.com/acm/contest/625/B 分析: 全部的状态只有1<<18 个 , 所以我们可以预处理 f[u][j] , 然后建立出全部的u可以 ...
- js高级程序设计 笔记 --- DOM
DOM是针对HTML和XML文档的一个API.DOM描绘了一个层次化的节点树,允许开发人员添加.移除和修改页面的某一部分. 1,节点层次 DOM可以将任何HTML或XML文档描绘成一个由多层节点构成的 ...