我的编程空间,编程开发者的网络收藏夹
学习永远不晚

SpringBoot中如何使用Aop

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

SpringBoot中如何使用Aop

这篇文章将为大家详细讲解有关SpringBoot中如何使用Aop,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

什么是aop

AOP(Aspect OrientedProgramming):面向切面编程,面向切面编程(也叫面向方面编程),是目前软件开发中的一个热点,也是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

使用场景

利用AOP可以对我们边缘业务进行隔离,降低无关业务逻辑耦合性。提高程序的可重用性,同时提高了开发的效率。一般用于日志记录,性能统计,安全控制,权限管理,事务处理,异常处理,资源池管理。使用场景

为什么需要面向切面编程

面向对象编程(OOP)的好处是显而易见的,缺点也同样明显。当需要为多个不具有继承关系的对象添加一个公共的方法的时候,例如日志记录、性能监控等,如果采用面向对象编程的方法,需要在每个对象里面都添加相同的方法,这样就产生了较大的重复工作量和大量的重复代码,不利于维护。面向切面编程(AOP)是面向对象编程的补充,简单来说就是统一处理某一“切面”的问题的编程思想。如果使用AOP的方式进行日志的记录和处理,所有的日志代码都集中于一处,不需要再每个方法里面都去添加,极大减少了重复代码。

技术要点

  • 通知(Advice)包含了需要用于多个应用对象的横切行为,完全听不懂,没关系,通俗一点说就是定义了“什么时候”和“做什么”。

  • 连接点(Join Point)是程序执行过程中能够应用通知的所有点。

  • 切点(Poincut)是定义了在“什么地方”进行切入,哪些连接点会得到通知。显然,切点一定是连接点。

  • 切面(Aspect)是通知和切点的结合。通知和切点共同定义了切面的全部内容——是什么,何时,何地完成功能。

  • 引入(Introduction)允许我们向现有的类中添加新方法或者属性。

  • 织入(Weaving)是把切面应用到目标对象并创建新的代理对象的过程,分为编译期织入、类加载期织入和运行期织入。

整合使用

导入依赖

在springboot中使用aop要导aop依赖

 <!--aop 切面-->        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-aop</artifactId>        </dependency>

注意这里版本依赖于spring-boot-start-parent父pom中的spring-boot-dependencies

编写拦截的bean

这里我们定义一个controller用于拦截所有请求的记录

@RestControllerpublic class AopController {    @RequestMapping("/hello")    public String sayHello(){        System.out.println("hello");        return "hello";    }}

定义切面

SpringBoot在使用切面的时候采用@Aspect注解对POJO进行标注,该注解表明该类不仅仅是一个POJO,还是一个切面容器

定义切点

切点是通过@Pointcut注解和切点表达式定义的。

@Pointcut注解可以在一个切面内定义可重用的切点。

由于Spring切面粒度最小是达到方法级别,而execution表达式可以用于明确指定方法返回类型,类名,方法名和参数名等与方法相关的部件,并且实际中,大部分需要使用AOP的业务场景也只需要达到方法级别即可,因而execution表达式的使用是最为广泛的。如图是execution表达式的语法:

SpringBoot中如何使用Aop

execution表示在方法执行的时候触发。以“”开头,表明方法返回值类型为任意类型。然后是全限定的类名和方法名,“”可以表示任意类和任意方法。对于方法参数列表,可以使用“..”表示参数为任意类型。如果需要多个表达式,可以使用“&&”、“||”和“!”完成与、或、非的操作。

定义通知

通知有五种类型,分别是:

  • 前置通知(@Before):在目标方法调用之前调用通知

  • 后置通知(@After):在目标方法完成之后调用通知

  • 环绕通知(@Around):在被通知的方法调用之前和调用之后执行自定义的方法

  • 返回通知(@AfterReturning):在目标方法成功执行之后调用通知

  • 异常通知(@AfterThrowing):在目标方法抛出异常之后调用通知

