Spring AOP编程

Spring AOP(面向切面编程)是 Spring 框架的一个重要特性,它允许你在不修改现有代码的情况下,对程序的功能进行增强。下面从多个方面介绍 Spring AOP 的使用:

1. 添加依赖

如果你使用 Maven 项目,需要在 pom.xml 中添加 Spring AOP 和 AspectJ 的依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>6.1.3</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>6.1.3</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.9.1</version>
    </dependency>
</dependencies>

2. 定义业务类

定义一个简单的业务类,作为被增强的目标对象:
image
AppConfig.java

package cn.snnuedu.tuling_test.AOP;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan(basePackages = "cn.snnuedu.tuling_test.AOP")
@EnableAspectJAutoProxy
public class AppConfig {
}

LoggingAspect.java

package cn.snnuedu.tuling_test.AOP;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

    // 前置通知,在目标方法执行之前执行
    @Before("execution(* cn.snnuedu.tuling_test.AOP.UserService.addUser(..))")
    public void beforeAddUser(JoinPoint joinPoint) {
        System.out.println("Before adding user: " + joinPoint.getArgs()[0]);
    }

    // 后置通知,在目标方法执行之后执行
    @After("execution(* cn.snnuedu.tuling_test.AOP.UserService.addUser(..))")
    public void afterAddUser(JoinPoint joinPoint) {
        System.out.println("After adding user: " + joinPoint.getArgs()[0]);
    }
}    

Main.java

package cn.snnuedu.tuling_test.AOP;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        UserService userService = context.getBean(UserService.class);
        userService.addUser("John");
        context.close();
    }
}    

UserService.java

package cn.snnuedu.tuling_test.AOP;

import org.springframework.stereotype.Service;

@Service
public class UserService {
    public void addUser(String username) {
        System.out.println("Adding user: " + username);
    }
}    

image

定义切面类

创建一个切面类,使用 @Aspect 注解标记,在这个类中定义通知方法:

配置 Spring AOP

可以使用 Java 配置类来启用 Spring AOP 的自动代理功能:

测试代码

编写一个测试类,创建 Spring 容器并调用业务方法:
代码解释:

  • UserService 类:这是一个简单的业务类,包含一个 addUser 方法,用于添加用户。
  • LoggingAspect 类:这是一个切面类,使用 @Aspect 注解标记。@Before 和 @After 是通知注解,分别表示前置通知和后置通知。execution(* cn.snnuedu.tuling_test.AOP.UserService.addUser(..)) 是切入点表达式,用于指定哪些方法会被增强。
  • AppConfig 类:使用 @EnableAspectJAutoProxy 注解启用 Spring AOP 的自动代理功能,这样 Spring 会自动为目标对象创建代理。
  • Main 类:创建 Spring 容器,获取 UserService Bean 并调用 addUser 方法,观察通知方法的执行情况。

其他常见通知类型
除了前置通知和后置通知,Spring AOP 还支持以下常见的通知类型:

  • 环绕通知(@Around):可以在目标方法执行前后都进行增强,甚至可以决定是否执行目标方法。
  • 返回通知(@AfterReturning):在目标方法正常返回后执行。
  • 异常通知(@AfterThrowing):在目标方法抛出异常后执行。

通过 Spring AOP,你可以将一些通用的功能(如日志记录、事务管理等)从业务逻辑中分离出来,提高代码的可维护性和可复用性。

AOP的通知类型和实例

在 Spring AOP 里,除了 @Before 和 @After 通知类型,还有环绕通知、返回通知和异常通知。下面详细介绍这些通知类型及其使用示例。

环绕通知(@Around)

环绕通知是功能最为强大的通知类型,它能够在目标方法执行前后都进行增强操作,甚至可以决定是否执行目标方法。环绕通知的方法需要接收一个 ProceedingJoinPoint 类型的参数,通过调用 proceed() 方法来执行目标方法。

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

    @Around("execution(* cn.snnuedu.tuling_test.AOP.UserService.addUser(..))")
    public Object aroundAddUser(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Before method execution");
        Object result = null;
        try {
            // 执行目标方法
            result = joinPoint.proceed();
        } catch (Exception e) {
            System.out.println("Exception occurred: " + e.getMessage());
            throw e;
        }
        System.out.println("After method execution");
        return result;
    }
}

返回通知(@AfterReturning)

返回通知会在目标方法正常返回之后执行。可以通过 returning 属性指定一个参数名,将目标方法的返回值传递给通知方法。

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

    @AfterReturning(pointcut = "execution(* cn.snnuedu.tuling_test.AOP.UserService.addUser(..))", returning = "result")
    public void afterReturningAddUser(JoinPoint joinPoint, Object result) {
        System.out.println("Method returned: " + result);
    }
}

异常通知(@AfterThrowing)

异常通知会在目标方法抛出异常时执行。可以通过 throwing 属性指定一个参数名,将抛出的异常传递给通知方法。

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

    @AfterThrowing(pointcut = "execution(* com.example.demo.UserService.addUser(..))", throwing = "ex")
    public void afterThrowingAddUser(JoinPoint joinPoint, Exception ex) {
        System.out.println("Exception thrown: " + ex.getMessage());
    }
}

@Before:在目标方法执行之前执行。
@After:在目标方法执行之后执行,无论目标方法是否抛出异常。
@Around:在目标方法执行前后都可以进行增强,可控制目标方法的执行。
@AfterReturning:在目标方法正常返回后执行。
@AfterThrowing:在目标方法抛出异常时执行。
这些通知类型可以根据具体需求灵活组合使用,以实现不同的切面功能,如日志记录、性能监控、事务管理等。

posted @ 2025-03-20 20:37  lipu123  阅读(16)  评论(0)    收藏  举报