Skip to content

AOP实现原理 ​

深入理解Spring AOP的实现机制,掌握代理模式和切面织入原理,理解JDK动态代理和CGLIB代理的区别,掌握通知类型、切点表达式等核心概念。

📋 AOP概览 ​

AOP(Aspect-Oriented Programming,面向切面编程)是Spring的核心功能之一,通过代理模式实现横切关注点的分离。

🎯 一、代理模式基础 ​

1.1 代理模式概述 ​

代理模式为对象提供一个代理,以控制对这个对象的访问。Spring AOP使用代理模式来实现横切关注点。

代理模式的角色:

  • Subject(抽象主题):定义代理和真实对象的共同接口
  • RealSubject(真实主题):实现业务逻辑的具体对象
  • Proxy(代理):包含对真实主题的引用,控制对真实主题的访问

1.2 代理模式类型 ​

Spring AOP支持两种代理方式:

  1. JDK动态代理:基于接口实现
  2. CGLIB代理:基于类继承实现

代理选择规则:

java
// DefaultAopProxyFactory.createAopProxy
@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 ObjenesisCglibAopProxy(config);
    }
    else {
        return new JdkDynamicAopProxy(config);
    }
}

🎯 二、JDK动态代理 ​

2.1 JDK动态代理原理 ​

JDK动态代理使用java.lang.reflect.Proxy类在运行时动态创建代理对象。

核心类:

  • Proxy:代理类工厂
  • InvocationHandler:调用处理器接口

示例代码:

java
public interface UserService {
    void saveUser(User user);
    User getUser(Long id);
}

public class UserServiceImpl implements UserService {
    @Override
    public void saveUser(User user) {
        System.out.println("保存用户:" + user);
    }
    
    @Override
    public User getUser(Long id) {
        System.out.println("获取用户:" + id);
        return new User();
    }
}

// 调用处理器
public class UserServiceInvocationHandler implements InvocationHandler {
    private Object target;
    
    public UserServiceInvocationHandler(Object target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) 
            throws Throwable {
        System.out.println("前置处理");
        Object result = method.invoke(target, args);
        System.out.println("后置处理");
        return result;
    }
}

// 创建代理
UserService target = new UserServiceImpl();
InvocationHandler handler = new UserServiceInvocationHandler(target);
UserService proxy = (UserService) Proxy.newProxyInstance(
        target.getClass().getClassLoader(),
        target.getClass().getInterfaces(),
        handler);
proxy.saveUser(new User());

2.2 JdkDynamicAopProxy ​

Spring AOP中的JDK动态代理实现:

java
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
    
    private final AdvisedSupport advised;
    
    public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
        Assert.notNull(config, "AdvisedSupport must not be null");
        if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
            throw new AopConfigException("No advisors and no TargetSource specified");
        }
        this.advised = config;
    }
    
    @Override
    public Object getProxy() {
        return getProxy(ClassUtils.getDefaultClassLoader());
    }
    
    @Override
    public Object getProxy(@Nullable ClassLoader classLoader) {
        if (logger.isTraceEnabled()) {
            logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
        }
        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(
                this.advised, true);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }
    
    @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/hashCode/toString,或者是配置器方法
            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                return equals(args[0]);
            }
            else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                return hashCode();
            }
            else if (method.getDeclaringClass() == DecoratingProxy.class) {
                return AopProxyUtils.ultimateTargetClass(this.advised);
            }
            else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                    method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
            }
            
            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 {
                // 创建方法调用对象
                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;
            }
            else if (retVal == null && returnType != Void.TYPE && 
                    returnType.isPrimitive()) {
                throw new AopInvocationException(
                        "Null return value from advice does not match primitive return type for: " + method);
            }
            return retVal;
        }
        finally {
            if (target != null && !targetSource.isStatic()) {
                targetSource.releaseTarget(target);
            }
            if (setProxyContext) {
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }
}

invoke方法流程:

🎯 三、CGLIB代理 ​

3.1 CGLIB代理原理 ​

CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,通过继承目标类来创建代理对象。

CGLIB代理的特点:

  • 不需要接口
  • 通过继承目标类实现
  • 不能代理final类和final方法

示例代码:

java
public class UserService {
    public void saveUser(User user) {
        System.out.println("保存用户:" + user);
    }
}

// 方法拦截器
public class UserServiceMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, 
            MethodProxy proxy) throws Throwable {
        System.out.println("前置处理");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("后置处理");
        return result;
    }
}

// 创建代理
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);
enhancer.setCallback(new UserServiceMethodInterceptor());
UserService proxy = (UserService) enhancer.create();
proxy.saveUser(new User());

3.2 ObjenesisCglibAopProxy ​

Spring AOP中的CGLIB代理实现:

java
class ObjenesisCglibAopProxy extends CglibAopProxy {
    
    public ObjenesisCglibAopProxy(AdvisedSupport config) {
        super(config);
    }
    
