【Spring(六)】使用篇:AOP在开发中的使用

news2024/12/29 10:58:39

有关Spring的所有文章都收录于我的专栏:👉Spring👈
目录
一、前言
二、演示
三、切面类中声明通知方法
四、使用


相关文章

【Spring(一)】如何获取对象(Bean)【Spring(一)】如何获取对象(Bean)
【Spring(二)】java对象属性的配置(Bean的配置)【Spring(二)】java对象属性的配置(Bean的配置)
【Spring(三)】熟练掌握Spring的使用【Spring(三)】熟练掌握Spring的使用
【Spring(四)】Spring基于注解的配置方式【Spring(四)】Spring基于注解的配置方式
【Spring(五)】引入篇:AOP的底层原理之动态代理【Spring(五)】引入篇:AOP的底层原理之动态代理

一、前言

 通过我们上一节对AOP的引入和底层原理的讲解,我相信大家对AOP有了很深的理解。即使我们还没讲AOP的使用。大家肯定不希望做一个只会API的程序员。只要对原理有了解,一个技术也就能很快的上手。

二、演示

 我们在正式开始之前,先演示一下基本使用。

<context:component-scan base-package="com.jl.spring.aop.exer"/>
<aop:aspectj-autoproxy/>
public interface Cal {
    public double cal1(int n);
    public double cal2(int n);
}
package com.jl.spring.aop.exer;

import org.springframework.stereotype.Component;

/**
 * @author long
 * @date 2022/9/11
 */
@Component
public class MyCal implements Cal{
    @Override
    public double cal1(int n) {
        int result=0;
        for (int i = 1; i <= n; i++) {
            result += i;
        }
        System.out.println("1+2+...=" + result);
        return result;
    }

    @Override
    public double cal2(int n) {
        int result = 0;
        if (n == 0){
            System.out.println("1+2+...=" + result);
            return result;
        }
        if (n == 1){
            System.out.println("1+2+...=" + 1);
            return 1;
        }
        result = 1;
        for (int i = 1; i <= n; i++) {
            result *= i;
        }
        System.out.println("1+2+...=" + result);
        return result;
    }
}
package com.jl.spring.aop.exer;

import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * @author long
 * @date 2022/9/11
 */
@Aspect
@Component
public class MyCalAspect {
    @Before(value = "execution(public double com.jl.spring.aop.exer.MyCal.*(..))")
    public void showBegin(){
        System.out.println("开始执行计算");
    }
    @AfterReturning(value = "execution(public double com.jl.spring.aop.exer.MyCal.*(..))")
    public void showEndn(){
        System.out.println("结束执行计算");
    }
}

测试类

@Test
public void MyCalAnnotation(){
    ApplicationContext ioc = new ClassPathXmlApplicationContext("mycal.xml");
    Cal bean = ioc.getBean(Cal.class);
    bean.cal1(2);
}

运行结果:
在这里插入图片描述
我们主要介绍基于注解的AOP的使用

三、切面类中声明通知方法

  1. 前置通知:@before
  2. 返回通知:@AfterReturning
  3. 异常通知:@AfterThrowing
  4. 后置通知:@After
  5. 环绕通知:@Around

这五个注解,我们在【使用】中会全部进行讲解。

四、使用

 和前面几节中使用注解一样,我们想要让Spring容器将我们的类扫描实例化到容器中,我们就得在xml配置文件中告诉Spring容器要扫描的包,同时还要开始基于注解的AOP功能。

<!--需要扫描的包-->
<context:component-scan base-package="com.jl.spring.aop.exer"/>
<!--开启基于注解的AOP功能-->
<aop:aspectj-autoproxy/>

AOP切入表达式

exexution([权限修饰符][返回值类型][简单类名/全类名][方法名][参数类名])

举例:

