基于Spring AOP的JDK动态代理和CGLIB代理
一.AOP的概念
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
二.主要用途
将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
三.代理
AOP的实现关键在于AOP框架自动创建的AOP代理。AOP代理主要分为两大类:
1.静态代理:使用AOP框架提供的命令进行编译,从而在编译阶段就可以生成AOP代理类,因此也称为编译时增强;静态代理一Aspectj为代表。
2.动态代理:在运行时借助于JDK动态代理,CGLIB等在内存中临时生成AOP动态代理类,因此也被称为运行时增强,Spring AOP用的就是动态代理。
那么其实在Spring框架中用到就是JDK动态代理或者是CGLIB代理。
四.JDK动态代理
JDK动态代理用到了一个类Proxy,下面举个例子来说明一下,Proxy这个类是如何实现JDK的动态代理的。
有一个需求就是,当用户名为空的时候,不能调用业务方法,当用户名不为空是可以调用业务方法。
1.新建一个业务接口,并书写业务方法。
package cn.service; public interface DoService { //添加 public void add(); //查询 public void selectInfo(); //更新 public void update(); }
2.新建一个业务接口实现类
package cn.service.impl; import cn.service.DoService; public class DoServiceImpl implements DoService{ //用户名 private String userName; @Override public void add() { System.out.println("添加的方法"); } @Override public void selectInfo() { System.out.println("查询的方法"); } @Override public void update() { System.out.println("更新的方法"); } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } }
一般如果我们需要进行这样一个业务需求我们会相到 一个办法就是在所有的方法中进行一个判断就是判读用户名是否为空,显然这样很麻烦,所有我们用到了JDK动态代理,主函数 -->代理-->目标对象的方法。这样,以后不管是修改判断条件,还是查找等,可以直接在代理类中进行处理。
3.创建代理对象工厂类
package cn.aop; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import cn.service.impl.DoServiceImpl; /** * 代理工厂类 * @author hyj * */ public class JDKProxyFactory implements InvocationHandler{ //要返回的代理对象 private Object obj; /** * 通过代理工厂的方式来创建代理类 * @param obj 要代理的类的对象 * @return */ public Object createProxyIntance(Object obj){ this.obj=obj; //第一个参数是目标对象的类加载器 //第二个参数是目标对象实现的接口 //第三个参数传入一个InvocationHandler实例,该参数和回调有关系。 return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object proxyObject=null; DoServiceImpl ds=(DoServiceImpl)obj; if(ds.getUserName()!=null){ proxyObject= method.invoke(ds, args); }else{ System.out.println("用户名为空,已拦截"); } return proxyObject; } public Object getObj() { return obj; } public void setObj(Object obj) { this.obj = obj; } }
4.测试类
package cn.test; import cn.aop.JDKProxyFactory; import cn.service.DoService; import cn.service.impl.DoServiceImpl; public class TestHappy { public static void main(String[] args) { JDKProxyFactory jpf=new JDKProxyFactory(); DoService ds=(DoService)jpf.createProxyIntance(new DoServiceImpl("fsf")); ds.selectInfo(); } }
步骤:
- 首先调用代理工厂的createProxyIntance(Object obj)创建DoServiceImpl类的代理类.
- 在该方法内,调用Proxy.newProxyInstance()方法创建代理对象。第一个参数是目标对象的类加载器,第二个参数是目标对象实现的接口,第三个参数传入一个InvocationHandler实例,该参数和回调有关系。
- 每当调用目标对象的方法的时候,就会回调该InvocationHandler实例的方法,也就是public Object invoke()方法,我们就可以把限制的条件放在这里,条件符合的时候,就可以调用method.invoke()方法真正的调用目标对象的方法,否则,则可以在这里过滤掉不符合条件的调用。
五.CGLIB代理
在这一步中,我们使用一个Enhancer类来创建代理对象,不再使用Proxy。使用Enhancer类,需要为其实例指定一个父类,也就是我们 的目标对象。这样,我们新创建出来的对象就是目标对象的子类,有目标对象的一样。除此之外,还要指定一个回调函数,这个函数就和Proxy的 invoke()类似。
总体来说,使用CGlib的方法和使用Proxy的方法差不多,只是Proxy创建出来的代理对象和目标对象都实现了同一个接口。而CGlib的方法则是直接继承了目标对象。
1.引入jar包
2.创建CGLIB实现代理的类
package cn.aop; import java.lang.reflect.Method; import cn.service.impl.DoServiceImpl; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; /** * CGLIB实现代理 * @author hyj * */ public class CGLIBProxyFactory implements MethodInterceptor { //要放回的代理对象 private Object obj; public Object createProxy(Object obj){ //把传进来的代理对象赋值给obj this.obj=obj; Enhancer enhancer = new Enhancer(); //需要为其实例指定一个父类,也就是我们 的目标对象,那么我们新创建出来的对象就是目标对象的子类,有目标对象的一样 enhancer.setSuperclass(this.obj.getClass()); //除此之外,还要指定一个回调函数,这个函数就和Proxy的 invoke()类似 enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object proxyObject=null; DoServiceImpl ds=(DoServiceImpl)obj; if(ds.getUserName()!=null){ proxyObject= methodProxy.invoke(ds, args); }else{ System.out.println("用户名为空,已拦截"); } return proxyObject; } }
测试类
@Test public void CGLIBProxyTest(){ CGLIBProxyFactory gb=new CGLIBProxyFactory(); DoServiceImpl ds= (DoServiceImpl)gb.createProxy(new DoServiceImpl("sf")); ds.add(); }
基于Spring AOP的JDK动态代理和CGLIB代理的更多相关文章
- 设计模式---JDK动态代理和CGLIB代理
Cglig代理设计模式 /*测试类*/ package cglibProxy; import org.junit.Test; public class TestCglib { @Test public ...
- JDK动态代理和 CGLIB 代理
JDK动态代理和 CGLIB 代理 JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期期间创建一个接口的实现类来完成对目标对象的代理. 代码示例 接口 public interface ...
- JDK动态代理和CGLIB代理的区别
一.原理区别: java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理. 而cglib动态代理是利用asm开源包,对代理对象类的class文件 ...
- 动态代理:JDK动态代理和CGLIB代理的区别
代理模式:代理类和被代理类实现共同的接口(或继承),代理类中存有指向被代理类的索引,实际执行时通过调用代理类的方法.实际执行的是被代理类的方法. 而AOP,是通过动态代理实现的. 一.简单来说: JD ...
- JDK动态代理和cglib代理详解
JDK动态代理 先做一下简单的描述,通过代理之后返回的对象已并非原类所new出来的对象,而是代理对象.JDK的动态代理是基于接口的,也就是说,被代理类必须实现一个或多个接口.主要原因是JDK的代理原理 ...
- JDK动态代理和cglib代理
写一个简单的测试用例,Pig实现了Shout接口 public class MyInvocation implements InvocationHandler { Object k; public M ...
- SpringAOP-JDK 动态代理和 CGLIB 代理
在 Spring 中 AOP 代理使用 JDK 动态代理和 CGLIB 代理来实现,默认如果目标对象是接口,则使用 JDK 动态代理,否则使用 CGLIB 来生成代理类. 1.JDK 动态代理 那么接 ...
- 静态代理、动态代理和cglib代理
转:https://www.cnblogs.com/cenyu/p/6289209.html 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处 ...
- 基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别。
基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别. 我还是喜欢基于Schema风格的Spring事务管理,但也有很多人在用基于@Tras ...
随机推荐
- socket Bio demo
最近在做socket通信,最开始是基于Bio开发(其实开发的时候也不知道这种是基于BIO).但是问题来了,客户端发的报文,服务端接收会少,为了解决问题,只能恶补一下相关知识. 服务端: import ...
- 第10章 Shell编程(3)_字符处理命令和条件判断
3. 字符处理命令 3.1 排序命令:sort (1)sort命令:#sort [选项] 文件名 选项 作用 -f 忽略大小写 -n 以数值型进行排序,默认使用字符串型排序 -r 反向排序 -t 指定 ...
- 解决IE浏览器文字上面放无内容的元素选不中的方法
<div class="md1"> <p><i>sdgsgereryeryery</i></p> <label c ...
- [LeetCode] Remove K Digits 去掉K位数字
Given a non-negative integer num represented as a string, remove k digits from the number so that th ...
- [LeetCode] Reverse Words in a String II 翻转字符串中的单词之二
Given an input string, reverse the string word by word. A word is defined as a sequence of non-space ...
- [LeetCode] Permutation Sequence 序列排序
The set [1,2,3,…,n] contains a total of n! unique permutations. By listing and labeling all of the p ...
- 理解javascript里的ABC--apply bind call
一,三者共同点 js中的apply,call,bind是对于初学者比较难的概念之一,比如说我..参考几篇文章之后,统一来讲, 1.这三个函数都属于Function.prototype下面的方法,如下图 ...
- 启动Maven项目启动报错:java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
tomcat在发布项目的时候没有同时发布maven依赖所添加的jar包,你需要设置一下eclipse:项目 -> 属性 -> Deployment Assembly -> Add - ...
- html5+css+div随时笔记
首先给头部文件引用格式 <link href="<%=basePath%>temp/public/css/style.css" rel="stylesh ...
- MVC5知识点记录
IIS/ASP.NET管道 原理永远是重中之重,所以在开篇的地方,先了解一下地址栏输入网址回车之后的故事. 不同IIS版本处理请求也不一样 IIS5 IIS 5.x 运行在进程InetInfo.exe ...