首页 > 编程语言 >AOP切面编程

AOP切面编程

时间:2024-08-08 10:50:20浏览次数:13  
标签:service 方法 编程 example 切面 AOP execution com public

AOP切面编程

一些知识

切面:处理共同逻辑的模块

@Aspect	用在类上,表示这个类是一个切面

目标:被切面作用的业务模块

切入点:用于指定那些切面作用于哪些目标组件上,一般用表达式实现。

通知:切面和切入点的执行循序;分为:前置通知,后置通知,最终通知,环绕通知,异常通知

前置通知(Before Advice):
注解:@Before
知识点:在目标方法执行之前执行的通知。常用于记录日志、权限检查等操作。

后置通知(After Returning Advice):
注解:@AfterReturning
知识点:在目标方法成功执行并返回结果之后执行的通知。适用于记录方法返回值或者进行后续处理。

最终通知(After Advice):
注解:@After
知识点:在目标方法执行之后执行的通知,无论方法是否抛出异常。用于释放资源等操作。

环绕通知(Around Advice):
注解:@Around
知识点:环绕通知可以在目标方法执行前后进行自定义操作,甚至可以决定是否执行目标方法。它是功能最强的通知类型,可以用于事务管理、性能监控等。

异常通知(After Throwing Advice):
注解:@AfterThrowing
知识点:在目标方法抛出异常后执行的通知。用于记录异常日志、处理异常等。

切面的实现

1、导包

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>

2、定义类加注解

@Aspect

3、通知后面的表达式

execution(*com.qst.springbootsecd.service..*.*(..))
解释如下:
符号含义
execution()
表达式的主体;
第一个”*“符号
表示返回值的类型任意;
com.sample.service.imp1AOP所切的服务的包名,即,我们的业务部分
包名后面的”..“表示当前包及子包
第二个”“表示类名,*即所有类。此处可以自定义,下文有举例
*(..)表示任何方法名,括号表示参数,两个点表示任何参数类型。

效果:

前置通知

@Before("execution(* com.example.service.UserService.*(..))")
public void beforeAdvice() {
    // 在目标方法执行前执行的逻辑
}

后置通知

@After("execution(* com.example.service.UserService.*(..))")
public void afterAdvice() {
    // 在目标方法执行后执行的逻辑
}

返回通知

@AfterReturning(pointcut = "execution(* com.example.service.UserService.*(..))", returning = "result")
public void afterReturningAdvice(Object result) {
    // 在目标方法返回结果后执行的逻辑,result 是目标方法的返回值
}

异常通知

@AfterThrowing(pointcut = "execution(* com.example.service.UserService.*(..))", throwing = "ex")
public void afterThrowingAdvice(Exception ex) {
    // 在目标方法抛出异常后执行的逻辑,ex 是目标方法抛出的异常
}

环绕通知

@Around("execution(* com.example.service.UserService.*(..))")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
    // 在目标方法执行前后执行特定的逻辑,可以控制目标方法的执行
    // 执行目标方法
    Object result = joinPoint.proceed();
    // 在目标方法执行后执行的逻辑
    return result;
}

一些小tips:

1、在spring容器中JoinPoint可以被自动注入,我们可以用它来帮我们获取调用的类名、方法名

切点的实现

表达式

execution([可见性] 返回类型 [声明类型].方法名(参数) [异常类型])

其中:

execution:切入点表达式关键字;

[可见性]:可选,指定方法的可见性,如 public、private、protected 或 *;

返回类型:指定方法的返回类型,如 void、int、String 等;

[声明类型]:可选,指定方法所属的类、接口、注解等声明类型;

方法名:指定方法的名称,支持通配符 *;

参数:指定方法的参数类型列表,用逗号分隔,支持通配符 *;

[异常类型]:可选,指定方法可能抛出的异常类型。

例:

execution(public * com.example.service.UserService.addUser(…)):指定 com.example.service.UserService 类中的 addUser 方法;

execution(* com.example.service..(…)):指定 com.example.service 包下的所有方法;

execution(* com.example.service….(…)):指定 com.example.service 包及其子包下的所有方法;

execution(* com.example.service.UserService.*(String)):指定 com.example.service.UserService 类中所有参数类型为 String 的方法。

此外,切入点表达式还支持 &&(逻辑与)、||(逻辑或)和 !(逻辑非)等运算符,以及 @annotation、@within、@args 等注解限定符。

注解方式

内置配置

@Aspect
@Component
public class LogAspect {
    @Around("@annotation(com.xxx.LogExecutionTime)")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object proceed = joinPoint.proceed();
        long executionTime = System.currentTimeMillis() - start;
        System.out.println(joinPoint.getSignature() + " executed in " + executionTime + "ms");
        return proceed;
    }
}

注解配置(Annotation)

1、先创建一个注解类,将注解类的包名放入Pointcut里,当调用注解时就会运行该切面

@Before("@annotation(com.easyjob.annotation.GlobalInterceptor)")

2、直接 @Pointcut("@annotation(com.xxx.LogExecutionTime)")

