cglib代理
简介:
github地址:https://github.com/cglib/cglib,可以访问这个地址查看cglib源码和相关文档。
简单的摘录了wiki上关于cglib的描述:
cglib is a powerful, high performance and quality Code Generation Library,It is used to extend JAVA classes and implements interfaces at runtime.
重点是后面这句话:它用于在【运行时】扩展JAVA类并实现接口。这也就是动态代理的精髓吧。
我们都知道,动态代理可以通过jdk动态代理,那和cglib有什么区别呢。第一,jdk动态代理的对象必须实现了某个接口,所代理的对象是实现了某个接口的所有类。
而cglib并没有这个要求。第二,cglib的效率比jdk要高许多。
下面介绍一个梨子:
首先定义一个目标类
package demo.cglib;
public class Target {
public void first() {
System.out.println("first");
}
public void second() {
System.out.println("second");
}
public void third() {
System.out.println("third");
}
public String toString() {
return "target class";
}
}
然后我们需要为目标类写一个方法拦截类。这个类需要实现MethodInterceptor接口,先看一下这个接口:
package net.sf.cglib.proxy; /**
* General-purpose {@link Enhancer} callback which provides for "around advice".
* @author Juozas Baliuka <a href="mailto:baliuka@mwm.lt">baliuka@mwm.lt</a>
* @version $Id: MethodInterceptor.java,v 1.8 2004/06/24 21:15:20 herbyderby Exp $
*/
public interface MethodInterceptor
extends Callback
{
/**
* All generated proxied methods call this method instead of the original method.
* The original method may either be invoked by normal reflection using the Method object,
* or by using the MethodProxy (faster).
* @param obj "this", the enhanced object
* @param method intercepted Method
* @param args argument array; primitive types are wrapped
* @param proxy used to invoke super (non-intercepted method); may be called
* as many times as needed
* @throws Throwable any exception may be thrown; if so, super method will not be invoked
* @return any value compatible with the signature of the proxied method. Method returning void will ignore this value.
* @see MethodProxy
*/
public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
MethodProxy proxy) throws Throwable; }
这个接口只有一个方法,我们的具体代理增强逻辑就是在这个方法中实现的。
这里还有一个点,可以看到MethodInterceptor继承了Callback接口,那么我们来看看Callback接口的内容:
package net.sf.cglib.proxy; /**
* All callback interfaces used by {@link Enhancer} extend this interface.
* @see MethodInterceptor
* @see NoOp
* @see LazyLoader
* @see Dispatcher
* @see InvocationHandler
* @see FixedValue
*/
public interface Callback
{
}
嗯,它是个空接口,起到标志的作用,下面具体实现增强类的时候会看到它
那么,了解了这些,开始写我们的拦截类把
package demo.cglib; import java.lang.reflect.Method; import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; public class TargetInterceptor implements MethodInterceptor { @Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("method:"+method.getName()+" ---begain---");
Object result = proxy.invokeSuper(obj, args);
System.out.println("method:"+method.getName()+" ---end---");
return result;
} }
这里只是写了简单的方法执行前后的简单操作,下面测试一下
package demo.cglib;
import net.sf.cglib.proxy.Enhancer;
public class DemoTest {
public static void main(String[] args) {
TargetInterceptor interceptor = new TargetInterceptor();
Enhancer eh = new Enhancer();
eh.setSuperclass(Target.class);
eh.setCallback(interceptor);
Target target = (Target)eh.create();
target.first();
target.second();
target.third();
}
}
输出结果:
method:first ---begain---
first
method:first ---end---
method:second ---begain---
second
method:second ---end---
method:third ---begain---
third
method:third ---end---
到这里,似乎很完美了。我们代理只要实现MethodInterceptor接口的intercept方法,在里面实现我们的逻辑就好了。
但是,现在我有一个需求:当调用first()方法时,我不希望被代理。调用时second()执行我们的拦截类实现的代理逻辑,而当调用third()方法时,会有一个
默认的返回值。
这里你可能说,我直接在intercept方法里判断啊,当方法名是first时,当方法是second时....
这样做可以,但是不够优雅,而且像不被代理和返回默认值这样的方法。我们完全有理由在调用之初就被过滤掉,而不需要进入到intercept()这一层再去进行一个判断。
下面讲一下过滤的实现方式。首先介绍两个实现了Callback接口的接口:
package net.sf.cglib.proxy; /**
* Methods using this {@link Enhancer} callback will delegate directly to the
* default (super) implementation in the base class.
*/
public interface NoOp extends Callback
{
/**
* A thread-safe singleton instance of the <code>NoOp</code> callback.
*/
public static final NoOp INSTANCE = new NoOp() { };
}
这个类的意思就是No Operation,也就是不进行操作
package net.sf.cglib.proxy; /**
* {@link Enhancer} callback that simply returns the value to return
* from the proxied method. No information about what method
* is being called is available to the callback, and the type of
* the returned object must be compatible with the return type of
* the proxied method. This makes this callback primarily useful
* for forcing a particular method (through the use of a {@link CallbackFilter}
* to return a fixed value with little overhead.
*/
public interface FixedValue extends Callback {
/**
* Return the object which the original method invocation should
* return. This method is called for <b>every</b> method invocation.
* @return an object matching the type of the return value for every
* method this callback is mapped to
*/
Object loadObject() throws Exception;
}
这个接口需要实现loadObject,固定返回的类型
这里我们给它一个简单的实现,返回固定值 “dog” 字符串
package demo.cglib;
import net.sf.cglib.proxy.FixedValue;
public class TargetResultFixed implements FixedValue {
@Override
public Object loadObject() throws Exception {
System.out.println("返回固定值");
return "dog";
}
}
还要实现一个过滤接口,先来看一下这个接口
package net.sf.cglib.proxy; import java.lang.reflect.Method; /**
* Map methods of subclasses generated by {@link Enhancer} to a particular
* callback. The type of the callbacks chosen for each method affects
* the bytecode generated for that method in the subclass, and cannot
* change for the life of the class.
* <p>Note: {@link CallbackFilter} implementations are supposed to be
* lightweight as cglib might keep {@link CallbackFilter} objects
* alive to enable caching of generated classes. Prefer using {@code static}
* classes for implementation of {@link CallbackFilter}.</p>
*/
public interface CallbackFilter {
/**
* Map a method to a callback.
* @param method the intercepted method
* @return the index into the array of callbacks (as specified by {@link Enhancer#setCallbacks}) to use for the method,
*/
int accept(Method method); /**
* The <code>CallbackFilter</code> in use affects which cached class
* the <code>Enhancer</code> will use, so this is a reminder that
* you should correctly implement <code>equals</code> and
* <code>hashCode</code> for custom <code>CallbackFilter</code>
* implementations in order to improve performance.
*/
boolean equals(Object o);
}
这里主要的实现逻辑在accept内,下面是实现类
package demo.cglib;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.CallbackFilter;
public class TargetMethodFilter implements CallbackFilter {
@Override
public int accept(Method method) {
if(method.getName().equals("first")) {
return 0;
}
if(method.getName().equals("second")) {
return 1;
}
return 2;
}
}
在这里说明一下,这里返回的数字代表着所调用的代理类的序号。之前我们已经看到过,代理增强需要设置Callback,就是上面的enhancer.setCallback()方法,但是上面
只用了一个拦截类。当有多个拦截类时,我们定义一个Callback数组,然后设置setCallbacks(),上面返回的数字,就代表所调用的对应数组中哪个拦截方式。
下面来测试一下
package demo.cglib; import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.NoOp; public class DemoTest {
public static void main(String[] args) {
TargetInterceptor interceptor = new TargetInterceptor();
Callback resultFixed = new TargetResultFixed();
Callback noOp = NoOp.INSTANCE;
// 这里定义了拦截类数组
Callback[] callbacks = {noOp,interceptor,resultFixed};
//过滤逻辑类
CallbackFilter filter = new TargetMethodFilter();
Enhancer eh = new Enhancer();
eh.setSuperclass(Target.class);
// 设置拦截数组,过滤方法返回的整数将对应数组中的具体拦截类,然后被执行
eh.setCallbacks(callbacks);
eh.setCallbackFilter(filter);
Target target = (Target)eh.create(); target.first();
target.second();
target.third();
}
}
输出结果:
first
method:second ---begain---
second
method:second ---end---
返回固定值
当然上面介绍的知识cglib的一些简单的应用和原理,了解更过可以去github上参考项目源码和文档,当然更多的应该是
多去实践和测试。很多东西都是很简单的东西堆砌拼凑出伟大的东西,就像计算机不就是0和1么,但是无数的0和1各种不同的拼凑
就可以代表无穷的信息。从小到大,从简单到复杂,重要的是掌握原理和精髓。
cglib代理的更多相关文章
- 基于Spring AOP的JDK动态代理和CGLIB代理
一.AOP的概念 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的 ...
- (转)Java动态代理与CGLib代理
<br>public class UserDAOImpl{ <br><br> public void save() { <br> / ...
- 获取JDK动态代理/CGLIB代理对象代理的目标对象。
问题描述:: 我现在遇到个棘手的问题,要通过spring托管的service类保存对象,这个类是通过反射拿到的,经过实验发现这个类只能反射取得sservice实现了接口的方法,而extends类的方法 ...
- Spring强制使用CGLIB代理事务
Spring强制使用CGLIB代理事务 springaopjdkreferenceclasspath Spring1.2: 将事务代理工厂[TransactionProxyFactoryBean] ...
- java静态代理,动态代理,cglib代理
代理模式在我们的应用中是很常见的,例如拦截器,spring的事务管理等.之所以能被代理,是因为java允许我们通过反射机制动态构造目标对象,并调用相应的方法. 就好像拿到了目标对象的引用,自然可以在目 ...
- IT忍者神龟之Java动态代理与CGLib代理
<br>public class UserDAOImpl{ <br><br> public void save() { <br> / ...
- Spring框架_代理模式(静态代理,动态代理,cglib代理)
共性问题: 1. 服务器启动报错,什么原因? * jar包缺少.jar包冲突 1) 先检查项目中是否缺少jar包引用 2) 服务器: 检查jar包有没有发布到服务器下: ...
- jdk动态代理与cglib代理、spring aop代理实现原理
原创声明:本博客来源与本人另一博客[http://blog.csdn.net/liaohaojian/article/details/63683317]原创作品,绝非他处摘取 代理(proxy)的定义 ...
- jdk动态代理与cglib代理、spring aop代理实现原理解析
原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象 ...
- 何为代理?jdk动态代理与cglib代理、spring Aop代理原理浅析
原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象 ...
随机推荐
- 【Zigbee技术入门教程-02】一图读懂ZStack协议栈的基本架构和工作机理
[Zigbee技术入门教程-02]一图读懂ZStack协议栈的基本架构和工作机理 广东职业技术学院 欧浩源 ohy3686@foxmail.com Z-Stack协议栈是一个基于任务轮询方式的操作 ...
- Form表单提交,Ajax请求,$http请求的区别
做过前端同学想必都避免不了要和后台server打交道.而以下这三种与后台交互的方式想必大家都不陌生. Form表单提交,Ajax请求,Angular的$http请求 以前一直搞不清楚什么时候应该用哪种 ...
- 产品经理和Scrum Master都必须是领域专家吗?
注明:原文来自 Mike Cohn的邮件推送,我已将原文贴在最后供参考,翻译的目的是为了锻炼自己的能力和理解水平,如有版权侵犯,请告之. Scrum Master 和 产品经理应该是领域专家吗?让我们 ...
- C# 爬虫 抓取小说
心血来潮,想研究下爬虫,爬点小说. 通过百度选择了个小说网站,随便找了一本小书http://www.23us.so/files/article/html/13/13655/index.html. 1. ...
- postgresql如何维护WAL日志/归档日志
WAL日志介绍 wal全称是write ahead log,是postgresql中的online redo log,是为了保证数据库中数据的一致性和事务的完整性.而在PostgreSQL 7中引入的 ...
- 将位图导入为ArcGIS面要素
本文根据笔者经验,介绍一种从位图图像导入ArcGIS称为要素的方法.这种方法适用于从现有出版物图片中获取地理信息的情况. 首先要说明的是,从位图导入要素是非常非常不精确的方式,如果有其它数据来源,那么 ...
- 关于用VMware克隆linux系统后,无法联网找不到eth0网卡的问题
当使用克隆后的虚拟机时发现系统中的网卡eth0没有了,使用ifconfig -a会发现只有eth1.因为系统是克隆过来的,原有的eth0以及ip地址都是原先网卡的,VMware发现已经被占用,就会创建 ...
- Springmvc_validation 效验器
springmvc-validation效验器的使用介绍 对于任何一个应用来说,都会做数据的有效性效验,但是只在前端做并不是很安全,考虑到安全性這个时候会要求我们在服务端也对数据进行有效验证,spri ...
- ORACLE分区表、分区索引详解
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt160 ORACLE分区表.分区索引ORACLE对于分区表方式其实就是将表分段 ...
- hashMap和treeMap
前言 首先介绍一下什么是Map.在数组中我们是通过数组下标来对其内容索引的,而在Map中我们通过对象来对对象进行索引,用来索引的对象叫做key,其对应的对象叫做value.这就是我们平时说的键值对. ...