SpringAOP技术

目录

一、概念引入

1.引入依赖

2.工具类

3.实体类

4.持久层实现类

5.业务层实现类

6.配置文件

7.测试类

8.运行

查看数据库:

9.现在如果转账过程中出现异常

AccountServiceImpl(模拟异常)

再运行:

查看数据库: 

10.现在做事务管理

AccountServiceImpl(事务管理)

运行

查看数据库:

11.生成代理对象

代理对象:

业务层实现类

查看数据库:

二、AOP的概述

1.什么是AOP的技术

2.AOP的优势

3.AOP的底层原理

三、Spring的AOP技术-配置文件方式

1.引入依赖

2.spring的配置文件

3.写具体的接口和实现类

4.将目标类配置到spring中

5.定义切面类

6.在配置文件中定义切面类

7.在配置文件中完成AOP的配置

8.测试类

9.运行结果

四、用AOP实现事务管理(转账) 

1.实体类

2.工具类

3.业务层

4.持久层

5.切面类

6.配置文件

7.测试类

8.运行

9.查看数据库

10.现在模拟异常

查看数据库:​编辑

11.切面类中加一个环绕通知的方法

切面类

配置文件

五、Spring的AOP技术--注解方式

1.半注解

(1)业务层

(2)切面类

(3)配置文件中开启自动代理,扫描包

(4)测试类

(5)运行

(6)通知类型的注解

2.纯注解

(1)配置类

(2)测试类



一、概念引入

入门案例(概念引入)

1.引入依赖

<dependencies><!--spring的核心依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.2.RELEASE</version></dependency><!-- https://mvnrepository.com/artifact/commons-logging/commons-logging --><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency><!-- https://mvnrepository.com/artifact/log4j/log4j --><!--日志--><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.12</version></dependency><!--测试--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!--连接池 alibaba的--><!-- https://mvnrepository.com/artifact/com.alibaba/druid --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.10</version></dependency><!--mysql驱动--><!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version></dependency><!--spring-test--><!-- https://mvnrepository.com/artifact/org.springframework/spring-test --><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.0.2.RELEASE</version><scope>test</scope></dependency>
</dependencies>

2.工具类

