【Java框架】Spring框架(二)——Spring基本核心(AOP)

目录

  • 面向切面编程AOP
    • AOP的目标:让我们可以“专心做事”
      • 专心做事
      • 专心做事解决方案1.0
      • 专心做事解决方案2.0
        • 蓝图
    • AOP应用场景
    • AOP原理
    • AOP相关术语
      • 术语理解
  • AOP案例实现
    • 前置/后置/异常/最终增强的配置实现
      • 1.依赖
      • 2.业务类
      • 3.日志类
      • 4.配置
        • 切入点表达式匹配规则举例
    • 环绕增强的配置实现(1替4)
      • 1.service类不变
      • 2.日志类
      • 3.配置
    • Spring AOP配置元素
    • 注解实现AOP
      • 1.service类不变
      • 2.日志类
      • 3.配置

面向切面编程AOP

AOP的目标:让我们可以“专心做事”

专心做事

  • 我们作为开发系统可以分为两大部分:业务功能和辅助业务的隐性功能。
  • 例如开发一个商城系统,商品模块的商品添加业务就是业务功能;
  • 而保证商品添加不出问题,如程序在执行商品添加时的入参/出参记录、事务处理等就属于辅助业务的隐性功能
  • 通常这些隐性的辅助功能一来都比较通用,二来跟业务平没有什么联系。
  • 因此就需要考虑将这些通用功能集中处理,来简化编码、专心做事。

专心做事解决方案1.0

解决方案:把公共代码抽取到一个父类的BaseService,让具体的模块Service继承BaseService,然后调用父类的功能,这样做即:通过继承的方式实现对业务方法的功能的增强。如:
通用功能类

public class BaseService {    // 新增事务public void transaction(){System.out.println("事务功能");}   // 入参日志public void before(){System.out.println("记录入参日志功能");}// 出参日志public void afterReturnLog(){System.out.println("记录出参日志功能");}// 资源最终关闭public void afterLog(){System.out.println("资源close功能...");}
}

业务类

public class UserServiceImpl extends BaseService{public void save(User user){super.before();super.transaction();// 调用Dao新增用户super.afterReturnLog();super.after();}
}
public class GoodsServiceImpl extends BaseService{public void save(Goods goods){super.before();super.transaction();// 调用Dao新增商品super.afterReturnLog();super.after();}
}

但是这样做还有一个问题,虽然我们其他模块也需要此功能时,可以采用继承的方式来做,但是一个很严重的问题是:我们的业务功能在去调用的时候,对业务功能的增强实际上还是硬编码了。还是没有解决方便维护的问题,那我们期望能够解决的问题是:能否“神不知鬼不觉”的在不改变源代码的情况下去扩展功能呢? 答案肯定是可以的,那这就是AOP,同时,这个也是我们学习AOP的原因所在,也是AOP的作用所在。

专心做事解决方案2.0

蓝图

在这里插入图片描述
如果从系统的横向角度来看,我们的日志功能,事务功能、资源关闭功能是把系统的各个模块中的各个业务方法在执行之前从前面拦截了,好像拿了一把刀把一个完整的苹果切成一半,形成了一个切面。这个也就是 "面向切面编程 中切面的含义

AOP应用场景

日志记录、性能统计、安全控制、事务处理、异常处理

AOP原理

  • 将复杂的需求分解出不同方面,将散布在系统中的公共功能集中解决
  • 采用代理机制组装起来运行,在不改变原程序的基础上对代码段进行增强处理,增加新的功能
  • 核心:动态代理
    在这里插入图片描述

AOP相关术语

  • 增强处理/通知(Advice)
    所谓通知/增强是指拦截到 Joinpoint 之后所要做的事情就是通知。说白了,就是一段功能性的代码。
    • 前置增强
    • 后置增强
    • 环绕增强、异常抛出增强、最终增强等类型
  • 切入点(Pointcut):
    切入点就是对连接点中哪些点进行拦截的定义,对连接点(一般所有方法都可做连接点)进行条件筛选。
  • 连接点(Join Point):
    连接点就是可以被拦截的点,在程序中,通常指的是方法,在Spring中只支持方法类型的连接点。在其他的地方可能支持类,这里记住方法就行了。
  • 切面(Aspect):
    是切入点和通知/增强的结合。
  • 目标对象(Target object)
  • AOP代理(AOP proxy)
  • 织入(Weaving):
    指的是在把增强的方法加入到目标对象(切点方法的拥有者)来创建新的对象的过程,spring采用的是动态代理织入(jdk动态代理和子类动态代理都有),AspectJ采用编译期织入和类装载织入。

术语理解

用LOL中远古龙BUFF来理解吧:比如你现在在蓝色方,蓝色方刚刚跟对面打了一波5V5团战,1换5,蓝色方辅助挂了,这个时候已经30分钟后了,你们开始去打远古龙,打掉远古龙的时候辅助还没有复活,因此只有你们四个人获得了远古龙BUFF。

