• Spring framework Day21:Spring AOP 注解结合配置类示例


    前言

    Spring AOP是一种强大的面向切面编程工具,它能够帮助我们更好地处理与核心业务逻辑无关的横切关注点。通过使用注解和配置类的方式,我们可以更加简洁和灵活地实现AOP。

    本文将以一个示例来介绍如何结合注解和配置类来使用Spring AOP。通过这个示例,你将了解如何使用注解来定义切点、通知和切面,并通过配置类来启用和配置AOP。

    前面三章我们都是通过 xml 文件去配置,那么这章我们开始使用 Java 配置类加注解来完成案例。

    注意:使用 xml 是为了让大家了解 xml 怎么去配置,现在常用的都是注解加 Java 配置类来实现。

    在开始之前,请确保你已经具备了Spring框架的基础知识,并且已经正确配置了Spring环境。

    接下来,我们将一步步地介绍这个示例,让我们开始吧!

    一、开始学习

    1、新建项目,结构如下

     2、添加 spring 依赖
    1. <dependencies>
    2. <dependency>
    3. <groupId>org.springframeworkgroupId>
    4. <artifactId>spring-contextartifactId>
    5. <version>5.3.23version>
    6. dependency>
    7. <dependency>
    8. <groupId>ch.qos.logbackgroupId>
    9. <artifactId>logback-classicartifactId>
    10. <version>1.4.5version>
    11. dependency>
    12. <dependency>
    13. <groupId>org.aspectjgroupId>
    14. <artifactId>aspectjweaverartifactId>
    15. <version>1.9.8version>
    16. dependency>
    17. dependencies>
    3、在 service 包下新建一个 UserService 类(被代理的目标类)
    1. @Slf4j
    2. @Service
    3. public class UserService {
    4. /**
    5. * 目标方法,也就是需要被增强的方法
    6. * 因此它就是一个连接点
    7. * @param name
    8. */
    9. public String add(String name){
    10. log.info("添加用户..." + name);
    11. return "success";
    12. }
    13. }
    4、在 aspect 包下新建一个 UserAspect 切面类
    1. @Slf4j
    2. // 将切面纳入容器管理
    3. @Component
    4. /**
    5. * 使用 @Aspect 注解标识当前类为一个切面
    6. */
    7. @Aspect
    8. public class UserAspect {
    9. @Pointcut("execution(* edu.nf.ch21.service.UserService.*(..))")
    10. public void pointcut() {
    11. }
    12. @Before("pointcut()")
    13. public void before(JoinPoint jp) {
    14. log.info("前置通知");
    15. }
    16. /**
    17. * 后置通知
    18. *
    19. * @param jp
    20. * @param returnVal
    21. */
    22. @AfterReturning(value = "pointcut()", returning = "returnVal")
    23. public void afterReturning(JoinPoint jp, Object returnVal) {
    24. log.info("后置通知,目标方法返回值:" + returnVal);
    25. }
    26. /**
    27. * 环绕通知
    28. *
    29. * @param jp
    30. * @return
    31. */
    32. @Around("pointcut()")
    33. public Object around(ProceedingJoinPoint jp) throws Throwable {
    34. log.info("环绕通知前,方法参数:" + jp.getArgs()[0]);
    35. Object returnVal = jp.proceed();
    36. log.info("环绕通知后,方法返回值:" + returnVal);
    37. return returnVal;
    38. }
    39. /**
    40. * 异常通知
    41. *
    42. * @param jp
    43. * @param e
    44. */
    45. @AfterThrowing(value = "pointcut()", throwing = "e")
    46. public void afterThrowing(JoinPoint jp, Exception e) {
    47. log.info("异常通知:" + e.getMessage());
    48. }
    49. /**
    50. * 最终通知
    51. * @param jp
    52. */
    53. @After("pointcut()")
    54. public void after(JoinPoint jp){
    55. log.info("最终通知");
    56. }
    57. }

    这个切面类定义了一个pointcut()切点方法,用于指定哪些方法需要被拦截。这里使用了execution()表达式来匹配edu.nf.ch21.service.UserService类中的所有方法。

    接下来,针对这个切点方法,定义了五个通知方法:

    • before()方法是一个前置通知,在目标方法执行之前执行,并且拦截到JoinPoint参数,可以获取目标方法的信息。
    • afterReturning()方法是一个后置通知,在目标方法正常返回时执行,拦截到JoinPoint和目标方法的返回值returnVal参数。
    • around()方法是一个环绕通知,可以在目标方法执行前、执行后都做一些处理,并拦截到ProceedingJoinPoint参数,可以手动调用目标方法并获取返回值。
    • afterThrowing()方法是一个异常通知,在目标方法抛出异常时执行,拦截到JoinPointException参数。
    • after()方法是一个最终通知,在目标方法执行结束后(包括正常结束和异常结束)执行,拦截到JoinPoint参数。

     其中还使用了很多的注解,它们分别是什么意思?

    1. @Component: 这是Spring框架的注解之一,用于将类标识为一个可被Spring容器扫描和管理的组件。在这个示例中,@Component注解表示将UserAspect类作为一个切面组件纳入到Spring容器中。

    2. @Aspect: 这是AspectJ框架的注解,用于标识一个类为切面。切面是一个包含了各种通知和切点的类,用于对其他类中的方法进行拦截和增强。

    3. @Pointcut: 这是一个自定义的方法级别注解,用于定义一个切点。切点决定了哪些方法会被拦截和应用切面逻辑。在这个示例中,pointcut()方法使用了@Pointcut注解来定义切点。

    4. @Before: 这是一个前置通知注解,用于在目标方法执行之前执行某段逻辑。在这个示例中,before()方法使用了@Before注解,表示在匹配到的方法执行之前会执行before()方法中的逻辑。

    5. @AfterReturning: 这是一个后置返回通知注解,用于在目标方法正常返回时执行某段逻辑。在这个示例中,afterReturning()方法使用了@AfterReturning注解,并通过value属性指定了切点,returning属性指定了目标方法返回值的参数名,表示在匹配到的方法正常返回时会执行afterReturning()方法中的逻辑。

    6. @Around: 这是一个环绕通知注解,用于在目标方法执行前和执行后执行某段逻辑。在这个示例中,around()方法使用了@Around注解,并通过value属性指定了切点,表示在匹配到的方法执行前后会执行around()方法中的逻辑。注意,around()方法的参数类型为ProceedingJoinPoint,可以手动调用目标方法。

    7. @AfterThrowing: 这是一个异常通知注解,用于在目标方法抛出异常时执行某段逻辑。在这个示例中,afterThrowing()方法使用了@AfterThrowing注解,并通过value属性指定了切点,throwing属性指定了异常的参数名,表示在匹配到的方法抛出异常时会执行afterThrowing()方法中的逻辑。

    8. @After: 这是一个最终通知注解,用于在目标方法执行结束后执行某段逻辑,无论是否抛出异常。在这个示例中,after()方法使用了@After注解,并通过value属性指定了切点,表示在匹配到的方法执行结束后会执行after()方法中的逻辑。

    总结起来,这些注解一起使用可以实现对目标方法的拦截和增强,例如在方法执行前后打印日志、记录返回值、处理异常等。

    5、在 config 包下新建一个  AppConfig 配置类
    1. @Configuration
    2. @ComponentScan(basePackages = "edu.nf.ch21")
    3. // 启用 AspectJ 注解处理器
    4. // proxyTargetClass 指定为 true 表示强制使用 cglib 生成代理
    5. @EnableAspectJAutoProxy(proxyTargetClass = true)
    6. public class AppConfig {
    7. }

    这段代码是一个Spring配置类,用于配置Spring容器和启用AspectJ注解处理器。下面是对每个注解的解释:

    • @Configuration: 这是一个Spring框架的注解,用于表示该类是一个配置类。配置类通常用于定义Bean的创建和配置,以及其他的Spring配置。

    • @ComponentScan: 这是一个Spring框架的注解,用于指定要扫描的包或类的路径。在这个示例中,basePackages属性指定了要扫描的基础包路径为"edu.nf.ch21",意味着Spring容器会扫描并加载该包及其子包中的组件。

    • @EnableAspectJAutoProxy: 这是一个Spring框架的注解,用于启用AspectJ注解处理器,并开启基于AspectJ的自动代理功能。proxyTargetClass = true表示使用cglib生成代理对象而不是默认的基于接口的JDK动态代理方式。

    这些注解的组合作用是将该配置类纳入Spring容器的管理,并启用AspectJ注解处理器和自动代理功能,从而实现AOP(面向切面编程)的特性。

    6、测试
    1. public class Main {
    2. public static void main(String[] args) {
    3. ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    4. UserService bean = context.getBean(UserService.class);
    5. bean.add("qiu");
    6. }
    7. }

     运行结果

    使用注解开发,效率是不是很高,没错,在实际开发中注解和 Java 配置类确实是很开。也是开发中最常用的一种,当然 xml 也可以,只不过是使用 Java 配置类加注解开发会比较好看,阅读性好。大家根据自己的选择使用,推荐使用的是这种方法。

     

    二、使用Spring AOP 注解结合配置类和使用 xml 有什么区别

    使用Spring AOP注解和配置类与使用XML方式定义AOP有以下区别:

    1. 配置方式:使用注解的方式是通过在代码中添加注解来定义切面、切点和通知等,而使用XML方式是通过编写XML配置文件来定义AOP元素。

    2. 代码可读性:使用注解方式可以直接在Java代码中看到AOP相关的配置,使得代码更加紧凑和可读。而使用XML方式需要打开独立的XML配置文件,可能会增加代码的复杂性。

    3. 配置灵活性:使用注解方式可以更灵活地进行配置,可以直接将切面和通知应用于具体的类或方法,也可以使用通配符来匹配一组类或方法。而使用XML方式则需要在配置文件中明确指定切入点和通知的目标。

    4. IDE支持:使用注解方式可以充分利用现代IDE的代码提示和自动补全功能,提升开发效率。而使用XML方式则需要手动编写XML配置文件,可能会增加书写错误的风险。

    5. 集成和维护:使用注解方式可以更加方便地进行代码集成和版本控制,同时也更容易进行维护和重构。而使用XML方式则可能导致配置文件随着系统变得越来越庞大和难以管理。

    总的来说,注解方式相对于XML方式更加简洁、灵活和方便于代码维护,但对于复杂的AOP配置或需要与第三方库进行集成的情况,XML方式可能更为适用。选择使用哪种方式还取决于个人或团队的偏好和具体的项目需求。

    三、gitee 案例

    案例完整地址:https://gitee.com/qiu-feng1/spring-framework.git

     

  • 相关阅读:
    3000字教你如何加快Spring Boot启动
    微信小程序案例2-3:婚礼邀请函
    【OS】AUTOSAR架构下MCAL Modules软件分区问题分析
    Django基础之django模型层(一)单表操作
    spidev的使用(SPI用户态API)
    静态路由+PAT转换(讲解+实验)
    corosync+pacemaker+web集群
    21天学习第十一天-Set集合
    接口测试入门必会知识总结(学习笔记)
    企业怎样选择适合的服务器租用?
  • 原文地址:https://blog.csdn.net/zhiqiuqiu2/article/details/133906304