1.CGLIB包的介绍
代理为控制要访问的目标对象提供了一种途径。当访问对象时,它引入了一个间接的层。JDK自从1.3版本开始,就引入了动态代理,而且常常被用来动态地创 建代理。JDK的动态代理用起来很是简单,当它有一个限制,就是使用动态代理的对象必须实现一个或多个接口。若是想代理没有实现接口的继承的类,该怎么 办?如今咱们可使用CGLIB包
CGLIB是一个强大的高性能的代码生成包。它普遍的被许多AOP的框架使用,例如spring AOP和dynaop,为他们提供方法的interception(拦截)。最流行的OR Mapping工具hibernate也使用CGLIB来代理单端single-ended(多对一和一对一)关联(对集合的延迟抓取,是采用其余机制实 现的)。EasyMock和jMock是经过使用模仿(moke)对象来测试Java代码的包。它们都经过使用CGLIB来为那些没有接口的类建立模仿 (moke)对象。
CGLIB包的底层是经过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。除了CGLIB包,脚本语言例如 Groovy和BeanShell,也是使用ASM来生成java的字节码。当不鼓励直接使用ASM,由于它要求你必须对JVM内部结构包括class文 件的格式和指令集都很熟悉。java
Figure 1: CGLIB Library and ASM Bytecode Frameworkspring
图 一显示了和CGLIB包和一些框架和语言的关系图。须要注意的是一些框架例如Spring AOP和Hibernate,它们为了知足须要常常同时使用JDK的动态代理和CGLIB包。Hiberater使用JDK的动态代理实现一个专门为 WebShere应用服务器的事务管理适配器;Spring AOP,若是不强制使用CGLIB包,默认状况是使用JDK的动态代理来代理接口。
2.CGLIB 代理的APIS
CGLIB包的基本代码不多,当学起来有必定的困难,主要是缺乏文档,这也是开源软件的一个不足之处。目前CGLIB的版本是(2.1.2),主要由一下部分组成:数组
net.sf.cglib.core
底层字节码处理类,他们大部分与ASM有关系。
• net.sf.cglib.transform
编译期或运行期类和类文件的转换
• net.sf.cglib.proxy
实现建立代理和方法拦截器的类
• net.sf.cglib.reflect
实现快速反射和C#风格代理的类
• net.sf.cglib.util
集合排序工具类
• net.sf.cglib.beans
JavaBean相关的工具类服务器
大多时候,仅仅为了动态地建立代理,你仅须要使用到代理包中不多的一些API。
正 如咱们先前所讨论的,CGLIB包是在ASM之上的一个高级别的层。对代理那些没有实现接口的类很是有用。本质上,它是经过动态的生成一个子类去覆盖所要 代理类的不是final的方法,并设置好callback,则原有类的每一个方法调用就会转变成调用用户定义的拦截方法(interceptors),这比 JDK动态代理方法快多了。app
Figure 2: CGLIB library APIs commonly used for proxying classes框架
图2 为咱们演示了建立一个具体类的代理时,一般要用到的CGLIB包的APIs。net.sf.cglib.proxy.Callback接口在CGLIB包 中是一个很关键的接口,全部被net.sf.cglib.proxy.Enhancer类调用的回调(callback)接口都要继承这个接口。 net.sf.cglib.pr用oxy.MethodInterceptor接口是最通用的回调(callback)类型,它常常被基于代理的AOP用 来实现拦截(intercept)方法的调用。这个接口只定义了一个方法
public Object intercept(Object object, java.lang.reflect.Method method,
Object[] args, MethodProxy proxy) throws Throwable;工具
当net.sf.cglib.proxy.MethodInterceptor作为全部代理方法的回调 (callback)时,当对基于代理的方法调用时,在调用原对象的方法的以前会调用这个方法,如图3所示。第一个参数是代理对像,第二和第三个参数分别 是拦截的方法和方法的参数。原来的方法可能经过使用java.lang.reflect.Method对象的通常反射调用,或者使用 net.sf.cglib.proxy.MethodProxy对象调用。net.sf.cglib.proxy.MethodProxy一般被首选使 用,由于它更快。在这个方法中,咱们能够在调用原方法以前或以后注入本身的代码。性能
Figure 3: CGLIB MethodInterceptor测试
net.sf.cglib.proxy.MethodInterceptor可以知足任何的拦截(interception )须要,当对有些状况下可能过分。为了简化和提升性能,CGLIB包提供了一些专门的回调(callback)类型。例如:this
net.sf.cglib.proxy.FixedValue
net.sf.cglib.proxy.NoOp
net.sf.cglib.proxy.LazyLoader
net.sf.cglib.proxy.Dispatcher
net.sf.cglib.proxy.ProxyRefDispatcher
如 图3所示,代理类的因此方法常常会用到回调(callback),当是你也可使用net.sf.cglib.proxy.CallbackFilter 有选择的对一些方法使用回调(callback),这种考虑周详的控制特性在JDK的动态代理中是没有的。在JDK代理中,对 java.lang.reflect.InvocationHandler方法的调用对代理类的因此方法都有效。
除了代理类外,CGLIB经过提供一个对java.lang.reflect.Proxy的drop-in替代来实现对对接口的代理。由于这种代理能力的替代不多被用到,所以相应的APIs也不多提到。
CGLIB的代理包也对net.sf.cglib.proxy.Mixin提供支持。基本上,它容许多个对象被绑定到一个单个的大对象。在代理中对方法的调用委托到下面相应的对象中。
接下来咱们看看如何使用CGLIB代理APIs建立代理。
建立一个简单的代理CGLIB代理最核心的是net.sf.cglib.proxy.Enhancer类,为了建立一个代理,最起码你要用到这个类。首先,让咱们使用NoOp回调建立一个代理:
/**
* Create a proxy using NoOp
callback. The target class
* must have a default zero-argument constructor.
*
* @param targetClass the super class of the proxy
* @return a new proxy for a target class instance
*/
public Object createProxy(Class targetClass) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetClass);
enhancer.setCallback(NoOp.INSTANCE);
return enhancer.create();
}
返回值是target类一个实例的代理。在这个例子中,咱们为net.sf.cglib.proxy.Enhancer 配置了一个单一的回调(callback)。咱们能够看到不多直接建立一个简单的代理,而是建立一个 net.sf.cglib.proxy.Enhancer的实例,在net.sf.cglib.proxy.Enhancer类中你可以使用静态帮助方法创 建一个简单的代理。通常推荐使用上面例子的方法建立代理,由于它容许你经过配置net.sf.cglib.proxy.Enhancer实例很好的控制代 理的建立。
要注意的是,target类是做为产生的代理的父类传进来的。不一样于JDK的动态代理,它不能在建立代理时传target对 象,target对象必须被CGLIB包来建立。在这个例子中,默认的无参数构造器时用来建立target实例的。若是你想用CGLIB来建立有参数的实 例,用net.sf.cglib.proxy.Enhancer.create(Class[], Object[])方法替代net.sf.cglib.proxy.Enhancer.create()就能够了。方法中第一个参数定义了参数的类型,第 二个是参数的值。在参数中,基本类型应被转化成类的类型。
Use a MethodInterceptor为了更好的使用代理,咱们可使用本身定义的MethodInterceptor类型回调(callback)来代替net.sf.cglib.proxy.NoOp回调。当对代理中全部方法的调用时,都会转向MethodInterceptor类型的拦截(intercept)方法,在拦截方法中再调用底层对象相应的方法。下面咱们举个例子,假设你想对目标对象的全部方法调用进行权限的检查,若是没有通过受权,就抛出一个运行时的异常AuthorizationException。其中AuthorizationService.java接口的代码以下:
package com.lizjason.cglibproxy;
import java.lang.reflect.Method;
/**
* A simple authorization service for illustration purpose.
*
* @author Jason Zhicheng Li (jason@lizjason.com)
*/
public interface AuthorizationService {
/**
* Authorization check for a method call. An AuthorizationException
* will be thrown if the check fails.
*/
void authorize(Method method);
}
对net.sf.cglib.proxy.MethodInterceptor接口的实现的类AuthorizationInterceptor.java代码以下:
package com.lizjason.cglibproxy.impl;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import com.lizjason.cglibproxy.AuthorizationService;
/**
* A simple MethodInterceptor implementation to
* apply authorization checks for proxy method calls.
*
* @author Jason Zhicheng Li (jason@lizjason.com)
*
*/
public class AuthorizationInterceptor implements MethodInterceptor {
private AuthorizationService authorizationService;
/**
* Create a AuthorizationInterceptor with the given
* AuthorizationService
*/
public AuthorizationInterceptor (AuthorizationService authorizationService) {
this.authorizationService = authorizationService;
}
/**
* Intercept the proxy method invocations to inject authorization check.
* The original method is invoked through MethodProxy.
* @param object the proxy object
* @param method intercepted Method
* @param args arguments of the method
* @param proxy the proxy used to invoke the original method
* @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.
*/
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy ) throws Throwable {
if (authorizationService != null) {
//may throw an AuthorizationException if authorization failed
authorizationService.authorize(method);
}
return methodProxy.invokeSuper(object, args);
}
}
咱们能够看到在拦截方法中,首先进行权限的检查,若是经过权限的检查,拦截方法再调用目标对象的原始方法。因为性能的缘由,对原始方法的调用咱们使用CGLIB的net.sf.cglib.proxy.MethodProxy对象,而不是反射中通常使用
java.lang.reflect.Method对象。
Use a CallbackFilter
net.sf.cglib.proxy.CallbackFilter容许咱们在方法层设置回调(callback)。假如你有一个PersistenceServiceImpl类,它有两个方法:save和load,其中方法save须要权限检查,而方法load不须要权限检查。
package com.lizjason.cglibproxy.impl;
import com.lizjason.cglibproxy.PersistenceService;
/**
* A simple implementation of PersistenceService interface
*
* @author Jason Zhicheng Li (jason@lizjason.com)
*/
public class PersistenceServiceImpl implements PersistenceService {
public void save(long id, String data) {
System.out.println(data + " has been saved successfully.");
}
public String load(long id) {
return "Jason Zhicheng Li";
}
}
注意到PersistenceServiceImpl类实现了PersistenceService接口,所以没有要求要使用CGLIB建立代理。
net.sf.cglib.proxy.CallbackFilter 接口的实现以下:
package com.lizjason.cglibproxy.impl;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.CallbackFilter;
/**
* An implementation of CallbackFilter forPersistenceServiceImpl
*
* @author Jason Zhicheng Li (jason@lizjason.com)
*/
public class PersistenceServiceCallbackFilter implements CallbackFilter {
//callback index for save method
private static final int SAVE = 0;
//callback index for load method
private static final int LOAD = 1;
/**
* Specify which callback to use for the method being invoked.
* @method the method being invoked.
* @return the callback index in the callback array for this method
*/
public int accept(Method method) {
String name = method.getName();
if ("save".equals(name)) {
return SAVE;
}
// for other methods, including the load method, use the
// second callback
return LOAD;
}
}
accept方法中对代理方法和回调进行了匹配,返回的值是某方法在回调数组中的索引。下面是PersistenceServiceImpl类代理的实现。
...
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(PersistenceServiceImpl.class);
CallbackFilter callbackFilter = new PersistenceServiceCallbackFilter();
enhancer.setCallbackFilter(callbackFilter);
AuthorizationService authorizationService = ...
Callback saveCallback = new AuthorizationInterceptor(authorizationService);
Callback loadCallback = NoOp.INSTANCE;
Callback[] callbacks = new Callback[]{saveCallback, loadCallback };
enhancer.setCallbacks(callbacks);
...
return (PersistenceServiceImpl)enhancer.create();
在这个例子中save方法使用了AuthorizationInterceptor实例,load方法使用了NoOp实例。此外,你也能够经过
net.sf.cglib.proxy.Enhancer.setInterfaces(Class[])方法指定代理对象所实现的接口。
除了为net.sf.cglib.proxy.Enhancer指定回调数组,你还能够经过net.sf.cglib.proxy.Enhancer.setCallbackTypes(Class[])方法指定回调类型数组。当建立代理时,若是你没有回调实例的数组,就可使用回调类型。象使用回调同样,你必须使用,net.sf.cglib.proxy.CallbackFilter为每个方法指定一个回调类型索引。你能够从http://www.lizjason.com/downloads/下载设置回调类型和接口的完整代码。
cglib 的几个测试demo
public class MyClass {
public void method() {
System.out.println("MyClass.method()");
}
}
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.proxy.MethodInterceptor;
public class Main {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MyClass.class);
enhancer.setCallback( new MethodInterceptorImpl() );
MyClass my = (MyClass)enhancer.create();
my.method();
}
private static class MethodInterceptorImpl implements MethodInterceptor {
public Object intercept(Object obj,
Method method,
Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println(method);
proxy.invokeSuper(obj, args);
return null;
}
}
}
执行结果:
public void cglib_test.MyClass.method()
MyClass.method()
使用CallbackFilter
public class MyClass {
public void method() {
System.out.println("MyClass.method()");
}
public void method2() {
System.out.println("MyClass.method2()");
}
}
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.NoOp;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter;
public class Main {
public static void main(String[] args) {
Callback[] callbacks =
new Callback[] { new MethodInterceptorImpl(), NoOp.INSTANCE };
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MyClass.class);
enhancer.setCallbacks( callbacks );
enhancer.setCallbackFilter( new CallbackFilterImpl() );
MyClass my = (MyClass)enhancer.create();
my.method();
my.method2();
}
private static class CallbackFilterImpl implements CallbackFilter {
public int accept(Method method) {
if ( method.getName().equals("method2") ) {
return 1;
} else {
return 0;
}
}
}
private static class MethodInterceptorImpl implements MethodInterceptor {
public Object intercept(Object obj,
Method method,
Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println(method);
return proxy.invokeSuper(obj, args);
}
}
}
执行结果:
public void cglib_test.MyClass.method()
MyClass.method()
MyClass.method2()
public interface MyInterfaceA {
public void methodA();
}public interface MyInterfaceB {
public void methodB();
}public class MyInterfaceAImpl implements MyInterfaceA {
public void methodA() {
System.out.println("MyInterfaceAImpl.methodA()");
}
}public class MyInterfaceBImpl implements MyInterfaceB {
public void methodB() {
System.out.println("MyInterfaceBImpl.methodB()");
}
}
import net.sf.cglib.proxy.Mixin;
public class Main {
public static void main(String[] args) {
Class[] interfaces = new Class[] { MyInterfaceA.class,
MyInterfaceB.class };Object[] delegates = new Object[] { new MyInterfaceAImpl(),
new MyInterfaceBImpl() };Object obj = Mixin.create(interfaces, delegates);
MyInterfaceA myA = (MyInterfaceA) obj;
myA.methodA();MyInterfaceB myB = (MyInterfaceB) obj;
myB.methodB();
}
}
执行结果:
MyInterfaceAImpl.methodA() MyInterfaceBImpl.methodB()