在Spring AOP中,代理对象是通过动态代理技术创建的。Spring AOP主要使用两种类型的代理:基于接口的代理(JDK动态代理)和基于类的代理(CGLIB动态代理)。
在Spring AOP中,选择使用哪种代理方式取决于被代理的目标类是否实现了接口以及其他因素。您可以在配置中使用 proxyTargetClass 属性来指定使用基于类的代理。
总之,无论是JDK动态代理还是CGLIB动态代理,Spring都会自动创建代理对象并将切面逻辑织入目标对象的方法中,实现AOP功能。
CGLIB(Code Generation Library)是一个基于字节码生成的类库,它能够在运行时动态生成目标类的子类作为代理对象。相比于JDK动态代理,CGLIB动态代理不要求目标类实现接口,可以代理普通的类。下面是CGLIB动态代理的大致实现过程:
CGLIB动态代理的优势是它可以代理没有实现接口的类,同时不需要目标类实现任何接口,因此更灵活。然而,它也有一些限制,例如不能代理被标记为 final 的类和方法,以及某些JVM限制等。
CGLIB的底层使用了字节码操作库ASM来操作字节码,这也是其实现动态代理的核心技术。通过生成新的类并在其中插入切面逻辑,CGLIB实现了在运行时动态地创建代理对象。
CGLIB(Code Generation Library)是通过使用字节码操作库ASM(Java字节码操控框架)来实现动态生成子类的。下面是CGLIB动态生成子类的一般技术细节:
总体来说,CGLIB利用ASM库的字节码操作能力,在运行时创建了一个新的子类,该子类继承自目标类并包含切面逻辑。通过重写方法并在方法中插入切面逻辑,CGLIB实现了动态代理的功能。这种方式相对于JDK动态代理,更适合代理那些没有实现接口的类。
Spring中的默认动态代理机制是基于JDK动态代理。当被代理的类实现了接口时,Spring会使用JDK动态代理来生成代理对象。
但是,当被代理的类没有实现接口时,Spring会自动切换到使用CGLIB动态代理。这是因为CGLIB可以代理那些没有接口的类,通过创建子类来实现代理。
你也可以通过配置来明确选择使用哪种代理方式,例如,如果你希望强制使用CGLIB代理,可以在配置中设置相应的选项。
JDK动态代理是通过Java的反射机制来实现的,主要涉及到两个核心类:java.lang.reflect.Proxy 和 java.lang.reflect.InvocationHandler。
基本流程如下:
以下是一个简化的示例:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface MyInterface {
void doSomething();
}
class MyTarget implements MyInterface {
public void doSomething() {
System.out.println("Target doing something.");
}
}
class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before invoking method.");
Object result = method.invoke(target, args);
System.out.println("After invoking method.");
return result;
}
}
public class Main {
public static void main(String[] args) {
MyInterface target = new MyTarget();
MyInvocationHandler handler = new MyInvocationHandler(target);
MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler
);
proxy.doSomething();
}
}
在这个示例中,MyInvocationHandler实现了InvocationHandler接口,Main类创建了一个MyInterface的代理对象,当调用代理对象的doSomething方法时,实际会触发invoke方法,在其中添加了前后的逻辑。
在JDK动态代理中,底层使用了Java的字节码生成技术,主要依赖于java.lang.reflect.Proxy类。该类使用了Java的反射机制以及字节码操作库来动态生成代理类的字节码。具体来说,它使用了sun.misc.ProxyGenerator类来生成字节码。
以下是大致的技术细节:
整个过程中,字节码生成技术是核心,它允许在运行时动态创建代理类,并在其中插入所需的代理逻辑。字节码生成技术允许在不事先编写具体代理类的情况下创建代理对象,从而实现动态代理的功能。
需要注意的是,因为sun.misc.ProxyGenerator并不是官方公开支持的API,所以在某些情况下可能会受到限制,而且不同的JDK版本可能会有不同的实现细节。