Spring学习——SpringAOP

news2024/12/24 19:37:28
0. IOC思想(DI)

1. 关键注解
	
	@Repository
	public class DeptDaoImpl1 implements DeptDao{}
	
	@Repository
	@Primary
	public class DeptDaoImpl2 implements DeptDao{}
	
	@Service
	public class DeptServiceImpl implements DeptService{
	
		@Autowired
		@Qulifier("deptDaoImpl2")
		private DeptDao deptDao;
	}

2. 创建对象
	自定义对象:@Repository  @Service  @Controller  @Component  
	第三方对象:@Bean  @Configuration

3. 对象作用域@Scope
	单例:只有一个, 默认容器启动,对象创建(@Lazy延迟到第一次获取)
	多例:每次获取,创建一个新的

4. 单元测试
	@RunWith(运行器)
	@ContextConfiguration(classes=)

日志功能

需求:在业务层类中的方法中打印日志,记录方法执行前后以及方法发生异常的时间点

基本方式实现

导入初始工程

在这里插入图片描述

添加日志功能

修改DeptServiceImpl,添加日志功能

在这里插入图片描述

测试

在这里插入图片描述

分析代码问题

目前代码存在两个问题

  1. 代码耦合性高:业务代码和日志代码耦合在了一起
  2. 代码复用性低:日志代码在每个方法都要书写一遍

jdk动态代理

在这里插入图片描述

复制工程

在这里插入图片描述

准备目标类

目标类指的是要被代理的类

在这里插入图片描述

准备增强类

增强类指的是要给被代理类添加的功能

在这里插入图片描述

创建代理对象

在测试类中,使用JDK技术创建代理对象,然后调用方法

在这里插入图片描述

cglib动态代理

CGLIB(Code Generation )动态代理利用ASM字节码操作框架在运行时生成代理类,它通过继承的方式代理目标对象,因此可以代理没有实现接口的类。

在这里插入图片描述

复制工程

在这里插入图片描述

删除接口

删除DeptService接口,并删除实现类中对接口的实现

在这里插入图片描述

创建代理对象

package com.itheima.test;

import com.itheima.config.SpringConfig;
import com.itheima.log.Logger;
import com.itheima.service.impl.DeptServiceImpl;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.InvocationHandler;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.lang.reflect.Method;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class DeptServiceTest {

    @Autowired
    private DeptServiceImpl deptServiceImpl;

    @Autowired
    private Logger logger;

    @Test
    public void test1() {
        //1. 准备目标对象(deptService就是)

        //2. 编写增强逻辑
        //注意: 这个InvocationHandler是org.springframework.cglib.proxy.InvocationHandler提供的
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object res = null;

                logger.m1();
                try {
                    res = method.invoke(deptServiceImpl,args);
                }catch (Exception e){
                    logger.m3();
                }
                logger.m2();

                return res;
            }
        };

        //3. 创建代理对象
        DeptServiceImpl proxyInstance = (DeptServiceImpl) Enhancer.create(DeptServiceImpl.class, invocationHandler);

        //4. 调用代理对象的方法
        proxyInstance.findAll();
    }
}

小结

首先明确在创建代理实现类时,jdk的速度要高于cglib,所以选择的时候:

当被代理类有接口的时候,使用jdk动态代理;当被代理类没有接口的时候,使用cglib动态代理

不同点:

在这里插入图片描述

总结

在这里插入图片描述

当核心业务(保存)和增强业务(日志)同时出现时,我们可以在开发时对他们分别开发,运行时再组装在一起(使用动态代理的方式)。

这样做的好处是:

  1. 逻辑清晰:开发核心业务的时候,不必关注增强业务的代码
  2. 代码复用性高:增强代码不用重复书写

这就是一种 AOP ( 面向切面编程 ) 的思想,它的目的就是在不修改源代码的基础上,对原有功能进行增强。

我的总结: 开发阶段分别开发,运行阶段组装运行

AOP

AOP介绍

AOP( 面向切面编程 )是一种思想,它的目的就是在不修改源代码的基础上,对原有功能进行增强。

在这里插入图片描述

SpringAOP是对AOP思想的一种实现,Spring底层同时支持jdk和cglib动态代理。

Spring会根据被代理的类是否有接口自动选择代理方式:

  • 如果有接口,就采用jdk动态代理
  • 如果没接口,就采用cglib的方式

在AOP中有一些核心概念,需要大家了解

