4.0.0
com.learn
demo
0.0.1-SNAPSHOT
javassist
javassist
3.12.1.GA
org.springframework
spring-core
3.0.6.RELEASE
org.springframework
spring-context
3.0.6.RELEASE
org.springframework
spring-aop
3.0.6.RELEASE
org.springframework
spring-orm
3.0.6.RELEASE
org.aspectj
aspectjrt
1.6.1
aspectj
aspectjweaver
1.5.3
cglib
cglib
2.1_2
com.mchange
c3p0
0.9.5.2
mysql
mysql-connector-java
5.1.37
package com.learn.aop;
import java.lang.reflect.Method;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import com.learn.annotation.ExtTransaction;
import com.learn.transaction.TransactionUtils;
/**
* 我们把代码重构一下
* 要不然会比较麻烦
*
* @author Leon.Sun
*
*/
@Aspect
@Component
public class AopExtTransaction {
// 一个事务实例子 针对一个事务
@Autowired
private TransactionUtils transactionUtils;
// 使用异常通知进行 回滚事务
/**
* 我们还有个异常通知没有封装完
* 异常我们要单独讲
* 所以我们先讲这个
*
*
*/
@AfterThrowing("execution(* com.learn.service.*.*.*(..))")
public void afterThrowing() {
// 获取当前事务进行回滚
// TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
transactionUtils.rollback();
}
// 环绕通知 在方法之前和之后处理事情
/**
* 我们要把这段代码重构一下
* 所以这个时候我们怎么做呢
* 因为看那么长的代码我看起来也痛苦
* 这样的话我们就比较简单了
*
* 我把所有的方法都给抽取出来
* 该比较舒服一点
* 有没有什么疑问
* 这应该没有什么疑问
* 是不是这样的
* 所以在这边讲一下
* 你们下去写代码的时候
* 就是别人看的时候也知道
* 获取这样的一个注解
* 然后进行begin
*
*
*
* @param pjp
* @throws Throwable
*/
@Around("execution(* com.learn.service.*.*.*(..))")
public void around(ProceedingJoinPoint pjp) throws Throwable {
/**
* 1.获取该方法上是否加上注解
* 我们拿到事务注解
* 第一步获取目标代理对象
*
* 首先进入到AOP代码里面去了
* 看到没有
* 进入到AOP代码里面去了之后
* 获取这个方法有没有加这个注解
*
*/
ExtTransaction extTransaction = getMethodExtTransaction(pjp);
/**
* 这边只要调用它就行了
* 看起来就轻松一点
* 然后把这个状态传进来
* 直接传入注解里面去
* 在这里我们是可以拿返回结果的
* 然后这边就是状态了
*
* 有注解的时候我们在begin方法里面判断一下
* 判断一下他到底有没有这个注解
* 这个注解不等于null
* 不等于null的情况下
*
* 开启完事务之后
*
*
*/
TransactionStatus transactionStatus = begin(extTransaction);
// 2.调用目标代理对象方法
/**
* 就会调用我们的目标代理对象方法
* 会走到我们的add方法里面来
*
*/
pjp.proceed();
// 3.判断该方法上是否就上注解
/**
* 然后在这里就直接判断不等于null的情况下
* 然后整个我就封装的比较简单
* 我全部抽出来
* 不执行的情况就走异常通知的
* 大概就讲完了
* 有没有什么疑问呢
* 就这样封装完了
*
* 是不是走commit
* 你的状态就不为空
* 走到里面去
* 不等于null的情况我就提交事务
*
*
*/
commit(transactionStatus);
}
/**
* 然后我再把它封装一下
* 这样看起来不是很爽
* 代码全部放在这里面去
* 其实这段代码也要封装一下
*
*
*
* @param extTransaction
* @return
*/
private TransactionStatus begin(ExtTransaction extTransaction) {
System.out.println("开启事务.......................");
/**
* 没加事务就不会走到这里面去
* 就不会begin
* 也不会commit的
* 如果为null就直接return掉
* return null就行了
*
* 走到这里判断一下
* 判断你有没有加注解
* 如果加了注解的情况下就开启这么一个事务
* 是不是这样的
* 你看一下
* 是不是开启事务
*
*
*/
if (extTransaction == null) {
return null;
}
// 2.如果存在事务注解,开启事务
/**
* 我喜欢这样去写
* 看着舒服一点
*
* 不等于null就开启这个事务了
* 是不是这样的
*
*
*/
return transactionUtils.begin();
}
/**
* 把这个封装完
* 我就封装的比较加简单
* 尤其是写这样的代码
*
*
* @param transactionStatus
*/
private void commit(TransactionStatus transactionStatus) {
System.out.println("提交事务.......................");
/**
* 这里通过状态判断会好一点
* 如果transactionStatus不等于null的情况下
* 我再次提交这个事务
* 因为只有当他有状态的情况下
* 才有这样的一个权限
* 待会我们演示一把
* 只要transactionStatus他不为null的情况下
* 我才会提交
* 如果没有为空说明有事务
* 如果为空
* 那就根本没有走到里面去
* 在这里就直接走完就行了
* 没必要去提交事务了
* 是不是这样的
* 这段代码就大体的这样写了以后
* 这个时候我就说一下
* 因为之前我都是封装起来的
* 会有的
* 我待会演示就知道了
* 我待会讲你就知道
* 没加事务就不会走到这里面去
*
*/
if (transactionStatus != null) {
/**
* 如果他不等于null的情况下的时候
* 是不是这样的
*
*/
transactionUtils.commit(transactionStatus);
}
}
/**
* 我们定义一个方法
* 获取这个注解getMethodExtTransaction
* 获取方法上的一个注解
* 看有没有这个注解吗
* 我在上面写个注释
* 获取方法上是否存在事务注解
* 然后这里面怎么写呢
* 我们得重构过来
* 因为代码太多了
* 看起来比较痛苦
* 是不是同样要传入ProceedingJoinPoint切入点过来
* 是不是写完了
* 然后我们把异常抛出去
*
*
*
* @param pjp
* @return
* @throws NoSuchMethodException
* @throws SecurityException
*/
private ExtTransaction getMethodExtTransaction(ProceedingJoinPoint pjp)
throws NoSuchMethodException, SecurityException {
String methodName = pjp.getSignature().getName();
Class> classTarget = pjp.getTarget().getClass();
Class>[] par = ((MethodSignature) pjp.getSignature()).getParameterTypes();
/**
* 我们看一下方法是哪一个
* 是不是add方法
*
*
*/
Method objMethod = classTarget.getMethod(methodName, par);
/**
* 然后看一下add方法有没有注解
* 是不是有的
* 有没有加上注解
* 是没有没有提交
* 是不是有这样的一个注解
* 有这样的注解的话
*
*
*/
ExtTransaction extTransaction = objMethod.getDeclaredAnnotation(ExtTransaction.class);
return extTransaction;
}
}
package com.learn.service;
//user 服务层
public interface UserService {
public void add();
public void del();
}
package com.learn.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.learn.annotation.ExtTransaction;
import com.learn.dao.UserDao;
import com.learn.service.UserService;
import com.learn.transaction.TransactionUtils;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private TransactionUtils transactionUtils;
@Autowired
private UserDao userDao;
/**
* 这里加了一个事务注解
* 就开始事务
*
* 我们加自定义的注解@ExtTransaction
* 我们这里不要try
* 因为我们要演示一下异常场景
* 异常通知我们会单独讲的
* 上面加个注解
* 我们自己写的这个
* 我们怎么判断我们的这个事务到底有没有成功呢
* 只要执行到userDao.add("test001", 20);之后
* 不要插入到数据库里面去
* 是不是肯定是对的
* 是不是这样的
*
*
*/
// @Transactional
// @ExtTransaction
public void add() {
userDao.add("test001", 20);
// int i = 1/0;
/**
* 到这里的时候数据是不是没有
* 看到没有
*
* 走过了之后是不是走完了
* 我们查一下有没有数据
* 没有吧
* 没有的话我们继续走
*
*
*/
System.out.println("####################################");
/**
* 走到这里
* 没有异常的情况下还是会回到AOP里面去
* 回到commit里面来
*
*
*/
userDao.add("test002", 21);
}
/**
* 这里没有加注解就不开启事务
* 那么最后怎么做呢
*
*
*
*
*/
public void del() {
System.out.println("del");
}
}
package com.learn;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.learn.service.UserService;
public class Test001 {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) applicationContext.getBean("userServiceImpl");
userService.add();
}
}