Spring framework Day20:Spring AOP xml配置示例三

前言

本章节我们继续学习 AspectJ!

AspectJ是一个基于Java语言的面向切面编程(AOP)的扩展框架,它的诞生解决了很多传统面向对象编程的问题。在传统的面向对象编程中,开发者通常会将一些通用功能或者横切关注点(cross-cutting concern)手动地嵌入到业务逻辑中,导致代码难以维护和理解。而AspectJ的出现则让开发者可以通过一种简单而优雅的方式来解决这些问题,使得应用程序的代码变得更加清晰、易于维护。

在本文中,我们将介绍AspectJ的基本概念、语法和使用方法。首先,我们将简要介绍AOP的概念,并与传统的面向对象编程作对比,以突出AspectJ的优越性。其次,我们将详细阐述AspectJ的语法和组成部分,包括切入点、通知和切面等。最后,我们将提供一些实际的示例来帮助读者更好地理解如何使用AspectJ来解决常见的应用程序开发问题。

相信通过本文的介绍,读者将会深入理解AspectJ的强大之处,掌握如何使用这个框架来构建高效、易于维护的应用程序。

一、开始学习

1、新建项目,结构如下

Spring framework Day20:Spring AOP xml配置示例三_第1张图片

2、添加 spring 依赖
 
    
    
        
        
            org.springframework
            spring-context
            5.3.23
        
 
        
            ch.qos.logback
            logback-classic
            1.4.5
        
 
         
            org.aspectj
            aspectjweaver
            1.9.8
        
 
 
    
3、在 service 包下新建一个类 UserService 类
@Slf4j
public class UserService {

    /**
     * 目标方法,也就是需要被增强的方法
     * 因此它就是一个连接点
     * @param name
     */
    public String add(String name){
        log.info("添加用户..." + name);
        return "success";
    }

}
4、在 aspect 包下新建一个 ServiceAspect 切面类

@Slf4j
public class ServiceAspect {

    /**
     * 自定义前置通知,可以给一个参数
     * 这个参数为连接点(JoinPoint)
     * 通过这个连接点可以拦截目标方法的参数等信息
     *
     * @param jp
     */
    public void before(JoinPoint jp) {
        log.info("执行前置通知,拦截的目标方法参数:" + jp.getArgs()[0]);
    }

    /**
     * 后置通知
     *
     * @param jp        连接点
     * @param returnVal 目标的方法的返回值
     */
    public void afterReturning(JoinPoint jp, Object returnVal) {
        log.info("后置通知,目标方法返回值:" + returnVal);
    }

    /**
     * 环绕通知
     *
     * @param jp 连接点,继承 JoinPoint 接口
     * @return
     */
    public Object around(ProceedingJoinPoint jp) throws Throwable {
        log.info("环绕通知前,目标方法参数:" + jp.getArgs()[0]);
        // 调用目标方法对象的方法
        Object returnVal = jp.proceed();
        log.info("环绕通知后,目标方法返回值:" + returnVal);
        return returnVal;
    }

    /**
     * 异常通知,当目标对象产生异常时会执行
     * 后置通知将不会再生效
     *
     * @param jp 连接点
     * @param e  目标方法产生的异常对象
     */
    public void afterThrowing(JoinPoint jp, Exception e) {
        log.info("异常通知,异常信息:" + e.getMessage());
    }

    /**
     * 最终通知,不管有没有异常产生最终通知都会被执行
     * @param jp 连接点
     */
    public void after(JoinPoint jp){
        log.info("最终通知");
    }

}

这个示例中的ServiceAspect类是一个使用AspectJ编写的切面类,其中包含了几个不同类型的通知方法。

  1. before(JoinPoint jp) 方法是一个前置通知。在目标方法执行之前被拦截执行。它接收一个JoinPoint对象作为参数,可以通过该对象获取目标方法的参数信息。在这个示例中,我们使用log.info方法记录了拦截的目标方法参数。

  2. afterReturning(JoinPoint jp, Object returnVal) 方法是一个后置通知。在目标方法成功返回之后被拦截执行。它接收一个JoinPoint对象和目标方法的返回值作为参数。在这个示例中,我们使用log.info方法记录了目标方法的返回值。

  3. around(ProceedingJoinPoint jp) 方法是一个环绕通知。它可以在目标方法执行的前后进行处理。在这个示例中,我们首先通过log.info方法记录了目标方法的参数信息,然后调用jp.proceed()方法来执行目标方法,最后再通过log.info方法记录了目标方法的返回值。注意,在环绕通知中必须显式地调用jp.proceed()方法来触发目标方法的执行。

  4. afterThrowing(JoinPoint jp, Exception e) 方法是一个异常通知。当目标方法抛出异常时被拦截执行。它接收一个JoinPoint对象和抛出的异常对象作为参数。在这个示例中,我们使用log.info方法记录了异常信息。

  5. after(JoinPoint jp) 方法是一个最终通知。无论目标方法是否成功执行,最终总会被执行。在这个示例中,我们使用log.info方法输出了一条简单的日志。

通过编写这些通知方法,我们可以根据不同的需求,在目标方法的不同执行阶段进行拦截和处理。例如,可以在前置通知中进行参数验证,后置通知中记录返回值,异常通知中处理异常情况等。AspectJ提供了灵活的语法和丰富的可操作性,使得开发人员可以轻松地实现横切关注点的处理。

 5、在 rsources 下新建一个 beans.xml 文件



    
    
    
    
    
    
        
        
        
        
            

            
            

            
            

            
            

            
            

            
            

        
    


XML配置代码是使用Spring AOP来实现切面编程的示例。XML配置代码是使用Spring AOP来实现切面编程的示例。





在这个示例中,userService是一个具体的业务类,serviceAspect是一个切面类,用于包含横切关注点的逻辑。

继续,配置AOP:


    
    

    
    
        
        
        
        
        
    

标签中,首先定义了切入点(pointcut),用于确定哪些方法将被拦截。在这个示例中,切入点被命名为myPointcut,它使用了表达式语言来匹配edu.nf.ch20.service.UserService类的所有方法。

然后,通过标签配置了不同类型的通知(advice),包括(前置通知)、(后置通知)、(环绕通知)、(最终通知)和(异常通知)。这些通知指向了切面类中对应的方法。

总结来说,这段XML配置代码实现了对edu.nf.ch20.service.UserService类的方法进行切面编程,并在不同的执行阶段触发对应的通知方法。这样可以将横切关注点的业务逻辑与核心业务逻辑分离,提高了代码的可维护性和可重用性。

具体来说,这段代码的作用如下:

  1. 配置目标对象和切面:通过配置元素,将目标对象和切面类实例化并装配到Spring容器中。目标对象是具体的业务类,而切面类包含了与横切关注点相关的逻辑。

  2. 配置切入点:使用元素配置切入点,即确定哪些方法将被拦截和应用切面的逻辑。在这个示例中,切入点使用表达式execution(* edu.nf.ch20.service.UserService.*(..)),表示拦截edu.nf.ch20.service.UserService类的所有方法。

  3. 配置通知:通过等元素,配置了不同类型的通知(advice)。这些通知指向切面类中的相应方法,并在目标对象的方法执行前、后、返回结果时、发生异常时等特定时机触发执行。

通过以上配置,可以实现以下主要功能:

  • 前置通知(Before Advice):在目标方法执行前执行切面中的方法,可以做一些准备工作、参数验证等操作。

  • 后置通知(After Advice):在目标方法执行后执行切面中的方法,可以进行一些清理工作、记录日志、统计时间等操作。

  • 环绕通知(Around Advice):在目标方法执行前后,或者替代目标方法执行,都可以执行切面中的方法。可以自由控制目标方法的执行,并进行一些额外的处理。

  • 最终通知(After-returning Advice):在目标方法正常返回结果后执行切面中的方法,可以对返回结果进行处理或记录日志。

  • 异常通知(After-throwing Advice):在目标方法发生异常时执行切面中的方法,可以处理异常、记录日志或进行补偿操作。

通过将横切关注点与核心业务逻辑分离,AOP提供了一种更加灵活和可维护的代码组织方式。它可以帮助开发人员在不改变原有业务逻辑的情况下,统一处理与业务无关的横切关注点,提高代码的可重用性、可维护性和可测试性。

6、测试
public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        UserService bean = context.getBean(UserService.class);
        bean.add("qiu");
    }

}

 运行结果

 

 二、总结

上一章我们使用了MethodBeforeAdvice、AfterReturningAdvice、MethodInterceptor和ThrowsAdvice接口这四个接口去重写它们的方法来实现通知。这样有什么不好呢,每一次编写切面类的时候都需要实现这些接口,太繁重了,还有,重写异常通知时需要自己编写,而且方法名必须是afterThrowing,写错了还不行。

本章节通过使用 AspectJ ,我们自己来定义通知,自己编写。那么使用 AspectJ 的时候,可以实现接口重写他们的方法来实现通知,也可以自定义通知,它们有什么区别呢?

MethodBeforeAdvice、AfterReturningAdvice、MethodInterceptor和ThrowsAdvice接口是Spring框架中用于实现不同类型通知的接口。

  1. MethodBeforeAdvice:这个接口用于实现前置通知,即在目标方法执行之前被触发的通知。它的before方法会在目标方法执行前被调用,可以在该方法中添加需要执行的逻辑。

  2. AfterReturningAdvice:这个接口用于实现后置通知,即在目标方法成功返回后被触发的通知。它的afterReturning方法会在目标方法成功返回后被调用,可以在该方法中对返回结果进行处理或记录日志等操作。

  3. MethodInterceptor:这个接口用于实现环绕通知,即在目标方法的执行过程中进行拦截并控制其执行。它的invoke方法会在目标方法执行前后被调用,通过该方法可以手动控制目标方法的执行,包括传入参数、获取返回结果等。

  4. ThrowsAdvice:这个接口用于实现异常通知,即在目标方法抛出异常时被触发的通知。它没有定义具体的方法,而是通过在实现类中定义异常处理方法来实现不同类型异常的处理。

与自定义通知相比,这些接口提供了一种约定和规范化的方式来实现通知逻辑。开发者只需实现相应的接口,并将其配置到Spring容器中,框架会在合适的时机调用相应的方法。这种方式可以使通知与被拦截的目标方法解耦,并且能够与Spring的AOP功能无缝集成。

而自定义通知则更加灵活,开发者可以根据需要编写自己的通知类,不受特定接口的限制。自定义通知可以通过注解、切面表达式或者基于XML的配置来实现,具有更高的自由度和可定制性。开发者可以自己控制通知的触发时机和执行逻辑,更好地满足特定业务需求。

总之,使用Spring的通知接口可以快速实现常见类型的通知,并与Spring的AOP功能结合使用;而自定义通知则更加灵活,可以更好地满足自定义需求,但需要更多的开发额外处理。选择采用哪种方式取决于具体场景和需求。

 

三、gitee 案例

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

你可能感兴趣的:(spring,framework,spring,xml,java)