@Aspect
@Component
public class LogAspect {
    @Pointcut("@annotation(com.xxx.LogExecutionTime)")
    private void pointcut() {
        // 切点表达式定义方法,方法修饰符可以是private或public
    }
    @Around("pointcut()")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object proceed = joinPoint.proceed();
        long executionTime = System.currentTimeMillis() - start;
        System.out.println(joinPoint.getSignature() + " executed in " + executionTime + "ms");
        return proceed;
    }
}

公共配置

public class CommonPointcut {
    @Pointcut("@annotation(com.xxx.LogExecutionTime)")
    public void pointcut() {
        // 注意定义切点的方法的访问权限为public
    }
}
@Aspect
@Component
public class LogAspect {
    @Around("com.xxx.CommonPointcut.pointcut()")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object proceed = joinPoint.proceed();
        long executionTime = System.currentTimeMillis() - start;
        System.out.println(joinPoint.getSignature() + " executed in " + executionTime + "ms");
        return proceed;
    }
}

文章一(SpringAOP(面向切面编程))

标签:service,方法,编程,example,切面,AOP,execution,com,public
From: https://www.cnblogs.com/fengmian13wl/p/18348493

相关文章

  • Spring AOP:面向切面编程的最佳实践 ( 一 )
    1.AOP思想1.1.为什么需要面向切面编程如果在一个类或者多个类的多个业务逻辑方法中,在开始,结尾部分包含功能相同的代码称之为横切关注点也叫切面,这种结构可能符合传统的面向对象编程(OOP)的封装特性,但可能导致代码难以维护和扩展。面向切面编程是一种编程范式。它允......
  • 系统编程 days4 文件3
    前提:函数fileno(FILE*stream)作用:获得一个文件流指针的文件描述符,为了将FILE*fp型转化为intfd型函数fdopen(intfd,constchar*mode)intfd型转化为FILE*fp型文件属性目录顺序:1.打开目标目录2.读取目录3.关闭目录打开目录函数opendir获得一个目录流指针,返回值为Dir*=d......
  • 趣味Python游戏编程:第3章 递归函数的威力:扫雷
    趣味Python游戏编程:第3章递归函数的威力:扫雷在第2章中,我们制作了一个拼图游戏,玩家通过鼠标操作图片块移动。本章设计一款扫雷游戏,玩法是在一个方块阵列中随机埋设一定数量的地雷,然后由玩家逐个打开方块,并以排除所有地雷为最终游戏目标。如果玩家打开的方块中有地雷,则游戏......
  • Java的网络编程?
    Java的网络编程涉及使用Java的API来创建和管理网络应用程序,例如客户端和服务器之间的通信。Java提供了一系列的类和接口来支持网络编程,主要包括java.net包中的功能。网络编程通常包括以下几个方面:Java网络编程的基本概念协议:TCP/IP(传输控制协议/网际协议):一种面向......
  • linux 软件编程学习第八天 线程
    进程1.waitpid   pid_twaitpid(pid_tpid,int*wstatus,intoptions);  功能:    回收指定的子进程空间  参数:    pid:要回收的子进程的pid    wstatus:回收状态的指针    options:回收选项      0阻......
  • 编程小白如何成为大神?大学新生的最佳入门攻略
    编程小白如何成为大神?大学新生的最佳入门攻略编程已成为当代大学生的必备技能,但面对众多编程语言和学习资源,新生们常常感到迷茫。如何选择适合自己的编程语言?如何制定有效的学习计划?如何避免常见的学习陷阱?让我们一起探讨大学新生入门编程的最佳路径,为你的大学生活和未来职业......
  • Python并发编程
    简介多线程:threading,利用cpu和io可以同时执行的原理,让CPU不会等待IO完成多进程:multiprocess,利用多核CPU的能力,真正的并行执行任务异步IO:asynio,在单线程利用CPU和IO同时执行的原理,实现函数异步执行 使用Lock对共享资源加锁,防止冲突访问使用Queue实现不......
  • Java并发编程——线程创建的4种常见方式
    文章目录一、继承Thread类创建创建线程类1.1Thread类解析1.2使用方法1.3优缺点二、实现Runable接口创建线程类2.1Runable接口解析2.2使用方法2.3优缺点三、使用Callable和FutureTask创建线程3.1Callable接口解析3.2RunnableFuture接口解析3.3Futu......
  • 音频应用编程-I.MX6U嵌入式Linux C应用编程学习笔记基于正点原子阿尔法开发板
    音频应用编程Linux下ALSA框架概述ALSA简介:ALSA是AdvancedLinuxSoundArchitecture(高级的Linux声音体系)的缩写地位与功能:现已成为Linux下的主流音频体系架构,提供音频和MIDI支持,替代了旧版本中的OSS(开放声音系统)框架设计:ALSA是Linux系统下标准且先进的......
  • AI 大模型时代呼唤新一代基础设施,DataOps 2.0和调度编排愈发重要
    在AI时代,DataOps2.0代表了一种全新的数据管理和操作模式,通过自动化数据管道、实时数据处理和跨团队协作,DataOps2.0能够加速数据分析和决策过程。它融合了人工智能和机器学习技术,使得数据的获取、清洗和分析更加高效,推动企业在快速变化的市场中保持竞争优势。另一方面,在AI......