代码中定义了三种类型的通知,使用@Before注解标识前置通知,打印“beforeAdvice...”,使用@After注解标识后置通知,打印“AfterAdvice...”,使用@Around注解标识环绕通知,在方法执行前和执行之后分别打印“before”和“after”。这样一个切面就定义好了,代码如下:

@Aspect@Componentpublic class AopAdvice {    @Pointcut("execution (* com.shangguan.aop.controller.*.*(..))")    public void test() {    }    @Before("test()")    public void beforeAdvice() {        System.out.println("beforeAdvice...");    }    @After("test()")    public void afterAdvice() {        System.out.println("afterAdvice...");    }    @Around("test()")    public void aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {        System.out.println("before");        try {            proceedingJoinPoint.proceed();        } catch (Throwable t) {            t.printStackTrace();        }        System.out.println("after");    }}

运行结果

SpringBoot中如何使用Aop

案例场景

这里我们通过一个日志记录场景来完整的使用Aop切面业务层只需关心代码逻辑实现而不用关心请求参数和响应参数的日志记录

那么首先我们需要自定义一个全局日志记录的切面类GlobalLogAspect

然后在该类添加@Aspect注解,然后在定义一个公共的切入点(Pointcut),指向需要处理的包,然后在定义一个前置通知(添加@Before注解),后置通知(添加@AfterReturning)和环绕通知(添加@Around)方法实现即可

日志信息类

package cn.soboys.core;import lombok.Data;@Datapublic class LogSubject {        private String description;        private String username;        private String startTime;        private String spendTime;        private String url;        private String method;        private String ip;        private Object parameter;        private Object result;        private String city;        private String device;}

全局日志拦截

package cn.soboys.core;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.reflect.MethodSignature;import java.lang.reflect.Method;public class BaseAspectSupport {    public Method resolveMethod(ProceedingJoinPoint point) {        MethodSignature signature = (MethodSignature)point.getSignature();        Class<?> targetClass = point.getTarget().getClass();        Method method = getDeclaredMethod(targetClass, signature.getName(),                signature.getMethod().getParameterTypes());        if (method == null) {            throw new IllegalStateException("无法解析目标方法: " + signature.getMethod().getName());        }        return method;    }    private Method getDeclaredMethod(Class<?> clazz, String name, Class<?>... parameterTypes) {        try {            return clazz.getDeclaredMethod(name, parameterTypes);        } catch (NoSuchMethodException e) {            Class<?> superClass = clazz.getSuperclass();            if (superClass != null) {                return getDeclaredMethod(superClass, name, parameterTypes);            }        }        return null;    }}

GlobalLogAspect

