Spring AOP实现原理

发布时间:2024年01月19日

Spring AOP(Aspect-Oriented Programming)实现原理主要基于代理模式。在Spring AOP中,会根据配置动态地在运行时创建代理对象,用来包裹目标对象。根据代理的类型,Spring AOP使用JDK动态代理或CGLIB来创建这些代理。

AOP主要概念

  1. Aspect: 定义跨多个类的行为,通常包含多个通知(Advices)。
  2. Join Point: 方法执行过程中的某个特定点,比如方法调用前、调用后、抛出异常后等。
  3. Advice: 定义在特定的join point上需要执行的动作,比如before, after, around等类型的advice。
  4. Pointcut: 定义哪些join points匹配通知(advice),它是一组表达式。
  5. Target Object: 被一个或多个aspects通知的对象。
  6. AOP Proxy: AOP框架为目标对象创建的代理,用于拦截某些方法调用,并提供通知的执行。

Spring AOP实现原理

在Spring中,AOP代理的创建过程主要由ProxyFactory类处理:

  1. 确定代理模式: 如果目标类实现了至少一个接口,则默认使用JDK动态代理,否则使用CGLIB。
  2. 收集advice: Spring会查找与目标方法匹配的advice(通过Pointcut定义)。
  3. 创建代理对象: 根据advice和目标对象创建代理实例。
  4. 代理使用: 当调用代理上的方法时,代理会根据advice执行相关的通知逻辑。

源码解析

让我们通过源码解析,看一下Spring是如何创建AOP代理的。

创建AOP代理

AbstractAutoProxyCreator类中有创建AOP代理的逻辑:

protected Object createProxy(Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
        AutoProxyUtils.exposeTargetClass(this.beanFactory, beanName, beanClass);
    }

    ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.copyFrom(this);

    if (!proxyFactory.isProxyTargetClass()) {
        if (shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        } else {
            evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }

    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    proxyFactory.addAdvisors(advisors);
    proxyFactory.setTargetSource(targetSource);
    customizeProxyFactory(proxyFactory);

    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }

    return proxyFactory.getProxy(getProxyClassLoader());
}
进行方法拦截

当代理对象的方法被调用时,方法拦截的逻辑是通过ReflectiveMethodInvocation来处理的:

public Object proceed() throws Throwable {
    // We start with an index of -1 and increment early.
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }

    Object interceptorOrInterceptionAdvice =
        this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
        // Evaluate dynamic method matcher here: static part will already have
        // been evaluated and found to match.
        InterceptorAndDynamicMethodMatcher dm =
            (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
        if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
            return dm.interceptor.invoke(this);
        }
        else {
            // Dynamic matching failed.
            // Skip this interceptor and invoke the next in the chain.
            return proceed();
        }
    }
    else {
        // It's an interceptor, so we just invoke it: The pointcut will have
        // been evaluated statically before this object was constructed.
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}
Advice的执行

以上proceed()方法确保了各种advice按照设定的顺序执行。对于@Around@Before@After@AfterReturning@AfterThrowing等,都是通过相应的Advice实现类来实现具体的拦截逻辑。

代码演示

下面是一个使用Spring AOP的例子。我们定义一个简单的服务类和一个切面:

@Service
public class SimpleService {

    public void performOperation() {
        // 模拟方法执行
        System.out.println("Performing operation...");
    }
}

@Aspect
@Component
public class LoggingAspect {

    @Before("execution(* SimpleService.performOperation(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Logging before operation: " + joinPoint.getSignature().getName());
    }
}

在这个例子中,LoggingAspect定义了一个@Before通知,它会在SimpleService.performOperation()方法执行前打印一条日志。

总结

Spring AOP是基于代理模式的,它在运行时动态地创建代理对象,并根据定义的切面和通知来增加额外的行为。通过使用JDK动态代理或CGLIB,Spring能够将通知应用到目标对象的方法上。深入理解和使用Spring AOP能够让您在不改变现有业务逻辑代码的情况下,增加如日志、事务管理、安全控制等横切关注点。

文章来源:https://blog.csdn.net/qq_43012298/article/details/135671309
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。