Spring系列篇--关于AOP【面向切面】的详解

目录

一.AOP是什么

二.案例演示 

1.前置通知1.1 先准备接口

1.2然后再准备好实现类

1.3对我们的目标对象进行JavaBean配置 

1.4 编写前置系统日志通知

1.5配置系统通知XML中的JavaBean

1.6 配置代理XML中的JavaBean

1.7 测试代码开始测试

注意这里有一个报错问题!!!

2. 后置通知2.1 先准备好后置通知的系统日志

2.2 配置后置系统通知的XML的JavaBean

 2.3 测试结果

3.环绕通知

3.2 环绕通知的系统日志

3.3 配置环绕通知的XML的JavaBean与前置通知和后置通知一致

3.4 测试结果

4.异常通知4.1 异常通知的系统日志和其他系统日志不同的是,方法名为固定的afterThrowing,不能修改

5.过滤通知5.1 直接在XML中配置JavaBean

四.总结aop是面向切面编程,普通程序由上而下正常执行,aop的程序执行是先执行到目标对象的目标方法中,如果连接点上由前置通知,则先执行前置通知再执行目标方法,最后如果目标方法有后置通知则最后执行后置通知代码,不管是前置通知,后置通知,环绕通知,异常通知,过滤通知,代码都是非业务核心代码,如日志、事务的管理(开启、提交、回滚)         


一.AOP是什么

简介:
面向切面编程(Aspect-Oriented Programming)是一种编程范式,它的主要目的是通过预编译和运行期动态代理实现程序功能的横切(cross-cutting)特性,如日志记录、性能统计、事务监控等。它可以帮助开发者将这些原本分散在各个方法或类中的业务逻辑抽象出来,提高代码复用性,降低耦合度
AOP(Aspect-Oriented Programming)是Spring框架的一个重要特性,它通过将横切关注点(cross-cutting concerns)从核心业务逻辑中分离出来,以模块化的方式在整个应用程序中重复使用。以下是关于AOP的简介及其特点:

AOP是一种编程范式,它通过将横切关注点切割出来,将其模块化,并将其应用于多个类和模块,以提高代码的重用性和可维护性。
横切关注点是指与核心业务逻辑无关但存在于多个类或模块中的非功能性需求,例如日志记录、性能监控、事务管理等。
特点:

模块化:AOP允许将横切关注点从核心业务逻辑中提取出来,形成独立的切面(Aspect),使得关注点的逻辑可以独立于各个模块。
解耦:AOP通过解耦横切关注点与核心业务逻辑,使得它们可以独立演化和变化,提高了模块之间的松耦合程度。
重用性:AOP允许将切面应用于多个类和模块,从而实现了关注点的重用,避免了代码的重复编写。
可维护性:将横切关注点抽象为切面后,使得代码结构更清晰,易于理解和维护。
动态性:AOP可以在运行时动态地将切面应用到目标对象上,而不需要修改目标对象的源代码,增强了系统的灵活性和可扩展性。
多样性:Spring框架支持不同类型的切面编程,包括基于代理的AOP和基于字节码增强的AOP。这样可以选择最适合应用程序需求的AOP实现方式。
在Spring框架中,AOP的实现采用了代理模式和动态代理技术。Spring提供了多种AOP的实现方式,包括基于XML配置的AOP、基于注解的AOP和基于纯Java配置的AOP(JavaConfig)等,开发者可以根据具体需求选择适合的方式来配置和使用AOP。
 

面向切面:
1.专业术语
①目标对象:
专业解释:被通知(被代理)的对象

通俗理解:在书店中,商品就是目标。每个商品都有自己的属性(比如价格、名称、库存等)和行为(比如计算促销价格、更新库存等)。收银员通过扫描商品的条形码来与商品进行交互,调用商品的方法来获取商品信息以及执行一些操作。商品本身即代表了目标

②连接点:
专业解释:程序执行过程中明确的点,如方法的调用,或者异常的抛出

通俗理解:在书店中,我们可以将顾客结账的行为看作一个连接点

③通知:
专业解释:在某个特定的连接点上执行的动作,同时Advice也是程序代码的具体实现,例如一个实现日志记录的代码(通知有些书上也称为处理)

通俗理解:

