Spring AOP 实现原理:动态代理与字节码增强

基于Spring Framework 6.1.5源码深度剖析

一、引言:AOP的本质与Spring的解决方案

面向切面编程(Aspect-Oriented Programming,AOP)是软件开发中的一种重要编程范式,它通过将横切关注点(Cross-cutting Concerns)从业务逻辑中分离出来,实现了关注点的模块化。日志记录、事务管理、安全检查、性能监控等都是典型的横切关注点。

Spring AOP作为Spring框架的核心功能之一,为Java开发者提供了简洁而强大的AOP解决方案。不同于AspectJ的编译期织入和类加载期织入,Spring AOP采用的是**运行期织入(Runtime Weaving)**的方式,通过动态代理技术在目标对象的方法调用时织入增强逻辑。

Spring AOP的代理机制主要有两种实现方式:

  1. JDK动态代理:基于接口的代理,使用Java反射机制实现
  2. CGLIB代理:基于类的代理,使用字节码生成技术实现

本文将基于Spring Framework 6.1.5源码,深入剖析这两种代理机制的实现原理,帮助读者理解Spring AOP的核心技术。

二、Spring AOP核心架构

2.1 AOP核心组件体系

Spring AOP的实现建立在多个核心组件之上,这些组件协同工作来完成代理对象的创建和方法拦截。

creates

implements

implements

creates

creates

extends

uses

AdvisedSupport

-TargetSource targetSource

-List<Advisor> advisors

-List<Class> interfaces

+addAdvisor(Advisor)

+getTargetSource()

+getProxiedInterfaces()

«interface»

AopProxy

+getProxy() : Object

+getProxy(ClassLoader) : Object

JdkDynamicAopProxy

-AdvisedSupport advised

+invoke(Object, Method, Object[])

CglibAopProxy

-AdvisedSupport advised

+getProxy() : Object

+buildProxy(ClassLoader, boolean)

DefaultAopProxyFactory

+createAopProxy(AdvisedSupport) : AopProxy

ProxyFactory

+getProxy() : Object

ProxyConfig

2.2 AdvisedSupport:配置管理中心

AdvisedSupport是Spring AOP配置管理的核心类,它继承自ProxyConfig并实现了Advised接口。这个类负责存储和管理代理对象的所有配置信息:

// Spring Framework 6.1.5 - AdvisedSupport.java
public class AdvisedSupport extends ProxyConfig implements Advised {

    /** 目标源,封装了被代理对象的获取逻辑 */
    TargetSource targetSource = EMPTY_TARGET_SOURCE;

    /** 是否已经过滤过特定目标类的Advisors */
    private boolean preFiltered = false;

    /** 顾问链工厂,负责构建方法拦截器链 */
    private AdvisorChainFactory advisorChainFactory = DefaultAdvisorChainFactory.INSTANCE;

    /** 代理对象需要实现的接口列表 */
    private List<Class<?>> interfaces = new ArrayList<>();

    /** 通知器列表,包含了所有的切面逻辑 */
    private List<Advisor> advisors = new ArrayList<>();

    /** 方法缓存,用于存储每个方法的拦截器链 */
    @Nullable
    private transient Map<MethodCacheKey, List<Object>> methodCache;
}

AdvisedSupport的职责包括:

  • 目标对象管理:通过TargetSource封装目标对象的获取和释放逻辑
  • 通知器管理:维护Advisor列表,支持动态添加和删除通知器
  • 接口管理:管理代理对象需要实现的接口
  • 方法缓存:缓存每个方法的拦截器链,提高调用效率

三、JDK动态代理实现原理

3.1 JdkDynamicAopProxy核心实现

JdkDynamicAopProxy是Spring对JDK动态代理的封装,它实现了InvocationHandler接口。让我们深入分析其核心实现:

