spring底层原理之aop

q1871901600 发布于 2024-11-21 47 次阅读


spring通过注解和代理工具类(jdk动态代理 和 cglib)实现的AOP

jdk动态代理部分源码:

// config就是ProxyFactory对象

// optimize为true,或proxyTargetClass为true,或用户没有给ProxyFactory对象添加interface
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
 Class<?> targetClass = config.getTargetClass();
 if (targetClass == null) {
  throw new AopConfigException("TargetSource cannot determine target class: " +
    "Either an interface or a target is required for proxy creation.");
 }
    // targetClass是接口,直接使用Jdk动态代理
 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
  return new JdkDynamicAopProxy(config);
 }
    // 使用Cglib
 return new ObjenesisCglibAopProxy(config);
}
else {
    // 使用Jdk动态代理
 return new JdkDynamicAopProxy(config);
}

从上面源码可以看出,spring首先判断了该类是否是接口,如果是接口则使用JDK动态代理,如果不是则使用Cglib,

Cglib原理

CGLIB 主要通过字节码增强技术,在运行时动态生成代理类,它的核心是基于 ASM 库操作字节码,从而生成一个继承自目标类的代理类。这意味着,CGLIB 通过生成目标类的子类并重写方法来实现代理,而不是像 java.lang.reflect.Proxy 那样基于接口进行代理。

CGLIB 代理的基本流程可以总结为以下几点:

创建代理类的子类:CGLIB 通过继承目标类来生成代理类。因此,CGLIB 不能代理 final 类,因为 final 类无法被继承。
重写方法:CGLIB 代理类会重写目标类的非 final 方法,在重写的方法中加入自定义的拦截逻辑,例如方法增强、日志记录等。
MethodInterceptor:CGLIB 的核心拦截机制是通过 MethodInterceptor 接口来实现的,所有被代理的方法调用都会被拦截,并进入 intercept() 方法处理。

public class RealService$$EnhancerByCGLIB extends RealService {
    private MethodInterceptor interceptor;

    public RealService$$EnhancerByCGLIB(MethodInterceptor interceptor) {
        this.interceptor = interceptor;
    }

    @Override
    public void doSomething() {
        try {
            Method method = RealService.class.getMethod("doSomething");
            interceptor.intercept(this, method, null, null); // 调用拦截器
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

这个代理类的结构说明:

继承目标类 RealService:CGLIB 生成的代理类是 RealService 的子类,因此它继承了所有 RealService的方法。
拦截器 interceptor:代理类持有一个 MethodInterceptor 实例,在方法调用时会调用 interceptor 的 intercept 方法。
方法重写:代理类会重写父类的方法,在调用方法时先通过拦截器进行额外的处理,然后调用原方法逻辑(通过 invokeSuper 调用父类方法)。

CGLIB 的核心是通过 ASM 库直接操作字节码。ASM 是一个 Java 字节码操作框架,允许开发者动态生成、修改 Java 类。CGLIB 使用 ASM 生成代理类的字节码,并动态加载到 JVM 中。

ASM 字节码增强的基本原理:
ClassReader:用于读取目标类的字节码。
ClassWriter:用于生成新的字节码,通常通过继承或修改现有的类字节码生成新的类。
MethodVisitor:用于访问方法的字节码指令,从而可以修改方法的实现。
在 CGLIB 中,当我们使用 Enhancer 生成代理类时,CGLIB 会通过 ASM 读取目标类的字节码,并根据 MethodInterceptor 的配置动态生成代理类的字节码。然后,JVM 会将这些动态生成的字节码加载到内存中,从而完成代理类的创建。

Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(TargetClass.class);
enhancer.setCallback(new MyMethodInterceptor());
TargetClass proxy = (TargetClass) enhancer.create();

spring注解失效的原因
1. 配置错误
2.扫描路径不正确
3.依赖缺失

参考文章:

CGLIB原理-CSDN博客

一个会写python的Java工程师
最后更新于 2024-11-21