博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
cglib代理的使用
阅读量:6984 次
发布时间:2019-06-27

本文共 4128 字,大约阅读时间需要 13 分钟。

一、什么是CGLIB?

总的来说,无论是cglib、jdk动态代理又或者是aop面向切面编程,都运用到了一个最重要的设计模式--代理模式!万变不离其终,学好代理模式,打遍天下无敌手!

cglib就是一个字节码生成转换的库嘛!这倒是不难理解,它主要被AOP,测试,数据访问框架用来生成动态代理对象拦截字段访问

今天我们就来说说cglib在代理方面的应用!

二、CGLIB源码粗略解读!

首先我们来看看cglib源码的包结构:

从cglib核心包中可以看到有个proxy的包,我们一起去探个究竟!展开proxy可以发现:

在该包中的Enhancer类和MethodInterceptor接口是整个包的核心所在!Enhancer就是“增强”的意思嘛!主要用于生成动态子类以启用方法拦截,什么意思?这样子讲!cglib类代理的基本思想就是对被代理类生成一个新的类(proxy),该类是继承自被代理类的,并对被代理类方法执行前后执行一些操作,这些操作的通常就是一些回调操作,可以是MethodInterceptorLazyLoader,CallbackFilter,其中MethodInterceptor是最常用的。

所有被Enhancer关联的对象默认都是实现Factory接口的,该接口提供了一组可以设置对象回调类型的方法,你可以通过调用setUseFactory(false)取消此特性!

需要注意的是,cglib是无法代理final修饰的方法的,因为这是java语言规范决定的!

MethodInterceptor是一个提供环绕通知的通用回调接口!Aop中有这样的术语,那就是前置通知后置通知环绕通知,非常好理解,就是一个在方法执行前的通知,一个方法执行后的通知,另外一个就是方法执行前后都通知。

该接口只有一个intercept()方法:

public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,                               MethodProxy proxy) throws Throwable;复制代码

所有对被代理类方法的执行都会跳转到这个方法上面来,而原来的方法则通过反射得到的Method对象或者MethodProxy对象进行调用。

三、老规矩,来个栗子一起团圆!

import java.lang.reflect.Method;import net.sf.cglib.proxy.Callback;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;class Student {	private String name = "zhangsan";	public String getStuName() {		return name;	}}public class CglibMethodInterceptTest {	public static void main(String[] args) {		//创建一个Enhancer对象		Enhancer enchaner = new Enhancer();		//设置被代理的类		enchaner.setSuperclass(Student.class);		//创建一个回调接口		Callback interceptor = new MethodInterceptor() {			@Override			public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)					throws Throwable {				System.err.println("原方法名是 : " + method.getName());				System.err.println("原方法声明的类为 " + method.getDeclaringClass());				System.err.println("我是 " + (String) proxy.invokeSuper(obj, args));				System.err.println("我调用结束了");				return null;			}		};		enchaner.setCallback(interceptor);		Student student = (Student) enchaner.create();		student.getStuName();	}}复制代码

输出的结果为:

原方法名是 : getStuName原方法声明的类为 class wokao666.test.Student我是 zhangsan我调用结束了复制代码

过滤器的使用

package wokao666.test;import java.lang.reflect.Method;import net.sf.cglib.proxy.Callback;import net.sf.cglib.proxy.CallbackFilter;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;import net.sf.cglib.proxy.NoOp;class Student {	private String name = "zhangsan";	private String rename = "rename";	public String getStuName() {		return name;	}	public String getRename() {		return rename;	}}public class CglibMethodInterceptTest {	public static void main(String[] args) {		//创建一个Enhancer对象		Enhancer enchaner = new Enhancer();		//设置被代理的类		enchaner.setSuperclass(Student.class);		//创建一个回调接口		Callback interceptor = new MethodInterceptor() {			@Override			public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)					throws Throwable {				System.err.println("原方法名是 : " + method.getName());				System.err.println("原方法声明的类为 " + method.getDeclaringClass());				System.err.println("我是 " + (String) proxy.invokeSuper(obj, args));				System.err.println("我调用结束了");				return proxy.invokeSuper(obj, args);			}		};		CallbackFilter callbackFilter = new CallbackFilter() {			@Override			public int accept(Method method) {				int flag = 0;				if ("getStuName".equals(method.getName())) {					System.err.println("我将此方法过滤掉了,不对该方法进行拦截");					return 1;				}				return 0;			}		};		Callback[] callbacks = new Callback[] { interceptor, NoOp.INSTANCE };		enchaner.setCallbackFilter(callbackFilter);		enchaner.setCallbacks(callbacks);		Student student = (Student) enchaner.create();		System.err.println(student.getStuName());		System.err.println(student.getRename());	}}复制代码
我将此方法过滤掉了,不对该方法进行拦截zhangsan原方法名是 : getRename原方法声明的类为 class wokao666.test.Student我是 rename我调用结束了rename复制代码

NoOp.INSTANCE:这个NoOp表示no operator,即什么操作也不做,代理类直接调用被代理的方法不进行拦截。

getStuName对应的CallbackFilter中定义的索引1,在Callback[]数组中使用的过滤为NoOp,因此直接执行了被代理方法。

getRename对应CallbackFilter中定义的索引0,在Callback[]数组中使用的过滤为interceptor,因此执行了方法拦截器进行拦截。

我写的只是一点皮毛,建议大家在此基础上多动手,结合源代码多写写一些例子,写多了,懂得就多了!

转载地址:http://zljpl.baihongyu.com/

你可能感兴趣的文章
HDU - 5008 Boring String Problem (后缀数组+二分法+RMQ)
查看>>
Swift - 实现点击UITableView单元格时自动展开单元格
查看>>
Cocos2d-x3.0 Button
查看>>
图解.NET Stack和Heap的本质区别
查看>>
Matlab中struct的用法
查看>>
Mysql LIMIT如何正确对其进行优化
查看>>
Spring10种常见异常解决方法
查看>>
深入理解JavaScript系列(6):S.O.L.I.D五大原则之单一职责SRP
查看>>
onSaveInstanceState和onRestoreInstanceState触发的时机
查看>>
设计模式学习02—工厂模式
查看>>
html5--6-10 CSS选择器7--伪类选择器
查看>>
激光数据匹配(MATLAB Robotics System Toolbox)
查看>>
file_put_contents执行返回false,file_put_contents false(linux服务器httpd)
查看>>
JavaScript学习总结一(String对象的用法)
查看>>
处理手势冲突和错乱的一点经验
查看>>
Struts2防止表单重复提交
查看>>
[转]Python格式化输出
查看>>
CSS - 修改input - placeholder 和 readonly 的样式
查看>>
在多线程情况下 局部变量与全局变量 哪个比较安全呢
查看>>
算法评测
查看>>