1、 Java中的动态代理
代理是一种设计模式。代理模式也叫做委托模式,它是一项基本设计技巧。许多其他的模式,如状态模式、策略模式、访问者模式本质上是在更特殊的场合采用了委托模式,而且在日常的应用中,代理模式可以提供非常好的访问控制。

- 类图中的角色
- Subject:抽象主题角色,抽象主题类可以是抽象类也可以是接口,是一个最普通的业务类型定义,无特殊要求。
- RealSbject:具体主题角色,也叫做被委托角色、被代理角色。它才是冤大头,是业务逻辑的具体执行者。
- Proxy:代理主题角色,也叫做委托类、代理类。它负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在真实主题角色处理完毕前后做预处理和善后处理工作。----《设计模式之禅》
其中, Subject 是程序中的业务逻辑接口, RealSubject 是实现了 Subject 接口的真正业务类, Proxy 是实现了 Subject 接口的代理类,其中封装了 RealSubject 对象。在程序中不会直接调动 RealSubject 对象的方法,而是使用 Proxy 对象实现相关功能。 Proxy.operation()方法的实现会调 用 Real Subject对象的 operation()方法执行真正的业务逻辑,但是处理完业务逻辑, Proxy.operation()会在 RealSubject.operation()方法调用前后进行预处理和相关的后置处理。这就 是所谓的“代理模式” ----《Mybatis技术内幕》
总结:
代理模式的思想:用一个代理对象将目标对象包装起来,所有对目标对象的调用,都将转移到对代理对象的调用。在代理对象中根据具体的场景和业务需要来决定调用目标对象之前进行一些其他的操作,如打印日志等等。甚至可以决定是否对目标对象进行调用,参考Mybatis的拦截器和mapper动态代理,以及spring的aop。
Java中的动态代理分为JDK动态代理和cglib动态代理,前者可以代理接口,后者代理类。
2、JDK动态代理
代理模式也有一种被称为“静态代理模式”的,这是因为在编译阶段就要为每个 RealSubject 类创建创建一个 Proxy 类, 当需要代理的类很多时,这就会出现大量的 Proxy 类。 我们可以使用 JDK 动态代理解决这个问题。
JDK动态代理类图:

2.1、介绍
何时使用代理?
假设有一个表示接口的 Class 对象(有可能只包含一个接口,) 它的确切类型在编译时无 法知道。这确实有些难度。要想构造一个实现这些接口的类, 就需要使用 newlnstance 方法 或反射找出这个类的构造器。但是, 不能实例化一个接口,需要在程序处于运行状态时定义 一个新类。
为了解决这个问题, 有些程序将会生成代码;将这些代码放置在一个文件中;调用编译 器;然后再加载结果类文件。很自然, 这样做的速度会比较慢,并且需要将编译器与程序放 在一起。而代理机制则是一种更好的解决方案。代理类可以在运行时创建全新的类。这样的代理类能够实现指定的接口。尤其是,它具有下列方法:
- 指定接口所需要的全部方法。
- Object 类中的全部方法, 例如, toString、 equals 等。 ----《Java核心技术》
JDK动态代理是代理模式的一种。JDK动态代理用于代理接口,不可代理类。在JDK动态代理中有两个重要的类,分别是InvocationHandler和Proxy。
-
InvocationHandler:InvocationHandleris the interface implemented by theinvocation handlerof a proxy instance. InvocationHandler是被每个代理实例(对象)的调用处理器 (invocation handler)实现的接口。Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the
invoke methodof its invocation handler. 每个代理实例都有一个相关联的调用处理器。当一个代理实例的方法被调用时,方法调用被编码并发送到其调用处理程序的 invoke方法。 -
Proxy:provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods. 为生成动态代理类和实例提供静态方法,而且它还是通过那些静态方法创建出的所有动态代理类的父类。----来自Proxy类注释
从上述定义和类图可知,InvocationHandler是Proxy类的一个成员变量h,InvocationHandler里面只定义了一个invoke方法,每个代理对象都有对应的实现了InvocationHandler接口的调用处理器,所有对代理对象方法的调用,最终都会落实到对调用处理器的invoke方法的调用,在invoke方法里面,我们可以决定是否采用反射调用目标对象的方法和做一些其他的业务上的特殊处理。
2.2、示例
UML类图
- Human.class
interface Human {
public void eat(String food, String like);
public String getBelief();
}
- SupMan.class
class SupMan implements Human {
@Override
public void eat(String food, String like) {
System.out.println(like+food);
}
@Override
public String getBelief() {
return "我是最帅的!";
}
}
-
MyInvocationHandler.class
class MyInvocationHandler implements InvocationHandler { //被代理的对象,实际的方法执行者 //https://juejin.im/post/5c1ca8df6fb9a049b347f55c //https://docs.oracle.com/javase/8/docs/technotes/guides/reflection/proxy.html private Object object; public void setObject(Object object) { this.object = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(object, args); } } -
ProxyTest.class
public class ProxyTest { public static void main(String[] args) throws IOException { //打印出的动态生成的代理类 //也可以在jvm启动参数中添加-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); SupMan supMan = new SupMan(); //获取代理对象,注意这里只能强转为接口类型不可以是Human的某个具体实现类 //因为代理对象对应的类和被代理类是两个在继承和实现关系上不相关的两个类 //方法返回的实际类型是public final class Proxy0 extends Proxy implements Human Human proxyInstance = (Human) getProxyInstance(supMan); System.out.println(proxyInstance.getBelief()); proxyInstance.eat("臭豆腐","我喜欢吃"); } public static Object getProxyInstance(Object object) { MyInvocationHandler myInvocationHandler = new MyInvocationHandler(); myInvocationHandler.setObject(object); return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(),myInvocationHandler); } } -
Proxy0.class----动态生成的代理类
所有的代理类都覆盖了 Object 类中的方法 toString、 equals 和 hashCode。如同所有的代 理方法一样,这些方法仅仅调用了调用处理器的 invoke。Object 类中的其他方法(如 clone 和 getClass) 没有被重新定义 。
没有定义代理类的名字,Sun 虚拟机中的 Proxy类将生成一个以字符串 $Proxy 开头的类名。----《Java核心技术》
public final class Proxy0 extends Proxy implements Human {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m4;
private static Method m0;
public Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void eat(String var1, String var2) throws {
try {
super.h.invoke(this, m3, new Object[]{var1, var2});
} catch (RuntimeException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
public final String getBelief() throws {
try {
return (String)super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.shihy.jdk.Human").getMethod("eat", Class.forName("java.lang.String"), Class.forName("java.lang.String"));
m4 = Class.forName("com.shihy.jdk.Human").getMethod("getBelief");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
总结:JDK动态代理,一般会创建一个被代理对象(一般会创建,也存在不创建的,参考下面源码解析的InvocationHandler),然后将被代理对象传入调用处理器InvocationHandler作为其成员变量,以后作为反射方法的参数使用。创建代理对象时候,又会将这个调用处理器InvokerHandler传给代理对象作为其成员变量h,以后会用这个h调用其invoke方法。所以就相当于代理对象是对被代理对象的一层包装。
- 流程
- 浅出
2.3、JDK动态代理源码
Proxy
源码:java.lang.reflect.Proxy
- 包含一个调用处理器最为其成员变量
/**
* the invocation handler for this proxy instance.
* @serial
*/
protected InvocationHandler h;
- newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)方法
/*
* loader:一个类加栽器( class loader)
* interfaces:一个 Class 对象数组, 每个元素都是需要实现的接口
* h:一个调用处理器
*/
@CallerSensitive
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);
}
/*
* Look up or generate the designated proxy class.
* 获取代理类
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
//获取代理类的构造方法
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;
}
});
}
//创建代理对象
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);
}
}
- getProxyClass0(ClassLoader loader, Class<?>... interfaces)方法
/**
* Generate a proxy class. Must call the checkProxyAccess method
* to perform permission checks before calling this.
*/
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
//如果指定的类加载器中已经创建了实现指定接口的代理类,则查找缓存
//否则,会通过ProxyClassFactory 创建实现指定接口的代理类
return proxyClassCache.get(loader, interfaces);
}
proxyClassCache是定义在 Proxy 类中的静态字段,主要用于缓存已经创建过的代理类,定义如下:
/**
* a cache of proxy classes
* 以ClassLoader对象为key,计算出hash值,从WeakCache的
* private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map 中获取
*/
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
WeakCache.get()方法若在缓存中找不到则会调用则会创建 Factory 对象并调用其 get()方法获取代理类。Factory 是 WeakCache 中的内部类, Factory.get()方法会调用 ProxyClassFactory.apply()方法创建并加载代理类。
ProxyClassFactory
源码:java.lang.reflect.Proxy.ProxyClassFactory
- apply(ClassLoader loader, Class<?>[] interfaces)方法
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
........省略部分代码,对interfaces集合进行一系列检查
/*
* Choose a name for the proxy class to generate.
* proxyPkg为接口所在的包+.
* // prefix for all proxy class names
* private static final String proxyClassNamePrefix = "$Proxy";
* num是一个AtomicLong原子类原子加1得到的值
*/
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* Generate the specified proxy class.
* 生成代理类,并写入文件。该方法我们也可以手动调用,随意生成我们想要的代理类
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
........省略部分代码
//加载代理类,并返回Class对象
return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
........省略部分代码
}
}
ProxyGenerator
源码:sun.misc.ProxyGenerator
- ProxyGenerator. generateProxyClass()方法会按照指定的名称和接口集合生成代理类的字节码,并根据条件决定是否保存到磁盘上。该方法的具体代码如下 :
public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
//动态生成代理类的字节码,具体生成过程待研究
final byte[] var4 = var3.generateClassFile();
//如果saveGeneratedFiles值为true,会将生成的代理类的字节码保存到文件中
//private static final boolean saveGeneratedFiles = (Boolean)AccessController
// .doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"));
//所以我们可以使用
//System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
//在程序运行第一步就把系统属性sun.misc.ProxyGenerator.saveGeneratedFiles设置为true
if (saveGeneratedFiles) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
try {
int var1 = var0.lastIndexOf(46);
Path var2;
if (var1 > 0) {
//获取代理类文件要写入的地址,根据代理类全限定名获取,如com.shihy.jdk.$Proxy0,
//var3就是com.shihy.jdk,该路径相对于开发工具里面的项目的根目录。
Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
Files.createDirectories(var3);
var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
} else {
var2 = Paths.get(var0 + ".class");
}
//写出代理类的class文件
Files.write(var2, var4, new OpenOption[0]);
return null;
} catch (IOException var4x) {
throw new InternalError("I/O exception saving generated file: " + var4x);
}
}
});
}
//返回上面生成的代理类的字节码
return var4;
}
InvocationHandler
源码:java.lang.reflect.InvocationHandler
所有自定义的调用处理器的父接口,里面只定义了一个方法invoke。一般情况下,在自定义的调用处理器里面,被代理对象会作为其成员变量,用来利用反射调用method方法。这只是大部分情况,也有例外,参考org.apache.ibatis.binding.MapperProxy,这个调用处理器就没有被代理对象作为成员变量。org.apache.ibatis.plugin.Plugin,这个调用处理器就存在被代理对象作为成员变量。
public interface InvocationHandler {
/**
* Processes a method invocation on a proxy instance and returns
* the result. This method will be invoked on an invocation handler
* when a method is invoked on a proxy instance that it is
* associated with.
* 处理代理实例上的方法调用并返回结果。当在与其关联的代理实例上调用方法时,将在调用处理程序上调用此方法。
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
3、cglib
普通的jdk实现动态代理的主要不足在于:它只能代理实现了接口的类,如果一个类没有继承于任何的接口,那么就不能代理该类,原因是我们动态生成的所有代理类都必须继承Proxy这个类,正是因为Java的单继承,所以注定会抛弃原类型的父类。而我们的cglib通过扫描该类以及其父类中所有的public非final修饰的方法,通过asm定义该类的子类字节码,其中该子类重写了父类所有的方法,然后返回该子类的实例作为代理类。也就是说我们的cglib是用该类的子类作为代理类来实现代理操作的。当然cglib的缺点也是呼之欲出,对于被代理类中的非public或者final修饰的方法,不能实现代理。----参考www.cnblogs.com/yangming199…
cglib动态代理类图:
3.1、介绍
-
cglib的底层技术:
CGLIB是一个强大的高性能的代码生成包。它广泛地被许多AOP的框架使用,例如Spring AOP和dynaop,为它们提供方法的Interception(拦截)。最流行的OR Mapping工具Hibernate也使用CGLIB来代理单端single-ended(多对一和一对一)关联(对集合的延迟抓取是采用其他机制实现的)。EasyMock和jMock是通过使用模仿(moke)对象来测试Java代码的包。它们都通过使用CGLIB来为那些没有接口的类创建模仿(moke)对象。
CGLIB包的底层通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。除了CGLIB包,脚本语言例如Groovy和BeanShell,也是使用ASM来生成Java的字节码。当然不鼓励直接使用ASM,因为它要求你必须对JVM内部结构(包括class文件的格式和指令集)都很熟悉。----《Spring源码深度解析》
-
cglib实现代理需要用到的API:实现
MethodInterceptor接口,利用Enhancer类生成代理类的对象 -
cglib可以代理类也可以代理接口。代理接口,则被代理的接口中的方法,最终会被认为是Object中的方法,所以当代理类对象调用接口中对应的方法的时候,会最终调用到Object中(默认继承Objcet类,代理方法中会调用super.xxxx()),会报
java.lang.NoSuchMethodError: java.lang.Object.xxxx()Ljava/lang/String;一般不会用cglib代理接口。 -
缺点:它需要继承我们的被代理类,所以如果委托类被修饰为 final,那就意味着,这个类 CGLIB 代理不了。即便某个类不是 final 类,但是其中如果有 final 修饰的方法,那么该方法也是不能被代理的。这一点从我们反射的源码可以看出来,CGLIB 生成的代理类需要重写被代理类中所有的方法,而一个修饰为 final 的方法是不允许重写的。
-
MethodInterceptor:方法拦截器,General-purpose {@link Enhancer} callback which provides for "around advice".通用的{@link增强器}回调,提供了“周围通知”。
-
Enhancer:增强器,Generates dynamic subclasses to enable method interception.生成动态子类以启用方法拦截。
3.2、示例
UML类图

-
引入maven依赖
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.6</version> </dependency> -
HelloService.class
//被代理类
public class HelloService {
public HelloService() {
System.out.println("HelloService构造");
}
/**
* 该方法不能被子类覆盖,Cglib是无法代理final修饰的方法的
*/
final public String sayOthers(String name) {
System.out.println("HelloService:sayOthers>>"+name);
return null;
}
public void sayHello() {
System.out.println("HelloService:sayHello");
}
}
- MyMethodInterceptor.class
public class MyMethodInterceptor implements MethodInterceptor {
// 所有生成的代理方法都调用此方法而不是原始方法
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("======插入前置通知======");
methodProxy.invokeSuper(o, objects);
System.out.println("======插入后者通知======");
return null;
}
}
- CglibTest.class
public class CglibTest {
public static void main(String[] args) {
// 获取代理类class文件,存入本地磁盘方便我们反编译查看源码
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:\\shihy\\proxy_dynamic\\target\\classes\\com\\shihy\\cglib");
// 通过CGLIB动态代理获取代理对象
Enhancer enhancer = new Enhancer();
// 为代理类提供父类或接口。接口的话会比类有些特殊,生成的代理类会默认继承Object,那么所有方法的
// 调用都会调用到Object类,若调用的方法是在接口中定义的,很明显Object中不可能有我们自己定义的方法,就会报
// Exception in thread "main" java.lang.NoSuchMethodError: java.lang.Object.getBelief()Ljava/lang/String;
enhancer.setSuperclass(HelloService.class);
// 设置enhancer的回调对象,Callback的子类
enhancer.setCallback(new MyMethodInterceptor());
// 创建代理类和代理对象
HelloService proxy= (HelloService)enhancer.create();
Human P = null;
// 通过代理对象调用目标方法
proxy.sayHello();
}
}
HelloService$$EnhancerByCGLIB$$f6637286.class
该类是就是动态生成的代理类,这里只贴出关键代码,后续源码进行详细分析。
public class HelloService$$EnhancerByCGLIB$$f6637286 extends HelloService implements Factory {
........省略部分代码
private MethodInterceptor CGLIB$CALLBACK_0;
........省略部分代码
final void CGLIB$sayHello$0() {
super.sayHello();
}
public final void sayHello() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
var10000.intercept(this, CGLIB$sayHello$0$Method, CGLIB$emptyArgs, CGLIB$sayHello$0$Proxy);
} else {
super.sayHello();
}
}
........省略部分代码
}
总结:与JDK动态代理不同的是,cglib从头到尾都没有创建被代理类的对象,而是自己动态生成一个继承自被代理类的代理类。然后直接创建代理类的对象,调用代理类的方法,最终会调用到父类中也就是被代理类中的同名方法。
- 流程:

-
深入

-
浅出

3.3、cglib动态代理源码解析
MethodInterceptor
源码:net.sf.cglib.proxy.MethodInterceptor
实现CGLIB动态代理必须实现MethodInterceptor(方法拦截器)接口,源码如下:
/**
* General-purpose {@link Enhancer} callback which provides for "around advice".
* 通用增强器回调,提供了“周围通知”
*/
public interface MethodInterceptor extends Callback
{
/**
* All generated proxied methods call this method instead of the original method.
* The original method may either be invoked by normal reflection using the Method object,
* or by using the MethodProxy (faster).
* @param obj "this", the enhanced object
* @param method intercepted Method
* @param args argument array; primitive types are wrapped
* @param proxy used to invoke super (non-intercepted method); may be called
* as many times as needed
* 这个接口只有一个intercept()方法,这个方法有4个参数:
* 1)obj表示增强的对象(代理对象)
* 2)method表示被代理类的方法对象;
* 3)args表示方法的参数值;
* 4)proxy表示代理类和被代理类同名方法之间的关系;
*/
public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
MethodProxy proxy) throws Throwable;
}
Enhancer
源码:net.sf.cglib.proxy.Enhancer
- 两个关键的属性
.......省略部分代码
//设置要继承的类或要实现的接口
private Class superclass;
//设置我们自定义的方法拦截器
private Callback[] callbacks;
.......省略部分代码
net.sf.cglib.proxy.Enhancer#setSuperclass方法
/*
* 设置生成的类将扩展的类。为了方便起见,如果提供的超类实际上是一个接口,
* 则将使用适当的参数调用setInterfaces方法。非接口参数不能被声明为final,必须有一个可访问的构造函数。
*/
public void setSuperclass(Class superclass) {
if (superclass != null && superclass.isInterface()) {
setInterfaces(new Class[]{ superclass });
} else if (superclass != null && superclass.equals(Object.class)) {
// affects choice of ClassLoader
this.superclass = null;
} else {
this.superclass = superclass;
}
}
net.sf.cglib.proxy.Enhancer#setCallback
/*
*设置单个Callback使用--自定义的方法拦截器。
*如果您使用{@link #createClass}将被忽略。
*/
public void setCallback(final Callback callback) {
setCallbacks(new Callback[]{ callback });
}
net.sf.cglib.proxy.Enhancer#create()
/*
*如果需要,生成一个新类并使用指定的回调(如果有的话)来创建一个新的对象实例。使用超类的无参数构造函数。
*/
public Object create() {
classOnly = false;
argumentTypes = null;
return createHelper();
}
net.sf.cglib.proxy.Enhancer#createHelper
private Object createHelper() {
//校验callbackTypes、filter是否为空,以及为空时的处理。
preValidate();
//通过newInstance()方法创建EnhancerKey对象,作为Enhancer父类AbstractClassGenerator.create()方法
//创建代理对象的参数。
Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
ReflectUtils.getNames(interfaces),
filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter),
callbackTypes,
useFactory,
interceptDuringConstruction,
serialVersionUID);
this.currentKey = key;
//这一步先创建代理类再创建代理对象,创建代理类的代码在
//net.sf.cglib.core.AbstractClassGenerator#create中的Object obj = data.get(this, getUseCache());
//往下跟代码跟到 ---->net.sf.cglib.proxy.Enhancer#generate中就可看到创建代理类
Object result = super.create(key);
return result;
}
net.sf.cglib.core.AbstractClassGenerator#create
protected Object create(Object key) {
try {
ClassLoader loader = getClassLoader();
Map<ClassLoader, ClassLoaderData> cache = CACHE;
ClassLoaderData data = cache.get(loader);
if (data == null) {
synchronized (AbstractClassGenerator.class) {
cache = CACHE;
data = cache.get(loader);
if (data == null) {
Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache);
data = new ClassLoaderData(loader);
newCache.put(loader, data);
CACHE = newCache;
}
}
}
this.key = key;
//生成代理类的class文件
Object obj = data.get(this, getUseCache());
if (obj instanceof Class) {
return firstInstance((Class) obj);
}
//创建代理类对象
return nextInstance(obj);
} catch (RuntimeException e) {
throw e;
} catch (Error e) {
throw e;
} catch (Exception e) {
throw new CodeGenerationException(e);
}
}
真正创建代理对象方法在nextInstance()方法中,该方法为抽象类AbstractClassGenerator的一个方法,签名如下:
abstract protected Object nextInstance(Object instance) throws Exception;
在子类Enhancer中实现,实现源码如下:
net.sf.cglib.proxy.Enhancer#nextInstance
protected Object nextInstance(Object instance) {
EnhancerFactoryData data = (EnhancerFactoryData) instance;
if (classOnly) {
return data.generatedClass;
}
Class[] argumentTypes = this.argumentTypes;
Object[] arguments = this.arguments;
if (argumentTypes == null) {
argumentTypes = Constants.EMPTY_CLASS_ARRAY;
arguments = null;
}
return data.newInstance(argumentTypes, arguments, callbacks);
}
net.sf.cglib.proxy.Enhancer.EnhancerFactoryData#newInstance
/*
* 为给定的参数类型创建代理实例,并分配方法拦截器。
* 理想情况下,对于每个代理类,应该只使用一组参数类型,否则它将不得不花费时间在构造函数查找上。
*/
public Object newInstance(Class[] argumentTypes, Object[] arguments, Callback[] callbacks) {
//1. 设置方法拦截器,见下面1.1和1.2
setThreadCallbacks(callbacks);
try {
// Explicit reference equality is added here just in case Arrays.equals does not have one
if (primaryConstructorArgTypes == argumentTypes ||
Arrays.equals(primaryConstructorArgTypes, argumentTypes)) {
// If we have relevant Constructor instance at hand, just call it
// This skips "get constructors" machinery
return ReflectUtils.newInstance(primaryConstructor, arguments);
}
// Take a slow path if observing unexpected argument types
//2. 调用代理类的构造器返回代理类对象,见下面2.1
return ReflectUtils.newInstance(generatedClass, argumentTypes, arguments);
} finally {
// clear thread callbacks to allow them to be gc'd
//3. 清空ThreadLocal
setThreadCallbacks(null);
}
}
- 1
net.sf.cglib.proxy.Enhancer.EnhancerFactoryData#setThreadCallbacks
private void setThreadCallbacks(Callback[] callbacks) {
try {
//这里会调用代理类的CGLIB$SET_THREAD_CALLBACKS方法,设置方法拦截器
setThreadCallbacks.invoke(generatedClass, (Object) callbacks);
} catch (IllegalAccessException e) {
throw new CodeGenerationException(e);
} catch (InvocationTargetException e) {
throw new CodeGenerationException(e.getTargetException());
}
}