* 目标对象(Target)
	被代理的对象

* 连接点(JoinPoint)
	目标对象中得所有方法

* 切入点(PointCut)
	目标对象中得要进行功能增强那部分方法

* 增强 (Advice 通知)
	一个具体增强功能(增强对象  增强方法)

* 切面 (Aspect)
	切面是一种描述,描述的是: 哪个增强方法   加入到了  哪个切点  的   什么位置
	增强方法和切点方法的执行顺序

在这里插入图片描述

入门案例

使用SpringAop完成在业务层类中的方法上打印日志

创建模块,导入依赖

在这里插入图片描述

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.26</version>
        </dependency>
        
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.6</version>
        </dependency>

        <!--切点表达式解析坐标-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.7</version>
        </dependency>

        <!--测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.3.6</version>
        </dependency>
    </dependencies>

创建实体类

创建业务层接口和实现类

在这里插入图片描述

创建日志类

在这里插入图片描述

配置切面

我们需要把切面相关的内容配置在这种增强类中

在这里插入图片描述

创建配置类

在这里插入图片描述

单元测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)

在这里插入图片描述

通知类型

四大通知

四大通知描述的就是增强方法在切点方法的什么位置上执行

- 前置通知(before):增强方法在切点运行之前执行
- 返回后通知(after-returning):增强方法在某切点正常完成后执行的通知,不包括抛出异常的情况
- 异常后通知(after-throwing):增强方法在某切点抛出异常退出时执行的通知
- 后置通知(after):增强方法在某切点退出的时候执行的通知(不论是正常返回还是异常退出)
try{
	前置通知(before)
       
	//切点执行位置
       
	返回后通知(after-returning)
}catch(Execption e){
	异常后通知(after-throwing)
}finally{
	后置通知(after)
}

① 添加通知方法

在这里插入图片描述

② 测试

在这里插入图片描述

环绕通知

它是一种特殊的通知,他允许以编码的形式实现四大通知

① 添加通知方法

在这里插入图片描述

② 测试

在这里插入图片描述

切点表达式

切点表达式用于挑选切点

execution

execution() :指定一组规则来匹配某些类中的方法,匹配中的就是切点

* 代表一个或多个位置
.. 代表0个或多个位置

在这里插入图片描述

@annotation

@annotation:指定一个注解,凡是标有此注解的方法都是切点

① 自定义注解

在这里插入图片描述

② 在需要作为切点的方法上添加注解
在这里插入图片描述

③ 设置切点表达式

在这里插入图片描述

④ 测试

在这里插入图片描述

记录日志详情

在这里插入图片描述

事务管理

事务回顾

事务是一组操作的集合,它是一个不可分割的工作单位,这些操作 要么同时成功,要么同时失败。

开启事务(一组操作开始前,开启事务):start transaction / begin ;

提交事务(这组操作全部成功后,提交事务):commit ;

回滚事务(中间任何一个操作出现异常,回滚事务):rollback ;

转账案例

添加账户表

-- 创建账户表,并且添加两条测试数据
create table account (
                         id int primary key auto_increment,
                         name varchar(32),
                         balance float
);
insert into account (name, balance) VALUES ('A', 1000), ('B', 1000);

导入工程

在这里插入图片描述

添加持久层代码

在Mapper接口中添加加钱和减钱的方法

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

添加业务层代码

在Service接口和实现类中添加转账方法

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

测试

在测试类中添加转账方法

在这里插入图片描述

事务管理

注解:@Transactional

位置:业务(service)层的方法上、类上、接口上

作用:将当前方法交给spring进行事务管理,方法执行前,开启事务;成功执行完毕,提交事务;出现异常,回滚事务

配置事务管理器

在配置类中配置事务管理器,并开启声明式事务

在这里插入图片描述

添加事务注解

在转账方法上添加@Transactional注解,注意方法中要模拟异常

在这里插入图片描述

测试

在测试方法中对转账方法进行测试

在这里插入图片描述

事务属性

rollbackFor

默认情况下,只有出现 RuntimeException 才回滚异常,rollbackFor属性用于控制让非运行时异常也回滚。

在这里插入图片描述

propagation

propagation称为事务传播行为,表示当一个事务方法被另一个事务方法调用时,应该如何进行事务控制

在这里插入图片描述

Spring支持通过配置的形式来实现7种事务传播行为,我们需要掌握其中的前两种

