Spring——AOP前言(写一个小demo为了好学习AOP)

1.AOP的概念

1.1 AOP简单样例

我们来先通过一个例子来对AOP进行理解,这个例子就是有关Spring的事务的一个样例,有关Spring是怎么实现事务的,这个事务其实本质上就是对于我们代码的一个增强。废话不多说,上程序,请各位同学自行感悟。

<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.2.RELEASE</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.12</version></dependency><!--有单元测试的环境,Spring5版本,Junit4.12版本--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!--连接池--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.10</version></dependency><!--mysql驱动包--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version></dependency><!-- Spring整合Junit测试的jar包 --><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.0.2.RELEASE</version><scope>test</scope></dependency>
</dependencies>

        然后我们去看一眼我们的数据库,有没有一个Spring_db的表,(如果没有请参照上一篇博客第四小节应该有,创建数据库的sql语句)

        然后我们创建一个model的包,包中有创建一个Account的实体类

/*** JavaBean 实体类* 封装数据*/
public class Account {private int id;private String name;private double money;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getMoney() {return money;}public void setMoney(double money) {this.money = money;}public Account() {}public Account(int id, String name, double money) {this.id = id;this.name = name;this.money = money;}@Overridepublic String toString() {return "Account{" +"id=" + id +", name='" + name + '\'' +", money=" + money +'}';}
}

        然后创建Dao的包,写一个AccountDao的接口

/*** 持久层接口* 实现保存转账金额的方法*/
public interface AccountDao {public void saveAll (Account account);
}

        再写一个AccountDaoImpl的实现类

/*** 持久层的实现类*/
public class AccountDaoImpl implements AccountDao {@Overridepublic void saveAll(Account account) {//jdbc的程序System.out.println("持久层保存成功");}
}

        创建service包,再service包下写AccountService的接口

/*** 业务层的接口*/
public interface AccountService {public void saveAll(Account account, Account account1);
}

        然后写一个AccountServiceImpl的实现类

public class AccountServiceImpl implements AccountService{private AccountDao accountDao;public void setAccountDao(AccountDao accountDao) {this.accountDao = accountDao;}@Overridepublic void saveAll(Account account, Account account1) {System.out.println("业务层保存方法执行");accountDao.saveAll(account);accountDao.saveAll(account1);}
}

        写一个applicationcontext.xml的配置文件

<?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"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><bean id="accountService" class="com.qcby.service.AccountServiceImpl"><property name="accountDao" ref="accountDao"/></bean><bean id="accountDao" class="com.qcby.dao.AccountDaoImpl"/>
</beans>

        然后在test下创建com.qcby的包结构,写一个Test1的测试类

public class Test1 {@Testpublic void run1(){ApplicationContext ac=new ClassPathXmlApplicationContext("applicationcontext.xml");AccountService as=(AccountService) ac.getBean("accountService");Account account=new Account(1,"熊大",10000.00);Account account1=new Account(2, "熊二",9999.99);as.saveAll(account,account1);}
}

        然后我们去写持久层,在写持久层的时候,我们首先要有一个工具类

import com.alibaba.druid.pool.DruidDataSource;
import java.sql.Connection;
public class TxUtils {//静态的类属性 连接池对象public static DruidDataSource ds=null;//使用ThreadLocal存储当前线程中的connection对象private static ThreadLocal<Connection> threadLocal=new ThreadLocal<>();//在静态代码中创建数据库连接池static {try {//通过代码创建druid数据库连接池ds=new DruidDataSource();ds.setDriverClassName("com.mysql.jdbc.Driver");ds.setUrl("jdbc:mysql///spring_db");ds.setUsername("root");ds.setPassword("2020");}catch (Exception e){throw new ExceptionInInitializerError(e);}}public static Connection getConnection() throws Exception{Connection conn=threadLocal.get();if (conn==null){//从数据源获取数据连接connconn= getDataSource().getConnection();//把conn对象存储到当前线程threadLocal.set(conn);}return conn;}/*** 开启事务*/public static void startTransaction() {try{Connection conn=threadLocal.get();if (conn==null){conn=getConnection();threadLocal.set(conn);}//开启事务conn.setAutoCommit(false);} catch (Exception e) {throw new RuntimeException(e);}}/*** 回滚事务*/public static void rollback(){try{Connection conn=threadLocal.get();if (conn!=null){conn.rollback();}} catch (Exception e) {throw new RuntimeException(e);}}/*** 提交事务*/public static void commit(){try{Connection conn=threadLocal.get();if (conn!=null){conn.commit();}} catch (Exception e) {throw new RuntimeException(e);}}/*** 关闭数据库连接,这里的关闭指的是把数据库连接还给数据库连接池*/public static void close(){try{Connection conn=threadLocal.get();if (conn!=null){conn.close();threadLocal.remove();}} catch (Exception e) {throw new RuntimeException(e);}}/*** 获取数据*/public static DruidDataSource getDataSource(){return ds;}
}

