前言:动态代理作为代理模式的一种扩展形式,广泛应用于框架(尤其是基于AOP的框架)的设计与开发。
jdk动态代理
下面将代码实例展示
package cn.mode.proxy;
/**
* 接口类
* @author zzh
*
*/
public interface People {
void say(int i);
}
package cn.mode.proxy;
/**
* 实现类
* @author zzh
*
*/
public class Girl implements People {
@Override
public void say(int i) {
if (i == 1) {
System.out.println("我在吃饭");
} else {
System.out.println("我什么事都没做");
}
}
}
package cn.mode.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Date;
/**
* 代理类
* @author zzh
*
*/
public class SayHandler implements InvocationHandler {
private Object obj;
//构造方法传入代理
public SayHandler(Object obj) {
this.obj = obj;
}
public SayHandler() {
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("开始代理,时间:" + new Date());
Object result = method.invoke(obj, args);
System.out.println("代理结束");
return result;
}
}
package cn.mode.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
* 测试类
* @author zzh
*
*/
public class Test {
public static void main(String[] args) {
People people = new Girl();
//代理类
InvocationHandler handler = new SayHandler(people);
//代理对象
People proxy = (People) Proxy.newProxyInstance(People.class.getClassLoader(), new Class[]{People.class}, handler);
proxy.say(1);
}
}
输出:
开始代理,时间:Sun Mar 27 21:24:58 CST 2016
我在吃饭
代理结束
jdk动态代理只能代理一个或多个接口,如果需要动态代理具体类或抽象类,可以使用cglib动态代理。
cglib动态代理
看一个例子
package cn.mode.proxy.cglib;
public class People {
public void say() {
System.out.println("吃吃");
}
}
package cn.mode.proxy.cglib;
public class Girl extends People {
@Override
public void say() {
System.out.println("我在吃饭");
}
}
package cn.mode.proxy.cglib;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class PeopleProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class<?> clazz){
//设置需要创建子类的类
enhancer.setSuperclass(clazz);
//回调
enhancer.setCallback(this);
//通过字节码技术动态创建子类实例
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("代理前");
Object object = proxy.invokeSuper(obj, args);
System.out.println("代理后");
return object;
}
}
package cn.mode.proxy.cglib;
public class Test {
public static void main(String[] args) {
PeopleProxy proxy = new PeopleProxy();
People people = (People) proxy.getProxy(Girl.class);
people.say();
}
}
输出:
代理前
我在吃饭
代理后
对比
jdk的动态代理使用的反射,cglib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用。
jdk动态代理创建的时间的比cglib快,cglib的创建后的使用效率比较高,对于创建后使用频率较多的建议使用cglib。
由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。