当前位置: 首页 > news >正文

【推荐】深入浅出学习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.过滤通知

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

 结果展示:

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

相关文章:

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

目录 1.AOP是什么? 2.案列&#xff1a; 3.spring的aop的专业术语 4.代码模拟 4.1 前置通知 3.2.后置通知 3.3.环绕通知 3.4.异常通知 3.5.过滤通知 1.AOP是什么? 面向切面编程&#xff08;Aspect-Oriented Programming&#xff09;是一种编程范式&#xff0c;它的主要…...

使用 HTML、CSS 和 JavaScript 创建多步骤表单

使用 HTML、CSS 和 JavaScript 创建多步骤表单 为了处理又长又复杂的表单&#xff0c;我们需要将它们分成多个步骤。通过一次只在屏幕上显示一些输入&#xff0c;表单会感觉更容易理解&#xff0c;并防止用户感到被大量的表单字段淹没。 在本文中&#xff0c;我将逐步指导如何…...

C语言笔试训练【第九天】

文章目录 &#x1f47f;1、下列程序的输出是&#xff08; &#xff09;&#x1f48e;2、二维数组X按行顺序存储&#xff0c;其中每个元素占1个存储单元。若 X[4][4] 的存储地址为 Oxf8b82140 , X[9][9] 的存储地址为 Oxf8b8221c ,则 X[7][7] 的存储地址为&#xff08; &#xf…...

左邻右舍裂差法求和 以及 连续自然数的立方和公式

左邻右舍裂差法求和 1 2 2 3 3 4 4 5 . . . n ( n 1 ) ? 1\times22\times33\times44\times5...n\times(n1)? 12233445...n(n1)? 看成数列 a n n 2 n , ( n ∈ N ) a_nn^2n, (n\in N^) an​n2n,(n∈N) 的前 n n n 项和 S n S_n Sn​. 原理&#xff1a;将…...

阿里云故障洞察提效 50%,全栈可观测建设有哪些技术要点?

本文根据作者在「TakinTalks 稳定性社区 」公开分享整理而成 #一分钟精华速览# 全栈可观测是一种更全面、更综合和更深入的观测能力&#xff0c;能协助全面了解和监测系统的各个层面和组件&#xff0c;它不仅仅是一个技术上的概念&#xff0c;更多地是技术与业务的结合。在“…...

docker run 命令30个常用参数详解

文章目录 0.前言docker run 命令示例 2.Docker run 多种用法知其然知其所以然1. 基本用法2. 启动交互式容器3. 映射端口4. 挂载文件/目录5. 设置环境变量6. 指定容器名称7. 后台运行容器8. 重启策略9. 其他参数 2. docker run 命令参数详解1. -d&#xff1a;以后台模式&#xf…...

[kali]kali linux镜像下载地址

百度网盘地址 链接:https://pan.baidu.com/s/1cxySSyQdLIkox-w_CSka4Q 提取码&#xff1a;cevu 官方下载合集 https://www.kali.org/downloads/&#xff08;所有版本&#xff09; 独立链接&#xff1a; 2020.3版本 64位&#xff1a;https://cdimage.kali.org/kali-2020.…...

考研408 | 【操作系统】操作系统的概述

操作系统的概念和功能 导图 操作系统的功能和目标 1.作为系统资源的管理者 2.向上层提供方便易用的服务 3.作为最接近硬件的层次 操作系统的特征 导图 并发 并发VS并行 共享 并发和共享的关系 虚拟 异步 操作系统的发展和分类 导图 1.手工操作 2.批处理阶段--单道批处理系统…...

VM部署CentOS并且设置网络

最近在准备学习k8s&#xff0c;需要部署服务器&#xff0c;所以需要在虚拟机中部署centOS服务&#xff0c;下面是在虚拟机中部署CentOs服务。 其中VM地址在下面 链接&#xff1a;https://pan.baidu.com/s/1hSKr5RfwsabdzNOvHmZ5kw?pwdkys5 提取码&#xff1a;kys5 其中Cent…...

多维时序 | MATLAB实现KOA-CNN-BiGRU-Attention多变量时间序列预测

多维时序 | MATLAB实现KOA-CNN-BiGRU-Attention多变量时间序列预测 目录 多维时序 | MATLAB实现KOA-CNN-BiGRU-Attention多变量时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 MATLAB实现KOA-CNN-BiGRU-Attention多变量时间序列预测&#xff0c;KOA-…...

深入Redis线程模型

目录 1.前言 2.Redis为什么快&#xff1f; 3.Redis 为何选择单线程&#xff1f; 3.1可维护性 3.2并发处理 3.3性能瓶颈 4.Reactor设计模式 5.Redis4.0前 单线程模型 - Event Loop 6.Redis4.0后 多线程异步任务 7.Redis6.0后 多线程网络模型 1.前言 这篇文章我们主要围绕…...

idea cannot download sources 解决方法

问题 点击class文件右上角下载源码失败 解决方案 找到idea terminal 控制台cd 至maven工程执行 mvn dependency:resolve -Dclassifiersources...