前置通知(Before Advice):在切入点前执行的代码,在读者购买图书之前,我们可以记录读者购买的图书信息
后置通知(After Advice):在切入点后执行的代码,在读者购买图书之后,我们可以更新图书库存
环绕通知(Around Advice):在切入点前后都执行的代码,我们可以对读者进行额外的安全检查和记录日志
异常通知(After-Throwing Advice):异常通知是在切入点发生异常时执行的额外功能代码。假设当顾客购买商品的数量大于库存数量时,就会发生异常。我们希望在顾客购买商品时检查库存,并在发生异常时执行异常通知,向顾客显示错误信息并处理异常情况
过滤通知(After-Returning Advice):过滤通知是在切入点成功执行后执行的额外功能代码。假设我们有一个特殊会员组,他们在购买商品时可以获得额外的积分。我们可以使用过滤通知来筛选出这些特殊会员,并在成功购买后给他们添加积分
④代理:
专业解释:将通知应用到目标对象后创建的对象(代理=目标+通知)

通俗理解:在书店中,收银员是一个代理角色。他们既代表顾客与商品交互,又代表书店执行一些额外的任务。当顾客带着商品到收银台时,收银员会扫描每个商品的条形码,获取商品信息并计算总价。这里,收银员即充当了顾客与商品之间的代理角色,也充当了超市执行计算总价等额外任务的代理角色

⑤切入点:
专业解释:

多个连接点的集合,定义了通知应该应用到那些连接点 (也将Pointcut理解成一个条件 ,此条件决定了容器在什么情况下将通知和目标组合成代理返回给外部程序)

通俗理解:在书店场景中,我们可能希望在计算折扣方法之前或之后记录日志和进行库存管理。这些切入点决定了我们在代码中操作的位置

⑥适配器:
专业解释:适配器是一个中间组件,用于将面向切面编程框架与原始的业务逻辑代码连接起来(适配器=通知(Advice)+切入点(Pointcut))

通俗理解:在书店场景中,适配器可以将代理对象与书店的购买图书业务逻辑连接起来,使得代理对象能够在购买图书的过程中添加额外的功能

2.代码演示
        在上面场景模拟的代码中,我们能够发现记录日志的代码基本相同,那么有没有可能将这部分的代码抽取出来进行封装,统一进行维护呢?同时也可以将日志代码和业务代码完全分离,解耦合

  那么我们便可以将业务方法中的非业务核心代码(日志记录)抽离出来形成一个横切面,并且将这个横切面封装成一个对象,将所有的记录日志的代码写到这个对象中,以实现与业务代码的分离,这便是面向切面编程的思想

2.1将记录日志的代码进行封装
 

三.案例演示 


1.前置通知
1.1 先准备接口

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

1.2然后再准备好实现类

package com.lya.aop.biz.impl;import com.YU.aop.biz.IBookBiz;
import com.YU.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);}}

1.3对我们的目标对象进行JavaBean配置 

<!--目标对象-->
    <bean class="com.lya.aop.biz.impl.BookBizImpl" id="bookBiz"></bean>

1.4 编写前置系统日志通知

package com.lya.aop.advice;import java.lang.reflect.Method;
import java.util.Arrays;import org.springframework.aop.MethodBeforeAdvice;/*** 买书、评论前加系统日志* @author YU**/
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+")被调用了");}}

1.5配置系统通知XML中的JavaBean

<!--通知-->
    <bean class="com.lya.aop.advice.MyMethodBeforeAdvice" id="myMethodBeforeAdvice"></bean>

1.6 配置代理XML中的JavaBean

<!-- 代理--><bean class="org.springframework.aop.framework.ProxyFactoryBean" id="bookProxy"><!-- 配置目标对象 --><property name="target" ref="bookBiz"></property><!-- 配置代理接口,目标对象的接口 --><property name="proxyInterfaces"><value>com.YU.aop.biz.IBookBiz</value></property><property name="interceptorNames"><list><value>myMethodBeforeAdvice</value></list></property></bean>

1.7 测试代码开始测试