  • Joint point(连接点): 在上面的故事里,你们四个有了远古龙BUFF,就是都能被增强,可以看到远古龙BUFF是可以作用在上面所有人的身上,因为如果辅助不挂他也会有BUFF。在Spring中,这些人就等于可以被增强的方法。
  • Pointcut(切点): 在上面的故事里,只有你们四个有远古龙BUFF,但辅助没有。可以看出来Pointcut(切点)是有条件的Joint point(连接点),活着的人被增强了。
  • Advice(通知/增强): 你们四个在打掉远古龙的时候活着,那么你们四个就被增强了。
  • Aspect(切面): 切点和通知的结合,上面的切点就是活着的你们四个(四个点),通知是打掉远古龙后获得的BUFF,切点有很多,连载一起就像一个面一样。

AOP案例实现

在这里插入图片描述在这里插入图片描述

前置/后置/异常/最终增强的配置实现

1.依赖

	<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.22</version><scope>provided</scope></dependency><!-- aop依赖 --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.6</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.1.9.RELEASE</version></dependency>

2.业务类

@Slf4j
@Service
public class UserServiceImpl implements UserService {@Resourceprivate UserMapper userMapper;@Overridepublic Object saveUser(String userName) {//log.info("调用org.aop.service.impl.UserServiceImpl的saveUser(),入参是{}",user);boolean result = userMapper.insertUser(userName) > 0;//log.info("调用org.aop.service.impl.UserServiceImpl的saveUser()完毕,返回值是{}",result);return result;}@Overridepublic boolean updateUser(User user) {//log.info("调用org.aop.service.impl.UserServiceImpl的updateUser(),入参是{}",user);boolean result = userMapper.updateUser(user) > 0;//log.info("调用org.aop.service.impl.UserServiceImpl的updateUser()完毕,返回值是{}",result);return result;}
}

3.日志类

package org.aop.log;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;import java.util.Arrays;/*** @author: zjl* @datetime: 2024/3/30* @desc:*/
@Slf4j
public class MyServiceLogger {//前置增强public void before(JoinPoint jp) {log.info("调用 " + jp.getTarget() + " 的 " + jp.getSignature().getName() + " 方法。方法入参:" + Arrays.toString(jp.getArgs()));}//后置增强public void afterReturning(JoinPoint jp, Object result) {log.info("调用 " + jp.getTarget() + " 的 " +  jp.getSignature().getName() + " 方法。方法返回值:" + result);}//异常处理增强public void afterThrowing(JoinPoint jp, Throwable e) {log.info("调用 " + jp.getTarget() + " 的 " +  jp.getSignature().getName() + " 方法。方法抛出异常:" + e);}//最终增强public void after(JoinPoint jp) {log.info("调用 " + jp.getTarget() + " 的 " +  jp.getSignature().getName() + " 方法。方法执行完毕。模拟关闭资源...");}

4.配置

在这里插入图片描述

增强处理类型特 点
Before前置增强处理,在目标方法前织入增强处理
AfterReturning后置增强处理,在目标方法正常执行(不出现异常)后织入增强处理
AfterThrowing异常增强处理,在目标方法抛出异常后织入增强处理
After最终增强处理,不论方法是否抛出异常,都会在目标方法最后织入增强处理
Around环绕增强处理,在目标方法的前后都可以织入增强处理
<?xml version="1.0" encoding="UTF-8"?>
<beans  xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.2.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.2.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-3.2.xsd"><!--                    配置相关的AOP                --><bean id="myServiceLog" class="org.aop.log.MyServiceLogger"/><aop:config><aop:pointcut id="pointcut"expression="execution(* org.aop.service..*.*(..)))"/><aop:aspect ref="myServiceLog"><aop:before method="before"pointcut-ref="pointcut"></aop:before><aop:after-returning method="afterReturning"pointcut-ref="pointcut" returning="result"/><aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="e"/><aop:after method="after" pointcut-ref="pointcut"/></aop:aspect></aop:config>
</beans>
切入点表达式匹配规则举例
public * addNewUser(entity.User): “*”表示匹配所有类型的返回值。
public void *(entity.User): “*”表示匹配所有方法名。
public void addNewUser(..): “..”表示匹配所有参数个数和类型。
* com.zjl.service.*.*(..):匹配com.zjl.service包下所有类的所有方法。
* com.zjl.service..*.*(..):匹配com.zjl.service包及其子包下所有类的所有方法

环绕增强的配置实现(1替4)

1.service类不变

2.日志类

注释掉前面四种增强的方法,加入这个环绕增强的方法