属性值含义
REQUIRED【默认值】需要事务,有则加入,无则创建新事务
REQUIRES_NEW需要新事务,无论有无,总是创建新事务
SUPPORTS支持事务,有则加入,无则在无事务状态中运行
NOT_SUPPORTED不支持事务,在无事务状态下运行,如果当前存在已有事务,则挂起当前事务
MANDATORY必须有事务,否则抛异常
NEVER必须没事务,否则抛异常
NESTED如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务, 则开启一个新的事务。
内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。
而内层事务操作失败并不会引起外层事务的回滚。

建新事务 |
| REQUIRES_NEW | 需要新事务,无论有无,总是创建新事务 |
| SUPPORTS | 支持事务,有则加入,无则在无事务状态中运行 |
| NOT_SUPPORTED | 不支持事务,在无事务状态下运行,如果当前存在已有事务,则挂起当前事务 |
| MANDATORY | 必须有事务,否则抛异常 |
| NEVER | 必须没事务,否则抛异常 |
| NESTED | 如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务, 则开启一个新的事务。
内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。
而内层事务操作失败并不会引起外层事务的回滚。 |

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

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

相关文章

UE5学习笔记24-添加武器弹药

一、给角色的武器添加弹药 1.创建界面&#xff0c;根据笔记23的界面中添加 2.绑定界面控件 UPROPERTY(meta (Bindwidget))UTextBlock* WeaponAmmoAmount;UPROPERTY(meta (Bindwidget))UTextBlock* CarriedAmmoAmount; 3.添加武器类型枚举 3.1创建武器类型枚举头文件 3.2创建文…

C++容器:map

1.铺垫 1.1map和unorder_map&#xff0c;两者的实现思想不同&#xff0c;但是用法是相同的&#xff1b;map的思想是平衡二叉树&#xff1b;unorder_map的思想是哈希&#xff1b; 1.2在现实及做题中&#xff0c;百分之99&#xff0c;都在使用unorder_map&#xff0c;接下来的讲…

2024 第一次周赛

A: 题目大意 骑士每连续 i 天每天会得到 i 个金币&#xff0c;&#xff08;i 1&#xff0c; 2&#xff0c; 3 &#xff0c; …&#xff09;,那么展开看每一天可以得到的金币数&#xff1a;1 2 2 3 3 3 4 4 4 5 5 5 5 5 … 可以发现就是1个1 &#xff0c;2个2, 3个3…,那么我…

P20机型HW睡眠省电-调研

摘要 AI睡眠场景识别 不激进的智能管控 睡眠省电 UI 以前有单独的睡眠开关选项&#xff0c;现在没有了&#xff0c;但是智能充电模式是使用AI睡眠模式 睡眠识别 华为专利上提到的论文《BTP-A Bedtime Predicting Algorithm》 各种事件状态&#xff08;亮灭屏、alarm、主动…

《数字信号处理》学习08-围线积分法(留数法)计算z 逆变换

目录 一&#xff0c;z逆变换相关概念 二&#xff0c;留数定理相关概念 三&#xff0c;习题 一&#xff0c;z逆变换相关概念 接下来开始学习z变换的反变换-z逆变换&#xff08;z反变化&#xff09;。 由象函数 求它的原序列 的过程就称为 逆变换。即 。 求z逆变换…

RTR-Chapter8

第八章 光与颜色 光量辐射度量学光度学色度学使用RGB颜色进行渲染 从场景到屏幕HDR显示编码色调映射色调再现变换曝光 颜色分级 光量 辐射度量学 辐射度量学&#xff08;radiometry&#xff09;研究的是对电磁辐射&#xff08;electromagnetic radiation&#xff09;的测量&am…

linux线程 | 线程的控制(二)

前言&#xff1a; 本节内容是线程的控制部分的第二个小节。 主要是列出我们的线程控制部分的几个细节性问题以及我们的线程分离。这些都是需要大量的代码去进行实验的。所以&#xff0c; 准备好接受新知识的友友们请耐心观看。 现在开始我们的学习吧。 ps:本节内容适合了解线程…

开源情报(OSINT)入门:初学者指南

欢迎来到令人兴奋的开源情报 (OSINT) 世界&#xff01;如果您是该领域的新手&#xff0c;OSINT 就是收集和分析公开信息以获取见解并制作情报产品。 无论您是安全爱好者、记者还是只是对 OSINT 感兴趣&#xff0c;本入门指南都将带您了解基础知识&#xff0c;让您开始第一次&a…