package com.qcby.utils;import java.sql.Connection;
import java.sql.SQLException;import javax.sql.DataSource;import com.alibaba.druid.pool.DruidDataSource;/*** 事务的工具类*/
public class TxUtils {private static DruidDataSource ds = null;// 使用ThreadLocal存储当前线程中的Connection对象private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();// 在静态代码块中创建数据库连接池---static代码块static {try {// 通过代码创建C3P0数据库连接池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);}}/*** @Method: getConnection* @Description: 从数据源中获取数据库连接* @Anthor:* @return Connection* @throws SQLException*/public static Connection getConnection() throws SQLException {// 从当前线程中获取ConnectionConnection conn = threadLocal.get();if (conn == null) {// 从数据源中获取数据库连接conn = getDataSource().getConnection();// 将conn绑定到当前线程threadLocal.set(conn);}return conn;}/*** @Method: startTransaction* @Description: 开启事务* @Anthor:**///jdbc开启事务靠链接开启public static void startTransaction() {try {Connection conn = threadLocal.get();if (conn == null) {conn = getConnection();// 把 conn绑定到当前线程上threadLocal.set(conn);}// 开启事务conn.setAutoCommit(false);} catch (Exception e) {throw new RuntimeException(e);}}/*** @Method: rollback* @Description:回滚事务* @Anthor:*/public static void rollback() {try {// 从当前线程中获取ConnectionConnection conn = threadLocal.get();if (conn != null) {// 回滚事务conn.rollback();}} catch (Exception e) {throw new RuntimeException(e);}}/*** @Method: commit* @Description:提交事务* @Anthor:*/public static void commit() {try {// 从当前线程中获取ConnectionConnection conn = threadLocal.get();if (conn != null) {// 提交事务conn.commit();}} catch (Exception e) {throw new RuntimeException(e);}}/*** @Method: close* @Description:关闭数据库连接(注意,并不是真的关闭,而是把连接还给数据库连接池)* @Anthor:**/public static void close() {try {// 从当前线程中获取ConnectionConnection conn = threadLocal.get();//从连接池拿到链接if (conn != null) {conn.close();// 解除当前线程上绑定connthreadLocal.remove();}} catch (Exception e) {throw new RuntimeException(e);}}/*** @Method: getDataSource* @Description: 获取数据源* @Anthor:* @return DataSource*/public static DataSource getDataSource() {// 从数据源中获取数据库连接return ds;}}

3.实体类

package com.qcby.model;import java.io.Serializable;public class Account implements Serializable {private Integer id;private String name;private Double money;public Account() {}public Account(Integer id, String name, Double money) {this.id = id;this.name = name;this.money = money;}public Integer getId() {return id;}public void setId(Integer 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;}@Overridepublic String toString() {return "Account{" +"id=" + id +", name='" + name + '\'' +", money=" + money +'}';}
}

4.持久层实现类

package com.qcby.dao.impl;import com.qcby.dao.AccountDao;
import com.qcby.pojo.Account;
import com.qcby.utils.TxUtils;import javax.sql.DataSource;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import com.mysql.jdbc.Driver;public class AccountDaoImpl implements AccountDao {//实现两个账户的转账@Overridepublic void updateSaveAll(Account account){Connection connection=null;PreparedStatement stmt=null;try{//获取连接connection = TxUtils.getConnection();String sql = "update  account set money = money + ? where name = ?";stmt = connection.prepareStatement(sql);stmt.setDouble(1, account.getMoney());stmt.setString(2, account.getName());// 查询int result = stmt.executeUpdate();System.out.println("修改影响了"+result+"行数据!!");}catch(Exception e){try {stmt.close();//connection.close();} catch (SQLException e1) {e1.printStackTrace();}}}
}

5.业务层实现类

package com.qcby.service.impl;import com.qcby.dao.AccountDao;
import com.qcby.model.Account;
import com.qcby.service.AccountService;public class AccountServiceImpl implements AccountService {private AccountDao accountDao;public void setAccountDao(AccountDao accountDao) {this.accountDao = accountDao;}@Overridepublic void updateSaveAll(Account account1, Account account2) {//保存账号1accountDao.updateSaveAll(account1);//保存账号2accountDao.updateSaveAll(account2);}
}

6.配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!--配置持久层和业务层--><bean id="accountService" class="com.qcby.service.impl.AccountServiceImpl"><property name="accountDao" ref="accountDao"></property></bean><bean id="accountDao" class="com.qcby.dao.impl.AccountDaoImpl"></bean></beans>

7.测试类

package com.qcby;import com.qcby.model.Account;
import com.qcby.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class demo {@Autowiredprivate AccountService accountService;@Testpublic void run(){Account account1=new Account(null,"aaa",500.00);Account account2=new Account(null,"bbb",-500.00);accountService.updateSaveAll(account1,account2);}
}

8.运行

查看数据库:

之前:

现在:

9.现在如果转账过程中出现异常

AccountServiceImpl(模拟异常)

package com.qcby.service.impl;import com.qcby.dao.AccountDao;
import com.qcby.model.Account;
import com.qcby.service.AccountService;public class AccountServiceImpl implements AccountService {private AccountDao accountDao;public void setAccountDao(AccountDao accountDao) {this.accountDao = accountDao;}@Overridepublic void updateSaveAll(Account account1, Account account2) {//保存账号1accountDao.updateSaveAll(account1);//模拟异常int a=1/0;//保存账号2accountDao.updateSaveAll(account2);}
}

再运行:

查看数据库: 

只有第一条数据变了,出现错误

10.现在做事务管理

AccountServiceImpl(事务管理)

package com.qcby.service.impl;import com.qcby.dao.AccountDao;
import com.qcby.model.Account;
import com.qcby.service.AccountService;
import com.qcby.utils.TxUtils;public class AccountServiceImpl implements AccountService {private AccountDao accountDao;public void setAccountDao(AccountDao accountDao) {this.accountDao = accountDao;}@Overridepublic void updateSaveAll(Account account1, Account account2) {//在这里进行事务管理try {//开启事务TxUtils.startTransaction();//保存账号1accountDao.updateSaveAll(account1);//模拟异常int a=1/0;//保存账号2accountDao.updateSaveAll(account2);//提交事务TxUtils.commit();}catch (Exception e){e.printStackTrace();//回滚事务TxUtils.rollback();}finally {//关闭资源TxUtils.close();}}
}

这里仍然有异常,但是进行了事务管理,

运行

查看数据库:

原来:

 现在:

 回滚了

11.生成代理对象

代理对象:

package com.qcby.proxy;import com.qcby.service.AccountService;
import com.qcby.utils.TxUtils;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*
* 传入目标对象,生成该对象的代理对象,返回。对目标对象的方法进行增强
* */
public class JdkProxy {//获取代理对象public static Object getProxy(AccountService accountService){/** 使用JDK动态代理生成代理对象* 第一个参数:类的加载其* 第二个参数:当前传入的对象实现了哪些接口要字节码的对象* 第三个参数:回调函数* */Object proxy = Proxy.newProxyInstance(JdkProxy.class.getClassLoader(), accountService.getClass().getInterfaces(), new InvocationHandler(){public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object result = null;try {//开启事务TxUtils.startTransaction();result = method.invoke(accountService,args);//提交事务TxUtils.commit();}catch (Exception e){e.printStackTrace();//回滚TxUtils.rollback();}finally {TxUtils.close();}return result;}});return proxy;}
}

业务层实现类

(有异常)(之前在这里写的事务就不用写了)

package com.qcby.service.impl;import com.qcby.dao.AccountDao;
import com.qcby.pojo.Account;
import com.qcby.service.AccountService;
import com.qcby.utils.TxUtils;import java.sql.SQLException;public class AccountServiceImpl implements AccountService {private AccountDao accountDao;//因为这里是空指针,所以要有set方法public void setAccountDao(AccountDao accountDao) {this.accountDao = accountDao;}public void updateSaveAll(Account account1, Account account2){try {//保存账号1accountDao.updateSaveAll(account1);//模拟异常int a=1/0;//保存账号2accountDao.updateSaveAll(account2);}catch (Exception e){e.printStackTrace();}}
}

测试类

(多了一个run2())

package com.qcby.springAopTest;import com.qcby.pojo.Account;
import com.qcby.proxy.JdkProxy;
import com.qcby.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {@Autowiredprivate AccountService accountService;@Testpublic void run1(){Account account1=new Account(null,"aaa",500.00);Account account2=new Account(null,"bbb",-500.00);accountService.updateSaveAll(account1,account2);}@Testpublic void run2(){Account account1=new Account(null,"aaa",500.00);Account account2=new Account(null,"bbb",-500.00);//生成代理对象Object proxyobj= JdkProxy.getProxy(accountService);AccountService proxy=(AccountService)proxyobj;proxy.updateSaveAll(account1,account2);}
}

运行:

查看数据库:

原来:

现在:

二、AOP的概述

1.什么是AOP的技术

AOP是Aspect Oriented Programming的缩写,意为:面向切面编程,它是通过预编译的方式或者运行期动态代理实现程序功能的统一维护的一种技术

2.AOP的优势

可以在不修改源代码的情况下对已有方法进行增强

(1)减少重复代码

(2)提高开发效率

(3)维护方便

3.AOP的底层原理

JDK的动态代理

三、Spring的AOP技术-配置文件方式

1.引入依赖

<dependencies><!--spring的核心依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.2.RELEASE</version></dependency><!-- https://mvnrepository.com/artifact/commons-logging/commons-logging --><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><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.0.2.RELEASE</version><scope>test</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- https://mvnrepository.com/artifact/aopalliance/aopalliance --><dependency><groupId>aopalliance</groupId><artifactId>aopalliance</artifactId><version>1.0</version></dependency><!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects --><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.0.2.RELEASE</version></dependency><!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.3</version></dependency>
</dependencies>

2.spring的配置文件

引入具体的AOP的schema约束

<?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.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"></beans>

3.写具体的接口和实现类

接口

package com.qcby.service;public interface UserService {public void save();
}

实现类

package com.qcby.service.impl;import com.qcby.service.UserService;/*
* 业务层实现类
* 实现AOP切面增强
* */
public class UserServiceImpl implements UserService {//目标对象目标方法@Overridepublic void save() {System.out.println("业务层:保存用户....");}
}

4.将目标类配置到spring中

<bean id="userService" class="com.qcby.service.impl.UserServiceImpl"></bean>

5.定义切面类

现在他就是一个普通的类,里面有一个普通的方法,所以要在配置文件里配置

/*
* 自定义切面类 = 切入点(表达式) + 通知(增强的代码)
* */
public class MyXmlAspect {//发送手机短信...public void log(){System.out.println("增强的方法执行了....");}
}

6.在配置文件中定义切面类

这时候是一个被spring管理的类,这句话只是把它交给spring去管理

<bean id="myAspect" class="com.qcby.aspect.MyXmlAspect"></bean>

7.在配置文件中完成AOP的配置

<!--配置AOP的增强-->
<aop:config><!--配置切面=切入点+通知 组成--><!-- 到这一步代表MyXmlAspect这个类已经是是一个切面类了,但是还没有通知 --><aop:aspect ref="myXmlAspect"><!--前置通知:userServiceImpl的save方法执行前会增强--> <!-- 这里是对方法进行增强 --><aop:before method="log" pointcut="execution(public void com.qcby.service.impl.UserServiceImpl.save())"/><!--后置通知--><aop:after-returning method="log" pointcut="execution(public void com.qcby.service.impl.UserServiceImpl.save*(..))"/><!--异常--><aop:after-throwing method="log" pointcut="execution(public void com.qcby.service.impl.UserServiceImpl.save*(..))"/></aop:aspect>
</aop:config>
切入点表达式(前置):(这个是只对save()方法进行增强,如果有一个save1()方法,最后的运行结果只会输出业务层:保护用户……)
pointcut="execution(public void com.qcby.service.impl.UserServiceImpl.save())"
<!--后置通知-->
<aop:after-returning method="log" pointcut="execution(public void com.qcby.service.impl.UserServiceImpl.save*(..))"/>
<!--异常通知-->
<aop:after-throwing method="log" pointcut="execution(* com.qcby.*.*.*ServiceImpl.save*(..))"/>
表达式: public可以不写,void这里必须写,可以写*包名+类名  不能省略不写,可以写*  UserserviceImpl AccountserviceImpl方法名  save() 可以写*参数列表   (..) 表示任意类型和个数的参数
比较通用的表达式:execution(public * cn.tx.*.*ServiceImpl.*(..))

8.测试类

import com.qcby.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {@Autowiredprivate UserService userService;@Testpublic void run1(){userService.save();}
}

9.运行结果

前置和后置都配置了,所以开始输出一次  增强的方法执行了...  ,最后再输出一次

四、用AOP实现事务管理(转账) 

在切面类里写四个方法(开启、提交、关闭、回滚)

开始的时候开启事务,完成提交事务,最后的时候关闭资源,有异常回滚

1.实体类

import java.io.Serializable;public class Account implements Serializable {private Integer id;private String name;private Double money;public Account() {}public Account(Integer id, String name, Double money) {this.id = id;this.name = name;this.money = money;}public Integer getId() {return id;}public void setId(Integer 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;}@Overridepublic String toString() {return "Account{" +"id=" + id +", name='" + name + '\'' +", money=" + money +'}';}
}

2.工具类

import com.alibaba.druid.pool.DruidDataSource;import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;/*** 事务的工具类*/
public class TxUtils {private static DruidDataSource ds = null;// 使用ThreadLocal存储当前线程中的Connection对象private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();// 在静态代码块中创建数据库连接池---static代码块static {try {// 通过代码创建C3P0数据库连接池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);}}/*** @Method: getConnection* @Description: 从数据源中获取数据库连接* @Anthor:* @return Connection* @throws SQLException*/public static Connection getConnection() throws SQLException {// 从当前线程中获取ConnectionConnection conn = threadLocal.get();if (conn == null) {// 从数据源中获取数据库连接conn = getDataSource().getConnection();// 将conn绑定到当前线程threadLocal.set(conn);}return conn;}/*** @Method: startTransaction* @Description: 开启事务* @Anthor:**///jdbc开启事务靠链接开启public static void startTransaction() {try {Connection conn = threadLocal.get();if (conn == null) {conn = getConnection();// 把 conn绑定到当前线程上threadLocal.set(conn);}// 开启事务conn.setAutoCommit(false);} catch (Exception e) {throw new RuntimeException(e);}}/*** @Method: rollback* @Description:回滚事务* @Anthor:*/public static void rollback() {try {// 从当前线程中获取ConnectionConnection conn = threadLocal.get();if (conn != null) {// 回滚事务conn.rollback();}} catch (Exception e) {throw new RuntimeException(e);}}/*** @Method: commit* @Description:提交事务* @Anthor:*/public static void commit() {try {// 从当前线程中获取ConnectionConnection conn = threadLocal.get();if (conn != null) {// 提交事务conn.commit();}} catch (Exception e) {throw new RuntimeException(e);}}/*** @Method: close* @Description:关闭数据库连接(注意,并不是真的关闭,而是把连接还给数据库连接池)* @Anthor:**/public static void close() {try {// 从当前线程中获取ConnectionConnection conn = threadLocal.get();//从连接池拿到链接if (conn != null) {conn.close();// 解除当前线程上绑定connthreadLocal.remove();}} catch (Exception e) {throw new RuntimeException(e);}}/*** @Method: getDataSource* @Description: 获取数据源* @Anthor:* @return DataSource*/public static DataSource getDataSource() {// 从数据源中获取数据库连接return ds;}}

3.业务层

import com.qcby.dao.AccountDao;
import com.qcby.pojo.Account;
import com.qcby.service.AccountService;public class AccountServiceImpl implements AccountService {private AccountDao accountDao;public void setAccountDao(AccountDao accountDao) {this.accountDao = accountDao;}@Overridepublic void updateSaveAll(Account account1, Account account2) {//账号1accountDao.updateSaveAll(account1);//模拟异常//int a=1/0;//账号2accountDao.updateSaveAll(account2);}
}

4.持久层

import com.qcby.dao.AccountDao;
import com.qcby.pojo.Account;
import com.qcby.utils.TxUtils;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;public class AccountDaoImpl implements AccountDao {@Overridepublic void updateSaveAll(Account account) {Connection connection = null;PreparedStatement stmt=null;try {connection=TxUtils.getConnection();String sql="update  account set money = money + ? where name = ?";stmt=connection.prepareStatement(sql);stmt.setDouble(1,account.getMoney());stmt.setString(2,account.getName());int num=stmt.executeUpdate();System.out.println("修改了"+num+"条数据");} catch (SQLException e) {try {stmt.close();} catch (SQLException ex) {ex.printStackTrace();}e.printStackTrace();}}
}

5.切面类

import com.qcby.utils.TxUtils;public class MyAspect {public void before(){System.out.println("转账之前开启事务");TxUtils.startTransaction();}public void afterThrowing(){System.out.println("转账异常,回滚事务");TxUtils.rollback();}public void after(){System.out.println("转账之后,关闭资源");TxUtils.close();}public void afterReturning(){System.out.println("转账成功,提交事务");TxUtils.commit();}}J

6.配置文件

<?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.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><bean id="accountService" class="com.qcby.service.impl.AccountServiceImpl"><property name="accountDao" ref="accountDao"></property></bean><bean id="accountDao" class="com.qcby.dao.impl.AccountDaoImpl"/><bean id="myAspect" class="com.qcby.aspect.MyAspect"/><!--配置AOP--><aop:config><aop:aspect ref="myAspect"><aop:before method="before" pointcut="execution(* com.qcby.service.impl.AccountServiceImpl.updateSaveAll(..))"></aop:before><aop:after-throwing method="afterThrowing" pointcut="execution(* com.qcby.service.impl.AccountServiceImpl.updateSaveAll(..))"></aop:after-throwing><aop:after-returning method="afterReturning" pointcut="execution(* com.qcby.service.impl.AccountServiceImpl.updateSaveAll(..))"></aop:after-returning><aop:after method="after" pointcut="execution(* com.qcby.service.impl.AccountServiceImpl.updateSaveAll(..))"></aop:after></aop:aspect></aop:config></beans>

7.测试类

import com.qcby.pojo.Account;
import com.qcby.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {@Autowiredprivate AccountService accountService;@Testpublic void run(){Account account1=new Account(1,"aaa",500.0);Account account2=new Account(2,"bbb",-500.0);accountService.updateSaveAll(account1,account2);}
}

8.运行

9.查看数据库

(原来是1500  1500)

10.现在模拟异常

查看数据库:

回滚了,数据没变

11.切面类中加一个环绕通知的方法

环绕通知包含所有的通知

切面类

/*** 环绕通知* 问题:目标对象的方法没有执行,需要手动执行目标对象的方法。*/
public void aroundLog(ProceedingJoinPoint point){try {System.out.println("增强的方法执行了...");TxUtils.startTransaction();// 让目标对象的方法去执行point.proceed();System.out.println("提交增强");TxUtils.commit();} catch (Throwable throwable) {throwable.printStackTrace();System.out.println("异常增强");TxUtils.rollback();}finally {System.out.println("关闭增强");TxUtils.close();}}

配置文件

配置AOP那部分改成下面这个

<!--配置AOP-->
<aop:config><!--配置切面--><aop:aspect ref="myAspect"><aop:around method="aroundLog" pointcut="execution(* com.qcby.service.impl.AccountServiceImpl.updateSaveAll(..))"></aop:around></aop:aspect>
</aop:config>

五、Spring的AOP技术--注解方式

1.半注解

配置文件中只有开启自动代理和扫描包

(1)业务层

import com.qcby.service.UserService;
import org.springframework.stereotype.Service;@Service
public class UserServiceImpl implements UserService {@Overridepublic void save() {System.out.println("业务层:保存用户....");}
}

(2)切面类

@Component //把该类交给IOC去管理
@Aspect //声明是切面类 == <aop:aspect ref="myXmlAspect">
public class MyXmlAspect {//发送手机短信...@Before(value = "execution(public void com.qcby.service.impl.UserServiceImpl.save(..))")//切面的表达式public void log(){System.out.println("增强的方法执行了....");}
}

(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.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!--扫描包--><context:component-scan base-package="com.qcby"></context:component-scan><!--开启自动代理--><aop:aspectj-autoproxy></aop:aspectj-autoproxy></beans>

(4)测试类

import com.qcby.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {@Autowiredprivate UserService userService;@Testpublic void run1(){userService.save();}
}

(5)运行

(6)通知类型的注解

 @Before -- 前置通知

​ @AfterReturing -- 后置通知

​ @Around -- 环绕通知

​ @After -- 最终通知

​ @AfterThrowing -- 异常抛出通知

2.纯注解

把配置文件换成了配置类,业务层、切面类和半注解的相同

(1)配置类

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;@Configuration //配置类
@ComponentScan(value = "com.qcby.service.impl") //扫描包结构
@EnableAspectJAutoProxy //开启自动代理 == <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
public class SpringConfig {
}

(2)测试类

import com.qcby.config.SpringConfig;
import com.qcby.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfig.class})
public class AopTest2 {@Autowiredprivate UserService userService;@Testpublic void run(){userService.save();}
}

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

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

相关文章

从富文本窥探苹果的代码秘密

从富文本窥探苹果的代码秘密 背景 在我们的业务场景下&#xff0c;为突出诸如 “利益点”和“利率” 等特性以推动订单成交&#xff0c;引入了 “富文本” 这一概念。富文本具备丰富格式的文本展示与编辑功能。然而&#xff0c;恰是由于富文本具有 “多样式”“复杂排版” 等特…

恒创科技:如何知道一台服务器能承载多少用户?

如何知道一台服务器能承载多少用户?其实服务器承载能力并非一个单一固定的数值&#xff0c;而是由多种因素共同决定的动态指标&#xff0c;所以想知道能承载的访客量&#xff0c;我们要先搞清楚究竟有哪些因素会影响服务器承载访客的数量。 影响服务器承载访客的因素&#xff…

vue3配置eslint代码规划和prettier自动格式化

eslint 安装依赖&#xff1a;npm install -D eslint/create-config初始化&#xff1a;npx eslint --init初始化后会在项目中自动创建eslint.config.js文件&#xff0c;把以下内容复制粘粘替换 import globals from "globals"; import pluginJs from "eslint/j…

6个步骤让你快速学会甘特图的制作

在项目管理中&#xff0c;一个清晰、详细的进度表格和进度计划表是确保项目顺利进行的重要工具。它们不仅帮助团队成员了解各自的任务和责任&#xff0c;还能有效监控项目的进展&#xff0c;及时发现并解决问题。 制作项目进度表格和制定项目进度计划表是项目管理中的关键步骤…

蒙特卡洛方法(MC Basic算法例子)

本文章中使用的算法和例子来源于bilibili中西湖大学赵世钰老师的【强化学习的数学原理】课程。网址&#xff1a;第5课-蒙特卡洛方法&#xff08;MC Basic算法例子&#xff09;_哔哩哔哩_bilibili 目录 一、任务目标 二、细节分析 三、代码演示 一、任务目标 1、初始的策略已…

数理统计(第4章第1节:1元方差分析)

目录 引例 基本概念 1元方差分析的数学模型 ​编辑离差平方和​编辑​编辑​编辑​编辑​编辑 单因子方差分析的假设检验​编辑 1元方差分析表 例子 引例 基本概念 1元方差分析的数学模型 离差平方和 单因子方差分析的假设检验 1元方差分析表 例子

Python酷库之旅-第三方库Pandas(192)

目录 一、用法精讲 891、pandas.Index.nunique方法 891-1、语法 891-2、参数 891-3、功能 891-4、返回值 891-5、说明 891-6、用法 891-6-1、数据准备 891-6-2、代码示例 891-6-3、结果输出 892、pandas.Index.value_counts方法 892-1、语法 892-2、参数 892-3、…

光控资本:普通股东、控股股东、大股东、实际控制人都是什么意思?

1、一般股东 一般股东是指持有公司一般股股份的出资者。一般股是指在公司的经营管理和盈利及财产的分配上享有一般权力的股份。 一般股的权力&#xff1a; 1、获得股利的权力。一般股股东在股市付出完债息、优先股股息后&#xff0c;能够获得股利&#xff0c;具体有多少要看…

SELS-SSL/TLS

一、了解公钥加密&#xff08;非对称加密&#xff09; 非对称加密中&#xff0c;用于加密数据的密钥与用于解密数据的密钥不同。私钥仅所有者知晓&#xff0c;而公钥则可自由分发。发送方使用接收方的公钥对数据进行加密&#xff0c;数据仅能使用相应的私钥进行解密。 你可以将…

openfoam中生成的3d案例提取得到slice后的2d案例

问题&#xff1a; 由于前期准备做3d的案例&#xff0c;并且模拟也比较费时间&#xff0c;现在生成了几十份3d的数据&#xff0c;但是现在只想要2d的数据来演示&#xff0c;该如何提取或者转换呢&#xff1f; 解决方法&#xff1a; 1.说明图片中的每个2d视图的points都是恒定不…

【SPIE出版,EI检索稳定】2024年人机交互与虚拟现实国际会议(HCIVR 2024,11月15-17日)

2024年人机交互与虚拟现实国际会议&#xff08;HCIVR 2024&#xff09; 2024 International Conference on Human-Computer Interaction and Virtual Reality 官方信息 会议官网&#xff1a;www.hcivr.org 2024 International Conference on Human-Computer Interaction and …

计算机网络 -- HTTP 协议详解

根据以往的内容我们可以得知&#xff0c;大多数网络协议一共有五层标准&#xff0c;今天我们将 探索 应用层的 HTTP 协议。 一 什么是HTTP协议 协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则。 HTTP 协议 &#xff0c;全称超文本传输协议 &#…

算法【Java】—— 动态规划之斐波那契数列模型

动态规划 动态规划的思路一共有五个步骤&#xff1a; 状态表示&#xff1a;由经验和题目要求得出&#xff0c;这个确实有点抽象&#xff0c;下面的题目会带大家慢慢感受状态标识状态转移方程初始化&#xff1a;避免越界访问 dp 表&#xff0c;所以在进行填表之前我们要预先填…

kafka使用指南

文章目录 前言特点架构一、zookeeper安装配置二、kafka安装配置三、快去试一下吧&#xff01;下一章:kafka命令之分区接入创建删除 前言 随着大数据时代的到来&#xff0c;高吞吐量的分布式发布订阅消息系统kafka得到了极大的应用&#xff0c;它具有高吞吐量、 特点 高吞吐量…

Windows 服务器中用户的分类

Windows 服务器中用户的分类 本地用户&#xff08;只能在本地登录&#xff09;如果你的服务器升级为域成员服务器&#xff0c;即刻失去本地服务。 漫游用户&#xff08;域用户就是漫游用户&#xff0c;可用在域内的任何一个设备上、且在权限允许的范围内进行登录和资源使用。 …

基于YOLO11/v10/v8/v5深度学习的建筑墙面损伤检测系统设计与实现【python源码+Pyqt5界面+数据集+训练代码】

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发…

Sublime Text 的PHP格式化插件phpfmt 的 setting 配置参数说明

phpfmt.sublime-settings 是 Sublime Text 中 phpfmt 插件的配置文件&#xff0c;用于定义代码格式化的各种参数。以下是一些常见的配置参数及其说明&#xff1a; 1、version 指定配置文件的版本&#xff0c;根据 phpfmt 插件的版本&#xff0c;此值可能有所不同。 2、php_b…

Oracle视频基础1.2.1练习

1.2.1 需求&#xff1a; 完整格式查看所有用户进程判断oracle启动状态 连接sqlplus不登陆 以sysdba身份登陆&#xff0c;通过登陆信息判断oracle启动状态 启动数据库&#xff0c;查系统全局区动态组件表 使用shell&#xff0c;启动监听然后返回sql ps -ef sqlplus /nolog con…

Ajax学习

目录 一、是什么 二、jQuery.ajax 三、初实现 四、再实现 五、应用 一、是什么 AJAX&#xff1a;Asynchronous JavaScript and XML&#xff08;异步的JavaScript和XML&#xff09; 是一种在无需重新加载整个网页的情况下&#xff0c;能够更新部分网页的技术 应用&#…

音频中sample rate是什么意思?

‌sample rate‌在数字信号处理中&#xff0c;指的是‌采样频率‌&#xff0c;即每秒钟从连续信号中抽取的样本数量。采样频率越高&#xff0c;信号的还原度越高&#xff0c;但同时也会增加计算负担和存储需求‌。 实际应用场景 在音频处理中&#xff0c;设置合适的采样率可以…