// public修饰符 double返回值类型 com.ji.spring.aop.exer.MyCal全类名 *所有的方法 (..)匹配任意数量、任意类型的参数 	
execution(public double com.jl.spring.aop.exer.MyCal.*(..))
  1. 切入表达式也可以指向类的方法, 这时切入表达式会对该类/对象生效。
  2. 切入表达式也可以指向接口的方法, 这时切入表达式会对实现了接口的类/对象生效。
  3. 切入表达式也可以对没有实现接口的类,进行切入。

JoinPoint

JoinPoint在调用前置通知获取到调用方法的签名, 和其它相关信息。

package com.jl.spring.aop.exer;

import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @author long
 * @date 2022/9/11
 */
@Aspect
@Component
public class MyCalAspect {
    @Before(value = "execution(public double com.jl.spring.aop.exer.MyCal.*(..))")
    public void showBegin(JoinPoint joinPoint){
        Signature signature = joinPoint.getSignature();
        System.out.println(signature.getName() +"开始执行计算");
    }
 	// 其他通知也一样
}

运行结果:
在这里插入图片描述

joinPoint常用的方法

public void beforeMethod(JoinPoint joinPoint){
    joinPoint.getSignature().getName(); // 获取目标方法名
    joinPoint.getSignature().getDeclaringType().getSimpleName(); // 获取目标方法所属
    类的简单类名
    joinPoint.getSignature().getDeclaringTypeName(); // 获取目标方法所属类的类名
    joinPoint.getSignature().getModifiers(); // 获取目标方法声明类型(public、private、protected)
    Object[] args = joinPoint.getArgs(); // 获取传入目标方法的参数,返回一个数组
    joinPoint.getTarget(); // 获取被代理的对象
    joinPoint.getThis(); // 获取代理对象自己
}

Aop返回通知获取结果

package com.jl.spring.aop.exer;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @author long
 * @date 2022/9/11
 */
@Aspect
@Component
public class MyCalAspect {
    @AfterReturning(value = "execution(public double com.jl.spring.aop.exer.MyCal.*(..))",returning = "res")
    public void showEndn(Object res){
        System.out.println("结束执行计算"+"结果是=" + res);
    }

}
  1. 在@AfterReturning直接的参数中使用returning来接收返回的结果。通过方法的参数来传递,对此结果可以进行相应的后续处理。
  2. returning底层是通过调用MyCal类的cal1()来获取到结果的。

结果截图:
在这里插入图片描述

AOP异常通知中获取异常

我们这里制造一个异常,看一下我们的异常通知。

package com.jl.spring.aop.exer;
import org.springframework.stereotype.Component;

/**
 * @author long
 * @date 2022/9/11
 */
@Component
public class MyCal implements Cal{
    @Override
    public double cal1(int n) {
        int result=0;
        for (int i = 1; i <= n; i++) {
            result = result / 0;
        }
        System.out.println("1+2+...=" + result);
        return result;
    }
}
package com.jl.spring.aop.exer;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @author long
 * @date 2022/9/11
 */
@Aspect
@Component
public class MyCalAspect {
	    @AfterThrowing(value = "execution(public double com.jl.spring.aop.exer.MyCal.*(..))",throwing = "throwable")
    public void showExceptionLog(Throwable throwable) {
        System.out.println("异常通知"+throwable);
    }
}

结果截图
在这里插入图片描述

AOP环绕通知(了解)

环绕通知可以完成其他四个通知可以做的事情。

package com.jl.spring.aop.exer;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;
@Aspect //表示是一个切面类[底层切面编程的支撑(动态代理+反射+动态绑定...)]
@Component //会注入SmartAnimalAspect2到容器
public class MyCalAspect2 {

