一、注解版和xml版的区别
1、 通知的四种常用类型
(1)aop:before
作用: 用于配置前置通知。指定增强的方法在切入点方法之前执行 属性: method:用于指定通知类中的增强方法名称 ponitcut-ref:用于指定切入点的表达式的引用 poinitcut:用于指定切入点表达式 执行时间点: 切入点方法执行之前执行
<aop:before method=“beginPrintLog” pointcut-ref=“pt1”/>
(2)aop:after-returning
作用: 用于配置后置通知 属性: method:指定通知中方法的名称。 pointct:定义切入点表达式 pointcut-ref:指定切入点表达式的引用 执行时间点: 切入点方法正常执行之后。它和异常通知只能有一个执行
<aop:after-returning method=“afterReturningPrintLog” pointcut-ref=“pt1”/>
(3)aop:after-throwing
作用: 用于配置异常通知 属性: method:指定通知中方法的名称。 pointct:定义切入点表达式 pointcut-ref:指定切入点表达式的引用 执行时间点: 切入点方法执行产生异常后执行。它和后置通知只能执行一个
<aop:after-throwing method=“afterThrowingPringLog” pointcut-ref=“pt1”/>
(4) aop:after
作用: 用于配置最终通知 属性: method:指定通知中方法的名称。 pointct:定义切入点表达式 pointcut-ref:指定切入点表达式的引用 执行时间点: 无论切入点方法执行时是否有异常,它都会在其后面执行。
<aop:after method=“afterPringLog” pointcut-ref=“pt1”/>
2、四种常用类型通知的执行顺序
(1)xml的织入顺序是按照xml里的写的顺序进行执行
(2)注解版织入的顺序则和运行时出现的情况进行分两种分析
Ⅰ.正常运行
注解通知正常执行时:
正常执行时会先执行 @before 然后再执行 @After 最后执行@ After-returning
所以正常情况下要在 TransactionManager里的标注事务的状态时对应的通知
如果一开始让@After对应为release()则事务将提前释放资源,造成无法提交,所以要把@After对应为Commit(),这样就可以先提交再释放资源
Ⅱ.抛出异常时 After 的执行顺序
如果一开始让@After对应为release()则事务将提前释放资源,造成无法提交,所以要把@After对应为rollBack(),这样就可以先抛异常再释放资源
1.需要改动是文件
1.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"
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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--开启注解扫描-->
<context:component-scan base-package="com.william"></context:component-scan>
<!--创建QueryRunner-->
<bean id="QueryRunner" class="org.apache.commons.dbutils.QueryRunner">
</bean>
<!--创建dataSource-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--引入属性文件-->
<context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
</beans>
2.在TransactionManager进行注解
代码:使用的是四种的执行顺序,没使用around环绕通知
执行顺序按照
package com.william.utils;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.sql.SQLException;
/**
* @author :lijunxuan
* @date :Created in 2019/5/27 16:50
* @description :
* @version: 1.0
*/
@Component
@Aspect
public class TransactionManager {
@Pointcut("execution(* com.william.service.Impl.*.*(..))")
public void pc(){}
@Autowired
ConnectionUtils connectionUtils;
@Before("pc()")
public void beganTransaction(){
try {
connectionUtils.getThreadConnection().setAutoCommit(false);
System.out.println(" beganTransaction "+connectionUtils.getThreadConnection());
} catch (SQLException e) {
e.printStackTrace();
}
}
@After("pc()")
public void Commit(){
try {
System.out.println(" Commit "+connectionUtils.getThreadConnection());
connectionUtils.getThreadConnection().commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
@AfterThrowing("pc()")
public void rollBack(){
try {
System.out.println(" rollBack "+connectionUtils.getThreadConnection());
connectionUtils.getThreadConnection().rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
@AfterReturning("pc()")
public void release(){
try {
System.out.println(" release "+connectionUtils.getThreadConnection());
connectionUtils.getThreadConnection().setAutoCommit(true);
connectionUtils.getThreadConnection().close();
connectionUtils.remove();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
二、使用around环绕通知可以解决上面的问题
配置方式:
<aop:config> <aop:pointcut expression="execution(* com.william.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 框架为我们提供的一种可以在代码中手动控制增强代码什么时候执行的方式。
注意: 通常情况下,环绕通知都是独立使用的
package com.william.utils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.sql.SQLException;
/**
* @author :lijunxuan
* @date :Created in 2019/5/27 16:50
* @description :
* @version: 1.0
*/
@Component
@Aspect
public class TransactionManager {
@Pointcut("execution(* com.william.service.impl.*.*(..))")
public void pc(){}
@Around("pc()")
public Object around(ProceedingJoinPoint joinPoint){
try {
beginTransaction();
//执行原始的方法
Object result = joinPoint.proceed();
commit();
return result;
} catch (Throwable throwable) {
throwable.printStackTrace();
rollback();
} finally {
release();
}
return null;
}
@Autowired
ConnectionUtils connectionUtils;
public void beginTransaction(){
try {
connectionUtils.getThreadConnection().setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
public void commit(){
try {
connectionUtils.getThreadConnection().commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
public void rollback(){
try {
connectionUtils.getThreadConnection().rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
public void release(){
try {
connectionUtils.getThreadConnection().setAutoCommit(true);
connectionUtils.getThreadConnection().close();
connectionUtils.remove();
} catch (SQLException e) {
e.printStackTrace();
}
}
}