// Spring Framework 6.1.5 - JdkDynamicAopProxy.java
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {

    /** 配置信息 */
    private final AdvisedSupport advised;

    /** 接口缓存 */
    private transient ProxiedInterfacesCache cache;

    /**
     * 创建JDK动态代理对象
     * @return 代理对象实例
     */
    @Override
    public Object getProxy(@Nullable ClassLoader classLoader) {
        if (logger.isTraceEnabled()) {
            logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
        }
        // 使用Proxy.newProxyInstance创建代理实例
        return Proxy.newProxyInstance(
            determineClassLoader(classLoader),
            this.cache.proxiedInterfaces,
            this  // InvocationHandler实例
        );
    }

    /**
     * InvocationHandler.invoke方法实现
     * 这是方法拦截的核心逻辑
     */
    @Override
    @Nullable
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object oldProxy = null;
        boolean setProxyContext = false;

        TargetSource targetSource = this.advised.targetSource;
        Object target = null;

        try {
            // 处理equals方法
            if (!this.cache.equalsDefined && AopUtils.isEqualsMethod(method)) {
                return equals(args[0]);
            }
            // 处理hashCode方法
            else if (!this.cache.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                return hashCode();
            }
            // 处理DecoratingProxy接口方法
            else if (method.getDeclaringClass() == DecoratingProxy.class) {
                return AopProxyUtils.ultimateTargetClass(this.advised);
            }

            Object retVal;

            // 如果需要暴露代理对象到AopContext
            if (this.advised.exposeProxy) {
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }

            // 获取目标对象
            target = targetSource.getTarget();
            Class<?> targetClass = (target != null ? target.getClass() : null);

            // 获取当前方法的拦截器链
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(
                method, targetClass);

            // 如果没有拦截器,直接调用目标方法
            if (chain.isEmpty()) {
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
            }
            else {
                // 创建ReflectiveMethodInvocation并执行拦截器链
                MethodInvocation invocation = new ReflectiveMethodInvocation(
                    proxy, target, method, args, targetClass, chain);
                // 执行拦截器链
                retVal = invocation.proceed();
            }

            // 处理返回值,确保返回的是代理对象而非目标对象
            Class<?> returnType = method.getReturnType();
            if (retVal != null && retVal == target &&
                returnType != Object.class && returnType.isInstance(proxy) &&
                !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                retVal = proxy;
            }

            return retVal;
        }
        finally {
            // 释放目标对象(如果从池中获取)
            if (target != null && !targetSource.isStatic()) {
                targetSource.releaseTarget(target);
            }
            // 恢复旧的代理上下文
            if (setProxyContext) {
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }
}

3.2 JDK动态代理工作流程

JDK动态代理的执行流程可以概括为以下步骤:

Target AdvisedSupport JdkDynamicAopProxy Proxy Client Target AdvisedSupport JdkDynamicAopProxy Proxy Client 执行拦截器链 alt [chain.isEmpty()] [chain.isNotEmpty()] methodCall() invoke(proxy, method, args) 处理特殊方法 (equals/hashCode) getInterceptorsAndDynamicInterceptionAdvice() List<Object> chain 直接调用目标方法 创建ReflectiveMethodInvocation invocation.proceed() 最终调用目标方法 处理返回值 return result

3.3 拦截器链的执行机制

拦截器链的执行是通过ReflectiveMethodInvocation实现的,这是一个责任链模式的典型应用:

// ReflectiveMethodInvocation.proceed()方法核心逻辑
@Override
@Nullable
public Object proceed() throws Throwable {
    // 如果拦截器链已经执行完毕,调用目标方法
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }

    // 获取下一个拦截器
    Object interceptorOrInterceptionAdvice =
        this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

    // 如果是动态拦截器,进行方法匹配
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
        InterceptorAndDynamicMethodMatcher dm =
            (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
        Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
        if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
            return dm.interceptor.invoke(this);
        }
        else {
            // 动态匹配失败,跳过此拦截器,继续执行下一个
            return proceed();
        }
    }
    else {
        // 普通拦截器,直接调用
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

四、CGLIB字节码增强实现原理

4.1 CglibAopProxy核心实现

当目标对象没有实现接口,或者配置强制使用类代理时,Spring会使用CGLIB来生成代理对象的子类。CglibAopProxy是对CGLIB的封装:

// Spring Framework 6.1.5 - CglibAopProxy.java
class CglibAopProxy implements AopProxy, Serializable {

    // CGLIB回调索引常量
    private static final int AOP_PROXY = 0;
    private static final int INVOKE_TARGET = 1;
    private static final int NO_OVERRIDE = 2;
    private static final int DISPATCH_TARGET = 3;
    private static final int DISPATCH_ADVISED = 4;
    private static final int INVOKE_EQUALS = 5;
    private static final int INVOKE_HASHCODE = 6;

    /** 配置信息 */
    protected final AdvisedSupport advised;

    /**
     * 创建CGLIB代理对象
     */
    @Override
    public Object getProxy(@Nullable ClassLoader classLoader) {
        return buildProxy(classLoader, false);
    }

    private Object buildProxy(@Nullable ClassLoader classLoader, boolean classOnly) {
        if (logger.isTraceEnabled()) {
            logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
        }

        try {
            Class<?> rootClass = this.advised.getTargetClass();
            Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

            // 处理已经是CGLIB代理的类
            Class<?> proxySuperClass = rootClass;
            if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
                proxySuperClass = rootClass.getSuperclass();
                // 添加原始接口
                Class<?>[] additionalInterfaces = rootClass.getInterfaces();
                for (Class<?> additionalInterface : additionalInterfaces) {
                    this.advised.addInterface(additionalInterface);
                }
            }

            // 验证类是否可以被代理
            validateClassIfNecessary(proxySuperClass, classLoader);

            // 配置CGLIB Enhancer
            Enhancer enhancer = createEnhancer();
            if (classLoader != null) {
                enhancer.setClassLoader(classLoader);
                // 对于可重新加载的类,禁用缓存
                if (classLoader instanceof SmartClassLoader smartClassLoader &&
                    smartClassLoader.isClassReloadable(proxySuperClass)) {
                    enhancer.setUseCache(false);
                }
            }

            // 设置父类和接口
            enhancer.setSuperclass(proxySuperClass);
            enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));

            // 设置命名策略和类加载器策略
            enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
            enhancer.setAttemptLoad(true);
            enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));

            // 获取回调数组
            Callback[] callbacks = getCallbacks(rootClass);
            Class<?>[] types = new Class<?>[callbacks.length];
            for (int x = 0; x < types.length; x++) {
                types[x] = callbacks[x].getClass();
            }

            // 设置回调过滤器
            ProxyCallbackFilter filter = new ProxyCallbackFilter(
                this.advised.getConfigurationOnlyCopy(),
                this.fixedInterceptorMap,
                this.fixedInterceptorOffset);
            enhancer.setCallbackFilter(filter);
            enhancer.setCallbackTypes(types);

            // 创建代理实例
            return (classOnly ? createProxyClass(enhancer) : createProxyClassAndInstance(enhancer, callbacks));
        }
        catch (CodeGenerationException | IllegalArgumentException ex) {
            throw new AopConfigException("Could not generate CGLIB subclass of " +
                this.advised.getTargetClass() +
                ": Common causes include using a final class or a non-visible class", ex);
        }
    }
}

4.2 CGLIB回调机制

CGLIB通过Callback机制实现方法拦截,Spring定义了多个回调来处理不同的情况:

/**
 * 获取CGLIB回调数组
 */
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
    // 参数优化:对于单例目标,使用固定的拦截器链
    // 用于AOP的回调
    Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

    // 用于目标对象调用的回调
    Callback targetInterceptor;

    // 如果目标是静态的且是公开的,使用优化的调度器
    if (this.advised.exposeProxy) {
        targetInterceptor = (isStatic && this.advised.targetSource.isStatic()) ?
            new StaticUnadvisedExposedInterceptor(this.advised.targetSource.getTarget()) :
            new DynamicUnadvisedExposedInterceptor(this.advised.targetSource);
    }
    else {
        targetInterceptor = (isStatic && this.advised.targetSource.isStatic()) ?
            new StaticUnadvisedInterceptor(this.advised.targetSource.getTarget()) :
            new DynamicUnadvisedInterceptor(this.advised.targetSource);
    }

    // 选择目标回调
    Callback targetDispatcher = (this.advised.targetSource.isStatic()) ?
        new StaticDispatcher(this.advised.targetSource.getTarget()) :
        new SerializableNoOp();

    // 构建回调数组
    Callback[] callbacks = new Callback[] {
        aopInterceptor,  // AOP_PROXY - 用于常规的AOP调用
        targetInterceptor,  // INVOKE_TARGET - 直接调用目标,不经过AOP
        new SerializableNoOp(),  // NO_OVERRIDE - 不重写的方法
        targetDispatcher,  // DISPATCH_TARGET - 调度到目标对象
        this.advisedDispatcher,  // DISPATCH_ADVISED - 调度到Advised配置
        new EqualsInterceptor(this.advised),  // INVOKE_EQUALS - equals方法
        new HashCodeInterceptor(this.advised)  // INVOKE_HASHCODE - hashCode方法
    };

    return callbacks;
}