MySQL进阶学习一(2024.10.07版)

2024-10-06 -------------------------------------------------------------------------------------------------------------------------------- 1.一条SQL语句是如何执行的 单进程的多线程模型 MySQL的物理目录 show global variables like "%basedir%"; …

初学Vue(3)(内置指令)

文章目录 十四、内置指令v-textv-htmlv-cloak&#xff08;没有值&#xff09;v-oncev-pre自定义指令一、定义语法二、配置对象中常用的3个问题三、备注 十四、内置指令 回顾&#xff1a; v-bind &#xff1a;单向绑定解析表达式&#xff0c;可简写为 :xxx v-model : 双向数据绑…

HTML快速入门--第一节--五个基本标签

一、网络编程的三大基石 1.1 url 统一资源定位符&#xff1a; 网址:整个互联网中可以唯一且准确的确定一个资源的位置 (url项目外) 网址:https://www.baidu.com/ https://www.baidu.com/ 协议://ip端口/项目名/页面名 协议:交通法规获取资源 ip端口 &#xff08;域名&…

安全企业邮箱优势与局限,密码策略反馈

密码策略是什么呢&#xff1f;如何设置出安全可靠的密码策略呢&#xff1f;企业邮箱安全始于密码策略&#xff0c;包括复杂性、长度、更新频率、重用限制和两步验证。实施需全员培训、密码管理工具、审计与监控。一文为你详细介绍密码策略。 一、如何设置好的密码策略&#xff…

【JavaScript】JavaScript开篇基础(3)

1.❤️❤️前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; Hello, Hello~ 亲爱的朋友们&#x1f44b;&#x1f44b;&#xff0c;这里是E绵绵呀✍️✍️。 如果你喜欢这篇文章&#xff0c;请别吝啬你的点赞❤️❤️和收藏&#x1f4d6;&#x1f4d6;。如果你对我的…

【微信小程序_11_全局配置】

摘要:本文介绍了微信小程序全局配置文件 app.json 中的常用配置项,重点阐述了 window 节点的各项配置,包括导航栏标题文字、背景色、标题颜色,窗口背景色、下拉刷新样式以及上拉触底距离等。通过这些配置可实现小程序窗口外观的个性化设置,提升用户体验。 微信小程序_11_全…

总看别人写贪吃蛇,自己也来写一个吧

贪吃蛇是一个流行度非常高的游戏&#xff0c;玩法十分简单&#xff0c;从最初的方块机上就有这个游戏了&#xff0c;后来出现的手机中也是加入了这个游戏&#xff0c;无聊的时候可以打发时间玩一会。这个游戏可谓是非常的简单&#xff0c;容易上手&#xff0c;所以直到现在&…

番外篇 | 常用的激活函数汇总 | 20+种激活函数介绍及其公式、图像等

前言:Hello大家好,我是小哥谈。激活函数(Activation Function)是神经网络中的一种重要概念,用于控制神经网络中神经元的激活方式。在传统的神经网络中,激活函数被用来将神经元的输出从数值转换为可以被神经网络其他部分理解的非数值形式。激活函数通常被定义为神经元的输…

电能表预付费系统-标准传输规范(STS)(2)

5. 标准传输规格参考模型 5.1 一般付费电表功能参考图 In a single-device payment meter all the essential functions are located in a single enclosure as depicted in Figure 1 above, while in a multi-device payment meter it is possible for the TokenCarrierToMe…

Pagehelper获取total错误

前言 在使用若依框架的pagehelper时&#xff0c;给分页表设置数据的时候前端只收到了分页的那一页的数据&#xff0c;总记录数不符合要求 我想要的效果如下&#xff0c;可以实现分页&#xff0c;和显示总记录数 但是实际情况为 但是我的数据库有11条记录&#xff0c;他这里明…

【python学习】1-2 配置python系统环境变量

1.点击“我的电脑”右键&#xff0c;点击属性&#xff0c;点击“高级系统设置”&#xff0c;再点击环境变量。 2.选择“系统变量”中的Path后&#xff0c;点击编辑。 3.点击新建&#xff0c;添加如图两个路径&#xff0c;即是python安装的路径位置后&#xff0c;点击确定。

前端脚手架插件安装总结(axios,element-ui,bootstrap,echarts等)

1.打开前端项目终端 输入命令 vue ui 进入图形化界面 a.选择插件 b.选择添加插件 c.安装插件 d.完成安装