package com.lya.util;import com.lya.biz.IBookBiz;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** @author 程序猿-小李哥* @site www.xiaolige.com* @company 猪八戒有限集团* @create 2023-08-17-15:34*/
public class Demo {public static void main(String[] args) {
//        今天所学:
//        1.AOP的介绍:专心做事//       2专业术语
//        1.连接点
//        2.通知:前,后,环绕
//        3.目标
//        4.代理
//        代理=目标+通知//        3配置xml初始化Spring容器IOCClassPathXmlApplicationContext context =new ClassPathXmlApplicationContext("spring.xml");//        演示一:目标对象
//        BookBizImpl bookBiz = context.getBean("bookTarget",BookBizImpl.class);
//        bookBiz.buy("晓东","欠你一夜",2000d);
//        bookBiz.comment("晓东","不看亏了,看了真爽啊!");//        演示二:前置通知
//        错误:类型强转,Object proxy1 = context.getBean("proxy");System.out.println(proxy1.getClass()+"代理的类型");
//      com.sun.proxy.$Proxy5代理的类型//      这里proxy==new bookbizimpl
//        BookBizImpl proxy = context.getBean("proxy",BookBizImpl.class);
//        proxy.buy("晓东","欠你一夜",2000d);
//        proxy.comment("晓东","不看亏了,看了真爽啊!");//        使用接口接收代理对象!!!因为代理对象实现了接口在xml中IBookBiz proxy = context.getBean("proxy",IBookBiz.class);proxy.buy("晓东","欠你一夜",2000d);proxy.comment("晓东","不看亏了,看了真爽啊!");}
}

注意这里有一个报错问题!!!

因为proxy代理已经实现了接口可以看作为一个实现类

 使用接口接收代理对象!!!因为代理对象实现了接口在xml中

测试结果:

 由测试结果可得知,不仅获取到了我们的参数,同时根据方法获取到了我们的系统日志,也就是前置通知

2. 后置通知
2.1 先准备好后置通知的系统日志

package com.zking.aop.advice;import java.lang.reflect.Method;
import java.util.Arrays;import org.springframework.aop.AfterReturningAdvice;/*** 买书返利* @author Administrator**/
public class MyAfterReturningAdvice implements AfterReturningAdvice {@Overridepublic void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {String target = arg3.getClass().getName();String methodName = arg1.getName();String args = Arrays.toString(arg2);System.out.println("【后置通知:买书返利】:"+target+"."+methodName+"("+args+")被调用了,"+"该方法被调用后的返回值为:"+arg0);}}

2.2 配置后置系统通知的XML的JavaBean

<!--后置通知-->
    <bean class="com.YU.aop.advice.MyAfterReturningAdvice" id="myAfterReturningAdvice"></bean>
并在前面已经配置好的代理接口中添加一个value值

 2.3 测试结果

 由测试结果我们可以得知,后置通知永远都在方法执行后才会显示通知,与前置通知不同的是每次前面的方法调用后都会返回一个参数

3.环绕通知


3.1 环绕通知就是前置通知和后置通知的结合,在实际应用开发中,我们一般不会单独编写前置通知和后置通知,单独使用前置通知或者后置通知时,我们会使用环绕通知,将里面前置(后置)通知的功能注释,以达到单独使用的目的

3.2 环绕通知的系统日志

package com.lya.advice;import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;import java.util.Arrays;/*** @author 程序猿-小李哥* @site www.xiaolige.com* @company 猪八戒有限集团* @create 2023-08-17-18:45** 环绕通知*/
public class AroundAdvice  implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {//获取目标对象的执行方法String methodName=invocation.getMethod().getName();//获取目标对象执行方法的参数Object[] params=invocation.getArguments();//获取目标对象Object target = invocation.getThis();System.out.println("[环绕通知] "+target.getClass().getName()+"."+methodName+","+ "执行的参数:"+ Arrays.toString(params));Object returnValue = invocation.proceed(); //放行操作System.out.println("[环绕通知] 返回参数等于:"+returnValue);return returnValue;}
}

3.3 配置环绕通知的XML的JavaBean与前置通知和后置通知一致

3.4 测试结果

由测试结果得知,环绕通知就是前置通知和后置通知的结合,优点就是不需要再多次去进行配置及编码,所以就像我们前面所说在实际开发应用中我们一般都会选择使用环绕通知

4.异常通知
4.1 异常通知的系统日志和其他系统日志不同的是,方法名为固定的afterThrowing,不能修改

package com.lya.advice;/*** @author 程序猿-小李哥* @site www.xiaolige.com* @company 猪八戒有限集团* @create 2023-08-17-18:56*/import org.springframework.aop.ThrowsAdvice;/*** 异常通知*/
public class ExceptionAdvice implements ThrowsAdvice {public void afterThrowing(PriceException e) {System.out.println("[异常通知] 价格异常,撤销订单!");}
}

价格异常

package com.lya.advice;/*** @author 程序猿-小李哥* @site www.xiaolige.com* @company 猪八戒有限集团* @create 2023-08-17-19:04** 价格异常通知*/
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);}
}