        这个工具类有几个值得注意的点我们来看一下,第一个,就是我们在类中设置了一个静态的类的属性 ,可以用threadLocal存储这对象,达到只用一个连接的目的,还有就是我们把close的方法写到这个工具类里了,因为我们不能在持久层关闭连接,我们可以从业务层进行关闭。

        然后我们再回到持久层,写连接

public class AccountDaoImpl implements AccountDao {@Overridepublic void saveAll(Account account) throws Exception {//jdbc的连接数据库进行保存数据//获取连接加载驱动 保证事务System.out.println("持久层保存操作!!!");//把数据存到数据库之中//获取连接Connection conn = TxUtils.getConnection();//编写sqlString sql="insert into account values(null,?,?)";//预编译SQLPreparedStatement statement= conn.prepareStatement(sql);//设置值statement.setString(1,account.getName());statement.setDouble(1,account.getMoney());//执行操作statement.executeUpdate();//关闭资源,(conn的关闭不能写在持久层)statement.close();}
}

        这时候我们的业务实现层肯定会有一个异常,跑出去就行了。

        然后运行一下test测试

        那么我们接下来模拟这么一个场景,就是插入第一条数据后,在插入第二条数据第二条数据时模拟一个异常。

try {accountDao.saveAll(account);int i=10/0;accountDao.saveAll(account1);
} catch (SQLException e) {e.printStackTrace();
}

        这时候就会有一个除零的异常

        按照测试代码,我们应该加入小明和小红两条数据,但是加入小明之后我们就出现异常就终止执行了,就没法插入小红的这条数据了。

@Test
public void run(){ApplicationContext ac=new ClassPathXmlApplicationContext("ApplicationContext.xml");AccountService accountService =(AccountService) ac.getBean("accountService");Account account=new Account(null,"小明",1000.0);Account account1=new Account(null,"小红",1000.0);accountService.saveAll(account,account1);
}

