首页 > 其他分享 >浅析SpringBoot中的AOP以及自定义注解类

浅析SpringBoot中的AOP以及自定义注解类

时间:2024-05-28 18:04:07浏览次数:16  
标签:自定义 .. joinPoint System 浅析 切面 AOP public SpringBoot

概念说明

Spring Boot中的AOP(面向切面编程)是一种编程范式,它允许开发者定义跨多个对象的横切关注点。横切关注点是与业务逻辑无关的功能,如日志记录、安全检查、事务管理等。AOP的主要目的是将横切关注点与业务逻辑分离,提高代码的模块化和可维护性。
AOP的核心概念包括:

  1. 切面(Aspect):横切关注点的模块化。切面通常表示为一个Java类,用于封装横切关注点的代码。
  2. 连接点(Joinpoint):程序执行过程中的某个特定点,如方法的执行或异常的抛出。在Spring AOP中,连接点总是方法的执行。
  3. 通知(Advice):切面在特定连接点上执行的动作。Spring AOP支持五种类型的通知:
    • 前置通知(Before):在连接点之前执行。
    • 后置通知(After):在连接点之后执行。
    • 返回通知(After Returning):在连接点正常完成后执行。
    • 异常通知(After Throwing):如果连接点抛出异常,则执行。
    • 环绕通知(Around):包围一个连接点的通知,可以在方法执行前后执行自定义行为。
  4. 切点(Pointcut):用于匹配连接点的断言。切点用于确定哪些连接点应该被通知所拦截。
  5. 引入(Introduction):允许声明额外的方法或字段。
  6. 目标对象(Target Object):被一个或多个切面所通知的对象。
  7. AOP代理(AOP Proxy):框架创建的对象,用于实现切面的契约。
  8. 织入(Weaving):将切面与其他应用程序类型或对象链接在一起的过程。在Spring AOP中,织入通常在运行时通过代理对象完成。

AOP在代码中的应用

以下几个例子是AOP在实际代码中的应用,通过它们可以更好的理解AOP:

  1. 日志切面:用于记录方法的进入和退出,以及方法的执行时间。
    @Aspect
    @Component
    public class LoggingAspect {
        @Before("execution(* com.example..*(..))")
        public void logBefore(JoinPoint joinPoint) {
            System.out.println("进入方法: " + joinPoint.getSignature().getName());
        }
        @AfterReturning(pointcut = "execution(* com.example..*(..))", returning = "result")
        public void logAfterReturning(JoinPoint joinPoint, Object result) {
            System.out.println("退出方法: " + joinPoint.getSignature().getName() + ",结果: " + result);
        }
        @AfterThrowing(pointcut = "execution(* com.example..*(..))", throwing = "e")
        public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
            System.out.println("方法: " + joinPoint.getSignature().getName() + " 发生异常: " + e);
        }
    }
    
  2. 性能监控切面:用于测量方法执行的时间。
    @Aspect
    @Component
    public class PerformanceAspect {
        @Around("execution(* com.example..*(..))")
        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() + " 执行耗时 " + executionTime + "ms");
            return proceed;
        }
    }
    
  3. 安全检查切面:用于在方法执行前检查用户权限。
    @Aspect
    @Component
    public class SecurityAspect {
        @Before("execution(* com.example..*(..))")
        public void checkSecurity(JoinPoint joinPoint) {
            // 模拟安全检查逻辑
            System.out.println("对方法: " + joinPoint.getSignature().getName() + " 进行安全检查");
            // 如果没有权限,可以抛出异常或返回特定结果
        }
    }
    
  4. 事务管理切面:用于管理数据库事务。
    @Aspect
    @Component
    public class TransactionAspect {
        @Before("execution(* com.example.service..*(..))")
        public void startTransaction() {
            // 开始数据库事务
            System.out.println("开始事务");
        }
        @AfterReturning("execution(* com.example.service..*(..))")
        public void commitTransaction() {
            // 提交数据库事务
            System.out.println("提交事务");
        }
        @AfterThrowing("execution(* com.example.service..*(..))")
        public void rollbackTransaction() {
            // 回滚数据库事务
            System.out.println("回滚事务");
        }
    }
    
  5. 缓存切面:用于缓存方法的返回结果,以减少数据库查询次数。
    @Aspect
    @Component
    public class CachingAspect {
        private Map<String, Object> cache = new HashMap<>();
        @Around("execution(* com.example.service..*(..))")
        public Object cacheResult(ProceedingJoinPoint joinPoint) throws Throwable {
            String methodName = joinPoint.getSignature().toShortString();
            List<Object> params = Arrays.asList(joinPoint.getArgs());
            String cacheKey = methodName + "_" + params.hashCode();
            if (cache.containsKey(cacheKey)) {
                System.out.println("返回缓存结果: " + cacheKey);
                return cache.get(cacheKey);
            }
            Object result = joinPoint.proceed();
            cache.put(cacheKey, result);
            return result;
        }
    }
    

在这些示例中,@Aspect注解表示该类是一个切面,@Component注解将切面注册为 Spring 容器的一个 Bean,使其能够被自动发现并织入到应用程序中。切点(Pointcut)用于定义通知(Advice)应该应用到哪些连接点(Joinpoint,通常是方法执行)。通过使用不同的通知类型(如@Before、@AfterReturning、@Around等),可以控制横切关注点在方法执行的哪个阶段被织入。

结合自定义注解使用AOP