    //演示环绕通知的使用-了解
    //1. @Around: 表示这是一个环绕通知[完成其它四个通知的功能]
    //2. value = "execution(public double com.jl.spring.aop.exer.MyCal.*(..))" 切入点表达式
    //3. doAround 表示要切入的方法 - 调用结构 try-catch-finally
    @Around(value = "execution(public double com.jl.spring.aop.exer.MyCal.*(..))")
    public Object doAround(ProceedingJoinPoint joinPoint) {
        Object result = null;
        String methodName = joinPoint.getSignature().getName();
        try {
            //1.相当于前置通知完成的事情
            Object[] args = joinPoint.getArgs();
            List<Object> argList = Arrays.asList(args);
            System.out.println("AOP环绕通知[-前置通知]" + methodName + "方法开始了--参数有:" + argList);
            //在环绕通知中一定要调用joinPoint.proceed()来执行目标方法
            result = joinPoint.proceed();
            //2.相当于返回通知完成的事情
            System.out.println("AOP环绕通知[-返回通知]" + methodName + "方法结束了--结果是:" + result);
        } catch (Throwable throwable) {
            //3.相当于异常通知完成的事情
            System.out.println("AOP环绕通知[-异常通知]" + methodName + "方法抛异常了--异常对象:" + throwable);
        } finally {
            //4.相当于最终通知完成的事情
            System.out.println("AOP环绕通知[-后置通知]" + methodName + "方法最终结束了...");
        }
        return result;
    }
}

结果截图:
在这里插入图片描述

AOP切入点表达式重用

package com.jl.spring.aop.exer;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @author long
 * @date 2022/9/11
 */
@Aspect
@Component
public class MyCalAspect {
    @Pointcut(value = "execution(public double com.jl.spring.aop.exer.MyCal.*(..))")
    public void myCut(){
        System.out.println("123");
    }

    @Before(value = "myCut()")
    public void showBegin(){
        System.out.println("开始执行计算");
    }

    @AfterReturning(value = "myCut()")
    public void showEnd(){
        System.out.println("结束执行计算");
    }


    @AfterThrowing(value = "myCut()")
    public void showExceptionLog() {
        System.out.println("异常通知");
    }

    @After(value =  "myCut()")
    public void showFinallyEndLog() {
        System.out.println("最终通知");
    }
   
}

结果截图:
在这里插入图片描述

通过切入点表达式的重用可以统一管理切入点。

切面的优先级问题

我们可以通过Order(value=值)来控制切面的优先级,值越小,优先级越高。

package com.jl.spring.aop.exer;

import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * @author long
 * @date 2022/9/11
 */
@Aspect
@Order(value = 2)
@Component
public class MyCalAspect {

    @Before(value = "execution(public double com.jl.spring.aop.exer.MyCal.*(..))")
    public void showBegin(){
        System.out.println("开始执行计算");
    }
    @AfterReturning(value = "execution(public double com.jl.spring.aop.exer.MyCal.*(..))")
    public void showEndn(){
        System.out.println("结束执行计算");
    }

    @AfterThrowing(value = "execution(public double com.jl.spring.aop.exer.MyCal.*(..))")
    public void showExceptionLog() {
        System.out.println("异常通知");
    }

    @After(value = "execution(public double com.jl.spring.aop.exer.MyCal.*(..))")
    public void showFinallyEndLog() {
        System.out.println("最终通知");
    }
}

当我们有多个切面类的时候,他的各个切面通知的顺序相当于javaWeb部分过滤器Filter过滤链的那个顺序。

基于XML配置AOP

注意:在配置之前,需要将之间用注解配的切面类注销

<!--xml方式-->    
<bean class="com.jl.spring.aop.exer.MyCalAspect" id="myCalAspect"/>
<bean class="com.jl.spring.aop.exer.MyCal" id="myCal"/>
<aop:config>
    <aop:pointcut id="myCut" expression="execution(public double com.jl.spring.aop.exer.MyCal.*(..))"/>
    <aop:aspect ref="myCalAspect">
        <aop:before method="showBegin" pointcut-ref="myCut"/>
        <aop:after-returning method="showEndn" pointcut-ref="myCut"/>
    </aop:aspect>
</aop:config>
package com.jl.spring.aop.exer;

import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * @author long
 * @date 2022/9/11
 */
public class MyCalAspect {

    public void showBegin(){
        System.out.println("开始执行计算");
    }
    public void showEndn(){
        System.out.println("结束执行计算");
    }
}