- 2
com.shihy.cglib.HelloService$$EnhancerByCGLIB$$f6637286#CGLIB$SET_THREAD_CALLBACKS
public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
//其中private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
//将方法拦截器放入到ThreadLocal中
CGLIB$THREAD_CALLBACKS.set(var0);
}
- 1
net.sf.cglib.core.ReflectUtils#newInstance(java.lang.reflect.Constructor, java.lang.Object[])
public static Object newInstance(final Constructor cstruct, final Object[] args) {
boolean flag = cstruct.isAccessible();
.......省略部分代码
if (!flag) {
cstruct.setAccessible(true);
}
//创建代理对象
Object result = cstruct.newInstance(args);
return result;
.......省略部分代码
} finally {
if (!flag) {
cstruct.setAccessible(flag);
}
}
}
- 2
com.shihy.cglib.HelloService$$EnhancerByCGLIB$$f6637286#HelloService$$EnhancerByCGLIB$$f6637286代理类构造器
public HelloService$$EnhancerByCGLIB$$f6637286() {
CGLIB$BIND_CALLBACKS(this);
}
private static final void CGLIB$BIND_CALLBACKS(Object var0) {
HelloService$$EnhancerByCGLIB$$f6637286 var1 = (HelloService$$EnhancerByCGLIB$$f6637286)var0;
if (!var1.CGLIB$BOUND) {
var1.CGLIB$BOUND = true;
//将方法拦截器从ThreadLocal中取出来
Object var10000 = CGLIB$THREAD_CALLBACKS.get();
if (var10000 == null) {
var10000 = CGLIB$STATIC_CALLBACKS;
if (var10000 == null) {
return;
}
}
//将方法拦截器赋值给代理类的成员变量,CGLIB$CALLBACK_0,这样代理对象就有了这个方法拦截器
var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
}
}
HelloService$$EnhancerByCGLIB$$f6637286
源码:com.shihy.cglib.HelloService$$EnhancerByCGLIB$$f6637286
从代理对象反编译源码可以知道,代理对象继承于HelloService,方法拦截器调用intercept()方法,intercept()方法由自定义MyMethodInterceptor实现,所以,最后调用MyMethodInterceptor中的intercept()方法,从而完成了由代理对象访问到目标对象的动态代理实现。
//代理类
public class HelloService$$EnhancerByCGLIB$$f6637286 extends HelloService 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$sayHello$0$Method;
private static final MethodProxy CGLIB$sayHello$0$Proxy;
//该参数用于,若方法是无参数方法,则调用方法拦截器的intercept方法时候,传入该参数,默认为长度为0的Object数组
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 void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
//默认为长度为0的Object数组
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("com.shihy.cglib.HelloService$$EnhancerByCGLIB$$f6637286");
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$1$Method = var10000[0];
CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
CGLIB$toString$2$Method = var10000[1];
CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
CGLIB$hashCode$3$Method = var10000[2];
CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
CGLIB$clone$4$Method = var10000[3];
CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
CGLIB$sayHello$0$Method = ReflectUtils.findMethods(new String[]{"sayHello", "(Ljava/lang/String;)V"}, (var1 = Class.forName("com.shihy.cglib.HelloService")).getDeclaredMethods())[0];
CGLIB$sayHello$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)V", "sayHello", "CGLIB$sayHello$0");
}
//父类也即被代理类的sayHello方法的代理方法
final void CGLIB$sayHello$0(String var1) {
super.sayHello(var1);
}
//代理类重写的被代理类中的方法
public final void sayHello(String var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
//调用拦截器的方法
var10000.intercept(this, CGLIB$sayHello$0$Method, new Object[]{var1}, CGLIB$sayHello$0$Proxy);
} else {
super.sayHello(var1);
}
}
final boolean CGLIB$equals$1(Object var1) {
return super.equals(var1);
}
public final boolean equals(Object var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
Object var2 = var10000.intercept(this, CGLIB$equals$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy);
return var2 == null ? false : (Boolean)var2;
} else {
return super.equals(var1);
}
}
final String CGLIB$toString$2() {
return super.toString();
}
public final String toString() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy) : super.toString();
}
final int CGLIB$hashCode$3() {
return super.hashCode();
}
public final int hashCode() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
return var1 == null ? 0 : ((Number)var1).intValue();
} else {
return super.hashCode();
}
}
final Object CGLIB$clone$4() throws CloneNotSupportedException {
return super.clone();
}
protected final Object clone() throws CloneNotSupportedException {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? var10000.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy) : super.clone();
}
public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
String var10000 = var0.toString();
switch(var10000.hashCode()) {
case -508378822:
if (var10000.equals("clone()Ljava/lang/Object;")) {
return CGLIB$clone$4$Proxy;
}
break;
case 771401912:
if (var10000.equals("sayHello(Ljava/lang/String;)V")) {
return CGLIB$sayHello$0$Proxy;
}
break;
case 1826985398:
if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
return CGLIB$equals$1$Proxy;
}
break;
case 1913648695:
if (var10000.equals("toString()Ljava/lang/String;")) {
return CGLIB$toString$2$Proxy;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return CGLIB$hashCode$3$Proxy;
}
}
return null;
}
public HelloService$$EnhancerByCGLIB$$f6637286() {
CGLIB$BIND_CALLBACKS(this);
}
public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
CGLIB$THREAD_CALLBACKS.set(var0);
}
public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
CGLIB$STATIC_CALLBACKS = var0;
}
private static final void CGLIB$BIND_CALLBACKS(Object var0) {
HelloService$$EnhancerByCGLIB$$f6637286 var1 = (HelloService$$EnhancerByCGLIB$$f6637286)var0;
if (!var1.CGLIB$BOUND) {
var1.CGLIB$BOUND = true;
Object var10000 = CGLIB$THREAD_CALLBACKS.get();
if (var10000 == null) {
var10000 = CGLIB$STATIC_CALLBACKS;
if (var10000 == null) {
return;
}
}
var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
}
}
public Object newInstance(Callback[] var1) {
CGLIB$SET_THREAD_CALLBACKS(var1);
HelloService$$EnhancerByCGLIB$$f6637286 var10000 = new HelloService$$EnhancerByCGLIB$$f6637286();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Callback var1) {
CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
HelloService$$EnhancerByCGLIB$$f6637286 var10000 = new HelloService$$EnhancerByCGLIB$$f6637286();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
CGLIB$SET_THREAD_CALLBACKS(var3);
HelloService$$EnhancerByCGLIB$$f6637286 var10000 = new HelloService$$EnhancerByCGLIB$$f6637286;
switch(var1.length) {
case 0:
var10000.<init>();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
default:
throw new IllegalArgumentException("Constructor not found");
}
}
public Callback getCallback(int var1) {
CGLIB$BIND_CALLBACKS(this);
MethodInterceptor var10000;
switch(var1) {
case 0:
var10000 = this.CGLIB$CALLBACK_0;
break;
default:
var10000 = null;
}
return var10000;
}
public void setCallback(int var1, Callback var2) {
switch(var1) {
case 0:
this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
default:
}
}
public Callback[] getCallbacks() {
CGLIB$BIND_CALLBACKS(this);
return new Callback[]{this.CGLIB$CALLBACK_0};
}
public void setCallbacks(Callback[] var1) {
this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
}
static {
CGLIB$STATICHOOK1();
}
}
HelloService$$EnhancerByCGLIB$$f6637286$$FastClassByCGLIB$$c213df86
源码:com.shihy.cglib.HelloService$$EnhancerByCGLIB$$f6637286$$FastClassByCGLIB$$c213df86
在FastClass中有两个方法,getIndex中对代理类的每个方法根据hash建立索引,invoke根据指定的索引,直接调用目标方法,避免了反射调用。所以当调用methodProxy.invokeSuper方法时,实际上是调用代理类的CGLIB$sayHello$0方法,CGLIB$sayHello$0直接调用了被代理类的sayHello方法。
//代理类的FastClass
public class HelloService$$EnhancerByCGLIB$$f6637286$$FastClassByCGLIB$$c213df86 extends FastClass {
........省略部分代码
//根据方法签名获取方法的索引
//var1方法签名
public int getIndex(Signature var1) {
String var10000 = var1.toString();
switch(var10000.hashCode()) {
........省略部分代码
case -1721191351:
if (var10000.equals("CGLIB$sayHello$0(Ljava/lang/String;)V")) {
return 16;
}
break;
........省略部分代码
}
return -1;
}
//根据方法的索引,直接调用代理类的方法
//var1:方法索引
//var2:代理对象
//var3:我们调用方法时候传入的参数,若是无参数的方法,代理类中会默认给个长度为0的Object数组
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
HelloService$$EnhancerByCGLIB$$f6637286 var10000 = (HelloService$$EnhancerByCGLIB$$f6637286)var2;
int var10001 = var1;
try {
switch(var10001) {
.......省略部分代码
case 17:
return var10000.CGLIB$toString$2();
case 18:
var10000.CGLIB$sayHello$0((String)var3[0]);
return null;
.......省略部分代码
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
........省略部分代码
}
HelloService$$FastClassByCGLIB$$d10caa66
源码:com.shihy.cglib.HelloService$$FastClassByCGLIB$$d10caa66
原理同代理类的FastClass。
//被代理类的FastClass
public class HelloService$$FastClassByCGLIB$$d10caa66 extends FastClass {
//根据方法签名获取方法的索引
public int getIndex(String var1, Class[] var2) {
.........
}
//根据方法的索引,直接调用对应的方法
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
.........
}
}
MethodProxy
源码:net.sf.cglib.proxy.MethodProxy
该类用于保存代理类被代理类中互相对应的两个方法的信息。如代理类中的CGLIB$sayHello$0(String var1)方法和被代理类中的sayHello(String var1) 之间对应。
我们知道 Method 是基于反射来调用方法的,但是反射的效率总是要低于直接的方法调用的,而 MethodProxy 基于 FastClass 机制对方法直接下标索引,并通过索引直接定位和调用方法,是一点性能上的提升。
总的来说,一个 MethodProxy 实例会对应一个FastClassInfo,FastClassInfo里面有两个 FastClass 实例,一个包装了被代理类的FastClass,并且暴露了该方法索引,另一个包装了代理类的FastClass,同样暴露了该方法在代理类中的索引。
- sig1和sig2分别保存着被代理类和代理类中该方法的签名,createInfo里面放着方法所属的类,c1被代理类,c2代理类。
- MethodProxy是代理类的成员变量,在代理类被加载的时候,在静态块中初始化。
private Signature sig1;//如:sayHello(Ljava/lang/String;)V
private Signature sig2;//如:CGLIB$sayHello$0(Ljava/lang/String;)V
private CreateInfo createInfo;
private static class CreateInfo{
Class c1;//如:class com.shihy.cglib.HelloService
Class c2;//如:class com.shihy.cglib.HelloService$$EnhancerByCGLIB$$f6637286
..........
}
private static class FastClassInfo{
FastClass f1;//包装着被代理类的FastClass,如:com.shihy.cglib.HelloService$$FastClassByCGLIB$$d10caa66
FastClass f2;//包装着代理类的FastClass,如:HelloService$$EnhancerByCGLIB$$f6637286$$FastClassByCGLIB$$c213df86
int i1;//当前方法在被代理类中的索引值
int i2;//当前方法在代理类中的索引值
}
net.sf.cglib.proxy.MethodProxy#invokeSuper方法
/*
* obj:the enhanced object,代理对象
* args:我们调用方法时候,传入的参数
*/
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
//初始化fastClassInfo属性,见下面源码
init();
FastClassInfo fci = fastClassInfo;
//根据代理类的FastClass中getIndex方法获取的索引值,继续调用代理类的FastClass的invoke方法,见上面的源码
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
-
net.sf.cglib.proxy.MethodProxy#init初始化fastClassInfo属性FastClass的创建时机:
net.sf.cglib.proxy.MethodProxy#invokeSupernet.sf.cglib.proxy.MethodProxy#initnet.sf.cglib.proxy.MethodProxy#helpernet.sf.cglib.reflect.FastClass.Generator#create
private void init()
{
if (fastClassInfo == null)
{
synchronized (initLock)
{
if (fastClassInfo == null)
{
CreateInfo ci = createInfo;
FastClassInfo fci = new FastClassInfo();
//在这里开始创建被代理类的FastClass,底层还是利用asm生成。
fci.f1 = helper(ci, ci.c1);
//在这里开始创建代理类的FastClass,底层还是利用asm生成。
fci.f2 = helper(ci, ci.c2);
//根据方法签名调用被代理类的FastClass的getIndex方法,获取方法对应的索引值
fci.i1 = fci.f1.getIndex(sig1);
//根据方法签名调用代理类的FastClass的getIndex方法,获取方法对应的索引值
fci.i2 = fci.f2.getIndex(sig2);
fastClassInfo = fci;
createInfo = null;
}
}
}
}
4、JDK动态代理和cglib动态代理的区别和性能对比
4.1区别
JDK动态代理具体实现原理:
-
通过实现InvocationHandlet接口创建自己的调用处理器(一般其内部会放一个被代理对象所属的类作为成员变量,特殊情况的参考Mybatis---不使用被代理对象);
-
通过为Proxy类指定ClassLoader对象、一组interface(一般是被代理对象所实现的接口)来创建动态代理类;
-
通过反射机制获取动态代理类的构造函数,其唯一参数类型就是调用处理器接口类型-----InvocationHandler.class;
-
通过构造函数创建动态代理类实例,构造时,自定义的调用处理器对象作为参数参入;
-
代理类实现了被代理的接口;
-
调用代理类对象的方法时候,会调用到调用处理器的invoke方法,在该方法中实现织入逻辑,一般情况下最终利用反射调用被代理对象的方法(特殊情况的参考Mybatis,不使用被代理对象);
CGLib动态代理实现原理:
- 通过实现MethodInterceptor接口创建在的方法拦截器;
- 通过增强器Enhancer,向其设置被代理类或被代理接口以及方法拦截器,来实现代理类和代理对象的创建;
- 代理类继承自被代理类,或者实现被代理接口;-----一般是代理一个类
- 调用代理类对象的方法时候,会调用到方法拦截器的intercept方法,在该方法中实现织入逻辑,若是代理类,通过FaseClass,最终调用到父类(被代理类)的方法;若是代理的接口,通过FaseClass,最终调用到Object中的方法(若调用的不是Object中的方法会报
java.lang.NoSuchMethodError:java.lang.Object.xxxx()Ljava/lang/String;的错误)
两者对比:
JDK动态代理只能对实现了接口的类生成代理,而不能针对类。
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,因为是继承,所以该类或方法最好不要声明成final;
----《Spring源码深度解析》
CGLib既可以代理类也可以代理接口;
JDK动态代理中一般会涉及一个被代理对象和一个代理对象,代理对象包装着被代理对象;CGLib动态代理中,从始至终只有一个代理对象,子类调用父类的方法的形式。
Spring中的使用:
如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP。
如果目标对象实现了接口,可以强制使用CGLIB实现AOP。
如果目标对象没有实现接口,必须采用CGLIB库,Spring会自动在JDK动态代理和CGLIB之间转换。
----《Spring源码深度解析》
4.2性能
- 使用CGLib实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,
在jdk6之前比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,
因为CGLib原理是动态生成被代理类的子类。
- 在jdk6、jdk7、jdk8逐步对JDK动态代理优化之后,在调用次数较少的情况下,JDK代理效率高于CGLIB代理效率,
只有当进行大量调用的时候,jdk6和jdk7比CGLIB代理效率低一点,但是到jdk8的时候,jdk代理效率高于CGLIB代理,
总之,每一次jdk版本升级,jdk代理效率都得到提升,而CGLIB代理消息确有点跟不上步伐。----blog.csdn.net/yhl_jxy/art…