返回

Spring AOP 源码解析和应用

后端

1. Spring AOP简介

1.1 概念

Spring AOP(Aspect Oriented Programming)是一种面向切面编程的技术,它允许开发人员将应用程序的各个方面(如安全、事务、日志记录等)从业务逻辑中分离出来,以便于维护和重用。Spring AOP 的核心思想是通过代理(Proxy)来拦截和修改方法调用。

1.2 注解方式使用AOP

在Spring中,可以使用注解的方式来配置AOP,非常方便,只需要在目标类上添加相应的注解即可。例如,以下代码使用了@Aspect注解来定义一个切面,并使用了@Before注解来定义在方法执行前执行的通知:

@Aspect
public class LoggingAspect {

    @Before("execution(* com.example.demo.service.*.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Method: " + joinPoint.getSignature().getName() + " is about to be executed");
    }
}

1.3 xml方式使用AOP

除了使用注解的方式,Spring还支持使用xml的方式来配置AOP。使用xml的方式需要在Spring配置文件中定义切面和通知,然后在目标类上使用<aop:config>标签来启用AOP。例如,以下代码使用了<aop:config>标签来启用AOP,并使用了<aop:aspect>标签来定义切面:

<aop:config>
    <aop:aspect ref="loggingAspect">
        <aop:before method="logBefore" pointcut="execution(* com.example.demo.service.*.*(..))"/>
    </aop:aspect>
</aop:config>

1.4 抛出问题?

a. Advice的执行顺序?

对比上面两张图片,可以看到@Around、@After、@Before这三个Advice的执行顺序是:

  1. @Around
  2. @Before
  3. 目标方法
  4. @After

b. 不同的Advice类型能同时应用在一个切入点吗?

可以,不同的Advice类型可以同时应用在一个切入点上,Spring会按照一定的顺序执行这些Advice。例如,以下代码同时使用了@Before和@AfterReturning两个Advice:

@Aspect
public class LoggingAspect {

    @Before("execution(* com.example.demo.service.*.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Method: " + joinPoint.getSignature().getName() + " is about to be executed");
    }

    @AfterReturning(pointcut = "execution(* com.example.demo.service.*.*(..))", returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        System.out.println("Method: " + joinPoint.getSignature().getName() + " returned result: " + result);
    }
}

2. Spring AOP 源码分析

Spring AOP 的核心实现是通过代理(Proxy)来拦截和修改方法调用。Spring AOP 提供了多种代理类型,包括JDK动态代理和CGLIB代理。JDK动态代理是基于Java的动态代理机制实现的,而CGLIB代理是基于CGLIB库实现的。

Spring AOP 的代理类是通过ProxyFactoryBean类来创建的。ProxyFactoryBean类是一个FactoryBean,它可以产生代理对象。ProxyFactoryBean类通过调用AdvisedSupport类的createAopProxy()方法来创建代理对象。

AdvisedSupport类是Spring AOP的核心类之一,它负责管理切面和通知。AdvisedSupport类包含了一个Advisor列表,Advisor列表中包含了所有的切面和通知。AdvisedSupport类还包含了一个TargetSource对象,TargetSource对象负责获取目标对象。

3. Spring AOP 使用示例

Spring AOP 可以用来实现各种各样的功能,包括安全、事务、日志记录、性能监控等。以下是一些 Spring AOP 的使用示例:

3.1 安全

Spring AOP 可以用来实现安全控制,例如,以下代码使用Spring AOP来控制对UserService类中getUser()方法的访问:

@Aspect
public class SecurityAspect {

    @Before("execution(* com.example.demo.service.UserService.getUser(..))")
    public void checkSecurity(JoinPoint joinPoint) {
        // 检查当前用户是否有权限访问getUser()方法
        if (!currentUser.hasPermission("USER_GET")) {
            throw new SecurityException("Access denied");
        }
    }
}

3.2 事务

Spring AOP 可以用来实现事务管理,例如,以下代码使用Spring AOP来管理UserService类中saveUser()方法的事务:

@Aspect
public class TransactionAspect {

    @Around("execution(* com.example.demo.service.UserService.saveUser(..))")
    public Object manageTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
        // 开始事务
        transactionManager.beginTransaction();
        
        try {
            // 执行目标方法
            Object result = joinPoint.proceed();
            
            // 提交事务
            transactionManager.commit();
            
            return result;
        } catch (Throwable e) {
            // 回滚事务
            transactionManager.rollback();
            
            throw e;
        }
    }
}

3.3 日志记录

Spring AOP 可以用来实现日志记录,例如,以下代码使用Spring AOP来记录UserService类中getUser()方法的调用:

@Aspect
public class LoggingAspect {

    @AfterReturning(pointcut = "execution(* com.example.demo.service.UserService.getUser(..))", returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        System.out.println("Method: " + joinPoint.getSignature().getName() + " returned result: " + result);
    }
}

4. 总结

Spring AOP 是一个强大的面向切面编程框架,它可以用来拦截和修改应用程序中的方法调用。Spring AOP 的核心思想是通过代理(Proxy)来拦截和修改方法调用。Spring AOP 可以用来实现各种各样的功能,包括安全、事务、日志记录、性能监控等。