    public Object around(ProceedingJoinPoint jp) throws Throwable {Object result = null;try {log.info("调用 " + jp.getTarget() + " 的 " +  jp.getSignature().getName() + " 方法。方法入参:" + Arrays.toString(jp.getArgs()));result = jp.proceed();log.info("调用 " + jp.getTarget() + " 的 " +  jp.getSignature().getName() + " 方法。方法返回值是:" + result);}catch (Exception e){log.info("调用 " + jp.getTarget() + " 的 " +  jp.getSignature().getName() + " 方法。发生了异常,异常信息为:" + e);}finally {log.info("调用 " + jp.getTarget() + " 的 " +  jp.getSignature().getName() + " 方法,进行最终处理,比如模拟资源关闭");}return result;}

3.配置

    <!--                    配置相关的AOP                --><bean id="myServiceLog" class="org.aop.log.MyServiceLogger"/><aop:config><aop:pointcut id="pointcut"expression="execution(* org.aop.service..*.*(..)))"/><aop:aspect ref="myServiceLog"><!--<aop:before method="before"pointcut-ref="pointcut"></aop:before><aop:after-returning method="afterReturning"pointcut-ref="pointcut" returning="result"/><aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="e"/><aop:after method="after" pointcut-ref="pointcut"/>--><aop:around method="around" pointcut-ref="pointcut"/></aop:aspect></aop:config>

Spring AOP配置元素

AOP配置元素描 述
<aop:config>AOP配置的顶层元素,大多数的<aop:*>元素必须包含在<aop:config>元素内
<aop:pointcut>定义切点
<aop:aspect>定义切面
<aop:after>定义最终增强(不管被通知的方法是否执行成功)
<aop:after-returning>定义after-returning增强
<aop:after-throwing>定义after-throwing增强
<aop:around>定义环绕增强
<aop:before>定义前置增强
<aop:aspectj-autoproxy>启动@AspectJ注解驱动的切面

注解实现AOP

1.service类不变

2.日志类

package org.aop.log;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;import java.util.Arrays;/*** @author: zjl* @datetime: 2024/3/30* @desc:*/
@Slf4j
@Aspect
@Component
public class MyServiceLogger {//1.针对service实现类中所有方法,记录某个方法在被调用时的入参信息//@Before("execution(* org.aop.service..*.*(..))")public void before(JoinPoint jp) {log.info("调用 " + jp.getTarget() + " 的 " + jp.getSignature().getName() + " 方法。方法入参:" + Arrays.toString(jp.getArgs()));}//2.针对service实现类中所有方法,记录某个方法被调用后的返回值信息//@AfterReturning(returning = "result", pointcut = "execution(* org.aop.service..*.*(..))")public void afterReturning(JoinPoint jp, Object result) {log.info("调用 " + jp.getTarget() + " 的 " +  jp.getSignature().getName() + " 方法。方法返回值:" + result);}//@AfterThrowing(throwing = "e", pointcut = "execution(* org.aop.service..*.*(..))")public void afterThrowing(JoinPoint jp, Throwable e) {log.info("调用 " + jp.getTarget() + " 的 " +  jp.getSignature().getName() + " 方法。方法抛出异常:" + e);}// @After("execution(* org.aop.service..*.*(..))")public void after(JoinPoint jp) {log.info("调用 " + jp.getTarget() + " 的 " +  jp.getSignature().getName() + " 方法。方法执行完毕。模拟关闭资源...");}@Around("execution(* org.aop.service..*.*(..))")public Object around(ProceedingJoinPoint jp) throws Throwable {Object result = null;try {log.info("调用 " + jp.getTarget() + " 的 " +  jp.getSignature().getName() + " 方法。方法入参:" + Arrays.toString(jp.getArgs()));result = jp.proceed();log.info("调用 " + jp.getTarget() + " 的 " +  jp.getSignature().getName() + " 方法。方法返回值是:" + result);}catch (Exception e){log.info("调用 " + jp.getTarget() + " 的 " +  jp.getSignature().getName() + " 方法。发生了异常,异常信息为:" + e);}finally {log.info("调用 " + jp.getTarget() + " 的 " +  jp.getSignature().getName() + " 方法,进行最终处理,比如模拟资源关闭");}return result;}
}

3.配置

<?xml version="1.0" encoding="UTF-8"?>
<beans  xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.2.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.2.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-3.2.xsd"><context:component-scan base-package="org.aop"/><aop:aspectj-autoproxy />
</beans>

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

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

相关文章

[linux]进程控制——进程终止

一、main函数的返回值 我们在编写C语言的程序时&#xff0c;通常会这样写&#xff1a; int main() {return 0; } 那么我们为什么要返回&#xff08;return&#xff09;0 呢&#xff1f; 其实&#xff0c;main函数也是一个函数&#xff0c;它也会被调用&#xff0c;所以谁调…

牛客周赛 Round 39(A,B,C,D,E,F,G)

比赛链接 官方题解&#xff08;视频&#xff09; B题是个贪心。CD用同余最短路&#xff0c;预处理的完全背包&#xff0c;多重背包都能做&#xff0c;比较典型。E是个诈骗&#xff0c;暴力就完事了。F是个线段树。G是个分类大讨论&#xff0c;出题人钦定的本年度最佳最粪 题目…

RT-Thread学习

RT-Thread三个版本——标准版本 RT-Thread&#xff0c;全称是Real Time-Thread&#xff0c;顾名思义&#xff0c;它是一个嵌入式实时多线程操作系统&#xff0c;基本属性之一是支持多任务&#xff1a;一个处理器核心在某一时刻只能运行一个任务&#xff0c;由于每次对一个任务…

HCIP【ospf综合实验】

目录 实验要求&#xff1a; 实验拓扑图&#xff1a; 实验思路&#xff1a; 实验步骤&#xff1a; 一、划分网段 二、配置IP地址 三、搞通私网和公网 &#xff08;1&#xff09;先搞通私网&#xff08;基于OSPF协议&#xff0c;在各个路由器上进行网段的宣告&#xff0c…

实现智能水控 | 基于ACM32 MCU的分体式水控方案

分体式水控概述 分体式水控是一种常见的水控系统&#xff0c;它的工作原理是通过水的流动来控制水的供应和排放&#xff0c;该系统一般由两部分组成&#xff1a;控制器和水阀。控制器负责监测水的流量和压力&#xff0c;根据设定的参数来控制水阀的开和关&#xff0c;从而实现水…

2024认证杯数学建模A题保暖纤维保暖能力原创论文讲解(含完整python代码)

大家好呀&#xff0c;从发布赛题一直到现在&#xff0c;总算完成了认证杯数学中国数学建模网络挑战赛第一阶段A题目保暖纤维的保暖能力完整的成品论文。 本论文可以保证原创&#xff0c;保证高质量。绝不是随便引用一大堆模型和代码复制粘贴进来完全没有应用糊弄人的垃圾半成品…

windows下vscode调试虚拟机linux c++工程的三种方法

vscode去远程调试方法有很多种&#xff0c;不同的插件对应了不同的调试方法&#xff0c;比如&#xff1a; 1.C/C插件进行GDB调试(编写launch.json文件) 2.C/C Runner插件 3.CMake Tools插件&#xff08;只针对CMake工程&#xff0c;需要搭配C/C插件一起使用&#xff0c;但无…

Gin框架小结

Gin 简介 Gin是一个轻量级的Web框架&#xff0c;用于构建高性能的Go语言Web应用程序。提供了路由管理、中间件支持、参数绑定和验证、错误处理、静态文件服务等功能。 Gin框架解决了什么问题和痛点 1.golang http 标准库本身提供了比较简单的路由注册能力&#xff0c;只支持…

记录一次内存溢出

1、查看catalina相关日志&#xff0c;确定关键字相关行号 文件&#xff1a;catalina.out命令1&#xff1a;cat -n catalina.out |grep -a OutOfMemoryError与内存溢出相关的如上&#xff0c;每一个行号其实都对应到具体时间点。可以发现&#xff0c;这个范围相符合&#xff1…

清明三天,用Python赚了4万?

每年4月&#xff0c;是Python圈子里接私活的旺季&#xff0c;特别是在节假日这种数据暴增的时间段&#xff0c;爬虫采集、逆向破解类的私活订单会集中爆发&#xff0c;量大价高。几乎所有的圈内人都在趁着旺季接私活。 正好&#xff0c;我昨天就做了一单爬虫逆向私活&#xff…

引领软件供应链安全 比瓴科技位居安全牛全景图第一

近日&#xff0c;安全牛第十一版《中国网络安全行业全景图》正式发布&#xff0c;比瓴科技入选全景图软件供应链安全赛道中开发流程安全管理、DevSecOps和软件成分分析三个重要细分领域&#xff0c;并位居开发流程安全管控领域第一。 安全牛本次全景图研究工作于23年正式启动&a…

什么是云安全?云安全包含哪些方面?

云计算彻底改变了数据存储的世界&#xff0c;它使企业可以远程存储数据并随时随地从任何位置访问数据。存和取变得简单&#xff0c;也使得云上数据极易造成泄露或者被篡改&#xff0c;所以云安全就显得非常重要了。那么什么是云安全&#xff1f;云安全的工作原理是什么&#xf…

做一个好的程序员难吗?只需要这10个习惯

在这个世界上&#xff0c;有数以百万计的人对软件开发充满热情&#xff0c;他们有很多名字&#xff0c;如软件工程师、程序员、编码员、开发人员。一段时间后&#xff0c;这些人可能会成为一名优秀的编码员&#xff0c;并且他们将非常熟悉如何使用计算机语言完成工作。但是&…

EasyRecovery激活秘钥2024最好用的电脑数据恢复软件下载

EasyRecovery数据恢复软件是一款专业且功能强大的数据恢复工具&#xff0c;它旨在帮助用户从各种存储设备中恢复由于各种原因&#xff08;如误删除、格式化、病毒攻击、系统崩溃等&#xff09;导致丢失的数据。这款软件支持多种存储介质&#xff0c;包括但不限于硬盘驱动器、U盘…

0.5W 3KVDC 隔离 单输出 DC/DC 电源模块 ——TPR-W5 系列

TPR-W5系列是一款需要隔离和电压转换的产品&#xff0c;工业级环境温度&#xff0c;温度范围从–40℃到105℃&#xff0c;用于PCB安装的国际标准结构。此系列产品小巧&#xff0c;效率高&#xff0c;低输出纹波及提供3000V以上的直流电压隔离&#xff0c;用于需要隔离的场合&am…

【Spring系列】- Spring事务底层原理

实验准备 配置文件 首先在配置文件中配置jdbcTemplate和事务管理器&#xff0c;并且需要开启事务的注解EnableTransactionManagement以及Configuration注解 ComponentScan("com.lyd") EnableTransactionManagement Configuration public class ApplicationConfig …

[入门]测试原则-ApiHug准备-测试篇-002

&#x1f917; ApiHug {Postman|Swagger|Api...} 快↑ 准√ 省↓ GitHub - apihug/apihug.com: All abou the Apihug apihug.com: 有爱&#xff0c;有温度&#xff0c;有质量&#xff0c;有信任ApiHug - API design Copilot - IntelliJ IDEs Plugin | Marketplace 写在前面…

低敏猫粮怎么选?看这一篇就够了!

亲爱的朋友们&#xff0c;你们是否曾经为了家中敏感肠胃的小猫咪而犯愁&#xff0c;不知道如何选择适合的猫粮呢&#xff1f;今天&#xff0c;就让我们一起聊聊低敏猫粮与普通猫粮的那些不同之处吧&#xff01;&#x1f431; 1️⃣ **成分差异**&#xff1a;首先&#xff0c;从…

Go 自定义14位时间类型 yyyyMMddHHmmss

目录 功能 代码 功能 数据库或者接口时间类型&#xff0c;经常会使用14位的时间格式。每次都转换有点麻烦。可以自定义一个时间类型。 自定义类型需要实现json接口中的MarshalJSON与UnmarshalJSON两个函数&#xff0c;这样在做json编码解码时就会自动转为14位的时间格式了。…

第四届大数据工程与教育国际会议(BDEE 2024)即将召开!

第四届大数据工程与教育国际会议&#xff08;BDEE 2024&#xff09;将于2024年8月9-11日在泰国清迈举行。数据驱动教育变革&#xff0c;智慧点亮未来课堂&#xff01;BDEE 2024是专注于大数据工程与教育领域的重要学术会议&#xff0c;全球大数据与教育精英齐聚&#xff0c;在数…