    @Override
    protected Object createProxyClassAndInstance(Enhancer enhancer, 
            Callback[] callbacks) {
        Class<?> proxyClass = enhancer.createClass();
        Object proxyInstance = null;
        
        if (objenesis.isWorthTrying()) {
            try {
                proxyInstance = objenesis.newInstance(proxyClass, 
                        enhancer.getUseCache());
            }
            catch (Throwable ex) {
                logger.debug("Unable to instantiate proxy using Objenesis, " +
                        "falling back to regular proxy construction", ex);
            }
        }
        
        if (proxyInstance == null) {
            try {
                proxyInstance = ReflectionUtils.accessibleConstructor(
                        proxyClass).newInstance();
            }
            catch (Throwable ex) {
                throw new AopConfigException("Unable to instantiate proxy", ex);
            }
        }
        
        ((Factory) proxyInstance).setCallbacks(callbacks);
        return proxyInstance;
    }
}

🎯 四、通知类型 ​

4.1 通知接口 ​

Spring AOP定义了多种通知接口:

  • BeforeAdvice:前置通知
  • AfterAdvice:后置通知
  • AroundAdvice:环绕通知
  • ThrowsAdvice:异常通知

4.2 前置通知 ​

MethodBeforeAdvice接口:

java
public interface MethodBeforeAdvice extends BeforeAdvice {
    void before(Method method, Object[] args, @Nullable Object target) 
            throws Throwable;
}

实现示例:

java
public class LogBeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) 
            throws Throwable {
        System.out.println("方法执行前:" + method.getName());
    }
}

4.3 后置通知 ​

AfterReturningAdvice接口:

java
public interface AfterReturningAdvice extends AfterAdvice {
    void afterReturning(@Nullable Object returnValue, Method method, 
            Object[] args, @Nullable Object target) throws Throwable;
}

4.4 环绕通知 ​

MethodInterceptor接口:

java
public interface MethodInterceptor extends Interceptor {
    Object invoke(MethodInvocation invocation) throws Throwable;
}

实现示例:

java
public class LogAroundAdvice implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("方法执行前:" + invocation.getMethod().getName());
        try {
            Object result = invocation.proceed();
            System.out.println("方法执行后:" + invocation.getMethod().getName());
            return result;
        }
        catch (Exception e) {
            System.out.println("方法执行异常:" + e.getMessage());
            throw e;
        }
    }
}

🎯 五、切点表达式 ​

5.1 切点表达式语法 ​

AspectJ切点表达式用于匹配需要被拦截的方法。

常用表达式:

java
// 匹配所有方法
execution(* *(..))

// 匹配指定包下的所有方法
execution(* com.example.service.*.*(..))

// 匹配指定类的方法
execution(* com.example.service.UserService.*(..))

// 匹配指定方法
execution(* com.example.service.UserService.saveUser(..))

// 匹配指定参数类型的方法
execution(* com.example.service.UserService.saveUser(com.example.model.User))

// 匹配指定注解的方法
@annotation(com.example.annotation.Log)

5.2 AspectJExpressionPointcut ​

Spring使用AspectJExpressionPointcut来解析切点表达式:

java
public class AspectJExpressionPointcut extends AbstractExpressionPointcut 
        implements ClassFilter, MethodMatcher {
    
    private final PointcutExpression pointcutExpression;
    
    public AspectJExpressionPointcut(String expression, Class<?> pointcutDeclarationScope) {
        this.pointcutExpression = buildPointcutExpression(expression, 
                pointcutDeclarationScope);
    }
    
    @Override
    public boolean matches(Class<?> targetClass) {
        return pointcutExpression.couldMatchJoinPointsInType(targetClass);
    }
    
    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        ShadowMatch shadowMatch = getShadowMatch(method, targetClass);
        return shadowMatch.alwaysMatches();
    }
}

🎯 六、AOP代理创建流程 ​

6.1 代理创建时机 ​

AOP代理在Bean创建过程中创建:

6.2 AbstractAutoProxyCreator ​

AbstractAutoProxyCreator负责自动创建AOP代理:

java
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
        implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
    
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, 
            String beanName) throws BeansException {
        Object cacheKey = getCacheKey(beanClass, beanName);
        
        if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
            if (this.advisedBeans.containsKey(cacheKey)) {
                return null;
            }
            if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return null;
            }
        }
        
        // 获取通知
        TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
        if (targetSource != null) {
            if (StringUtils.hasLength(beanName)) {
                this.targetSourcedBeans.add(beanName);
            }
            Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(
                    beanClass, beanName, targetSource);
            Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        }
        
        return null;
    }
    
    @Override
    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) 
            throws BeansException {
        if (bean != null) {
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }
    
    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;
        }
        
        // 获取通知
        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;
    }
}

📖 学习资源 ​

视频教程 ​

书籍推荐 ​

  • 《Spring源码深度解析》 - 郝佳
  • 《Spring技术内幕》 - 计文柯

网站资源 ​

✅ 学习检查清单 ​

  • [ ] 已理解代理模式原理
  • [ ] 已理解JDK动态代理实现
  • [ ] 已理解CGLIB代理实现
  • [ ] 已理解两种代理的区别
  • [ ] 已理解通知类型
  • [ ] 已理解切点表达式
  • [ ] 已理解AOP代理创建流程
  • [ ] 已理解拦截器链的执行机制
  • [ ] 已绘制AOP架构图
  • [ ] 已总结核心知识点

上一章节:IoC容器深度解析
下一章节:事务管理机制
返回目录:Spring源码深度解析