4.3 DynamicAdvisedInterceptor核心拦截器

DynamicAdvisedInterceptor是CGLIB代理的核心拦截器,类似于JDK代理的invoke方法:

/**
 * CGLIB MethodInterceptor实现
 * 用于拦截对目标对象的所有方法调用
 */
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {

    private final AdvisedSupport advised;

    public DynamicAdvisedInterceptor(AdvisedSupport advised) {
        this.advised = advised;
    }

    @Override
    @Nullable
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object oldProxy = null;
        boolean setProxyContext = false;
        Object target = null;

        try {
            // 处理exposeProxy配置
            if (this.advised.exposeProxy) {
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }

            // 获取目标对象
            target = getTarget();
            if (target == null) {
                throw new AopInvocationException(
                    "Target is null, cannot proceed with method invocation");
            }

            Class<?> targetClass = target.getClass();

            // 获取拦截器链
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

            Object retVal;

            // 如果没有拦截器链,直接调用目标方法
            if (chain.isEmpty() && Modifier.isPublic(method.getModifiers()) &&
                methodProxy.getDeclaringClass().isAssignableFrom(targetClass)) {
                // 使用MethodProxy进行快速调用
                retVal = methodProxy.invoke(target, args);
            }
            else {
                // 创建方法调用对象并执行拦截器链
                List<Object> chainToUse = chain;
                if (chain.isEmpty()) {
                    chainToUse = Collections.singletonList((MethodInterceptor) (mi -> mi.proceed()));
                }

                MethodInvocation invocation = new ReflectiveMethodInvocation(
                    proxy, target, method, args, targetClass, chainToUse);
                retVal = invocation.proceed();
            }

            // 处理返回值
            retVal = processReturnValue(proxy, target, method, retVal);

            return retVal;
        }
        finally {
            if (target != null && !this.advised.targetSource.isStatic()) {
                // 释放目标对象
                this.advised.targetSource.releaseTarget(target);
            }
            if (setProxyContext) {
                // 恢复旧的代理上下文
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }
}

4.4 CGLIB代理工作流程

Proxy Target AdvisedSupport CallbackFilter DynamicAdvisedInterceptor Proxy(CGLIB) Client Proxy Target AdvisedSupport CallbackFilter DynamicAdvisedInterceptor Proxy(CGLIB) Client 执行拦截器链 alt [chain.isEmpty()] [chain.isNotEmpty()] alt [callbackIndex == AOP_PROXY] [callbackIndex == INVOKE_TARGET] [callbackIndex == NO_OVERRIDE] methodCall() accept(method) callbackIndex intercept(proxy, method, args, methodProxy) getInterceptorsAndDynamicInterceptionAdvice() List<Object> chain methodProxy.invoke(target, args) 创建ReflectiveMethodInvocation invocation.proceed() 最终调用目标方法 处理返回值 return result 直接调用目标方法 return result 调用父类方法 return result

五、代理选择策略

5.1 DefaultAopProxyFactory代理选择逻辑

Spring通过DefaultAopProxyFactory来决定使用哪种代理方式:

// Spring Framework 6.1.5 - DefaultAopProxyFactory.java
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

    @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        // 检查是否优化或需要代理目标类
        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");
            }

            // 如果目标类是接口,使用JDK代理
            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                return new JdkDynamicAopProxy(config);
            }

            // 对于非接口的类,使用CGLIB代理
            return new CglibAopProxy(config);
        }
        else {
            // 默认使用JDK动态代理
            return new JdkDynamicAopProxy(config);
        }
    }

    /**
     * 判断是否没有用户提供的代理接口
     */
    private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
        Class<?>[] ifcs = config.getProxiedInterfaces();
        return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
    }
}

