使用一个代理将对象包装起来, 然后用该代理对象取代原始对象. 任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。
JDK动态代理
- 被代理的类必须实现接口,代理的方法是接口的方法
- 使用Proxy的静态方法:
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)生成一个代理类 - InvocationHandler 的 invoke方法就是代理类最后执行的方法
示例
interface Human {
void info();
void fly();
}
// 被代理类
static class SuperMan implements Human {
public void info() {
System.out.println("我是超人");
}
public void fly() {
System.out.println("I can fly!");
}
}
static class MyInvocationHandler implements InvocationHandler {
// 被代理类对象的声明
Object obj;
// 动态的创建一个代理类的对象
public Object bind(Object obj){
this.obj = obj;
//生成一个动态类
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("代理前操作。。。");
Object returnVal = method.invoke(obj, args);
System.out.println("代理后操作。。。");
return returnVal;
}
}
//调用
public static void main(String[] args) {
//创建一个被代理类的对象
SuperMan man = new SuperMan();
MyInvocationHandler handler = new MyInvocationHandler();
//返回一个代理类的对象
Object obj = handler.bind(man);
System.out.println(obj.getClass());
//代理实例 强转
Human hu = (Human)obj;
//通过代理类的对象调用重写的抽象方法
hu.info();
System.out.println();
hu.fly();
}
Proxy.newProxyInstance 源码
先getProxyClass0生成代理类 放回Class
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
//最关键一步,获取代理类(Human$Proxy0)的Class,使用native方法生成字节码
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
//通过反射获取构造方法:public Human$Proxy0(InvocationHandler ih){}
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
//相当于 new Human$Proxy0(h)
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
生成的代理类代码
通过newProxyInstance生成的类近似类:
public final class Human$Proxy0 extends Proxy implements Human {
private static Method info;
private static Method fly;
InvocationHandler ih;
public Human$Proxy0(InvocationHandler paramInvocationHandler) {
ih = paramInvocationHandler;
}
@Override
public void info() {
ih.invke(this, info, null);
}
@Override
public void fly() {
ih.invke(this, fly, null);
}
}
CGLIB代理
JDK代理必须实现接口,CGLIB不需要,主要是对指定的类生成一个子类,覆盖其中的方法。因为是继承,所以该类或方法不能声明成final。
示例
// 被代理类,未实现接口
static class SuperMan {
public void info() {
System.out.println("我是超人");
}
public void fly() {
System.out.println("I can fly!");
}
}
static class CGLibProxy implements MethodInterceptor {
// CGLib需要代理的目标对象
private Object targetObject;
public Object bind(Object obj) {
this.targetObject = obj;
Enhancer enhancer = new Enhancer();
// 设置父类--可以是类或者接口
enhancer.setSuperclass(obj.getClass());
enhancer.setCallback(this);
Object proxyObj = enhancer.create();
// 返回代理对象
return proxyObj;
}
@Override
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
Object obj = null;
System.out.println("代理前操作。。。");
// 执行目标目标对象方法
obj = method.invoke(targetObject, args);
System.out.println("代理后操作。。。");
return obj;
}
}
public static void main(String[] args) {
SuperMan man = new SuperMan();//创建一个被代理类的对象
// 添加如下代码,获取代理类源文件
String path = CGLibProxy.class.getResource(".").getPath();
System.out.println(path);
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, path);
CGLibProxy cgLibProxy = new CGLibProxy();
Object obj = cgLibProxy.bind(man);//返回一个代理类的对象
System.out.println(obj.getClass());
//class com.web.test.SuperMan$$EnhancerByCGLIB$$3be74240
SuperMan hu = (SuperMan)obj;
hu.info();//通过代理类的对象调用重写的抽象方法
System.out.println();
hu.fly();
}
生成的代理类代码
//继承自SuperMan
public class CglibProxy$SuperMan$$EnhancerByCGLIB$$7c617847 extends SuperMan implements Factory {
private boolean CGLIB$BOUND;
public static Object CGLIB$FACTORY_DATA;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
private MethodInterceptor CGLIB$CALLBACK_0;
private static Object CGLIB$CALLBACK_FILTER;
private static final Method CGLIB$info$0$Method;
private static final MethodProxy CGLIB$info$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$fly$1$Method;
private static final MethodProxy CGLIB$fly$1$Proxy;
private static final Method CGLIB$equals$2$Method;
private static final MethodProxy CGLIB$equals$2$Proxy;
private static final Method CGLIB$toString$3$Method;
private static final MethodProxy CGLIB$toString$3$Proxy;
private static final Method CGLIB$hashCode$4$Method;
private static final MethodProxy CGLIB$hashCode$4$Proxy;
private static final Method CGLIB$clone$5$Method;
private static final MethodProxy CGLIB$clone$5$Proxy;
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("com.proxy.CglibProxy$SuperMan$$EnhancerByCGLIB$$7c617847");
Class var1;
Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
CGLIB$equals$2$Method = var10000[0];
CGLIB$equals$2$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2");
CGLIB$toString$3$Method = var10000[1];
CGLIB$toString$3$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$3");
CGLIB$hashCode$4$Method = var10000[2];
CGLIB$hashCode$4$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$4");
CGLIB$clone$5$Method = var10000[3];
CGLIB$clone$5$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");
var10000 = ReflectUtils.findMethods(new String[]{"info", "()V", "fly", "()V"}, (var1 = Class.forName("com.proxy.CglibProxy$SuperMan")).getDeclaredMethods());
CGLIB$info$0$Method = var10000[0];
CGLIB$info$0$Proxy = MethodProxy.create(var1, var0, "()V", "info", "CGLIB$info$0");
CGLIB$fly$1$Method = var10000[1];
CGLIB$fly$1$Proxy = MethodProxy.create(var1, var0, "()V", "fly", "CGLIB$fly$1");
}
final void CGLIB$info$0() {
super.info();
}
public final void info() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
//使用代理接口Factory的intercept方法
if (var10000 != null) {
var10000.intercept(this, CGLIB$info$0$Method, CGLIB$emptyArgs, CGLIB$info$0$Proxy);
} else {
super.info();
}
}
//
}
Spring AOP
-
Spring中动态代理的实现 Spring代理实际上是对JDK代理和CGLIB代理做了一层封装,并且引入了AOP概念:Aspect、advice、joinpoint等等,同时引入了AspectJ中的一些注解@pointCut,@after,@before等等。Spring Aop严格的来说都是动态代理。
-
Spring在选择用JDK还是CGLiB的依据:
当Bean实现接口时,Spring就会用JDK的动态代理
当Bean没有实现接口时,Spring使用CGlib是实现 -
强制使用CGLIB实现AOP
spring.aop.proxy-target-class=true或者@EnableAspectJAutoProxy(proxyTargetClass = true) -
性能上区别 JDK1.6 1.7下,jdk代理创建比CGLiB快,执行方法比CGLiB慢
1.8 jdk代理更快
Spring AOP中JDK和CGLib动态代理哪个更快?