当前位置: 首页>编程语言>正文

spring切点如何获取参数名称 spring aop切点切面

Spring AOP简单介绍


什么是AOP

AOP(Aspect Oriented Programing)面向切面编程,相比较oop面向对象编程来说,Aop关注的不再是程序代码中某个类,某些方法,而考虑的更多的是一种面到面的切入,即层与层之间的一种切入,所以称之为切面。即通过AOP,可以在不修改方法的前提下,在其前后等插入新的功能。

AOP通常用于日志记录、性能统计、安全控制、事务处理等方面,实现公共功能性的重复使用。

AOP其底层是使用动态代理实现的(JDK和CGLIB)

AOP的主要优点如下:

  1. 降低模块与模块之间的耦合度,提高业务代码的聚合度。(高内聚低耦合)
  2. 提高了代码的复用性。
  3. 提高系统的扩展性。(高版本兼容低版本)
  4. 可以在不影响原有的功能基础上添加新的功能。

AOP基本概念

  1. Joinpoint(连接点):被拦截到的每个方法,spring aop的一个连接点即代表一个方法的执行。
  2. Pointcut(切入点):对连接点进行拦截的定义(匹配规则定义规定拦截哪些方法,对哪些方法进行处理),spring有专门的表达式语言定义。
  3. Advice(通知):拦截到每一个方法后所要做的操作。
  4. Aspect(切面):切入点与通知的结合,决定了切面的定义,切入点定义了要拦截哪些类的哪些方法,通知则定义了拦截过方法后要做什么,切面则是横切关注点的抽象,与类相似,类是对物体特征的抽象,切面则是横切关注点抽象。
  5. Target(目标对象):被代理的目标对象。
  6. Weave(织入):将切面应用到目标对象并生成代理对象的这个过程即为织入。

通知类型

  1. Before(前置通知):执行方法前通知
  2. AfterReturning(返回通知):方法正常结束返回后的通知
  3. AfterThrowing(异常抛出通知):抛出异常时通知
  4. After(最终通知):无论方法是否发生异常,均会执行该通知。在返回通知前执行
  5. Around(环绕通知):包围一个连接点的通知,这是最强大的一种通知类型,可以完成上面几种通知的功能。

实现AOP

首先,我们需要导入相关依赖,如下

<!--  spring AOP  -->
<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjweaver</artifactId>
	<version>1.8.13</version>
</dependency>

然后需要在spring配置文件中添加命名空间

xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd

例如

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
      https://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context.xsd
      http://www.springframework.org/schema/aop
      http://www.springframework.org/schema/aop/spring-aop.xsd">

实现AOP主要有两种方式,一种是通过注解实现,另一种通过xml实现

通过注解实现AOP

首先要在配置文件中开启自动代理,如下

<!-- 开启自动代理 -->
<aop:aspectj-autoproxy/>

定义切面类,所有的通知注解里都要指定切入点,如下

@Component// 交给IOC容器实例化
@Aspect// 声明当前类是一个切面类
public class LogCut {

    // 定义切入点,指定example包及其子包下的所有方法
    @Pointcut("execution(* org.example..*.*(..))")
    public void cut() {
    }

    // 前置通知
    @Before("cut()")
    public void before() {
        System.out.println("前置通知");
    }

    // 返回通知
    @AfterReturning("cut()")
    public void afterReturning() {
        System.out.println("返回通知");
    }

    // 异常抛出通知,throwing指定接受异常的形参名
    @AfterThrowing(value = "cut()", throwing = "e")
    public void afterThrowing(Exception e) {
        System.out.println("异常抛出通知");
        System.out.println(e.getMessage());
    }

    // 最终通知
    @After("cut()")
    public void after() {
        System.out.println("最终通知");
    }
}

接下来只要执行example包下的任一方法,都会进行切面,在对应的位置执行对应的方法。

若要使用环绕通知,如下

@Component// 交给IOC容器实例化
@Aspect// 声明当前类是一个切面类
public class LogCut {

    // 定义切入点,指定example包及其子包下的所有方法
    @Pointcut("execution(* org.example..*.*(..))")
    public void cut() {
    }
    
    @Around("cut()")
    public Object around(ProceedingJoinPoint pjp){
        System.out.println("前置通知");
        Object object = null;
        try {
            object = pjp.proceed();// 执行所调用的方法
            System.out.println("返回通知");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("异常抛出通知");
        } finally {
            System.out.println("最终通知");
        }
        return object;
    }

}

通过XML实现AOP

若使用xml实现,我们只需要将注解都去除后,在配置文件中添加aop配置即可,例如

<!-- 配置aop -->
  <aop:config>
    <aop:aspect ref="logCut">
      <!-- 定义aop切入点 -->
      <aop:pointcut id="cut" expression="execution(* org.example..*.*(..))"/>
      <!-- 前置通知 -->
      <aop:before method="before" pointcut-ref="cut"/>
      <!-- 异常抛出通知 -->
      <aop:after-throwing method="afterThrowing" throwing="e" pointcut-ref="cut"/>
      <!-- 环绕通知 -->
      <aop:around method="around" pointcut-ref="cut"/>
    </aop:aspect>
  </aop:config>

切入点规则定义

规则如下

execution(方法修饰符 包.类.方法(参数))

其中,除了参数使用..表示所有参数,其他都使用*作为通配符。在包中,使用..表示该包下的类及其子包下的类

例如:

  1. 拦截所有方法:execution(* *(..))
  2. 拦截所有公共的set方法:execution(public set*(..))
  3. 拦截com.xxx包下所有类的所有的方法:execution(* com.xxx.*.*(..))
  4. 拦截com.xxx包及其子包下所有类的所有的方法:execution(* com.xxx..*.*(..))



https://www.xamrdz.com/lan/5rq1957341.html

相关文章: