【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.rhkb.cn/news/311039.html

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

相关文章

车内AR互动娱乐解决方案,打造沉浸式智能座舱体验

美摄科技凭借其卓越的创新能力&#xff0c;为企业带来了革命性的车内AR互动娱乐解决方案。该方案凭借自研的AI检测和渲染引擎&#xff0c;打造出逼真的数字形象&#xff0c;不仅丰富了车机娱乐内容&#xff0c;更提升了乘客与车辆的互动体验&#xff0c;让每一次出行都成为一场…

若依安装过程

文章目录 参考博客环境准备下载redisjdk1.8下载nacos 后端mysqlnacos运行npm 参考博客 https://blog.csdn.net/qq_31536117/article/details/134603862 环境准备 下载redis 参考https://redis.com.cn/redis-installation.html jdk1.8下载 参考 https://zhuanlan.zhihu.co…

海外仓管理软件必要性分析:大幅度降本增效,精细化运营才是出路

随着全球化大趋势的推进和电商平台技术的高速发展&#xff0c;跨境电商的规模体量正在不断扩大。作为链接卖家和买家的桥梁&#xff0c;海外仓的重要程度自然是不用质疑。 在如此大的需求面前&#xff0c;本来应该是前景一片大好。但是事实似乎并没有这么乐观&#xff0c;随着…

电子元器件线上交易商城搭建的价值和必要性-加速度jsudo

随着科技的飞速发展&#xff0c;电子元器件行业正迎来前所未有的变革。为了满足市场对于电子元器件采购的便捷性、高效性和多样性的需求&#xff0c;电子元器件商城的开发显得尤为重要。本文将探讨电子元器件商城开发的重要性、主要功能以及它如何助力行业发展。 电子元器件商城…

研究生,该学单片机还是plc。?

PLC门槛相对较低&#xff0c;但是在深入学习和应用时&#xff0c;仍然有很高的技术要求。我这里有一套单片机入门教程&#xff0c;不仅包含了详细的视频 讲解&#xff0c;项目实战。如果你渴望学习单片机&#xff0c;不妨点个关注&#xff0c;给个评论222&#xff0c;私信22&am…

Nginx小册(博客笔记迁移)

nginx基础 1.常用命令 nginx -v #查看版本 ps -ef | grep nginx #输出linux进程、 nginx #启动nginx进程 nginx -s reload #重载配置 nginx -s stop # 停止进程 nginx -t # 检查是否有语法错误&#xff0c;以及配置文件地址2.nginx的配置文件 # 用户组的设置 windows上不生…

ES6: set和map数据结构以及使用场景

ES6:set和map数据结构 一、Set 数据结构&#xff1a;二、使用场景&#xff1a;使用Set 进行去重三、Map 数据结构四、使用场景&#xff1a;使用Map进行树型数据懒加载刷新五、Set和Map的区别六、Map、Set的实际使用场景 Set 和 Map 是 ES6 中引入的两种新的数据结构&#xff0c…

FlexLua低代码技术,十分钟搞定4G转LoRa网关设备

在当今物联网时代&#xff0c;无线通信技术的发展日新月异&#xff0c;4G和LoRa作为两种不同的通信技术&#xff0c;各自拥有独特的优势和应用场景。而4G转LoRa网关设备的出现&#xff0c;则将这两种技术有效地结合起来&#xff0c;为物联网应用提供了更多可能性。 4G转LoRa网关…

【自媒体创作利器】AI白日梦+ChatGPT 三分钟生成爆款短视频

AI白日梦https://brmgo.com/signup?codey5no6idev 引言 随着人工智能&#xff08;AI&#xff09;技术的快速发展&#xff0c;AI在各个领域都展现出了强大的应用潜力。其中&#xff0c;自然语言处理技术的进步使得智能对话系统得以实现&#xff0c;而ChatGPT作为其中的代表之一…

Bytebase 2.15.0 - GitOps 整体升级

&#x1f514; GitOps 整体升级 新版 GitOps 和之前版本不兼容&#xff0c;如果需要升级协助&#xff0c;请联系我们。 使用访问令牌进行身份验证。支持项目中配置多个 VCS 连接器。支持在 VCS 连接器中指定数据库分组为目标&#xff08;默认情况下应用于项目中的所有数据库&…

在深度残差收缩网络中,我对阈值的理解!

在深度残差收缩网络中&#xff0c;使用Sigmoid函数将输出归一化到0和1之间是为了确保阈值α的取值范围在可接受的范围内。Sigmoid函数具有将任意输入映射到(0, 1)区间的特性&#xff0c;这有助于控制阈值的大小和变化范围。 将阈值设置为(特征图的绝对值)(一个系数α)是基于以…

单链表使用里面为什么是二级指针

这里很多人就会疑问&#xff0c;为什么顺序表里面是一级指针&#xff0c;单链表里面是二级指针。 这里我们专门列出来进行讲解。 因为传递的不是二级指针的话&#xff0c;会导致传参之后&#xff0c;形参改变&#xff0c;实参不改变 你希望形参改变实参也改变就必须传递地址 简…

构建鸿蒙ACE静态库

搭建开发环境 根据说明文档下载鸿蒙全部代码&#xff0c;一般采取第四种方式获取最新代码(请保证代码为最新) 源码获取Windows下载编译环境 MinGW GCC 7.3.0版本 请添加环境变量IDE 可以使用两种 CLion和Qt,CLion不带有环境需要安装MinGW才可以开发,Qt自带MinGW环境&#xff0…

Springboot+Vue项目-基于Java+MySQL的校园周边美食探索及分享平台系统(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…

html球体涨水

简单 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><style>div…

在比特币中,1 sat 是多少美元?

普通人绝对想不到&#xff0c;比特币能在2024年达到这个价值&#xff0c;早知道的话&#xff0c;我当初就是破釜沉舟也得买一个啊。 而在4月19号&#xff0c;也将迎来比特币再次减半。减半并不是说玩家手中的比特币要被突然减去一半&#xff0c;而是在后续的挖矿过程中&#xf…

CSS基础之伪元素选择器(如果想知道CSS的伪元素选择器知识点,那么只看这一篇就足够了!)

前言&#xff1a;我们已经知道了在CSS中&#xff0c;选择器有基本选择器、复合选择器、伪类选择器、那么选择器学习完了吗&#xff1f;显然是没有的&#xff0c;这篇文章讲解最后一种选择器——伪元素选择器。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解更多内容可以访问我…

移动端web适配方案

以下是移动端适配的多个方案&#xff0c;也可以说说你是怎么做的。 正文 自适应&#xff1a;根据不同的设备屏幕大小来自动调整尺寸、大小 响应式&#xff1a;会随着屏幕的实时变动而自动调整&#xff0c;是一种更强的自适应 为什么要做移动端适配&#xff1f; 目前市面上…

2024很漂亮的个人主页HTML源码

源码介绍 很漂亮的个人主页HTML源码&#xff0c;源码由HTMLCSSJS组成&#xff0c;记事本打开源码文件可以进行内容文字之类的修改&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务器里面 截图效果 源码下载 很漂亮的个人主页HTML源码

第七讲:C语言指针(1)

目录 1、内存和地址 1.1、内存 1.2、究竟该如何理解编址 2、指针变量和地址 2.1、取地址操作符&#xff08;&&#xff09; 2.2、指针变量和解引⽤操作符 2.2.1、指针变量 2.2.2、如何理解指针类型 2.2.3、解引⽤操作符 2.3、指针变量的⼤⼩ 3、指针变量类型的意…