4.2 在我们正常程序出问题没有去配置异常通知时会出现报错,并且不会执行后面的后置通知,如以下情况

4.3 异常处理配置和前面的配置相同

4.4 当我们配置好异常通知模块时,程序出现异常时会上报日志进行提示

5.过滤通知
5.1 直接在XML中配置JavaBean

<!--过滤通知-->
    <bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" id="regexpMethodPointcutAdvisor">
        <property name="advice" ref="myAfterReturningAdvice"></property>
        <property name="pattern" value=".*buy"></property>
    </bean>


 

将图中指出部分替换成过滤通知

 测试结果:

对比框中内容,在调用过buy方法后进行过滤,第二次调用时不再buy方法而是comment方法 

四.总结
aop是面向切面编程,普通程序由上而下正常执行,aop的程序执行是先执行到目标对象的目标方法中,如果连接点上由前置通知,则先执行前置通知再执行目标方法,最后如果目标方法有后置通知则最后执行后置通知代码,不管是前置通知,后置通知,环绕通知,异常通知,过滤通知,代码都是非业务核心代码,如日志、事务的管理(开启、提交、回滚)         
 

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

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

相关文章

JVM虚拟机:初始化的介绍

本文重点 我们前面学习了三个步骤: 装载 连接 初始化 初始化 初始化的时候,会为静态成员变量赋值初始值,它有两种方式: ①声明类变量是指定初始值 ②使用静态代码块为类变量指定初始值 例子 最后输出的结果为3,它的过程是这样的: main方法中输出T.count,由于count是…

tkinter+爬虫+pygame实现音乐播放器

文章目录 前文安装模块示意图爬虫完整代码pygametkinter完整代码结尾前文 本文将涉及爬虫(数据的获取),pygame(音乐播放器),tkinter(界面显示),将他们汇聚到一起制造一个音乐播放器,欢迎大家的订阅。 安装模块 pip install requests,parsel,lxpy,pygame 示意图

文本图片怎么转Excel?分享一些好用的方法

在处理数据时&#xff0c;Excel 是一个非常强大的工具&#xff0c;但有时候需要将文本和图片转换为 Excel 格式&#xff0c;这可能会让人感到困惑。在本文中&#xff0c;我们将介绍一些好用的方法&#xff0c;以便您能够轻松地将文本和图片转换成 Excel 格式。 将文本图片为Exc…

部署piwigo网页 通过cpolar分享本地电脑上的图片

通过cpolar分享本地电脑上有趣的照片&#xff1a;发布piwigo网页 文章目录 通过cpolar分享本地电脑上有趣的照片&#xff1a;发布piwigo网页前言1. 设定一条内网穿透数据隧道2. 与piwigo网站绑定3. 在创建隧道界面填写关键信息4. 隧道创建完成 总结 前言 首先在本地电脑上部署…

K8S核心组件etcd详解(上)

1 介绍 https://etcd.io/docs/v3.5/ etcd是一个高可用的分布式键值存储系统&#xff0c;是CoreOS&#xff08;现在隶属于Red Hat&#xff09;公司开发的一个开源项目。它提供了一个简单的接口来存储和检索键值对数据&#xff0c;并使用Raft协议实现了分布式一致性。etcd广泛应用…

【hive】简单介绍hive的几种join

文章目录 前言1. Common Join2. Map Join介绍&#xff1a;使用方法&#xff1a;限制&#xff1a; 3. Bucket Map Join介绍&#xff1a;好处&#xff1a;使用条件&#xff1a;使用方法&#xff1a; 4. Sort Merge Bucket Map Join介绍&#xff1a;如何使用&#xff1a; 5. Skew …

如何在控制台查看excel内容

背景 最近发现打开电脑的excel很慢&#xff0c;而且使用到的场景很少&#xff0c;也因为mac自带了预览的功能。但是shigen就是闲不住&#xff0c;想自己搞一个excel预览软件&#xff0c;于是在一番技术选型之后&#xff0c;我决定使用python在控制台显示excel的内容。 具体的需…

NodeJs导出PDF