下面我们自定义一个注释@LogExecutionTime,添加该注释的方法会在执行结束时在日志中输出该方法的执行时间:

步骤 1: 定义注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD) // 注解应用的地方(方法)
@Retention(RetentionPolicy.RUNTIME) // 注解的生命周期(运行时)
public @interface LogExecutionTime {
    // 可以定义一些属性,例如是否启用日志
    boolean enabled() default true;
}

步骤 2: 创建切面

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LogExecutionTimeAspect {
    private static final Logger logger = LoggerFactory.getLogger(LogExecutionTimeAspect.class);
    @Pointcut("@annotation(logExecutionTime)")
    public void logExecutionTimePointcut(LogExecutionTime logExecutionTime) {
        // 定义切点
    }
    @AfterReturning(pointcut = "logExecutionTimePointcut(logExecutionTime)", returning = "result")
    public void logExecutionTime(JoinPoint joinPoint, LogExecutionTime logExecutionTime, Object result) {
        // 检查是否启用了日志
        if (logExecutionTime.enabled()) {
            long startTime = System.currentTimeMillis();
            // 方法执行结束,计算执行时间
            long endTime = System.currentTimeMillis();
            long executionTime = endTime - startTime;
            // 输出日志
            logger.info(joinPoint.getSignature() + " executed in " + executionTime + "ms");
        }
    }
}

步骤 3: 应用注解

在你的服务或控制器方法上使用@LogExecutionTime注解:

import org.springframework.stereotype.Service;
@Service
public class MyService {
    @LogExecutionTime(enabled = true)
    public void methodToLog() {
        // 需要记录执行时间的方法逻辑
    }
}

在这个例子中,@LogExecutionTime注解被用于标记methodToLog方法,表示这个方法的执行时间会被记录到日志中。LogExecutionTimeAspect切面会拦截使用了@LogExecutionTime注解的方法,并在方法执行结束后记录执行时间。如果enabled属性为true,则会输出日志。

标签:自定义,..,joinPoint,System,浅析,切面,AOP,public,SpringBoot
From: https://blog.csdn.net/qq_39354140/article/details/139272813

相关文章

  • 自定义一个简单的日历
    前言  此博客提供一个个人实现的自定义View,日历的内容全部是通过绘制实现的。 虽然是使用flutter实现自定义日历View的,但是关键核心思想是一致的,这边放到博客中提供给各位参考。后续有时间会继续提供Android版本的自定义日历.效果图代码最关键的是绘制日历内容的4个函数......
  • SpringBoot升级到3.2.0报错Invalid value type for attribute ‘factoryBeanObjectTyp
    1现象SpringBoot由3.1.0升级为3.2.0时报的错:直接debug进入该行,看到报错的bean信息:看到是MyBatis出问题。2处理MyBatis先想到mybatis-spring版本较低导致。大家应该都用的MyBatisPlus,其实可暂缓升级3.2,等待一段时间,升级MyBatisPlus即可,目前MyBatisPlus的mybatis-spring......
  • springboot+vue提高工作效率的市场摊位管理系统
    开发一个提高工作效率的市场管理系统,要解决的是,如何实现在界面不刷新的情况下获取后台返回的数据并显示在页面上,并做到不同权限的后台管理人员,登陆后界面显示其权限仅能操作的功能。通过自动化、数字化和智能化的管理流程,可以提高管理效率和市场服务质量,增强市场竞争力和可持续......
  • vue+java基于SpringBoot的私募基金投资管理系统的毕业设计
    当前,项目管理已然成为企业顺利高速发展的重要竞争手段,随着项目数量的增多,业务的复杂性、精确性要求提高,项目管理至关重要,对于私募基金管理项目这样风险性极高、业务复杂度极高的项目来说,更是需要进行规范化的项目管理以保证安全性、提高效率。功能1.   项目池管理模块项......
  • 微服务-Nacos-安装-集成SpringBoot
    微服务-SpringCloud-ALibaba-NacosNacos是阿里巴巴推出的SpringCloud的组件官网:什么是Nacos主要是为了解决微服务的架构中服务治理的问题服务治理就是进行服务的自动化管理,其核心是服务的注册与发现。服务注册:服务实例将自身服务信息注册到注册中心。服务发现:服务实......
  • CSS 之 自定义属性(变量)
    一、简介​CSS的自定义属性,又称为CSS变量或级联变量,用于定义一个带有值的、可重复使用的CSS属性(变量)。其包含的值可以在其作用域内的任意属性上重复使用,在使用时需要借助var()函数获取自定义属性的值。当自定义属性的值发生变化时,所有使用该自定义属性的CSS属性都会随之变......
  • Springboot计算机毕业设计学生考勤管理微信小程序【附源码】开题+论文+mysql+程序+部
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展,高校教学管理日益向数字化、智能化方向转变。传统的考勤管理方式不仅效率低下,而且容易出现误差,已无法满足现代高校管理的需求......
  • SpringBoot修改内置的Tomcat版本
    springboot内置tomcat各版本漏洞及修复情况参考链接:https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-core打开项目,找到pom.xml文件找到对应节点,按以下步骤修改:1、pom添加tomcat版本信息   <properties>       <java.version>1.8</java.ver......
  • 基于SpringBoot+Vue+uniapp的互助学习的详细设计和实现(源码+lw+部署文档+讲解等)
    文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言......
  • 基于SpringBoot+Vue+uniapp的考研论坛的详细设计和实现(源码+lw+部署文档+讲解等)
    文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言......