测试类

package com.jl.spring.aop.exer;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author long
 * @date 2022/9/11
 */
public class MyCalTest {
    @Test
    public void MyCalAnnotation(){
        ApplicationContext ioc = new ClassPathXmlApplicationContext("mycal.xml");
        Cal bean = ioc.getBean(Cal.class);
        bean.cal1(2);
    }
}

如果文章中有描述不准确或者错误的地方,还望指正。您可以留言📫或者私信我。🙏
最后希望大家多多 关注+点赞+收藏^_^,你们的鼓励是我不断前进的动力!!!
感谢感谢~~~🙏🙏🙏

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/43232.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

刷爆力扣之数组形式的整数加法

刷爆力扣之数组形式的整数加法 HELLO&#xff0c;各位看官大大好&#xff0c;我是阿呆 &#x1f648;&#x1f648;&#x1f648; 今天阿呆继续记录下力扣刷题过程&#xff0c;收录在专栏算法中 &#x1f61c;&#x1f61c;&#x1f61c; 该专栏按照不同类别标签进行刷题&…

Nodejs -- 一文了解Express模块

文章目录1. 初识Express1.1 Express简介1.1.1 什么是Express1.1.2 进一步理解Express1.1.3 Express能做什么1.2 Express的基本使用1.2.1 安装1.2.2 基本使用1.2.3 监听GET请求1.2.4 监听POST请求1.2.5 把内容响应给客户端1.2.6 获取URL中携带的查询参数1.2.7 获取URL中的动态参…

一文读懂TCP的三次握手(详细图解)

在学习TCP三次握手的过程前&#xff0c;首先熟悉几个缩写简称&#xff1a; TCB 传输控制块&#xff0c;打开后服务器/客户端进入监听&#xff08;LISTEN&#xff09;状态 SYNTCP报文标志位&#xff0c;该位为1时表示发起一个新连接ACKTCP报文标志位&#xff0c;该位为1时&…

傻白入门芯片设计,如何降低CPU功耗?(八)

低功耗芯片设计是本世纪以来最重要的新兴设计方法。可以说没有低功耗设计&#xff0c;就没有今天的智能手机&#xff0c;移动设备&#xff0c;物联网&#xff0c;及高性能计算等产业。随着芯片图形尺寸越来越小&#xff0c;低功耗设计在现在及未来的芯片中会起到越来越重要的作…

使用 Learner Lab - 使用 Lambda 转换图片为 base64 格式

使用 Learner Lab - 使用 Lambda 转换图片为 base64 格式 AWS Academy Learner Lab 是提供一个帐号让学生可以自行使用 AWS 的服务&#xff0c;让学生可以在 100 USD的金额下&#xff0c;自行练习所要使用的 AWS 服务&#xff0c;以下使用 使用 Lambda 转换图片为 base64 格式…

UNIAPP实战项目笔记46 订单确认页面的布局

UNIAPP实战项目笔记46 订单确认页面的布局 实际案例图片 订单页面 具体内容图片自己替换哈&#xff0c;随便找了个图片的做示例 具体位置见目录结构 完善布局页面和样式 代码 confirm-order.vue部分 confirm-order.vue 确认订单页面布局和渲染 flex 样式布局 <template>…

Uncaught TypeError: i.createPopper is not a function

“createPopper”不是我们使用引导程序时发生的函数错误 需要popper.js脚本但不在页面上加载它的组件或 在引导脚本之后加载它。要解决此错误&#xff0c;请包括引导程序 在运行 JavaScript 代码之前捆绑脚本。 这是一个工作示例&#xff0c;它加载引导捆绑包脚本来解决 错误。…

黑盒测试用例设计 - 边界值分析法

边界值的选择原则 如果输入条件规定了值的范围&#xff0c;则应取刚达到这个范围边界的值&#xff0c;以刚刚超越这个范围边界的值作为测试输入数据如果输入条件规定了值的个数&#xff0c;则用最大个数、最小个数、比最小个数少1、比最大个数多1的数作为测试数据如果程序的规…