package cn.soboys.core;import cn.hutool.core.date.DateUtil;import cn.hutool.core.date.TimeInterval;import cn.hutool.json.JSONUtil;import cn.soboys.core.utils.HttpContextUtil;import io.swagger.annotations.ApiOperation;import lombok.extern.slf4j.Slf4j;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.AfterThrowing;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.springframework.stereotype.Component;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestParam;import javax.servlet.http.HttpServletRequest;import java.lang.reflect.Method;import java.lang.reflect.Parameter;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;@Slf4j@Aspect@Componentpublic class GlobalLogAspect extends BaseAspectSupport {        @Pointcut("execution(public * cn.soboys.mallapi.controller.*.*(..))")    public void log() {    }        @Around("log()")    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {        LogSubject logSubject = new LogSubject();        //记录时间定时器        TimeInterval timer = DateUtil.timer(true);        //执行结果        Object result = joinPoint.proceed();        logSubject.setResult(result);        //执行消耗时间        String endTime = timer.intervalPretty();        logSubject.setSpendTime(endTime);        //执行参数        Method method = resolveMethod(joinPoint);        logSubject.setParameter(getParameter(method, joinPoint.getArgs()));        HttpServletRequest request = HttpContextUtil.getRequest();        // 接口请求时间        logSubject.setStartTime(DateUtil.now());        //请求链接        logSubject.setUrl(request.getRequestURL().toString());        //请求方法GET,POST等        logSubject.setMethod(request.getMethod());        //请求设备信息        logSubject.setDevice(HttpContextUtil.getDevice());        //请求地址        logSubject.setIp(HttpContextUtil.getIpAddr());        //接口描述        if (method.isAnnotationPresent(ApiOperation.class)) {            ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);            logSubject.setDescription(apiOperation.value());        }        String a = JSONUtil.toJsonPrettyStr(logSubject);        log.info(a);        return result;    }        private Object getParameter(Method method, Object[] args) {        List<Object> argList = new ArrayList<>();        Parameter[] parameters = method.getParameters();        Map<String, Object> map = new HashMap<>();        for (int i = 0; i < parameters.length; i++) {            //将RequestBody注解修饰的参数作为请求参数            RequestBody requestBody = parameters[i].getAnnotation(RequestBody.class);            //将RequestParam注解修饰的参数作为请求参数            RequestParam requestParam = parameters[i].getAnnotation(RequestParam.class);            String key = parameters[i].getName();            if (requestBody != null) {                argList.add(args[i]);            } else if (requestParam != null) {                map.put(key, args[i]);            } else {                map.put(key, args[i]);            }        }        if (map.size() > 0) {            argList.add(map);        }        if (argList.size() == 0) {            return null;        } else if (argList.size() == 1) {            return argList.get(0);        } else {            return argList;        }    }}

关于SpringBoot中如何使用Aop就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

SpringBoot中如何使用Aop

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

SpringBoot中如何使用Aop

这篇文章将为大家详细讲解有关SpringBoot中如何使用Aop,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。什么是aopAOP(Aspect OrientedProgramming):面向
2023-06-20

如何正确的使用SpringBoot AOP 拦截器

本篇文章给大家分享的是有关如何正确的使用SpringBoot AOP 拦截器,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。常用用于实现拦截的有:Filter、HandlerIn
2023-05-31

SpringBoot项目怎么使用aop

这篇“SpringBoot项目怎么使用aop”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“SpringBoot项目怎么使用a
2023-07-05

如何在Android中使用 AOP注解

今天就跟大家聊聊有关如何在Android中使用 AOP注解,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。一、简介在Android 里面 注解主要用来干这么几件事:和编译器一起给你一些
2023-05-31

SpringBoot项目使用aop案例详解

这篇文章主要介绍了SpringBoot项目使用aop的相关知识,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
2023-05-14

Spring AOP如何在java项目中使用

这篇文章将为大家详细讲解有关Spring AOP如何在java项目中使用 ,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。一、什么是AOP AOP(Aspect Oriented Progr
2023-05-31

springboot如何使用AOP+反射实现Excel数据的读取

这篇文章将为大家详细讲解有关springboot如何使用AOP+反射实现Excel数据的读取,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。如果我们遇到把excel表格中的数据导入到数据库,首
2023-06-29

SpringBoot中如何使用Servlet

今天小编给大家分享一下SpringBoot中如何使用Servlet的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。1.方式一(
2023-07-02

springboot中如何使用redis

这篇文章将为大家详细讲解有关springboot中如何使用redis,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。正文很多时候,我们会在springboot中配置redis,但是就那么几个配置就配好了,没
2023-05-30

SpringBoot如何使用AOP实现统计全局接口访问次数

本篇内容主要讲解“SpringBoot如何使用AOP实现统计全局接口访问次数”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“SpringBoot如何使用AOP实现统计全局接口访问次数”吧!AOP是
2023-07-02

使用Spring Aop如何配置xml

本篇文章给大家分享的是有关使用Spring Aop如何配置xml,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。AOP的配置方式有2种方式:xml配置和AspectJ注解方式。今
2023-05-31

使用SpringBoot怎么对Spring AOP进行集成

今天就跟大家聊聊有关使用SpringBoot怎么对Spring AOP进行集成,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。需要的jar包添加到工程里。新增Maven依赖如下:
2023-05-31

Logback如何在Springboot中使用

Logback如何在Springboot中使用?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。一、导入依赖普通项目 ch.qos.
2023-06-15

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录