1、cglib动态代理
-
引入cglib.jar+asm.jar包。不同于JDK动态代理,cglib代理是通过继承方式实现的(方法不能是final修饰的)
-
创建代理类:
/** * @ClassName Sweetheart * @Description TODO 代理类 * @Version 1.0 **/ public class Sweetheart implements MethodInterceptor { //底层通过继承实现 public Object getInstance(Class<?> targetProxy) { //Enhancer相当于Proxy工具 Enhancer enhancer = new Enhancer(); //把被代理类设置成父类 enhancer.setSuperclass(targetProxy); //回调下面的intercept(); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { //方法增强 before(); Object o1 = methodProxy.invokeSuper(o, objects); after(); return o1; } private void before() { System.out.println("打理公司"); } private void after() { System.out.println("管理人员"); } }
-
被代理类
/** * @ClassName Boss * @Description TODO 被代理对象 * @Version 1.0 **/ public class Boss { public void managementCompany() { System.out.println("管理公司"); } }
-
测试
/** * @ClassName CgLibProxyTest * @Description TODO * @Version 1.0 **/ public class CgLibProxyTest { public static void main(String[] args) { Sweetheart sweetheart = new Sweetheart(); Boss boss = (Boss) sweetheart.getInstance(Boss.class); boss.managementCompany(); } }
-
测试结果
上班帮boss整理文件,端茶倒水 管理公司 下班帮boss关门
-
利用cglib提供的.class生成工具,看看本地生成的文件
1)./** * @ClassName CgLibProxyTest * @Description TODO * @Version 1.0 **/ public class CgLibProxyTest { public static void main(String[] args) { System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "G:\\cglib_proxy_classes"); Sweetheart sweetheart = new Sweetheart(); Boss boss = (Boss) sweetheart.getInstance(Boss.class); System.out.println(boss.getClass()); boss.managementCompany(); } }
2). 会在G:\cglib_proxy_classes 文件夹下生成三个文件
CGLIB debugging enabled, writing to 'G:\cglib_proxy_classes' class com.ByteDance.cglibproxy.Boss$$EnhancerByCGLIB$$c39f714e 上班帮boss整理文件,端茶倒水 管理公司 下班帮boss关门
3). 用jad工具反编译一下
先看看生成的代理对象:
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov. // Jad home page: http://www.kpdus.com/jad.html // Decompiler options: packimports(3) // Source File Name: <generated> package com.ByteDance.cglibproxy; import java.lang.reflect.Method; import net.sf.cglib.core.ReflectUtils; import net.sf.cglib.core.Signature; import net.sf.cglib.proxy.*; // Referenced classes of package com.ByteDance.cglibproxy: // Boss public class Boss$$EnhancerByCGLIB$$c39f714e extends Boss implements Factory { static void CGLIB$STATICHOOK1() { Method amethod[]; Method amethod1[]; CGLIB$THREAD_CALLBACKS = new ThreadLocal(); CGLIB$emptyArgs = new Object[0]; Class class1 = Class.forName("com.ByteDance.cglibproxy.Boss$$EnhancerByCGLIB$$c39f714e"); Class class2; amethod = ReflectUtils.findMethods(new String[] { "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;" }, (class2 = Class.forName("java.lang.Object")).getDeclaredMethods()); Method[] _tmp = amethod; CGLIB$equals$1$Method = amethod[0]; CGLIB$equals$1$Proxy = MethodProxy.create(class2, class1, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1"); CGLIB$toString$2$Method = amethod[1]; CGLIB$toString$2$Proxy = MethodProxy.create(class2, class1, "()Ljava/lang/String;", "toString", "CGLIB$toString$2"); CGLIB$hashCode$3$Method = amethod[2]; CGLIB$hashCode$3$Proxy = MethodProxy.create(class2, class1, "()I", "hashCode", "CGLIB$hashCode$3"); CGLIB$clone$4$Method = amethod[3]; CGLIB$clone$4$Proxy = MethodProxy.create(class2, class1, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4"); amethod1 = ReflectUtils.findMethods(new String[] { "managementCompany", "()V" }, (class2 = Class.forName("com.ByteDance.cglibproxy.Boss")).getDeclaredMethods()); Method[] _tmp1 = amethod1; CGLIB$managementCompany$0$Method = amethod1[0]; CGLIB$managementCompany$0$Proxy = MethodProxy.create(class2, class1, "()V", "managementCompany", "CGLIB$managementCompany$0"); } final void CGLIB$managementCompany$0() { super.managementCompany(); } public final void managementCompany() { CGLIB$CALLBACK_0; if(CGLIB$CALLBACK_0 != null) goto _L2; else goto _L1 _L1: JVM INSTR pop ; CGLIB$BIND_CALLBACKS(this); CGLIB$CALLBACK_0; _L2: JVM INSTR dup ; JVM INSTR ifnull 37; goto _L3 _L4 _L3: break MISSING_BLOCK_LABEL_21; _L4: break MISSING_BLOCK_LABEL_37; this; CGLIB$managementCompany$0$Method; CGLIB$emptyArgs; CGLIB$managementCompany$0$Proxy; intercept(); return; super.managementCompany(); return; } final boolean CGLIB$equals$1(Object obj) { return super.equals(obj); } public final boolean equals(Object obj) { CGLIB$CALLBACK_0; if(CGLIB$CALLBACK_0 != null) goto _L2; else goto _L1 _L1: JVM INSTR pop ; CGLIB$BIND_CALLBACKS(this); CGLIB$CALLBACK_0; _L2: JVM INSTR dup ; JVM INSTR ifnull 57; goto _L3 _L4 _L3: this; CGLIB$equals$1$Method; new Object[] { obj }; CGLIB$equals$1$Proxy; intercept(); JVM INSTR dup ; JVM INSTR ifnonnull 50; goto _L5 _L6 _L5: JVM INSTR pop ; false; goto _L7 _L6: (Boolean); booleanValue(); _L7: return; _L4: return super.equals(obj); } final String CGLIB$toString$2() { return super.toString(); } public final String toString() { CGLIB$CALLBACK_0; if(CGLIB$CALLBACK_0 != null) goto _L2; else goto _L1 _L1: JVM INSTR pop ; CGLIB$BIND_CALLBACKS(this); CGLIB$CALLBACK_0; _L2: JVM INSTR dup ; JVM INSTR ifnull 40; goto _L3 _L4 _L3: this; CGLIB$toString$2$Method; CGLIB$emptyArgs; CGLIB$toString$2$Proxy; intercept(); (String); return; _L4: return super.toString(); } final int CGLIB$hashCode$3() { return super.hashCode(); } public final int hashCode() { CGLIB$CALLBACK_0; if(CGLIB$CALLBACK_0 != null) goto _L2; else goto _L1 _L1: JVM INSTR pop ; CGLIB$BIND_CALLBACKS(this); CGLIB$CALLBACK_0; _L2: JVM INSTR dup ; JVM INSTR ifnull 52; goto _L3 _L4 _L3: this; CGLIB$hashCode$3$Method; CGLIB$emptyArgs; CGLIB$hashCode$3$Proxy; intercept(); JVM INSTR dup ; JVM INSTR ifnonnull 45; goto _L5 _L6 _L5: JVM INSTR pop ; 0; goto _L7 _L6: (Number); intValue(); _L7: return; _L4: return super.hashCode(); } final Object CGLIB$clone$4() throws CloneNotSupportedException { return super.clone(); } protected final Object clone() throws CloneNotSupportedException { CGLIB$CALLBACK_0; if(CGLIB$CALLBACK_0 != null) goto _L2; else goto _L1 _L1: JVM INSTR pop ; CGLIB$BIND_CALLBACKS(this); CGLIB$CALLBACK_0; _L2: JVM INSTR dup ; JVM INSTR ifnull 37; goto _L3 _L4 _L3: this; CGLIB$clone$4$Method; CGLIB$emptyArgs; CGLIB$clone$4$Proxy; intercept(); return; _L4: return super.clone(); } public static MethodProxy CGLIB$findMethodProxy(Signature signature) { String s = signature.toString(); s; s.hashCode(); JVM INSTR lookupswitch 5: default 120 // -508378822: 60 // 421908091: 72 // 1826985398: 84 // 1913648695: 96 // 1984935277: 108; goto _L1 _L2 _L3 _L4 _L5 _L6 _L2: "clone()Ljava/lang/Object;"; equals(); JVM INSTR ifeq 121; goto _L7 _L8 _L8: break MISSING_BLOCK_LABEL_121; _L7: return CGLIB$clone$4$Proxy; _L3: "managementCompany()V"; equals(); JVM INSTR ifeq 121; goto _L9 _L10 _L10: break MISSING_BLOCK_LABEL_121; _L9: return CGLIB$managementCompany$0$Proxy; _L4: "equals(Ljava/lang/Object;)Z"; equals(); JVM INSTR ifeq 121; goto _L11 _L12 _L12: break MISSING_BLOCK_LABEL_121; _L11: return CGLIB$equals$1$Proxy; _L5: "toString()Ljava/lang/String;"; equals(); JVM INSTR ifeq 121; goto _L13 _L14 _L14: break MISSING_BLOCK_LABEL_121; _L13: return CGLIB$toString$2$Proxy; _L6: "hashCode()I"; equals(); JVM INSTR ifeq 121; goto _L15 _L16 _L16: break MISSING_BLOCK_LABEL_121; _L15: return CGLIB$hashCode$3$Proxy; _L1: JVM INSTR pop ; return null; } public static void CGLIB$SET_THREAD_CALLBACKS(Callback acallback[]) { CGLIB$THREAD_CALLBACKS.set(acallback); } public static void CGLIB$SET_STATIC_CALLBACKS(Callback acallback[]) { CGLIB$STATIC_CALLBACKS = acallback; } private static final void CGLIB$BIND_CALLBACKS(Object obj) { Boss$$EnhancerByCGLIB$$c39f714e boss$$enhancerbycglib$$c39f714e = (Boss$$EnhancerByCGLIB$$c39f714e)obj; if(boss$$enhancerbycglib$$c39f714e.CGLIB$BOUND) goto _L2; else goto _L1 _L1: Object obj1; boss$$enhancerbycglib$$c39f714e.CGLIB$BOUND = true; obj1 = CGLIB$THREAD_CALLBACKS.get(); obj1; if(obj1 != null) goto _L4; else goto _L3 _L3: JVM INSTR pop ; CGLIB$STATIC_CALLBACKS; if(CGLIB$STATIC_CALLBACKS != null) goto _L4; else goto _L5 _L5: JVM INSTR pop ; goto _L2 _L4: (Callback[]); boss$$enhancerbycglib$$c39f714e; JVM INSTR swap ; 0; JVM INSTR aaload ; (MethodInterceptor); CGLIB$CALLBACK_0; _L2: } public Object newInstance(Callback acallback[]) { CGLIB$SET_THREAD_CALLBACKS(acallback); CGLIB$SET_THREAD_CALLBACKS(null); return new Boss$$EnhancerByCGLIB$$c39f714e(); } public Object newInstance(Callback callback) { CGLIB$SET_THREAD_CALLBACKS(new Callback[] { callback }); CGLIB$SET_THREAD_CALLBACKS(null); return new Boss$$EnhancerByCGLIB$$c39f714e(); } public Object newInstance(Class aclass[], Object aobj[], Callback acallback[]) { CGLIB$SET_THREAD_CALLBACKS(acallback); JVM INSTR new #2 <Class Boss$$EnhancerByCGLIB$$c39f714e>; JVM INSTR dup ; aclass; aclass.length; JVM INSTR tableswitch 0 0: default 35 // 0 28; goto _L1 _L2 _L2: JVM INSTR pop ; Boss$$EnhancerByCGLIB$$c39f714e(); goto _L3 _L1: JVM INSTR pop ; throw new IllegalArgumentException("Constructor not found"); _L3: CGLIB$SET_THREAD_CALLBACKS(null); return; } public Callback getCallback(int i) { CGLIB$BIND_CALLBACKS(this); this; i; JVM INSTR tableswitch 0 0: default 30 // 0 24; goto _L1 _L2 _L2: CGLIB$CALLBACK_0; goto _L3 _L1: JVM INSTR pop ; null; _L3: return; } public void setCallback(int i, Callback callback) { switch(i) { case 0: // '\0' CGLIB$CALLBACK_0 = (MethodInterceptor)callback; break; } } public Callback[] getCallbacks() { CGLIB$BIND_CALLBACKS(this); this; return (new Callback[] { CGLIB$CALLBACK_0 }); } public void setCallbacks(Callback acallback[]) { this; acallback; JVM INSTR dup2 ; 0; JVM INSTR aaload ; (MethodInterceptor); CGLIB$CALLBACK_0; } 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$managementCompany$0$Method; private static final MethodProxy CGLIB$managementCompany$0$Proxy; private static final Object CGLIB$emptyArgs[]; private static final Method CGLIB$equals$1$Method; private static final MethodProxy CGLIB$equals$1$Proxy; private static final Method CGLIB$toString$2$Method; private static final MethodProxy CGLIB$toString$2$Proxy; private static final Method CGLIB$hashCode$3$Method; private static final MethodProxy CGLIB$hashCode$3$Proxy; private static final Method CGLIB$clone$4$Method; private static final MethodProxy CGLIB$clone$4$Proxy; static { CGLIB$STATICHOOK1(); } public Boss$$EnhancerByCGLIB$$c39f714e() { CGLIB$BIND_CALLBACKS(this); } }
首先代理对象会找managementCompany()方法 → 通过回调找拦截器的invoke()方法 → methodProxy.invokeSuper() → final void CGLIB$managementCompany$0() → 调用被代理对象super.managementCompany() 这里可以看到具体是由MethodProxy这个类进行实现的,看看这个类的源码
public class MethodProxy { private Signature sig1; private Signature sig2; private MethodProxy.CreateInfo createInfo; private final Object initLock = new Object(); private volatile MethodProxy.FastClassInfo fastClassInfo; public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) { MethodProxy proxy = new MethodProxy(); proxy.sig1 = new Signature(name1, desc); proxy.sig2 = new Signature(name2, desc); proxy.createInfo = new MethodProxy.CreateInfo(c1, c2); return proxy; } private void init() { if (this.fastClassInfo == null) { synchronized(this.initLock) { if (this.fastClassInfo == null) { MethodProxy.CreateInfo ci = this.createInfo; MethodProxy.FastClassInfo fci = new MethodProxy.FastClassInfo(); fci.f1 = helper(ci, ci.c1); fci.f2 = helper(ci, ci.c2); fci.i1 = fci.f1.getIndex(this.sig1); fci.i2 = fci.f2.getIndex(this.sig2); this.fastClassInfo = fci; this.createInfo = null; } } } } private static FastClass helper(MethodProxy.CreateInfo ci, Class type) { Generator g = new Generator(); g.setType(type); g.setClassLoader(ci.c2.getClassLoader()); g.setNamingPolicy(ci.namingPolicy); g.setStrategy(ci.strategy); g.setAttemptLoad(ci.attemptLoad); return g.create(); } private MethodProxy() { } public Signature getSignature() { return this.sig1; } public String getSuperName() { return this.sig2.getName(); } public int getSuperIndex() { this.init(); return this.fastClassInfo.i2; } FastClass getFastClass() { this.init(); return this.fastClassInfo.f1; } FastClass getSuperFastClass() { this.init(); return this.fastClassInfo.f2; } public static MethodProxy find(Class type, Signature sig) { try { Method m = type.getDeclaredMethod("CGLIB$findMethodProxy", MethodInterceptorGenerator.FIND_PROXY_TYPES); return (MethodProxy)m.invoke((Object)null, sig); } catch (NoSuchMethodException var3) { throw new IllegalArgumentException("Class " + type + " does not use a MethodInterceptor"); } catch (IllegalAccessException var4) { throw new CodeGenerationException(var4); } catch (InvocationTargetException var5) { throw new CodeGenerationException(var5); } } public Object invoke(Object obj, Object[] args) throws Throwable { try { this.init(); MethodProxy.FastClassInfo fci = this.fastClassInfo; return fci.f1.invoke(fci.i1, obj, args); } catch (InvocationTargetException var4) { throw var4.getTargetException(); } catch (IllegalArgumentException var5) { if (this.fastClassInfo.i1 < 0) { throw new IllegalArgumentException("Protected method: " + this.sig1); } else { throw var5; } } } public Object invokeSuper(Object obj, Object[] args) throws Throwable { try { this.init(); MethodProxy.FastClassInfo fci = this.fastClassInfo; return fci.f2.invoke(fci.i2, obj, args); } catch (InvocationTargetException var4) { throw var4.getTargetException(); } } private static class CreateInfo { Class c1; Class c2; NamingPolicy namingPolicy; GeneratorStrategy strategy; boolean attemptLoad; public CreateInfo(Class c1, Class c2) { this.c1 = c1; this.c2 = c2; AbstractClassGenerator fromEnhancer = AbstractClassGenerator.getCurrent(); if (fromEnhancer != null) { this.namingPolicy = fromEnhancer.getNamingPolicy(); this.strategy = fromEnhancer.getStrategy(); this.attemptLoad = fromEnhancer.getAttemptLoad(); } } } private static class FastClassInfo { FastClass f1; FastClass f2; int i1; int i2; private FastClassInfo() { } } }
可以看到具体是由fci.f2.invoke(fci.i2, obj, args); 调用代理方法的, 这个FastClassInfo中的f1和f2分别是下面两个文件,一个是代理类,一个是被代理类
FastClass f1 代理类
FastClass f2 被代理类
FastClass会为代理方法生成一个index,并且当做入参,这样就会快速找到对应的代理方法,而不需要通过反射来获取, 因此cglib在调用方法的时候效率比JDK代理要高; f1和f2不是在生成代理类时就有,而是在MethodProxy第一次调用invoke() 或者invokeSuper()时通过它的init()生成的,init()会先在缓存找。
2.Spring中应用
Spring中的ProxyFactoryBean最核心的getObject(),在spring中默认是生成singleton的代理bean,多实例的比较复杂
public Object getObject() throws BeansException {
initializeAdvisorChain();
if (isSingleton()) {
return getSingletonInstance();
} else {
if (this.targetName == null) {
logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " + "Enable prototype proxies by setting the 'targetName' property.");
}
return newPrototypeInstance();
}
}
spring通过AopProxy下的JdkDynamicAopProxy和CglibAopProxy来实现动态代理,
1、如果bean实现了接口,则用JdkDynamicAopProxy
2、如果bean没有实现接口,则用CglibAopProxy
在spring中,可用通过配置强制指定使用CglibAopProxy,如
1、<aop:aspectj-autoproxy proxy-target-class="true"/>,强制用cglib
2、@EnableAspectJAutoProxy(proxyTargetClass = true),强制用cglib (只要引入了AOP依赖后,默认开启)
3、yml加
spring:
aop:
proxy-target-class: true ,强制用cglib