CS:GO升级 Linux不再是“法外之地”

在前天的VAC大规模封禁中&#xff0c;有不少Linux平台的作弊玩家也迎来了“迟到”的VAC封禁。   一直以来&#xff0c;Linux就是VAC封禁的法外之地。虽然大部分玩家都使用Windows平台进行游戏。但实际上&#xff0c;使用Linux畅玩CS:GO的玩家也不在少数。 以前V社主要打击W…...

手写spring笔记

手写spring笔记 《Spring 手撸专栏》笔记 IoC部分 Bean初始化和属性注入 Bean的信息封装在BeanDefinition中 /*** 用于记录Bean的相关信息*/ public class BeanDefinition {/*** Bean对象的类型*/private Class beanClass;/*** Bean对象中的属性信息*/private PropertyVal…...

shell的两种属性: 交互(interactive)与登录(login)

1. 背景 在看shell变量的时候引起了兴趣: 局部变量&#xff0c;全局变量&#xff0c;环境变量&#xff0c;shell的配置文件&#xff0c;参考博客: http://c.biancheng.net/view/773.html 2. 交互式与非交互式 参考博客: shell的两个属性:是否交互式(interactive), 是否登录…...

实现简单的element-table的拖拽效果

第一步&#xff0c;先随便创建element表格 <el-table ref"dragTable" :data"tableData" style"width: 100%" border fit highlight-current-row><el-table-column label"日期" width"180"><template slot-sc…...

Web网页浏览器远程访问jupyter notebook服务器【内网穿透】

文章目录 前言1. Python环境安装2. Jupyter 安装3. 启动Jupyter Notebook4. 远程访问4.1 安装配置cpolar内网穿透4.2 创建隧道映射本地端口 5. 固定公网地址 前言 Jupyter Notebook&#xff0c;它是一个交互式的数据科学和计算环境&#xff0c;支持多种编程语言&#xff0c;如…...

干翻Dubbo系列第十一篇:Dubbo常见协议与通信效率对比

文章目录 文章说明 一&#xff1a;协议 1&#xff1a;什么是协议 2&#xff1a;协议和序列化关系 3&#xff1a;协议组成 &#xff08;一&#xff09;&#xff1a;头信息 &#xff08;二&#xff09;&#xff1a;体信息 4&#xff1a;Dubbo3中常见的协议 5&#xff1a;…...

春秋云镜 CVE-2020-17530

春秋云镜 CVE-2020-17530 S2-061 靶标介绍 对CVE-2019-0230的绕过&#xff0c;Struts2官方对CVE-2019-0230的修复方式是加强OGNL表达式沙盒&#xff0c;而CVE-2020-17530绕过了该沙盒。当对标签属性中的原始用户输入进行评估时&#xff0c;强制 OGNL 评估可能会导致远程代码执…...

【java毕业设计】基于Spring Boot+Vue+mysql的论坛管理系统设计与实现(程序源码)-论坛管理系统

基于Spring BootVuemysql的论坛管理系统设计与实现&#xff08;程序源码毕业论文&#xff09; 大家好&#xff0c;今天给大家介绍基于Spring BootVuemysql的论坛管理系统设计与实现&#xff0c;本论文只截取部分文章重点&#xff0c;文章末尾附有本毕业设计完整源码及论文的获取…...

基于算法竞赛的c++编程(28)结构体的进阶应用

结构体的嵌套与复杂数据组织 在C中&#xff0c;结构体可以嵌套使用&#xff0c;形成更复杂的数据结构。例如&#xff0c;可以通过嵌套结构体描述多层级数据关系&#xff1a; struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

uniapp 对接腾讯云IM群组成员管理(增删改查)

UniApp 实战&#xff1a;腾讯云IM群组成员管理&#xff08;增删改查&#xff09; 一、前言 在社交类App开发中&#xff0c;群组成员管理是核心功能之一。本文将基于UniApp框架&#xff0c;结合腾讯云IM SDK&#xff0c;详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

全球首个30米分辨率湿地数据集(2000—2022)

数据简介 今天我们分享的数据是全球30米分辨率湿地数据集&#xff0c;包含8种湿地亚类&#xff0c;该数据以0.5X0.5的瓦片存储&#xff0c;我们整理了所有属于中国的瓦片名称与其对应省份&#xff0c;方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例&#xff0c;也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下&#xff1a; 定义实例工厂类&#xff08;Java代码&#xff09;&#xff0c;定义实例工厂&#xff08;xml&#xff09;&#xff0c;定义调用实例工厂&#xff…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...

3403. 从盒子中找出字典序最大的字符串 I

3403. 从盒子中找出字典序最大的字符串 I 题目链接&#xff1a;3403. 从盒子中找出字典序最大的字符串 I 代码如下&#xff1a; class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

HDFS分布式存储 zookeeper

hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架&#xff0c;允许使用简单的变成模型跨计算机对大型集群进行分布式处理&#xff08;1.海量的数据存储 2.海量数据的计算&#xff09;Hadoop核心组件 hdfs&#xff08;分布式文件存储系统&#xff09;&a…...