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

news2024/12/30 3:47:02

目录

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 {

	@Override
	public 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 {

	@Override
	public 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 {

	@Override
	public 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.coloradmin.cn/o/891865.html

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

相关文章

Python面向对象版本贪吃蛇实现

先来一波效果图吧 看看如何设计代码实现 import random import sysimport pygame# 游戏状态 ready 未开始 gameing 游戏中 end 游戏结束class Util:"""工具类&#xff1a; 提供静态方法"""staticmethoddef click_check(sprite):""&…

Java基础篇--错误处理机制

尽管人人希望自己身体健康&#xff0c;处理的事情都能顺利进行&#xff0c;但在实际生活中总会遇到各种状况&#xff0c;比如感冒发烧&#xff0c;工作时电脑蓝屏、死机等。同样&#xff0c;在程序运行的过程中&#xff0c;也会发生各种非正常状况&#xff0c;例如&#xff0c;…

Netty注解实现服务调用

在之前完成了原生服务间的简单通信&#xff0c;现在我们将它整合到Spring环境中&#xff0c;这里就以实现服务的远程调用&#xff0c;简单模拟即可&#xff0c;具体代码需要自己动手改造。 既然是服务调用&#xff0c;那我们就使用代理模式来实现。 新建代理类&#xff0c;这里…

java八股文面试[java基础]—— 重载 和 重写

Java中&#xff0c;有一个名叫方法签名的东西&#xff0c;它的定义是这样的 Definition: Two of the components of a method declaration comprise the method signature—the method’s name and the parameter types. 大概意思是&#xff0c;方法签名有两部分组成——方法…

14、缓存预热+缓存雪崩+缓存击穿+缓存穿透

缓存预热缓存雪崩缓存击穿缓存穿透 ● 缓存预热、雪崩、穿透、击穿分别是什么&#xff1f;你遇到过那几个情况&#xff1f; ● 缓存预热你是怎么做到的&#xff1f; ● 如何避免或者减少缓存雪崩&#xff1f; ● 穿透和击穿有什么区别&#xff1f;它两一个意思还是截然不同&am…

8月16日上课内容 部署LVS-DR群集

本章结构&#xff1a; 数据包流向分析: 数据包流向分析&#xff1a; &#xff08;1&#xff09;客户端发送请求到 Director Server&#xff08;负载均衡器&#xff09;&#xff0c;请求的数据报文&#xff08;源 IP 是 CIP,目标 IP 是 VIP&#xff09;到达内核空间。 &#xf…

Linux 网络发包流程

哈喽大家好&#xff0c;我是咸鱼 之前咸鱼在《Linux 网络收包流程》一文中介绍了 Linux 是如何实现网络接收数据包的 简单回顾一下&#xff1a; 数据到达网卡之后&#xff0c;网卡通过 DMA 将数据放到内存分配好的一块 ring buffer 中&#xff0c;然后触发硬中断CPU 收到硬中…

跨境外贸业务,选择动态IP还是静态IP?

在跨境业务中&#xff0c;代理IP是一个关键工具。它们提供了匿名的盾牌&#xff0c;有助于克服网络服务器针对数据提取设置的限制。无论你是需要经营管理跨境电商店铺、社交平台广告投放&#xff0c;还是独立站SEO优化&#xff0c;代理IP都可以让你的业务程度更加丝滑&#xff…

神经网络基础-神经网络补充概念-54-softmax回归

概念 Softmax回归&#xff08;Softmax Regression&#xff09;是一种用于多分类任务的机器学习算法&#xff0c;特别是在神经网络中常用于输出层来进行分类。它是Logistic回归在多分类问题上的推广。 原理 Softmax回归的主要思想是将原始的线性分数&#xff08;得分&#xf…

【学习日记】【FreeRTOS】任务调度时如何考虑任务优先级——任务的自动切换

写在前面 本文开始为 RTOS 加入考虑任务优先级的自动调度算法&#xff0c;代码大部分参考野火。 本文主要是一篇学习笔记&#xff0c;加入了笔者自己对野火代码的梳理和理解。 一、基本思路 首先我们要知道&#xff0c;在 RTOS 中&#xff0c;优先级越高、越需要被先执行的的…

小程序商品如何指定人员

一般而言&#xff0c;商家小程序中有很多商品&#xff0c;不同商品可能由不同的供应商提供。当客户购买商品时&#xff0c;如何直接将订单发给不同的供应商呢&#xff1f;下面就来具体介绍一下。 1. 设置订单分发模式。在 订单管理->待处理订单 后面点击设置按钮&#xff0…

cve-2016-7193:wwlib 模块堆数据结构溢出

简介 漏洞编号&#xff1a;cve-2016-7193漏洞类型&#xff1a;堆溢出软件名称&#xff1a;Office模块名称&#xff1a;wwlib历史漏洞&#xff1a;较多影响的版本 攻击利用&#xff1a;APT 攻击利器-Word 漏洞 CVE-2016-7193 原理揭秘 操作环境 系统&#xff1a;Win10 1607软…

编译器过程

编译器过程 如果这个框架对应LLVM,为什么这么说LLVM是个框架呢?是因为它提供了中间表示的定义,即前端输出的文本格式定义. 那么 "前端" 可以是两者其一 : Clang 或者 LLVM-GCC "通用优化" 和 "x86后端" 是 LLVM 提供的. // LLVM 也提供 riscv后…

网络机顶盒什么牌子好?自费5000+测评整理网络机顶盒排行榜

在挑选网络机顶盒的时候很多人贪便宜选山寨杂牌&#xff0c;买回家问题频发&#xff0c;我做数码测评几年来身边的朋友们总会问我网络机顶盒什么牌子好&#xff0c;我自费购入了将近二十款网络机顶盒&#xff0c;通过软硬件的全方位对比后整理了网络机顶盒排行榜TOP5&#xff1…

CentOS7配置yum清华源、阿里源

CentOS7配置yum清华源、阿里源 本文为自己安装记录回顾用 下面的是Centos7 更换yum清华源、阿里源 Centos7默认的服务器是在国外&#xff0c;连接很慢。 更换成国内的镜像源&#xff0c;使用yum清华源、阿里源&#xff0c;连接就会快一点 下面介绍更换方法 前提&#xff1a;打…

SSD202D-logo分区添加dtb

SSD202D-kernel-uimage后面加入dtb_旋风旋风的博客-CSDN博客 1.由于内核的uimage老是压缩解压缩,拿到压缩包里面dtb实在困难; 2.把dtb烧在后面又有安全隐患;而且还会有打包升级方法ota之类的很多;又毙掉了, 3.最后直接把dtb放在logo的包里,但是logo包要想添加好,也要深刻的理…

【小梦C嘎嘎——启航篇】string常用接口的模拟实现

【小梦C嘎嘎——启航篇】string常用接口的模拟实现&#x1f60e; 前言&#x1f64c;string 模拟实现1、iterator 迭代器相关使用函数实现2、构造函数接口实现3、 传统写法——拷贝构造函数接口实现4、 现代写法——拷贝构造函数接口实现5、析构函数接口实现6、传统写法—— 赋…

开源网盘空间本地挂载神器,挂载百度、阿里云盘、OneDrive等云盘到本地工具-AList

开源网盘空间本地挂载神器&#xff0c;挂载百度、阿里云盘、OneDrive等云盘到本地工具-AList 什么是Alist 一个支持多种存储&#xff0c;支持网页浏览和 WebDAV 的文件列表程序&#xff0c;由 gin 和 Solidjs 驱动。 AList 是一款免费开源支持多存储的自建网盘程序 (文件列表…

吃肉原创——使用PYQT设计的yolov8目标检测GUI界面

需要快速编写一个GUI图形界面 pip install pyqt5 pip install pyqt5-tools然后去conda环境中查找启动程序 F:\APP\miniconda\envs\yolov8gui\Lib\site-packages\qt5_applications\Qt\bin\designer.exe双击可以启动&#xff0c;我们可以把它发送到桌面快捷方式 准备设计图&am…

最通俗易懂的 - Tomcat 核心源码仿写 第二版代码

– 更新信息 – 第一版代码实现了基本的交互功能&#xff0c;但只实现了单线程&#xff0c;此次迭代修改多线程&#xff0c;并升级为Maven项目&#xff0c;同时优化代码排版&#xff0c;提高代码可读性 第一版代码介绍博客地址&#xff1a;最通俗易懂的 - Tomcat 核心源码仿写…