CGLIB是一个强大、高性能的字节码生成库,它用于在运行时扩展Java类和实现接口;本质上它是通过动态的生成一个子类去覆盖所要代理的类(非final修饰的类和方法)。Enhancer是一个非常重要的类,它允许为非接口类型创建一个JAVA代理,Enhancer动态的创建给定类的子类并且拦截代理类的所有的方法,和JDK动态代理不一样的是不管是接口还是类它都能正常工作。
MethodInterceptor接口只定义了一个方法:
package net.sf.cglib.proxy;
import java.lang.reflect.Method;
public abstract interface MethodInterceptor
extends Callback
{
public abstract Object intercept(Object paramObject, Method paramMethod, Object[] paramArrayOfObject, MethodProxy paramMethodProxy)
throws Throwable;
}
创建一个HelloWorld类:
package com.test;
public class HelloWorld {
public String say(boolean say) throws Exception {
System.out.println("Hello Student");
if(!say) {
throw new Exception("回答错误!");
}
return "回答正确!";
}
}
创建Enhancer增强代理类的回调ProxyFactory类:
package controllers;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
*
* 所有方法的代理的回调
*
* @version 1.0
* @since JDK1.7
*/
public class ProxyFactory implements MethodInterceptor {
//要代理的真实对象
private Object obj;
public Object createProxy(Object target) {
this.obj = target;
Enhancer enhancer = new Enhancer();
//设置代理目标
enhancer.setSuperclass(this.obj.getClass());
//设置单一回调对象,在调用中拦截对目标方法的调用
enhancer.setCallback(this);
//设置类加载器
enhancer.setClassLoader(this.obj.getClass().getClassLoader());
return enhancer.create();
}
/**
*
* 方法描述 当对基于代理的方法回调时,在调用原方法之前会调用该方法
* 拦截对目标方法的调用
*
* @param obj 代理对象
* @param method 拦截的方法
* @param args 拦截的方法的参数
* @param proxy 代理
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
Object result = null;
try {
//前置通知
before();
result = proxy.invokeSuper(obj, args);
//后置通知
after();
} catch (Exception e) {
//异常通知
exception();
} finally {
//方法返回前通知
beforeReturning();
}
return result;
}
private void before() {
System.out.println("before method invoke...");
}
private void after() {
System.out.println("after method invoke...");
}
private void exception() {
System.out.println("exception method invoke...");
}
private void beforeReturning() {
System.out.println("beforeReturning method invoke...");
}
}
模拟场景类:
package controllers;
public class EnhancerTest {
public static void main(String[] args) throws Exception {
HelloWorld hello = new HelloWorld();
ProxyFactory proxy = new ProxyFactory();
HelloWorld world = (HelloWorld)proxy.createProxy(hello);
String result = world.say(false);
System.out.println(result);
}
}
输出结果是:
before method invoke...
Hello Student
after method invoke...
beforeReturning method invoke...
回答正确!
把true改为false的结果是:
before method invoke...
Hello Student
exception method invoke...
beforeReturning method invoke...
null
net.sf.cglib.proxy.FixedValue:为提高性能,FixedValue回调对强制某一特定方法返回固定值。
package controllers;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.FixedValue;
public class Test {
public static void main(String[] args) {
HelloWorld hello = new HelloWorld();
Enhancer enhancer = new Enhancer();
//设置代理目标
enhancer.setSuperclass(hello.getClass());
//设置单一回调对象,在调用中拦截对目标方法的调用
enhancer.setCallback(new FixedValue() {
@Override
public Object loadObject() throws Exception {
// TODO Auto-generated method stub
return "FixedValue";
}
});
//设置类加载器
enhancer.setClassLoader(hello.getClass().getClassLoader());
Object obj = enhancer.create();
System.out.println(obj);
}
}
net.sf.cglib.proxy.NoOp:NoOp回调把对方法调用直接委派到这个方法在父类中的实现(也可以理解成真实对象直接调用方法);
public static void main(String[] args) throws Exception {
HelloWorld hello = new HelloWorld();
Enhancer enhancer = new Enhancer();
//设置代理目标
enhancer.setSuperclass(hello.getClass());
//设置单一回调对象,在调用中拦截对目标方法的调用
enhancer.setCallback(NoOp.INSTANCE);
//设置类加载器
enhancer.setClassLoader(hello.getClass().getClassLoader());
HelloWorld obj = (HelloWorld)enhancer.create();
System.out.println(obj.say(true));
}
net.sf.cglib.proxy.LazyLoader:当实际的对象需要延迟装载时,可以使用LazyLoader回调。一旦实际对象被装载,它将被每一个调用代理对象的方法使用;
net.sf.cglib.proxy.Dispatcher:Dispathcer回调和LazyLoader回调有相同的特点,不同的是,当代理方法被调用时,装载对象的方法也总要被调用;
net.sf.cglib.proxy.ProxyRefDispatcher:ProxyRefDispatcher回调和Dispatcher一样,不同的是,它可以把代理对象作为装载对象方法的一个参数传递;
net.sf.cglib.proxy.CallbackFilter允许我们在方法层设置回调(callback),根据我们对方法处理的需求设置不同的回调;如下有一个类HelloWorld,里面有两个方法save和update,save方法需要做前置和后置处理,但是update方法不需要:
package controllers;
public class HelloWorld {
public String save() {
System.out.println("save...");
return "save";
}
public String update() {
System.out.println("update...");
return "update";
}
}
package controllers;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.CallbackFilter;
/**
*
* 回调过滤器
*
* @version 1.0
* @since JDK1.7
*/
public class CallBackFilterTest implements CallbackFilter{
/**
* 方法返回的值是和callback回调接口数组一一对应的数组下标
*/
@Override
public int accept(Method method) {
String name = method.getName();
if("save".equals(name)) {
return 0;
}
return 1;
}
}
accept方法中对代理方法和回调进行了匹配,返回的值是某个方法在回调数组中的索引;下面是Test类的示例,在这个例子中save方法使用了ProxyFactory回调,update方法使用了NoOp回调;:
package controllers;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.FixedValue;
import net.sf.cglib.proxy.NoOp;
public class Test {
public static void main(String[] args) throws Exception {
HelloWorld hello = new HelloWorld();
Enhancer enhancer = new Enhancer();
//设置代理目标
enhancer.setSuperclass(hello.getClass());
//设置调用过滤器
CallbackFilter filter = new CallBackFilterTest();
enhancer.setCallbackFilter(filter);
//创建各个目标代理方法的回调,回调的顺序要与过滤器索引一致
Callback callbacks[] = new Callback[] {new ProxyFactory(), NoOp.INSTANCE};
//设置单一回调对象,在调用中拦截对目标方法的调用
// enhancer.setCallback(NoOp.INSTANCE);
enhancer.setCallbacks(callbacks);
//设置类加载器
enhancer.setClassLoader(hello.getClass().getClassLoader());
HelloWorld obj = (HelloWorld)enhancer.create();
System.out.println(obj.update());
System.out.println("=============");
System.out.println(obj.save());
}
}
输出结果如下:
update...
update
=============
before method invoke...
save...
after method invoke...
beforeReturning method invoke...
save