浅谈Spring的AOP实现-动态代理
说起Spring的AOP(Aspect-Oriented Programming)面向切面编程大家都很熟悉(Spring不是这次博文的重点),但是我先提出几个问题,看看同学们是否了解,如果了解的话可以不用继续往下读:
1. Spring的AOP的实现方式有哪些?
2. 为什么使用代理机制?
3. 它们是怎么实现的?
4. 它们的区别是什么?
下面进入正题,Spring采用代理的方式实现AOP,具体采用了JDK的动态代理和CGLib实现。使用动态代理和CGLib的目的是在现有类的基础上增加一些功能。简单地将就是有一个Proxy类,实现了原始类的方法,并且在原始类的基础上增加了新的功能。那么这么做可以实现很多功能:
1. 在方法前后进行日志处理。
2. 进行额外的校验,比如参数的验证功能等。
3. 实现一些懒加载,也就是实例化的时候如果不去调用真正的方法的时候,这个类的属性就不会存在(Hibernate有这样类似的功能)。
下面咱们用简单的代码实现它是如何进行代理的,首先采用的是JDK的动态代理实现:
定义一个接口:
package com.hqs.proxy; /**
* 操作系统光接口
* @author hqs
*
*/
public interface OpSystem {
public void work();
}
定义一个实现类:
package com.hqs.proxy; /**
* Mac 的实现
* @author hqs
*
*/
public class Mac implements OpSystem { public void work() {
System.out.println("Mac is running");
} }
关键位置来了,我们通过实现JDK自带的反射机制的包的InvocationHandler来进行反射处理,实现它之后需要实现里边的invoke方法,这个invoke方法里边的参数分别为:代理类实例,用于调用method的;method参数是实际执行的方法;args所传输的参数数组。
package com.hqs.proxy; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class OpHandler implements InvocationHandler { private final OpSystem ops; public OpHandler(OpSystem ops) {
this.ops = ops;
} public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before system running");
method.invoke(ops, args);
System.out.println("After system running");
return null;
} public static void main(String[] args) {
Mac mac = new Mac();
OpHandler oph = new OpHandler(mac);
OpSystem os = (OpSystem)Proxy.newProxyInstance(oph.getClass().getClassLoader(),
mac.getClass().getInterfaces(), oph); os.work();
System.out.println(os.getClass());
} } 输出:
Before system running
Mac is running
After system running
class com.sun.proxy.$Proxy0
然后看到里边的main方法中,代理类实例化对象的方法Proxy.newProxyInstance,这个是JDK的反射方法去实例化代理类,其中有三个参数分别是,去实例化代理类的class loader;所代理的类的所有接口Class数组;hander处理类,用于做拦截使用的类。最后我输出了一下os.getClass(),大家可以看到的是代理类的实例,而不是真正代理类的实例,这么做的好处就是很方便的复用这个代理类,比如你可以重复调用它而不用去重新实例化新类,再一点就是你可以针对不同的方法进行拦截,比如你可以method.getName()去判断调用的方法名字是什么从而更细粒度的拦截方法。咱们继续看用CGLib的实现:
package com.hqs.proxy; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; /**
* CGLib Interceptor用于方法拦截
* @author hqs
*
*/
public class CGLibInterceptor implements MethodInterceptor { private final Mac mac; public CGLibInterceptor(Mac mac) {
this.mac = mac;
} @Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
System.out.println("Before system running");
method.invoke(mac, args);
System.out.println("After system running");
return null;
} public static void main(String[] args) {
Mac mac = new Mac(); //实例而非接口
MethodInterceptor handler = new CGLibInterceptor(mac);
Mac m = (Mac)Enhancer.create(mac.getClass(), handler);
m.work();
System.out.println(m.getClass()); } } 输出:
Before system running
Mac is running
After system running
class com.hqs.proxy.Mac$$EnhancerByCGLIB$$1f2c9d4a
首先需要引入cglib包,然后才能使用他的MethodInterptor,它也采用method.invoke实现对代理类的调用。它的代理类创建采用Enhancer的create方法,其中传入了需要创建的类的class,以及Callback对象,因为MethodInterceptor继承了Callback对象。用于指向方法前后进行调用的类。
public interface MethodInterceptor
extends Callback
这是这两个类的基本实现,那么它们的区别是什么呢?
- JDK的动态代理只能针对接口和其实现类,如果没有实现类只有接口也是可以代理的,这里就不在举例了。为什么JDK的动态代理只针对接口代理,因为这个是JDK的定义。
- 如果不针对接口实现动态代理那就用到了CGLib了,也就是可以针对具体的类进行代理,大家可以参考我的代码。
这些是它们的根本区别,但是Spring推荐使用JDK的动态代理,面向接口去编程。使用CGLib去做代理的时候需要注意,它生成的代理类存放在JVM的Perm space里边,那么是不是生成的代理对象就不进行回收了?其实不是的,不经常回收但是还是回收的,当类被加载,加载类的classLoader什么时候变得对垃圾回收可用的时候才进行回收。也就是你自己创建所有类移除classLoader之后,那么这个classLoader就会被回收,一般非常精通CGLib的话可以进行这块内容深入开发,因为它可以做出amzing的事情如果你熟悉的话。
如果有不对的地方欢迎拍砖~
浅谈Spring的AOP实现-动态代理的更多相关文章
- 浅谈Spring的AOP实现-代理机制
说起Spring的AOP(Aspect-Oriented Programming)面向切面编程大家都很熟悉(Spring不是这次博文的重点),但是我先提出几个问题,看看同学们是否了解,如果了解的话可以 ...
- Spring学习-- AOP入门动态代理
AOP 的拦截功能是由 java 中的动态代理来实现的.说白了,就是在目标类的基础上增加切面逻辑,生成增强的目标类(该切面逻辑或者在目标类函数执行之前,或者目标类函数执行之后,或者在目标类函数抛出异常 ...
- 浅谈spring中AOP以及spring中AOP的注解方式
AOP(Aspect Oriented Programming):AOP的专业术语是"面向切面编程" 什么是面向切面编程,我的理解就是:在不修改源代码的情况下增强功能.好了,下面在 ...
- 【Java EE 学习 51】【Spring学习第三天】【cglib动态代理】【AOP和动态代理】【切入点表达式】
一.cglib动态代理 1.简介 (1)CGlib是一个强大的,高性能,高质量的Code生成类库.它可以在运行期扩展Java类与实现Java接口. (2) 用CGlib生成代理类是目标类的子类. (3 ...
- Spring中的cglib动态代理
Spring中的cglib动态代理 cglib:Code Generation library, 基于ASM(java字节码操作码)的高性能代码生成包 被许多AOP框架使用 区别于JDK动态代理,cg ...
- Spring中的JDK动态代理
Spring中的JDK动态代理 在JDK1.3以后提供了动态代理的技术,允许开发者在运行期创建接口的代理实例.在Sun刚推出动态代理时,还很难想象它有多大的实际用途,现在动态代理是实现AOP的绝好底层 ...
- 浅谈Spring的事务隔离级别与传播性
浅谈Spring的事务隔离级别与传播性 这篇文章以一个问题开始,如果你知道答案的话就可以跳过不看啦@(o・ェ・)@ Q:在一个批量任务执行的过程中,调用多个子任务时,如果有一些子任务发生异常,只是回滚 ...
- Spring事务Transactional和动态代理(二)-cglib动态代理
系列文章索引: Spring事务Transactional和动态代理(一)-JDK代理实现 Spring事务Transactional和动态代理(二)-cglib动态代理 Spring事务Transa ...
- Spring事务Transactional和动态代理(三)-事务失效的场景
系列文章索引: Spring事务Transactional和动态代理(一)-JDK代理实现 Spring事务Transactional和动态代理(二)-cglib动态代理 Spring事务Transa ...
随机推荐
- SQL Server锁类型
SQL Server锁类型(SQL)收藏 1. HOLDLOCK: 在该表上保持共享锁,直到整个事务结束,而不是在语句执行完立即释放所添加的锁. 2. NOLOCK:不添加共享锁和排它锁,当这个选项生 ...
- 寻找Harris、Shi-Tomasi和亚像素角点
Harris.Shi-Tomasi和亚像素角点都是角点,隶属于特征点这个大类(特征点可以分为边缘.角点.斑点). 一.Harris角点检测是一种直接基于灰度图像的角点提取算法,稳定性较高,但是也可能出 ...
- 基于NIOS-II的示波器:PART4 系统调试&测试
本文记录了在NIOS II上实现示波器的第四部分. 本文主要包括:修改部分BUG,以及测试 本文所有的硬件以及工程参考来自魏坤示波仪,重新实现驱动并重构工程. version 1.0 界面修改& ...
- web切图的几个快捷键及总结
自由的控制视图系列 自由的浏览图片:按住空格后,鼠标拖动 自由的缩放图片:按住alt+滚轮 切换到实际像素(100%):Ctrl + 1 工作区类型切换:Tab 控制内容系列 通过画面上点选一个图 ...
- 团队作业4——第一次项目冲刺 tHe LaSt dAy
项目冲刺--终点 敏捷冲刺最后一天,没想到前一天就上榜了,我也很无奈啊. 那今天就老老实实写一篇博客好了. Mission 这次敏捷冲刺呢,我们主要做了前端页面,后台的数据库和添加了基本的增删查改的功 ...
- 团队作业8——Beta 阶段冲刺5th day
一.当天站立式会议 二.每个人的工作 (1)昨天已完成的工作(具体在表格中) 支付功能测试 (2)今天计划完成的工作(具体如下) 完善订单功能 (3)工作中遇到的困难(在表格中) 成员 昨天已完成的工 ...
- 【Beta】Daily Scrum Meeting——Day6
站立式会议照片 1.本次会议为第六次Meeting会议: 2.本次会议在早上9:35,在陆大楼召开,本次会议为30分钟讨论今天要完成的任务以及接下来的任务安排. 燃尽图 每个人的工作分配 成 员 昨天 ...
- 团队作业4——第一次项目冲刺(Alpha版本) Day3
1.由于大家课程都比较多,时间紧迫,今天最后一节课下课完在教室召开了简短的站立式会议,会议照片如下: 2.Leangoo任务分解图: 3.每个人的工作: 队员 今天已完成的工作 明天计划完成的工作 林 ...
- 201521123015 《Java程序设计》第5周学习总结
1. 本周学习总结 1.1 尝试使用思维导图总结有关多态与接口的知识点. 2. 书面作业 1.代码阅读:Child压缩包内源代码 1.1 com.parent包中Child.java文件能否编译通过? ...
- 201521123110 《JAVA程序设计》第3周学习总结
1.本章学习总结 ` ` 2.书面作业 1.代码阅读 public class Test1 { private int i = 1;//这行不能修改 private static int j = 2; ...