&#xff08;优于别人&#xff0c;并不高贵&#xff0c;真正的高贵应该是优于过去的自己。——海明威&#xff09; 场景 根据订单参数生成账单PDF 结果 示例代码 /* eslint-disable no-unused-vars */ /* eslint-disable no-undef */ /* eslint-disable complexity */ const…

【仿写tomcat】二、扫描java文件,获取带有@WebServlet注解的类

tomcat仿写 项目结构扫描文件servlet注解map容器servlet工具类启动类调用 项目结构 扫描文件之前当然要确定一下项目结构了&#xff0c;我这里的方案是tomcat和项目同级 项目的话就仿照我们平时使用的结构就好了&#xff0c;我们规定所有的静态资源文件都在webApp目录下存放…

Java进阶篇--数据结构

目录 一.数组&#xff08;Array&#xff09;&#xff1a; 1.1 特点&#xff1a; 1.2 基本操作&#xff1a; 1.3 使用数组的好处包括&#xff1a; 1.4 数组也有一些限制&#xff1a; 二.集合框架&#xff08;Collections Framework&#xff09;&#xff1a; 2.1 列表…

当你出差在外时,怎样轻松访问远程访问企业局域网象过河ERP系统?

文章目录 概述1.查看象过河服务端端口2.内网穿透3. 异地公网连接4. 固定公网地址4.1 保留一个固定TCP地址4.2 配置固定TCP地址 5. 使用固定地址连接 概述 ERP系统对于企业来说重要性不言而喻&#xff0c;不管是财务、生产、销售还是采购&#xff0c;都需要用到ERP系统来协助。…

miniconda克隆arcpy

arcpy环境克隆 前言尝试思考到此结束 前言 最近遇到了一些问题&#xff0c;需要用到arcpy来处理一些东西&#xff0c;但众所周知&#xff0c;arcgis的arcpy是python 2.0的&#xff0c;我不是很喜欢&#xff1b;所以我安装了arcgis pro 2.8&#xff0c;我发现这也是个坑&#x…

Git分布式版本控制系统

目录 2、安装git 2.1 初始环境 2.2 Yum安装Git 2.3 编译安装 2.4 初次运行 Git 前的配置 2.5 初始化及获取 Git 仓库 2.6 Git命令常规操作 2.6.2 添加新文件 2.6.3 删除git内的文件 2.6.4 重命名暂存区数据 2.6.5 查看历史记录 2.6.6 还原历史数据 2.6.7 还原未来…

react使用antd的table组件,实现点击弹窗显示对应列的内容

特别提醒&#xff1a;不能在table的columns的render里面设置弹窗组件渲染&#xff0c;因为这会导致弹窗显示的始终是最后一行的内容&#xff0c;因为这样渲染的结果是每一行都会重新渲染一遍这个弹窗并且会给传递一个content的值&#xff0c;渲染到最后一行的时候&#xff0c;就…

Unity的TimeScale的影响范围分析

大家好&#xff0c;我是阿赵。 这期来说一下Unity的TimeScale。 一、前言 Unity提供了Time这个类&#xff0c;来控制时间。其实我自己倒是很少使用这个Time&#xff0c;因为做网络同步的游戏&#xff0c;一般是需要同步服务器时间&#xff0c;所以我比较多是在使用System.Date…

问道管理:机器人概念走势活跃,新时达涨停,拓斯达、丰立智能等大涨

机器人概念17日盘中走势活跃&#xff0c;到发稿&#xff0c;拓斯达大涨18%&#xff0c;昊志机电涨近16%&#xff0c;丰立智能涨超13%&#xff0c;步科股份、优德精细涨超10%&#xff0c;新时达涨停&#xff0c;天玑科技、兆龙互联、中大力德涨逾9%。 消息面上&#xff0c;8月16…

解决ios隔空播放音频到macos没有声音的问题

解决ios隔空播放音频到macos没有声音的问题 一、检查隔空播放支持设备和系统要求二、打开隔空播放接收器三、重置MAC控制中心进程END 一、检查隔空播放支持设备和系统要求 Mac、iPhone、iPad 和 Apple Watch 上“连续互通”的系统要求 二、打开隔空播放接收器 ps;我设备是同一…

element+vue 表格行拖拽功能

解决方案 使用 sortable.js 步骤一&#xff1a; 安装 npm install vuedraggable步骤二&#xff1a;引入 import Sortable from sortablejs;步骤三&#xff1a; el-table 添加row-key属性&#xff0c;外层包一层 sortableDiv <div class"sortableDiv"> 拖…