[附源码]计算机毕业设计springboot电商小程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

[附源码]计算机毕业设计Springboot大学生志愿者服务管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

《web课程设计》期末网页制作 基于HTML+CSS+JavaScript制作公司官网页面精美

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

数据被删除怎么办?4个硬盘数据恢复工具分享

日常电脑工作中&#xff0c;都会用到硬盘。但是也很容易出现各种问题&#xff0c;比如数据误删&#xff0c;或者格式化等问题。我们怎么应对这种情况&#xff1f;有没有什么硬盘数据恢复工具&#xff1f;下面给大家分享一下关于硬盘数据恢复的工具&#xff01; ​ 工具一&#…

基于PHP+MySQL图书管理系统的设计与实现

开发本图书管理系统目的是为了实现对图书馆的图书,借阅等进行科学化的管理,便于图书信息以及借阅信息的查询和安全控制,提高设备使用效率,减少维护成本。 图书管理系统实现对图书的管理和借阅管理,利用PHP及技术来实现对图书信息的控制和管理。 图书管理系统功能结构图 通过对各…

Java并发-多线程售票案例

1. 前言 本节内容主要是使用 Java 的使用 Condition 和 Lock 机制对多线程售票案例进行实现。售票案例多数情况下主要关注多线程如何安全的减少库存&#xff0c;也就是剩余的票数&#xff0c;当票数为 0 时&#xff0c;停止减少库存。 2. 售票机制模型 如下图所示&#xff0…

简单聊聊什么是react-redux,它能解决哪些问题

或许 在大多数人眼中 redux是一个相对复查很多的知识点 但确实如果你熟悉了流程 其实也比较简单的 redux是一个数据管理方案 我们先来举个例子 目前我们知道 react中有两种组件数据通信的方式 分别是 props 父传子 定义事件 子传父 通过事件将自己的数据传给父级 那如果是兄弟…

论硬件开发过程中开发文档规范化的重要性

硬件开发的标准化是公司管理过程中的重要组成部分&#xff0c;它离不开硬件开发文档的规范化&#xff0c;很多公司并不了解开发文档的重要性&#xff0c;容易将其忽视。一个项目开发完成后&#xff0c;还有着漫长的生命周期、售后维护和更新迭代&#xff0c;总结出开发文档&…

APS排程软件与ERP、MES的集成方式

ERP通常是企业第一个引入的信息系统&#xff0c;主要处理财务、订单、物料、人力资源等企业运营的基本数据&#xff0c;但ERP不能解决生产现场的问题。而要实现制造过程的精益化&#xff0c;对生产中的每个环节全面优化和监管&#xff0c;还需要其它的信息系统帮助。 ERP&#…

内网渗透笔记

内网靶场搭建 国内的红日安全团队曾提供内网渗透实战靶场的下载&#xff08;大小共 13 G&#xff09;&#xff0c;你可以从百度网盘上下载&#xff0c;如果自己从头搭建测试环境的话&#xff0c;配置流程相当麻烦。 百度网盘&#xff1a;https://pan.baidu.com/s/1nC6V8e_EuK…

Win10 桌面图标出现空文件夹的删除及桌面图标排列问题

今天电脑开机后&#xff0c;桌面平白无故出现了两个空白的文件夹&#xff0c;也没有名字&#xff0c;如下图所示。 右键该文件夹后有以下下拉选项。 点击删除后&#xff0c;在回收站里面也没有这两个文件夹&#xff0c;在桌面鼠标右键&#xff0c;然后点击刷新后&#xff0c;…

【JavaScript高级】06-JavaScript对象知识增强

JavaScript对象的知识增强对属性操作的控制Object.defineProperty属性描述符属性描述符分类数据属性描述符&#xff08;理解&#xff09;存取属性描述符&#xff08;掌握&#xff09;对属性操作的控制 在前面我们的属性都是直接定义在对象内部&#xff0c;或者直接添加到对象内…