【推荐】深入浅出学习Spring框架【中】

目录

1.AOP是什么?  

2.案列:

3.spring的aop的专业术语

 4.代码模拟

4.1 前置通知

  3.2.后置通知

  3.3.环绕通知

  3.4.异常通知

 3.5.过滤通知


1.AOP是什么?  

  • 面向切面编程(Aspect-Oriented Programming)是一种编程范式,它的主要目的是通过预编译和运行期动态代理实现程序功能的横切(cross-cutting)特性,如日志记录、性能统计、事务监控等。它可以帮助开发者将这些原本分散在各个方法或类中的业务逻辑抽象出来,提高代码复用性,降低耦合度
  • 面向切面编程的核心思想是将程序分为两个部分:切入点和切面切入点(entry point)是程序执行过程中需要被拦截的代码段,而切面(weaving)则是实现横切功能的代码段。在运行时,通过动态代理技术,将切入点的代码交由切面织入,实现横切的效果
  • 面向切面编程是希望能够将通用需求功能从不相关的类当中分离出来,能够使得很多类共享一个行为,一旦发生变化,不必修改很多类,而只是修改这个行为即可
  • AOP通过提供另一种思考程序结构的方式来补充了面向对象编程(OOP)。OOP中模块化的基本单元是类(class),而AOP中模块化的基本单元是切面(aspect)。可以这么理解,OOP是解决了纵向的代码复用问题,AOP是解决了横向的代码复用问题.

2.案列:

场景模拟:这里我模拟的场景为线上书城系统

首先进行一个没有使用Aop的模拟代码展示:

实体类:Book:其中是书籍的属性,行为等
Dao类:BookDao:其中是有关于书籍操作的代码
业务逻辑层:BookBiz:...,BookBizImpl:...
Web层:new 对象//增加
public int add(Book book) {
b.add()
}//修改
public int edit(Book book) {
b.edit()
}//删除
public int del(Book book) {
b.del()
}//上架
public int up(Book book) {
b.up()
}//下架
public int down(Book book) {
b.down()
}

但是很多时候会出现这样的情况:

①用户购买了书籍,却说自己没有收到货物...

②店家发出的货物为空货物,而其却为了牟利,矢口否认...

针对这样的情况,很多时候都没有证据来证明到底是真是假,而在我们成熟的系统中,通常都会添加一个叫做‘日志记录’的东西,它可以用来记录和跟踪系统、应用程序或事件的活动和状态的过程,通俗来说就是使用这个系统的用户的每一步操作都会被记录下来,这样就话就成为一个证据:那成熟的系统应该是怎么样?

实体类:Book:其中是书籍的属性,行为等
Dao类:BookDao:其中是有关于书籍操作的代码
业务逻辑层:BookBiz:...,BookBizImpl:...
Web层:new对象//增加
public int add(Book book) {
b.add()
}//修改
public int edit(Book book) {
b.edit()
}//删除
public int del(Book book) {
b.del()
}//上架
public int up(Book book) {
datetime=..//操作时的时间
username=...//操作的用户名
args = ...//参数
logBiz.add(datetime,username,args);//将其都添加到日志中去b.up()
}//下架
public int down(Book book) {
datetime=..//操作时的时间
username=...//操作的用户名
args = ...//参数
logBiz.add(datetime,username,args);//将其都添加到日志中去b.down()
}

现在是在上架和下架中添加了日志记录,如果要在其他的方法操作中,也添加日志记录的话,那就需要将这一段代码再重复几次,这样就有点麻烦,而且还改变了原有代码的结构,如果需求发生改变,需要对打印的日志内容作出修改,那就必须修改用到了日志记录方法中的所有相关代码,如果是1000个方法呢?每次就需要手动去修改1000个方法中的代码,对项目的维护成本就会很高这也不利于我们的系统维护。然后我们可以用到AOP可以帮助开发者将将原本分散在各个方法或类中的业务逻辑抽象出来,提高代码复用性,降低耦合度,接下怎么提高代码的复用性:

3.spring的aop的专业术语

   项目代码但是从上往下依次执行,而现在加入了面向切面的思想,当我们的代码执行到目标对象是,查看连接点是否有前置通知,先执行前置通知,再执行目标方法,如果没有前置通知,那么就直接执行目标方法,最后看连接点上是否有后置通知,如果有,就再执行后置通知,如果没有就执行完了。

  •  连接点(Joinpoint):程序执行过程中明确的点,如方法的调用,或者异常的抛出.
  •  目标(Target):被通知(被代理)的对象,就是完成具体的业务逻辑 ,比如书籍的增删改查
  •  通知(Advice):在某个特定的连接点上执行的动作,同时Advice也是程序代码的具体实现,例如一个实现日志记录的代码(通知有些书上也称为处理)  ,完成切面编程,非业务核心代码
  •  代理(Proxy):将通知应用到目标对象后创建的对象(代理=目标+通知),  例子:外科医生+护士只有代理对象才有AOP功能,而AOP的代码是写在通知的方法里面的
  • 切入点(Pointcut):多个连接点的集合,定义了通知应该应用到那些连接点 , (也将Pointcut理解成一个条件 ,此条件决定了容器在什么情况下将通知和目标组合成代理返回给外部程序),比如给新增方法添加日志功能
  •  适配器(Advisor):适配器=通知(Advice)+切入点(Pointcut)

     注:目标对象只负责业务逻辑代码

              通知对象负责AOP代码,这二个对象都没有AOP的功能,只有代理对象才有。

 4.代码模拟

4.1 前置通知

        首先,我们先写service接口和实现类进行模拟,在里面写两个方法

package com.sy.aop.biz;public interface IBookBiz {// 购书public boolean buy(String userName, String bookName, Double price);// 发表书评public void comment(String userName, String comments);
}

     然后,写实现类,重新这两个方法,并且做了一个价格的判断

