JDK接口动态代理
JDK自带的动态代理通过动态的根据接口生成字节码(实现接口的一个具体类)的方式,为接口的实现类提供代理。被代理的对象和代理对象通过InvocationHandler建立关联
package com.tom;
import com.tom.model.User;
import com.tom.service.IUserService;
import com.tom.service.UserService;
import java.lang.reflect.*;
class JdkInvocationHandler<T> implements InvocationHandler {
//target是被代理的对象,构造注入到InvocationHandler中
private T target;
public JdkInvocationHandler(T target) {
this.target = target;
}
//invoke方法由代理对象调用,其中的proxy即是代理对象(不是被代理的对象)
//method和args是代理对象要执行的方法及其参数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(String.format("Start to call %s", method.getName()));
Object obj = method.invoke(this.target, args);
System.out.println(String.format("End to call %s", method.getName()));
return obj;
}
}
public class JdkProxyTest {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
InvocationHandler h = new JdkInvocationHandler<IUserService>(new UserService());
//****************第一种方法****************
//获得JDK的Proxy类字节码,类型为com.sun.proxy.$Proxy0
Class proxyClass = Proxy.getProxyClass(UserService.class.getClassLoader(), new Class[]{IUserService.class});
//获得com.sun.proxy.$Proxy0还有InvocationHandler参数的构造方法
Constructor proxyConstructor = proxyClass.getConstructor(InvocationHandler.class);
//构造$Proxy0的实例
IUserService service = (IUserService) proxyConstructor.newInstance(h);
//调用$Proxy0的save方法,方法实现是将方法调用转到InvocationHandler.invoke的调用
service.save(new User());
//****************第二种方法****************
//使用Proxy.newProxyInstance一步到位创建$Proxy0实例
service = (IUserService) Proxy.newProxyInstance(UserService.class.getClassLoader(), new Class[]{IUserService.class}, h);
service.save(new User());
}
}
cglib类动态代理
cglib是一个开源项目! 是强大的,高性能字节码生成类库,它可以在运行期扩展Java类与实现Java接口。CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。通过使用CGLIB来为那些没有接口的类创建代理对象。
Spring AOP提供了JDK接口动态代理和基于cglib类代理两种方式。使用cglib代理时,需要在配置中显式指明要使用cglib代理
cglib通过运行时创建被代理类的子类的方式生成字节码,通过被代理类的子类提供代理功能。因此声明为final的类不能被代理
CGLIB类动态代理
package com.tom;
import com.tom.model.User;
import com.tom.service.IUserService;
import com.tom.service.UserService;
import net.sf.cglib.proxy.*;
import java.lang.reflect.Method;
class UserServiceMethodInterceptor1 implements MethodInterceptor {
@Override
/**
*
* @param o 代理对象,例如com.tom.service.UserService$$EnhancerByCGLIB$$9257af4@360771
* @param method 被代理类定义的原始方法,比如UserService.save
* @param objects 方法调用的参数列表
* @param methodProxy 对method进行代理的方法,比如CGLIB$save$0
* @return
* @throws Throwable
*/
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//输出:MethodInterceptor is called ..save , CGLIB$save$0
System.out.println("MethodInterceptor1 is called .." + method.getName() + " , " + methodProxy.getSuperName());
//调动UserService的方法
return methodProxy.invokeSuper(o, objects);
}
}
class UserServiceMethodInterceptor2 implements MethodInterceptor {
@Override
/**
*
* @param o 代理对象,例如com.tom.service.UserService$$EnhancerByCGLIB$$9257af4@360771
* @param method 被代理类定义的原始方法,比如UserService.save
* @param objects 方法调用的参数列表
* @param methodProxy 对method进行代理的方法,比如CGLIB$save$0
* @return
* @throws Throwable
*/
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//输出:MethodInterceptor is called ..save , CGLIB$save$0
System.out.println("MethodInterceptor2 is called .." + method.getName() + " , " + methodProxy.getSuperName());
//调动UserService的方法
return methodProxy.invokeSuper(o, objects);
}
}
public class CglibTest {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);
enhancer.setClassLoader(UserService.class.getClassLoader());
//Callback干啥的,Callback接口没有任何方法
//MethodInterceptor接口继承了Callback接口,因此这里可以注入三个MethodInterceptor的实例
enhancer.setCallbacks(new Callback [] {new UserServiceMethodInterceptor1(), new UserServiceMethodInterceptor2(), NoOp.INSTANCE});
//过滤??
enhancer.setCallbackFilter(new CallbackFilter() {
@Override
public int accept(Method method) { //UserService中定义的所有方法都要过滤一遍,比如save,delete,hashCode,equals,finalize等
if (method.getName().equals("save")) {
return 0; //使用第一个拦截器(这里设置了两个Callback)进行拦截
}
if (method.getName().equals("delete")) {
return 1;
}
return 2; //使用第三个拦截器,不做任何拦截
}
});
//创建代理类实例,因为代理类被代理类的子类,因此,需要考虑父类的构造
IUserService proxyObj = (IUserService) enhancer.create();//调用父类的构造方法,create的重载方法可以调用指定参数的构造方法
//代理对象调用方法
proxyObj.save(new User());
proxyObj.delete(new User());
proxyObj.hashCode(); //不会调用拦截器
System.out.println(proxyObj.getClass().getName());
}
}
总结
cglib创建代理对象的速度比JDK动态代理慢几倍,代理对象调用方法执行时,cglib执行速度要比JDK快几倍,因此如果需要频繁的创建代理对象,可以使用JDK动态代理,如果代理对象是单例,考虑使用cglib代理
性能比较参考:http://exceptioneye.iteye.com/blog/1774631