AOP代理的创建

Spring Boot 在初始化过程中,会利用 BeanPostProcessor 后置处理器来创建 AOP 代理。其中,AnnotationAwareAspectJAutoProxyCreator 是关键的后置处理器,它会在 Bean 初始化前后进行处理,判断是否需要为 Bean 创建代理。

  1. 自动配置引入 AOP 相关组件
    Spring Boot 通过自动配置机制引入 AOP 相关组件。在 spring-boot-autoconfigure 模块中,有 AopAutoConfiguration 类,它会根据条件判断是否启用 AOP 自动配置。
    不配置默认是开启的
  1. AnnotationAwareAspectJAutoProxyCreator 后置处理
    AnnotationAwareAspectJAutoProxyCreator 继承自 AbstractAutoProxyCreator,而 AbstractAutoProxyCreator 实现了 BeanPostProcessor 接口。在 Bean 初始化完成后(createBean会调用initializeBean,调用postProcessAfterInitialization),postProcessAfterInitialization 方法会被调用,该方法会判断是否需要为 Bean 创建代理。
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

wrapIfNecessary 方法是创建代理的核心方法,其源码如下:

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    // Create proxy if we have advice.
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        Object proxy = createProxy(
                bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

在 wrapIfNecessary 方法中:
首先会进行一些过滤判断,如判断 Bean 是否为基础设施类、是否需要跳过等。
然后调用 getAdvicesAndAdvisorsForBean 方法获取适用于该 Bean 的增强(Advice)和切面(Advisor)。
如果存在适用于该 Bean 的增强和切面,则调用 createProxy 方法创建代理。

  1. 创建代理对象
    在DefaultAopProxyFactory的 createProxy 方法中:
    首先创建一个 ProxyFactory 对象,用于配置代理的相关信息。
    根据配置决定使用 JDK 动态代理还是 CGLIB 代理(通过 setProxyTargetClass 方法)。只有是接口类或代理类,lamda才走JDK
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {
    return new JdkDynamicAopProxy(config);
}

将获取到的增强和切面添加到 ProxyFactory 中。
最后调用 getProxy 方法创建代理对象并返回。

总结:
Spring Boot 在初始化时,通过自动配置引入 AnnotationAwareAspectJAutoProxyCreator 后置处理器,在 Bean 初始化完成后,该后置处理器会判断是否需要为 Bean 创建代理。如果需要,则通过 ProxyFactory 配置代理信息,并根据配置选择合适的代理方式(JDK 动态代理或 CGLIB 代理)创建代理对象。这样就完成了 AOP 代理的创建过程。

两种代理区别:
JDK 动态代理基于 Java 的 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 实现,它要求目标对象实现接口,生成的代理对象也实现相同的接口。代理对象重写的是接口中定义的方法,所以只有接口里定义的方法调用才会经过 InvocationHandler 的 invoke 方法,从而实现 AOP 增强。非接口的方法无法被JDK代理
JDK代理样例:

// 定义接口
interface MyInterface {
    void interfaceMethod();
}

// 实现接口的类
class MyClass implements MyInterface {
    @Override
    public void interfaceMethod() {
        System.out.println("Executing interface method.");
    }

    public void nonInterfaceMethod() {
        System.out.println("Executing non-interface method.");
    }
}

// 实现 InvocationHandler 接口
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

class MyInvocationHandler implements InvocationHandler {
    private Object target;

    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before method execution");
        Object result = method.invoke(target, args);
        System.out.println("After method execution");
        return result;
    }
}

// 测试代码
import java.lang.reflect.Proxy;

public class JdkProxyTest {
    public static void main(String[] args) {
        MyClass target = new MyClass();
        MyInvocationHandler handler = new MyInvocationHandler(target);
        MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                handler
        );
        // 调用接口方法,会被代理
        proxy.interfaceMethod();
        // 下面这行代码会编译错误,因为代理对象只能调用接口中定义的方法
        // proxy.nonInterfaceMethod(); 
    }
}

CGLIB(Code Generation Library)代理是通过继承目标类来实现的,它会在运行时生成目标类的子类,并重写目标类的方法,从而实现 AOP 增强。因此,只要目标类不是 final 类,其所有方法(包括接口方法和非接口方法)都可以被代理。

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

// 定义类
class MyClass {
    public void interfaceMethod() {
        System.out.println("Executing interface method.");
    }

    public void nonInterfaceMethod() {
        System.out.println("Executing non-interface method.");
    }
}

// 实现 MethodInterceptor 接口
class MyMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Before method execution");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("After method execution");
        return result;
    }
}

// 测试代码
public class CglibProxyTest {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(MyClass.class);
        enhancer.setCallback(new MyMethodInterceptor());
        MyClass proxy = (MyClass) enhancer.create();

        // 调用接口方法,会被代理
        proxy.interfaceMethod();
        // 调用非接口方法,也会被代理
        proxy.nonInterfaceMethod();
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容