package com.sy.aop.biz.impl;import com.sy.aop.biz.IBookBiz;
import com.sy.aop.exception.PriceException;public class BookBizImpl implements IBookBiz {public BookBizImpl() {super();}public boolean buy(String userName, String bookName, Double price) {// 通过控制台的输出方式模拟购书if (null == price || price <= 0) {throw new PriceException("book price exception");}System.out.println(userName + " buy " + bookName + ", spend " + price);return true;}public void comment(String userName, String comments) {// 通过控制台的输出方式模拟发表书评System.out.println(userName + " say:" + comments);}}

 接下来要写上面价格判断的异常 

package com.sy.aop.exception;public class PriceException extends RuntimeException {public PriceException() {super();}public PriceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {super(message, cause, enableSuppression, writableStackTrace);}public PriceException(String message, Throwable cause) {super(message, cause);}public PriceException(String message) {super(message);}public PriceException(Throwable cause) {super(cause);}}

然后,我们先创建一个类,将类名.方法名,携带的参数,作为日志存储到数据库。

package com.sy.aop.advice;import org.springframework.aop.MethodBeforeAdvice;import java.lang.reflect.Method;
import java.util.Arrays;/*** 买书、评论前加系统日志* @author shenyan**/
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {@Overridepublic void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
//		在这里,可以获取到目标类的全路径及方法及方法参数,然后就可以将他们写到日志表里去String target = arg2.getClass().getName();String methodName = arg0.getName();String args = Arrays.toString(arg1);System.out.println("【前置通知:系统日志】:"+target+"."+methodName+"("+args+")被调用了");}}

 最后,进行一个配置

!--aop-->
<!-- 目标对象 -->
<bean class="com.sy.aop.biz.impl.BookBizImpl" id="bookBiz"></bean><!-- 通知 -->
<bean class="com.sy.aop.advice.MyMethodBeforeAdvice" id="methodBeforeAdvice"></bean><!-- 代理=目标+通知 --><bean class="org.springframework.aop.framework.ProxyFactoryBean" id="bookProxy"><property name="target" ref="bookBiz"></property><property name="proxyInterfaces"><list><value>com.sy.aop.biz.IBookBiz</value></list></property><property name="interceptorNames"><list><value>myMethodBeforeAdvice</value></list></property></bean>

前台的一个验证:

package com.sy.aop.demo;import com.sy.aop.biz.IBookBiz;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** @author 谌艳* @site www.shenyan.com* @create 2023-08-17 21:13*/
public class demo1 {public static void main (String [] args){ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("spring-context.xml");IBookBiz bookBiz=(IBookBiz) context.getBean("bookBiz");bookBiz.buy("花花","天下掉下一个林妹妹",18.88);bookBiz.comment("嘿嘿","嘿嘿嘿真好看");}
}

结果为展示:

  3.2.后置通知

        有了前面的铺垫,直接再创建一个后置通知的类,比起前置通知,多了一个参数,就是返回参数

package com.sy.aop.advice;import org.springframework.aop.MethodBeforeAdvice;import java.lang.reflect.Method;
import java.util.Arrays;/*** 买书、评论前加系统日志* @author shenyan**/
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {@Overridepublic void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
//		在这里,可以获取到目标类的全路径及方法及方法参数,然后就可以将他们写到日志表里去String target = arg2.getClass().getName();String methodName = arg0.getName();String args = Arrays.toString(arg1);System.out.println("【前置通知:系统日志】:"+target+"."+methodName+"("+args+")被调用了");}}
接着,配置文件即可

 然后前台看结果;

package com.sy.aop.demo;import com.sy.aop.biz.IBookBiz;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** @author 谌艳* @site www.shenyan.com* @create 2023-08-17 21:13*/
public class demo1 {public static void main (String [] args){ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("/spring-context.xml");
//        IBookBiz bookBiz=(IBookBiz) context.getBean("bookBiz");IBookBiz bookBiz=(IBookBiz) context.getBean("bookProxy");bookBiz.buy("花花","天下掉下一个林妹妹",18.88);bookBiz.comment("嘿嘿","嘿嘿嘿真好看");}
}

  3.3.环绕通知

        结合了前置通知和后置通知,它两个都有所以一般常用这个,

        它只有一个参数,但是这一个参数相当于上面前置通知和后置通知的3,4个参数

package com.sy.aop.advice;import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;import java.util.Arrays;/*** 环绕通知* 	包含了前置和后置通知* * @author shenyan**/
public class MyMethodInterceptor implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation arg0) throws Throwable {String target = arg0.getThis().getClass().getName();String methodName = arg0.getMethod().getName();String args = Arrays.toString(arg0.getArguments());System.out.println("【环绕通知调用前:】:"+target+"."+methodName+"("+args+")被调用了");
//		arg0.proceed()就是目标对象的方法Object proceed = arg0.proceed();System.out.println("【环绕通知调用后:】:该方法被调用后的返回值为:"+proceed);return proceed;}}

  接着就是配置文件

 然后前台测试:

 结果展示:

  3.4.异常通知

        先建一个类,但是注意,这个异常通知的类,重写的话,方法名字只能是这个,否则报错

然后配置文件:

 然后在前台测试:

结果展示:

 3.5.过滤通知

        过滤通知就是那个适配器,它不需要再建一个类,直接再配置文件里面配置就可以了,需要正则判断,这里举例过滤的是后置通知

 结果展示:

  今天小编的分享就结束呐,生活总是需要不断去学习新的知识,多想想然后再去实操,持之以恒,经验和思维都会发生转变,我们要保持谦虚学习和自信的态度,各位加油!

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

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

相关文章

第十四届中国大学生服务外包大赛细品,上百支队伍与合合信息用AI共克“记账”难题

前言 熟悉我的小伙伴应该知道我在大学时期参与了很多竞赛&#xff0c;我向来对比赛是比较热枕的&#xff0c;以我个人观点&#xff0c;我认为可以通过竞赛激发学习激情和检验自己的技能水平掌握情况&#xff0c;大学生很少有机会能够了解到课堂之外市场的需求&#xff0c;外包…

P1123 取数游戏

取数游戏 题目描述 一个 N M N\times M NM 的由非负整数构成的数字矩阵&#xff0c;你需要在其中取出若干个数字&#xff0c;使得取出的任意两个数字不相邻&#xff08;若一个数字在另外一个数字相邻 8 8 8 个格子中的一个即认为这两个数字相邻&#xff09;&#xff0c;求…

EXCEL按列查找,最终返回该列所需查询序列所对应的值,VLOOKUP函数

EXCEL按列查找&#xff0c;最终返回该列所需查询序列所对应的值 示例&#xff1a;国标行业分类汉字&#xff0c;匹配id 使用VLOOKUP函数 第一参数&#xff1a;拿去查询的值。 第二参数&#xff1a;匹配的数据。 Ps&#xff1a;Sheet1!$C 21 : 21: 21:E 117 &#xff0c;需要…

Redis系列(三):深入解读Redis主从同步机制

首发博客地址 https://blog.zysicyj.top/ Redis高可靠靠什么保证&#xff1f; 为什么要提这个呢&#xff0c;因为Redis主从库目的呢其实就是为了实现高可靠。上篇文章中我们说过Redis的AOF、RDB日志其实就是为了减少数据丢失&#xff0c;这是高可靠的一部分。 这篇文章呢&#…

Lua 位和字节

一、位运算 从 Lua 5.3 版本开始&#xff0c;提供了针对数值类型的一组标准位运算符&#xff0c;与算数运算符不同的是&#xff0c;运算符只能用于整型数。 运算符描述&按位与|按位或&#xff5e;按位异或>>逻辑右移<<逻辑左移&#xff5e;&#xff08;一元运…

Git 如何使用TortoiseGit 操作本地仓库

初始化仓库 方法一: 新建一个文件夹,进入文件夹内部操作 1、右键--> 在这里创建Git 版本库 注意: 不要直接在桌面上操作,否则桌面就是一个仓库 方法二: 1、右键-->Git GUI here 方法三: 命令行模式 1、 git init 创建完毕仓库,我们发现,此时我们创建的文件夹下…

leetcode做题笔记83删除排序链表中的重复元素

给定一个已排序的链表的头 head &#xff0c; 删除所有重复的元素&#xff0c;使每个元素只出现一次 。返回 已排序的链表 。 输入&#xff1a;head [1,1,2] 输出&#xff1a;[1,2] 思路一&#xff1a;模拟题意 struct ListNode* deleteDuplicates(struct ListNode* head){i…

FreeRTOS qemu mps2-an385 bsp 移植制作 :系统运行篇

相关文章 FreeRTOS qemu mps2-an385 bsp 移植制作 &#xff1a;环境搭建篇 FreeRTOS qemu mps2-an385 bsp 移植制作 &#xff1a;系统启动篇 开发环境 Win10 64位 VS Code&#xff0c;ssh 远程连接 ubuntu VMware Workstation Pro 16 Ubuntu 20.04 FreeRTOSv202212.01&a…

React 全栈体系(二)

第二章 React面向组件编程 一、基本理解和使用 1. 使用React开发者工具调试 2. 效果 2.1 函数式组件 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>1_函数式组件</title> </head> &l…

计算机竞赛 python 爬虫与协同过滤的新闻推荐系统

1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; python 爬虫与协同过滤的新闻推荐系统 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;4分 该项目较为新颖&…

软件压力测试对软件产品起到什么作用?

一、软件压力测试是什么? 软件压力测试是一种通过模拟正常使用环境中可能出现的大量用户和大数据量的情况&#xff0c;来评估软件系统在压力下的稳定性和性能表现的测试方法。在软件开发过程中&#xff0c;经常会遇到一些性能瓶颈和稳定性问题&#xff0c;而软件压力测试的作…

C语言刷题指南(一)

&#x1f4d9;作者简介&#xff1a; 清水加冰&#xff0c;目前大二在读&#xff0c;正在学习C/C、Python、操作系统、数据库等。 &#x1f4d8;相关专栏&#xff1a;C语言初阶、C语言进阶、数据结构刷题训练营、有感兴趣的可以看一看。 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &am…

认识excel篇3之数据的有效性(数据验证)

数据有效性不仅能够对单元格的输入数据进行条件限制&#xff0c;还可以在单元格中创建下拉列表菜单方便用户选择输入。如果没有做数据验证&#xff0c;单元格内默认可以输入任意类型的数据。数据验证就是限制单元格输入数据&#xff08;必须输入符合要求的才能输入&#xff09;…

VS2022如何查看类成员都在哪里被调用了(VS如何打开Call Hierarchy视图)

文章目录 打开Call Hierarchy视图查看成员的调用 打开Call Hierarchy视图 单击菜单栏的“视图” > “调用层次结构”&#xff0c;即可打卡Call Hierarchy视图。 查看成员的调用 在代码编辑窗口&#xff0c;右键单击想要查看的类成员&#xff0c;然后选择“查看调用层次结…

机器学习算法之-逻辑回归(2)

为什么需要逻辑回归 拟合效果太好 特征与标签之间的线性关系极强的数据&#xff0c;比如金融领域中的 信用卡欺诈&#xff0c;评分卡制作&#xff0c;电商中的营销预测等等相关的数据&#xff0c;都是逻辑回归的强项。虽然现在有了梯度提升树GDBT&#xff0c;比逻辑回归效果更…

一、数学建模之线性规划篇

1.定义 2.例题 3.使用软件及解题 一、定义 1.线性规划&#xff08;Linear Programming&#xff0c;简称LP&#xff09;是一种数学优化技术&#xff0c;线性规划作为运筹学的一个重要分支&#xff0c;专门研究在给定一组线性约束条件下&#xff0c;如何找到一个最优的决策&…

JavaScript请求数据的4种方法总结(Ajax、fetch、jQuery、axios)

JavaScript请求数据有4种主流方式&#xff0c;分别是Ajax、fetch、jQuery和axios。 一、Ajax、fetch、jQuery和axios的详细解释&#xff1a; 1、 Ajax Ajax&#xff08;Asynchronous JavaScript and XML&#xff09;是一种使用JavaScript在用户的浏览器上发送请求的技术&…

使用低版本vcpkg时,bootstrap-vcpkg.bat无法生成vcpkg.exe的可能原因

缘由 需要使用vcpkg中低版本的第三方库&#xff0c;下载vcpkg后&#xff0c;回退至指定版本&#xff0c;运行bootstrap-vcpkg.bat生成vcpkg.exe时&#xff0c;命令行窗口总是一闪而过&#xff0c;但是vcpkg.exe却没有生成。 添加pause&#xff0c;查看错误 编辑bootstrap-vc…

docker的网络模式

docker0网络 docker容器的 虚拟网关loopback &#xff1a;回环网卡、TCP/IP网卡是否生效virtual bridge&#xff1a;linux 自身继承了一个虚拟化功能&#xff08;kvm架构&#xff09;&#xff0c;是原生架构的一个虚拟化平台&#xff0c;安装了一个虚拟化平台之后就会系统就会自…

区间预测 | MATLAB实现QRBiLSTM双向长短期记忆神经网络分位数回归时间序列区间预测

区间预测 | MATLAB实现QRBiLSTM双向长短期记忆神经网络分位数回归时间序列区间预测 目录 区间预测 | MATLAB实现QRBiLSTM双向长短期记忆神经网络分位数回归时间序列区间预测效果一览基本介绍模型描述程序设计参考资料 效果一览 基本介绍 区间预测 | MATLAB实现QRBiLSTM双向长短…