        然后我们去业务层中,加上事务的管理

public void saveAll(Account account, Account account1) {System.out.println("业务层方法执行了");//开启事务 conn是一个连接TxUtils.startTransaction();try {accountDao.saveAll(account);int i=10/0;accountDao.saveAll(account1);//提交事务TxUtils.commit();} catch (SQLException e) {e.printStackTrace();//回滚事务TxUtils.rollback();}}

        然后我们把那个除零的异常语句给注释掉,我们执行以下看一下效果

        能加进来

        然后我们去把那个异常的注释给解掉,然后再来运行看一下效果。

        数据库中就没有添加进去小明。说明进行了事务的回滚。

        然后如果我们要在业务写一个转账的方法,也需要些开启事务,提交事务,还有回滚事务,就比较麻烦了。

        就是加事务这个代码,我们会发现与业务本身的逻辑没有关系,就是需要在业务逻辑执行前开启事务,执行完提交事务,要是出现问题就要回滚事务。这个事务就式对我们代码的一个增强。

        我们如果要做到不在改源代码的情况下实现事务,我们实现的思路有哪些?

                jdk动态代理

                静态代理

                父子类(父类做业务逻辑,子类做增强)

                装饰者模式

        AOP的底层就是动态代理

1.2 jdk动态代理类

上面说了,我们用jdk的动态代理的目的就是实现代码的增强。

我们首先就要有一个代理的类

代理类中有一个获取代理对象的方法,这个方法有三个参数,类的加载器,代理对象所实现的接口,回调函数,然后就在invoke方法中写我们对原代码的增强 method让目标对象执行方法(反射调用)。

public class JdkProxy {//获取代理对象的方法//增强目标对象的方法public static Object getProxy(AccountService accountService){/*** 使用jdk的动态代理生成代理对象* Proxy一个有关反射的一个类 三个参数 类的加载器 代理对象所实现的接口 回调函数 并把对象给返回* 通过Java反射的一个类,里面有一个生成代理对象的方法* 静态代理和动态代理的区别 一个是继承,一个是基于接口实现的让目标对象执行方法(反射调用),然后*/Object proxy=Proxy.newProxyInstance(JdkProxy.class.getClassLoader(), accountService.getClass().getInterfaces(), new InvocationHandler() {///*** 调用代理对象的方法,invoke方法就会执行* method就是对目标对象方法* @param proxy* @param method* @param args* @return* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object result=null;try{//事务处理,开启事务TxUtils.startTransaction();//让目标对象执行方法(反射调用)method.invoke(accountService,args);//提交事务TxUtils.commit();}catch (Exception e){e.printStackTrace();//回滚事务TxUtils.rollback();}finally {TxUtils.close();}return proxy;}});return null;}

        然后在测试方法中这么使用就可以了

@Testpublic void run(){ApplicationContext ac=new ClassPathXmlApplicationContext("ApplicationContext.xml");AccountService accountService =(AccountService) ac.getBean("accountService");Account account=new Account(null,"小明",1000.0);Account account1=new Account(null,"小红",1000.0);
//        accountService.saveAll(account,account1);//增强的代理对象来执行Object proxyobj= JdkProxy.getProxy(accountService);//转型AccountService proxy=(AccountService) proxyobj;//调用逻辑proxy.saveAll(account,account1);}

        然后我们要是想看到这个方法的相互的调用的过程的话就打个断点debug走一下就明白了

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

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

相关文章

SOAP @WebService WSDL

SOAP & WebService & WSDL SOAP&#xff08;Simple Object Access Protocol&#xff09;WebService&#xff08;Web服务&#xff09;WSDL&#xff08;Web Services Description Language&#xff09; SOAP&#xff08;Simple Object Access Protocol&#xff09; **是一…

Ciallo~(∠・ω・ )⌒☆第十七篇 Ubuntu基础使用 其一

Ubuntu是一种基于Linux的操作系统&#xff0c;它是开源的、免费的&#xff0c;并且具有广泛的用户群体。 基本文件操作&#xff1a;Ubuntu使用命令行工具来进行文件操作。以下是一些常用的命令&#xff1a; 切换到用户主目录&#xff1a; cd ~ 切换到上级目录&#xff1a; cd .…

解密键盘输入:探索设备控制器的奥秘

流程初探 键盘是我们最常用的输入硬件设备之一。作为程序员&#xff0c;你知道当我们敲击键盘上的字母"A"时&#xff0c;操作系统会发生什么吗&#xff1f;下面我将简要介绍整个过程&#xff0c;以便你更容易理解为什么需要这些组件。 首先&#xff0c;让我们来看看…

Linux下 vim的用法

目录 前言 一、初始Vim 二、使用Vim 1.1命令模式 2.1底行模式 3.1插入模式 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 本篇文章会介绍vim的基本用法和为什么我们要学习vim。 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供…

PumpkinRaising靶机

端口扫描 目录扫描 访问80端口&#xff0c; 在页面上面发现提到了一个Jack&#xff0c;可能是一个用户名 f12查看源码 找到一个页面 拼接访问 查看源码 发现一个注释 解密 是一个目录 /scripts/spy.pcap 访问&#xff0c;自动下载了一个文件 wireshark打开流量包 找到第一个s…

IndexError: list index out of range | 列表索引超出范围完美解决方法

IndexError: list index out of range &#x1f4c9; | 列表索引超出范围完美解决方法 IndexError: list index out of range &#x1f4c9; | 列表索引超出范围完美解决方法摘要 &#x1f4c4;引言 &#x1f680; 什么是 IndexError: list index out of range&#xff1f;&…

vba代码插入折线图

xqwertyy52152018139hi303533312015 Sub test()Set sht1 ThisWorkbook.Worksheets("示例")x sht1.Range("I1").Lefty sht1.Range("I1").Topw sht1.Range("N15").Width * 15h sht1.Range("N15").Height * 25Set ch1 s…

路径规划 | 基于改进蝙蝠算法的多无人机路径规划(Matlab)

目录 效果一览基本介绍程序设计参考文献 效果一览 基本介绍 路径规划 | 基于改进蝙蝠算法的多无人机路径规划&#xff08;Matlab&#xff09; 蝙蝠算法&#xff08;Bat Algorithm&#xff09;是一种基于自然界蝙蝠群体行为的启发式优化算法。该算法模拟了蝙蝠在寻找食物时的行为…

Github Copilot 使用技巧

&#x1f3af;目标读者 本文不包含如何安装 Github Copilot本文介绍了 Github Copilot 使用方法和一些技巧 本人已经使用 Github Copilot 2 年了&#xff0c;交了 3 次年费&#xff0c;每年 100$ 着实心痛&#xff0c;但是用着确实爽歪歪 但是感觉一直只用了一小部分功能&am…

技术证书认证-附考试答案-AIGC与大模型通识-英特尔大湾区科技创新中心证书认证

目录 课程简介 面向人群 考核步骤 试题答案 知孤云出岫主页 课程以及考试链接&#xff1a;AIGC与大模型通识 - 英特尔大湾区科技创新中心 【英特尔大湾区科技创新中心】公益新课《AIGC与大模型通识》上线官网&#xff01;首期结业认证进行中&#xff0c;提升AI应用技能&…

顶顶通呼叫中心中间件-通话之前录音配置方法(mod_cti基于FreeSWITCH)

顶顶通呼叫中心中间件-通话之前录音配置方法(mod_cti基于FreeSWITCH) 1、修改配置文件 点击配置文件 -> 点击vars -> 根据图中配置 -> 点击提交XML ->重新启动freeswitch 修改成true就是电话接通开始录音&#xff0c;修改成false就是通话之前开始录音。 <!--应…

微信小程序免费《短视频去水印》

分享一个uniapp开发的微信小程序免费《短视频去水印》小程序 <template><view class"content"><view class"area-wrap"><textarea name"" v-model"state.content" maxlength"800" id"" cols…

~Keepalived高可用集群~

一、Keepalived简介 是一个用于实现高可用性的解决方案&#xff0c;它主要应用于云主机的主备切换&#xff0c;以达到高可用性&#xff08;HA&#xff09;的目的。当主服务器发生故障无法对外提供服务时&#xff0c;动态将虚拟IP切换到备服务器&#xff0c;继续对外提供服务&a…

宏定义———C语言

*符号代表全部的意思*.i代表的是全部的点i文件 宏定义 &#xff1a; 1.定义&#xff1a; #define 宏名 常量功能&#xff1a;宏名代替常量&#xff0c;宏名要求全大写且见名知义 2.示例&#xff1a; #include <stdio.h> #define PI 3.14 #define Q 4 #define P QQi…

虚幻5|给武器添加碰撞检测与伤害

本章内容衔接上两章&#xff0c;需要完成上两章才能用本章内容 虚幻5|角色武器装备的数据库学习&#xff08;不只是用来装备武器&#xff0c;甚至是角色切换也很可能用到&#xff09;-CSDN博客虚幻5|普通攻击&#xff0c;使用接口更方便-CSDN博客 如有疑问&#xff0c;可访问…

利用EditPlus进行Json数据格式化

利用EditPlus进行Json数据格式化 git下载地址&#xff1a;https://github.com/michael-deve/CommonData-EditPlusTools.git (安装过editplus的直接将里面的json.js文件复制走就行) 命令&#xff1a;Cscript.exe /nologo “D:\Program Files (x86)\EditPlus 3\json.js” D:\P…

简单的敏感词提示功能

简单的敏感词提示功能 1. 需求 公司现在接到通知&#xff0c;部分接口的部分手动输入字段&#xff0c;需要新增敏感词报红提示&#xff0c;敏感词汇现在应该是7000多个左右&#xff0c;需要我们提供一个敏感词校验接口&#xff0c;如果前端输入敏感词&#xff0c;则前端提示出…

【网络】UDP回显服务器和客户端的构造,以及连接流程

文章目录 回显服务器&#xff08;Echo Server&#xff09;0. 构造方法1. 接收请求2. 根据请求计算响应3. 将响应写回客户端4. 完整代码 客户端&#xff08;Echo Client&#xff09;0. 构造方法1. 读取输入2. 构造一个 UDP 请求3. 从服务器读取响应4. 完整代码 服务器与客户端连…

【自动化测试】技术交流论坛

前言 本篇使用Selenium3Junit5对个人技术交流论坛进行简单的自动化测试&#xff0c;如有错误&#xff0c;请在评论区指正&#xff0c;让我们一起交流&#xff0c;共同进步&#xff01; 文章目录 前言1. 项目基础描述2. 编写手工测试用例3. 测试用例转自动化测试用例3.1 前置准…

NVR方案背景与产品介绍与构建一套完整的NVR产品解决方案

一、NVR和DVR 在视频监控领域&#xff0c;DVR和NVR是两种常用的录像技术。它们在系统结构、视频处理、存储和访问方式等方面存在明显的区别。&#xff0c;但都在视频监控中扮演着重要的角色。首先来了解它们的区别和特点&#xff0c;这有助于在选择合适的设备时做出明智的决策…