5.2 代理选择决策流程

渲染错误: Mermaid 渲染失败: Parse error on line 2: ... B{config.isOptimize() ||
isProxyTar -----------------------^ Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'PS'

六、JDK代理 vs CGLIB代理对比

6.1 技术特性对比

特性 JDK动态代理 CGLIB代理
实现原理 Java反射机制 字节码生成(ASM)
代理对象 实现接口的代理类 继承目标类的子类
目标对象要求 必须实现至少一个接口 可以是普通类,但不能是final类
方法限制 只能代理接口方法 不能代理final/static方法
性能 接口方法调用较快 字节码生成有开销,但执行效率高
依赖 JDK内置,无额外依赖 需要CGLIB库(Spring已集成)
Spring默认选择 优先选择 在目标类无接口时使用

6.2 适用场景对比

场景 推荐方案 原因
目标类实现了接口 JDK动态代理 更符合面向接口编程思想,性能好
目标类没有实现接口 CGLIB代理 唯一选择
需要代理类的方法(非接口) CGLIB代理 JDK代理无法实现
目标类是final类 无法代理 需要重构设计,引入接口
需要代理final方法 无法代理 需要重构设计,使用接口方法
性能敏感场景 根据实际情况 JDK代理创建快,CGLIB执行快

6.3 性能对比

执行阶段

JDK代理

反射调用

CGLIB代理

直接调用

创建阶段

JDK代理

反射生成

CGLIB代理

字节码生成

性能分析:

  1. 创建阶段:JDK代理使用反射机制,创建速度快;CGLIB需要生成字节码并加载类,创建速度较慢
  2. 执行阶段:CGLIB通过直接调用方法,执行效率高;JDK代理通过反射调用,有一定性能损耗
  3. 内存占用:CGLIB需要生成额外的类,内存占用略高

6.4 实际应用示例

import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.JdkRegexpMethodPointcut;
import org.springframework.aop.MethodBeforeAdvice;

/**
 * Spring AOP代理示例
 * 演示JDK代理和CGLIB代理的使用
 */
public class SpringAopProxyExample {

    /**
     * 示例1:使用JDK动态代理
     * 目标类实现了接口
     */
    public static class JdkProxyExample {
        // 业务接口
        public interface UserService {
            void addUser(String username);
            void deleteUser(String username);
        }

        // 目标类:实现接口
        public static class UserServiceImpl implements UserService {
            @Override
            public void addUser(String username) {
                System.out.println("添加用户: " + username);
            }

            @Override
            public void deleteUser(String username) {
                System.out.println("删除用户: " + username);
            }
        }

        public static void main(String[] args) {
            // 创建代理工厂
            ProxyFactory proxyFactory = new ProxyFactory(new UserServiceImpl());

            // 添加前置通知
            proxyFactory.addAdvice(new MethodBeforeAdvice() {
                @Override
                public void before(Method method, Object[] args, Object target) throws Throwable {
                    System.out.println("前置通知: 准备执行方法 " + method.getName());
                }
            });

            // 获取代理对象(JDK代理)
            UserService proxy = (UserService) proxyFactory.getProxy();

            // 调用代理方法
            proxy.addUser("张三");
            proxy.deleteUser("李四");
        }
    }

    /**
     * 示例2:使用CGLIB代理
     * 目标类没有实现接口
     */
    public static class CglibProxyExample {
        // 目标类:没有实现接口
        public static class OrderService {
            public void createOrder(String orderId) {
                System.out.println("创建订单: " + orderId);
            }

            public void cancelOrder(String orderId) {
                System.out.println("取消订单: " + orderId);
            }
        }

        public static void main(String[] args) {
            // 创建代理工厂
            ProxyFactory proxyFactory = new ProxyFactory(new OrderService());

            // 强制使用CGLIB代理(即使有接口也使用类代理)
            proxyFactory.setProxyTargetClass(true);

            // 添加环绕通知
            proxyFactory.addAdvice(new MethodInterceptor() {
                @Override
                public Object invoke(MethodInvocation invocation) throws Throwable {
                    System.out.println("环绕通知-前置: 执行方法前");
                    Object result = invocation.proceed();
                    System.out.println("环绕通知-后置: 执行方法后");
                    return result;
                }
            });

            // 获取代理对象(CGLIB代理)
            OrderService proxy = (OrderService) proxyFactory.getProxy();

            // 调用代理方法
            proxy.createOrder("ORD001");
            proxy.cancelOrder("ORD002");
        }
    }

    /**
     * 示例3:配置切点通知
     * 精确匹配需要增强的方法
     */
    public static class PointcutExample {
        public static class ProductService {
            public void saveProduct() {
                System.out.println("保存产品");
            }

            public void updateProduct() {
                System.out.println("更新产品");
            }

            public void deleteProduct() {
                System.out.println("删除产品");
            }

            public void queryProduct() {
                System.out.println("查询产品");
            }
        }

        public static void main(String[] args) {
            ProxyFactory proxyFactory = new ProxyFactory(new ProductService());
            proxyFactory.setProxyTargetClass(true);

            // 创建正则表达式切点:只匹配save开头的方法
            JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
            pointcut.setPattern(".*save.*");

            // 创建通知
            MethodBeforeAdvice advice = new MethodBeforeAdvice() {
                @Override
                public void before(Method method, Object[] args, Object target) throws Throwable {
                    System.out.println("=== 日志记录: 执行保存操作 ===");
                }
            };

            // 组合切点和通知
            DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
            proxyFactory.addAdvisor(advisor);

            ProductService proxy = (ProductService) proxyFactory.getProxy();

            // 只有saveProduct会被增强
            proxy.saveProduct();    // 会触发通知
            proxy.updateProduct();  // 不会触发通知
            proxy.deleteProduct();  // 不会触发通知
            proxy.queryProduct();   // 不会触发通知
        }
    }
}

七、高级特性与最佳实践

7.1 TargetSource:目标源管理

TargetSource是Spring AOP中的一个高级特性,它允许开发者灵活地管理目标对象的获取和释放。常见的实现包括:

TargetSource类型 用途 应用场景
SingletonTargetSource 单例目标源 最常用的目标源,缓存目标对象
PrototypeTargetSource 原型目标源 每次调用都创建新的目标实例
ThreadLocalTargetSource 线程本地目标源 每个线程拥有独立的目标实例
HotSwappableTargetSource 热交换目标源 支持运行时切换目标实现
CommonsPool2TargetSource 对象池目标源 使用对象池管理目标对象
LazyInitTargetSource 延迟初始化目标源 延迟到首次调用时才创建目标

7.2 exposeProxy配置

在嵌套调用中,内部方法调用不会经过代理对象,导致内部方法调用无法被AOP增强。Spring提供了exposeProxy配置来解决这个问题:

/**
 * exposeProxy示例:解决内部调用问题
 */
public class ExposeProxyExample {

    public static class OrderService {
        public void createOrder() {
            System.out.println("创建订单");
            // 问题:内部直接调用,不会经过代理
            this.notifyUser();  // ❌ AOP不会生效
        }

        public void notifyUser() {
            System.out.println("通知用户");
        }
    }

    public static void main(String[] args) {
        ProxyFactory proxyFactory = new ProxyFactory(new OrderService());
        proxyFactory.setProxyTargetClass(true);

        // 关键配置:暴露代理对象
        proxyFactory.setExposeProxy(true);

        proxyFactory.addAdvice(new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println(">>> 前置通知");
                Object result = invocation.proceed();
                System.out.println("<<< 后置通知");
                return result;
            }
        });

        OrderService proxy = (OrderService) proxyFactory.getProxy();
        proxy.createOrder();  // notifyUser的通知不会触发

        // 解决方案:使用AopContext.currentProxy()获取当前代理
        // 修改OrderService.createOrder()方法:
        // ((OrderService) AopContext.currentProxy()).notifyUser();
    }
}

7.3 最佳实践

  1. 优先使用接口代理

    // ✅ 推荐:面向接口编程
    public interface UserService { ... }
    public class UserServiceImpl implements UserService { ... }
    
  2. 避免在目标类中调用自身方法

    // ❌ 不推荐:内部调用不会触发AOP
    public void methodA() {
        this.methodB();  // 不会触发AOP
    }
    
    // ✅ 推荐:通过代理调用
    public void methodA() {
        ((Service) AopContext.currentProxy()).methodB();
    }
    
  3. 慎用final类和final方法

    // ❌ CGLIB无法代理final类
    public final class FinalService { ... }
    
    // ❌ CGLIB无法代理final方法
    public final void finalMethod() { ... }
    
  4. 合理配置proxyTargetClass

    // 有接口时,默认使用JDK代理(推荐)
    ProxyFactory factory = new ProxyFactory(target);
    
    // 无接口时,必须设置为true(自动)
    factory.setProxyTargetClass(true);
    

八、总结

Spring AOP通过动态代理技术实现了优雅的面向切面编程,本文基于Spring Framework 6.1.5源码,深入分析了两种代理机制的实现原理:

8.1 核心技术点回顾

  1. AdvisedSupport:配置管理中心,存储所有代理配置信息
  2. JdkDynamicAopProxy:基于java.lang.reflect.Proxy的接口代理实现
  3. CglibAopProxy:基于CGLIB字节码生成的类代理实现
  4. 拦截器链:通过ReflectiveMethodInvocation实现责任链模式
  5. CallbackFilter:CGLIB回调过滤器,精确控制方法的拦截策略

8.2 代理选择策略

false

true

创建AOP代理

目标类实现接口?

proxyTargetClass?

CGLIB代理

JDK代理
推荐

✅ 性能好
✅ 符合接口编程
✅ 无额外依赖

⚠️ 创建慢
✅ 执行快
✅ 可代理类方法
❌ 不能代理final

8.3 应用建议

  • 优先选择接口代理:更符合面向接口编程的设计思想
  • 理解限制条件:final类和final方法无法被CGLIB代理
  • 注意内部调用:使用exposeProxy配合AopContext.currentProxy()解决
  • 性能权衡:根据实际场景选择合适的代理方式

Spring AOP的设计充分体现了简单性实用性的原则,通过运行期代理避免了编译期织入的复杂性,同时提供了足够的灵活性和强大的功能。理解其实现原理,有助于开发者更好地运用AOP技术,构建更加清晰、可维护的应用程序。


标签: Spring | AOP | 动态代理 | 字节码增强 | 源码解析

相关阅读:

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