————AOP技术其实就是字节码增强技术,JVM提供的动态代理追根究底也是字节码增强技术。
两种实现机制:一种是通过创建原始类的一个子类,现在的SpringAOP正式通过这种方式实现,另一种是非常暴力的,即直接修改原先的Class字节码,在许多类的跟踪过程中会用到这技术(类加载时修改字节码信息,运行时修改)。
字节码增强步骤:
1.在内存中获取到原始的字节码,然后通用一些开源提供的API来修改它的byte[]数组,得到一个新的byte[]。(ASM,javassist,cglib等技术)
2.将这个新的数组写到PermGen区域,也就是加载它或替换原来的Class字节码(也可以在进程外部调用完成)
反射和ASM区别
Spring AOP 代理实现有两种: JDK动态代理 和 Cglib框架动态代理
JDK中的动态代理是通过反射类Proxy
以及InvocationHandler
回调接口实现的,但是,JDK中所要进行动态代理的类必须要实现一个接口,也就是说只能对该类所实现接口中定义的方法进行代理,这在实际编程中具有一定的局限性,而且使用反射的效率也并不是很高。
JDK API 内置 ---- 通过 Proxy类,为目标对象创建代理 (必须面向接口代理 )
public class JdkProxyFactory implements InvocationHandler {
// 被代理对象
private Object target;
// 在构造方法对象时,传入被代理对象
public JdkProxyFactory(Object target) {
this.target = target;
}
// 创建代理
public Object createProxy() {
// 三个参数: 类加载器、 实现接口、 invocationhandler
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("记录日志!!!!!!");
// 调用目标真实方法
// target 被代理对象, args 方法参数 , method 被调用的方法
return method.invoke(target, args);
}
}
缺点: 使用Jdk动态代理,必须要求target目标对象,实现接口 ,如果没有接口,不能使用Jdk动态代理 。
使用CGLib实现动态代理,完全不受代理类必须实现接口的限制,而且CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。
CGLIB(Code Generation Library)是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。通常可以使用Java的动态代理创建代理,但当要代理的类没有实现接口或者为了更好的性能,CGLIB是一个好的选择。
CGLIB原理:动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用java反射的JDK动态代理要快。
CGLIB底层:使用字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。
CGLIB缺点:对于final方法,无法进行代理。
Cglib 不但可以对接口进行代理,也可以对目标类对象,实现代理(解决了 Jdk 只能对接口代理问题 )在spring3.2版本 core包中内置cglib 类 。
public class CglibProxyFactory implements MethodInterceptor {
// 被代理目标对象
private Object target;
// 在构造工厂时传入被代理对象
public CglibProxyFactory(Object target) {
this.target = target;
}
// 创建代理对象方法
public Object createProxy() {
// 1、 创建Enhancer对象
Enhancer enhancer = new Enhancer();
// 2、 cglib创建代理,对目标对象,创建子类对象
enhancer.setSuperclass(target.getClass());
// 3、传入 callback对象,对目标增强
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("记录日志......");
// 按照JDK编程
return method.invoke(target, args);
}
}
Cglib 创建代理思想: 对目标类创建子类对象 :
注意: