目录
1 环境搭建
1.1 第一步:准备必要的代码
1.2 第二步:拷贝必备的 jar 包到工程的 lib 目录
1.3 第三步:创建 spring 的配置文件并导入约束
1.4 第四步:配置 spring 的 ioc
1.5 第五步:抽取公共代码制作成通知
2 配置步骤
2.1 第一步:把通知类用 bean 标签配置起来
2.2 第二步:使用 aop:config 声明 aop 配置
2.3 第三步:使用 aop:aspect 配置切面
2.4 第四步:使用 aop:pointcut 配置切入点表达式
2.5 第五步:使用 aop:xxx 配置对应的通知类型
3 切入点表达式说明
4 环绕通知
-
1 环境搭建
- 示例:
- 在学习 spring 的 aop 时,采用账户转账作为示例。把 spring 的 ioc 也一起应用进来。
-
1.1 第一步:准备必要的代码
- 此处包含了实体类,业务层和持久层代码。沿用上一章节中的代码即可。
-
1.2 第二步:拷贝必备的 jar 包到工程的 lib 目录
- 此处要拷贝 spring 的 ioc 和 aop 两组 jar 包
-
1.3 第三步:创建 spring 的配置文件并导入约束
- 此处要导入 aop 的约束
-
<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> </beans>
-
1.4 第四步:配置 spring 的 ioc
-
<!-- 配置 service --> <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> </bean> <!-- 配置 dao --> <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"> <property name="dbAssit" ref="dbAssit"></property> </bean> <!-- 配置数据库操作对象 --> <bean id="dbAssit" class="com.itheima.dbassit.DBAssit"> <property name="dataSource" ref="dataSource"></property> <!-- 指定 connection 和线程绑定 --> <property name="useCurrentConnection" value="true"></property> </bean> <!-- 配置数据源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql:///spring_day02"></property> <property name="user" value="root"></property> <property name="password" value="1234"></property> </bean>
-
-
1.5 第五步:抽取公共代码制作成通知
- 事务控制类
-
public class TransactionManager { //定义一个 DBAssit private DBAssit dbAssit ; public void setDbAssit(DBAssit dbAssit) { this.dbAssit = dbAssit; } //开启事务 public void beginTransaction() { try { dbAssit.getCurrentConnection().setAutoCommit(false); } catch (SQLException e) { e.printStackTrace(); } } //提交事务 public void commit() { try { dbAssit.getCurrentConnection().commit(); } catch (SQLException e) { e.printStackTrace(); } } //回滚事务 public void rollback() { try { dbAssit.getCurrentConnection().rollback(); } catch (SQLException e) { e.printStackTrace(); } } //释放资源 public void release() { try { dbAssit.releaseConnection(); } catch (Exception e) { e.printStackTrace(); } } }
- 示例:
-
2 配置步骤
-
2.1 第一步:把通知类用 bean 标签配置起来
-
<!-- 配置通知 --> <bean id="txManager" class="com.itheima.utils.TransactionManager"> <property name="dbAssit" ref="dbAssit"></property> </bean>
-
2.2 第二步:使用 aop:config 声明 aop 配置
- aop:config:
- 作用:用于声明开始 aop 的配置
-
<aop:config> <!-- 配置的代码都写在此处 --> </aop:config>
- aop:config:
-
2.3 第三步:使用 aop:aspect 配置切面
- aop:aspect:
- 作用:
- 用于配置切面。
- 属性:
- id:给切面提供一个唯一标识。
- ref:引用配置好的通知类 bean 的 id。
- 作用:
-
<aop:aspect id="txAdvice" ref="txManager"> <!--配置通知的类型要写在此处--> </aop:aspect>
- aop:aspect:
-
2.4 第四步:使用 aop:pointcut 配置切入点表达式
- aop:pointcut:
- 作用:
- 用于配置切入点表达式。就是指定对哪些类的哪些方法进行增强。
- 属性:
- expression:用于定义切入点表达式。
- id:用于给切入点表达式提供一个唯一标识
- 作用:
-
<aop:pointcut expression="execution( public void com.itheima.service.impl.AccountServiceImpl.transfer( java.lang.String, java.lang.String, java.lang.Float ) )" id="pt1"/>
- aop:pointcut:
-
2.5 第五步:使用 aop:xxx 配置对应的通知类型
- aop:before
- 作用:
- 用于配置前置通知。指定增强的方法在切入点方法之前执行
- 属性:
- method:用于指定通知类中的增强方法名称
- ponitcut-ref:用于指定切入点的表达式的引用
- poinitcut:用于指定切入点表达式
- 执行时间点:
- 切入点方法执行之前执行
-
<aop:before method="beginTransaction" pointcut-ref="pt1"/>
- 作用:
- aop:after-returning
- 作用:
- 用于配置后置通知
- 属性:
- method:指定通知中方法的名称。
- pointct:定义切入点表达式
- pointcut-ref:指定切入点表达式的引用
- 执行时间点:
- 切入点方法正常执行之后。它和异常通知只能有一个执行
-
<aop:after-returning method="commit" pointcut-ref="pt1"/>
- 作用:
- aop:after-throwing
- 作用:
- 用于配置异常通知
- 属性:
- method:指定通知中方法的名称。
- pointct:定义切入点表达式
- pointcut-ref:指定切入点表达式的引用
- 执行时间点:
- 切入点方法执行产生异常后执行。它和后置通知只能执行一个
-
<aop:after-throwing method="rollback" pointcut-ref="pt1"/>
- 作用:
- aop:after
- 作用:
- 用于配置最终通知
- 属性:
- method:指定通知中方法的名称。
- pointct:定义切入点表达式
- pointcut-ref:指定切入点表达式的引用
- 执行时间点:
- 无论切入点方法执行时是否有异常,它都会在其后面执行。
-
<aop:after method="release" pointcut-ref="pt1"/>
- 作用:
- aop:before
-
-
3 切入点表达式说明
- execution:匹配方法的执行(常用)
- execution(表达式)
- 表达式语法:execution([修饰符] 返回值类型 包名.类名.方法名(参数))
- 写法说明:
- 全匹配方式:
-
public void com.itheima.service.impl.AccountServiceImpl.saveAccount(com.itheima.domain.Account)
- 访问修饰符可以省略
-
void com.itheima.service.impl.AccountServiceImpl.saveAccount(com.itheima.domain.Account)
- 返回值可以使用*号,表示任意返回值
-
* com.itheima.service.impl.AccountServiceImpl.saveAccount(com.itheima.domain.Account)
- 包名可以使用*号,表示任意包,但是有几级包,需要写几个*
-
* *.*.*.*.AccountServiceImpl.saveAccount(com.itheima.domain.Account)
- 使用..来表示当前包,及其子包
-
* com..AccountServiceImpl.saveAccount(com.itheima.domain.Account)
- 类名可以使用*号,表示任意类
-
* com..*.saveAccount(com.itheima.domain.Account)
- 方法名可以使用*号,表示任意方法
-
* com..*.*( com.itheima.domain.Account)
- 参数列表可以使用*,表示参数可以是任意数据类型,但是必须有参数
-
* com..*.*(*)
- 参数列表可以使用..表示有无参数均可,有参数可以是任意类型
-
* com..*.*(..)
- 全通配方式:
-
* *..*.*(..)
- 注:
- 通常情况下,我们都是对业务层的方法进行增强,所以切入点表达式都是切到业务层实现类。
-
execution(* com.itheima.service.impl.*.*(..))
- execution:匹配方法的执行(常用)
-
4 环绕通知
- 配置方式:
-
<aop:config> <aop:pointcut expression="execution(* com.itheima.service.impl.*.*(..))" id="pt1"/> <aop:aspect id="txAdvice" ref="txManager"> <!-- 配置环绕通知 --> <aop:around method="transactionAround" pointcut-ref="pt1"/> </aop:aspect> </aop:config>
- aop:around:
- 作用:
- 用于配置环绕通知
- 属性:
- method:指定通知中方法的名称。
- pointct:定义切入点表达式
- pointcut-ref:指定切入点表达式的引用
- 说明:
- 它是 spring 框架为我们提供的一种可以在代码中手动控制增强代码什么时候执行的方式。
- 注意:
- 通常情况下,环绕通知都是独立使用的
- /**
- * 环绕通知
- * @param pjp
- * spring 框架为我们提供了一个接口:ProceedingJoinPoint,它可以作为环绕通知的方法参数。
- * 在环绕通知执行时,spring 框架会为我们提供该接口的实现类对象,我们直接使用就行。
- * @return
- */
-
public Object transactionAround(ProceedingJoinPoint pjp) { //定义返回值 Object rtValue = null; try { //获取方法执行所需的参数 Object[] args = pjp.getArgs(); //前置通知:开启事务 beginTransaction(); //执行方法 rtValue = pjp.proceed(args); //后置通知:提交事务 commit(); }catch(Throwable e) { //异常通知:回滚事务 rollback(); e.printStackTrace(); }finally { //最终通知:释放资源 release(); } return rtValue; }
- 作用: