《四 spring源码》spring的事务注解@Transactional 原理分析
先了解什么是注解
注解
Jdk1.5新增新技术,注解。很多框架为了简化代码,都会提供有些注解。可以理解为插件,是代码级别的插件,在类的方法上写:@XXX,就是在代码上插入了一个插件。
注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。
注解分类:内置注解(也成为元注解 jdk 自带注解)、自定义注解(Spring框架)
什么是内置注解
(1) @SuppressWarnings 再程序前面加上可以在javac编译中去除警告--阶段是SOURCE
(2) @Deprecated 带有标记的包,方法,字段说明其过时----阶段是SOURCE
(3)@Overricle 打上这个标记说明该方法是将父类的方法重写--阶段是SOURCE
实现自定义注解
元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。Java5.0定义的元注解:
@Target
@Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。
- CONSTRUCTOR:用于描述构造器
- FIELD:用于描述域
- LOCAL_VARIABLE:用于描述局部变量
- METHOD:用于描述方法
- PACKAGE:用于描述包
- PARAMETER:用于描述参数
- TYPE:用于描述类、接口(包括注解类型) 或enum声明
表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)
3.@Documented
4.@interface
@Target(value = { ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface AddAnnotation { int userId() default 0; String userName() default "默认名称"; String[]arrays();
}
反射读取注解信息
public static void main(String[] args) throws ClassNotFoundException {
Class classInfo = Class.forName("com.entity.User");
// 获取到所有方法
Method[] methods = classInfo.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
//查看该方法是否存在注解
AddAnnotation declaredAnnotation = method.getDeclaredAnnotation(AddAnnotation.class);
if (declaredAnnotation == null) {
// 结束本次循环
continue;
}
// 获取userId
int userId = declaredAnnotation.userId();
System.out.println("userId:" + userId);
// 获取userName
String userName = declaredAnnotation.userName();
System.out.println("userName:" + userName);
// 获取arrays
String[] arrays = declaredAnnotation.arrays();
for (String str : arrays) {
System.out.println("str:" + str);
}
}
}
自定义事务注解
//编程事务(需要手动begin 手动回滚 手都提交)
@Component()
@Scope("prototype") // 设置成原型解决线程安全
public class TransactionUtils { private TransactionStatus transactionStatus;
// 获取事务源
@Autowired
private DataSourceTransactionManager dataSourceTransactionManager; // 开启事务
public TransactionStatus begin() {
transactionStatus = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
return transactionStatus;
} // 提交事务
public void commit(TransactionStatus transaction) {
dataSourceTransactionManager.commit(transaction);
} // 回滚事务
public void rollback() {
System.out.println("rollback");
dataSourceTransactionManager.rollback(transactionStatus);
} } 注解类 @Autowired
private TransactionUtils transactionUtils; @AfterThrowing("execution(* com.itmayiedu.service.*.*.*(..))")
public void afterThrowing() throws NoSuchMethodException, SecurityException {
// isRollback(proceedingJoinPoint);
System.out.println("程序发生异常");
// TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
// TransactionStatus currentTransactionStatus =
// TransactionAspectSupport.currentTransactionStatus();
// System.out.println("currentTransactionStatus:" +
// currentTransactionStatus);
transactionUtils.rollback();
} // // 环绕通知 在方法之前和之后处理事情
@Around("execution(* com.itmayiedu.service.*.*.*(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { // 调用方法之前执行
TransactionStatus transactionStatus = begin(proceedingJoinPoint);
proceedingJoinPoint.proceed();// 代理调用方法 注意点: 如果调用方法抛出异常不会执行后面代码
// 调用方法之后执行
commit(transactionStatus);
} public TransactionStatus begin(ProceedingJoinPoint pjp) throws NoSuchMethodException, SecurityException { // // 判断是否有自定义事务注解
ExtTransaction declaredAnnotation = getExtTransaction(pjp);
if (declaredAnnotation == null) {
return null;
}
// 如果有自定义事务注解,开启事务
System.out.println("开启事务");
TransactionStatus transactionStatu = transactionUtils.begin();
return transactionStatu;
} public void commit(TransactionStatus transactionStatu) {
if (transactionStatu != null) {
// 提交事务
System.out.println("提交事务");
transactionUtils.commit(transactionStatu);
}
} public ExtTransaction getExtTransaction(ProceedingJoinPoint pjp) throws NoSuchMethodException, SecurityException {
// 获取方法名称
String methodName = pjp.getSignature().getName();
// 获取目标对象
Class<?> classTarget = pjp.getTarget().getClass();
// 获取目标对象类型
Class<?>[] par = ((MethodSignature) pjp.getSignature()).getParameterTypes();
// 获取目标对象方法
Method objMethod = classTarget.getMethod(methodName, par);
// // 判断是否有自定义事务注解
ExtTransaction declaredAnnotation = objMethod.getDeclaredAnnotation(ExtTransaction.class);
if (declaredAnnotation == null) {
System.out.println("您的方法上,没有加入注解!");
return null;
}
return declaredAnnotation; } // 回滚事务
public void isRollback(ProceedingJoinPoint pjp) throws NoSuchMethodException, SecurityException {
// // 判断是否有自定义事务注解
ExtTransaction declaredAnnotation = getExtTransaction(pjp);
if (declaredAnnotation != null) {
System.out.println("已经开始回滚事务");
// 获取当前事务 直接回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
return;
}
} 使用自定义注解 @ExtTransaction
public void add() {
userDao.add("test001", 20);
int i = 1 / 0;
System.out.println("################");
userDao.add("test002", 21);
}
Spring事物传播行为
Spring中事务的定义:
Propagation(key属性确定代理应该给哪个方法增加事务行为。这样的属性最重要的部份是传播行为。)有以下选项可供使用:
PROPAGATION_REQUIRED—如果当前有事务,就用当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。//如果外层方法没有事务,就会以非事务进行执行。
PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
--- 如果当前有事务,就是以非事务进行执行
PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。
默认传播行为为REQUIRED
《四 spring源码》spring的事务注解@Transactional 原理分析的更多相关文章
- Spring源码情操陶冶-AnnotationConfigBeanDefinitionParser注解配置解析器
本文承接前文Spring源码情操陶冶-自定义节点的解析,分析spring中的context:annotation-config节点如何被解析 源码概览 对BeanDefinitionParser接口的 ...
- Spring源码情操陶冶-PropertyPlaceholderBeanDefinitionParser注解配置解析器
本文针对spring配置的context:property-placeholder作下简单的分析,承接前文Spring源码情操陶冶-自定义节点的解析 spring配置文件应用 <context: ...
- Spring源码解析 - AbstractBeanFactory 实现接口与父类分析
我们先来看类图吧: 除了BeanFactory这一支的接口,AbstractBeanFactory主要实现了AliasRegistry和SingletonBeanRegistry接口. 这边主要提供了 ...
- spring源码解析:元注解功能的实现
前言 众所周知,spring 从 2.5 版本以后开始支持使用注解代替繁琐的 xml 配置,到了 springboot 更是全面拥抱了注解式配置.平时在使用的时候,点开一些常见的等注解,会发现往往在一 ...
- spring源码 — 五、事务
spring提供了可配置.易扩展的事务处理框架,本文主要从一下几个方面说明spring事务的原理 基本概念 事务配置解析 事务处理过程 基本概念 事务隔离级别 在同时进行多个事务的时候,可能会出现脏读 ...
- spring源码学习之路---IOC实现原理(三)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 上一章我们已经初步认识了Be ...
- Spring源码学习之IOC容器实现原理(一)-DefaultListableBeanFactory
从这个继承体系结构图来看,我们可以发现DefaultListableBeanFactory是第一个非抽象类,非接口类.实际IOC容器.所以这篇博客以DefaultListableBeanFactory ...
- Spring源码剖析7:AOP实现原理详解
前言 前面写了六篇文章详细地分析了Spring Bean加载流程,这部分完了之后就要进入一个比较困难的部分了,就是AOP的实现原理分析.为了探究AOP实现原理,首先定义几个类,一个Dao接口: pub ...
- Spring源码窥探之:注解方式的AOP原理
AOP入口代码分析 通过注解的方式来实现AOP1. @EnableAspectJAutoProxy通过@Import注解向容器中注入了AspectJAutoProxyRegistrar这个类,而它在容 ...
随机推荐
- oracle 11g 常用命令
sqlplus system/123@ORCL; 查看oracle字符集: select * from nls_database_parameters where parameter ='NLS_CH ...
- Python实现排序算法之快速排序
Python实现排序算法:快速排序.冒泡排序.插入排序.选择排序.堆排序.归并排序和希尔排序 Python实现快速排序 原理 首先选取任意一个数据(通常选取数组的第一个数)作为关键数据,然后将所有比它 ...
- 【Lintcode】095.Validate Binary Search Tree
题目: Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is define ...
- DataGrid当列宽超出当前宽度时,没有数据也恒有滚动条
附件是DataGrid支持滚动条的文件. 具体使用如下: 1)DataGrid使用控件模板 <Setter Property="Template" Value="{ ...
- C# 获取Console的输入和输出 数据 (异步)
using System ; using System .Diagnostics; using System .IO; class Program { static void Main() ...
- VijosP1250:分组背包
背景 Wind设计了很多机器人.但是它们都认为自己是最强的,于是,一场比赛开始了~ 描述 机器人们都想知道谁是最勇敢的,于是它们比赛搬运一些物品. 它们到了一个仓库,里面有n个物品,每个物品都有一个价 ...
- js css3实现钟表效果
原理: 利用transform-origin改变旋转的圆心,实现秒数和分钟数的刻度线,利用transfrom translate实现钟表小时刻度的显示 html: <div class=&quo ...
- iOS公司账号($99)/企业账号($299)申请
公司账号($99)与企业账号($299)申请基本大同小异,最主要的差别就在于入口不一样 一.注册Apple ID 在iOSAppStore个人开发者账号申请中已经介绍过注册App ID的流程,这里不再 ...
- AS负责人说不必用Kotlin重写,但OkHttp拿Kotlin重写了一遍,就发了OkHttp 4.0!
虽然 Android Studio 的负责人 Jeffery 已经澄清,只是 Kotlin-First 而不是 Kotlin-Must,并不需要将 App 用 Kotlin 重写一遍.但是 OkHtt ...
- Automake使用(中级)
工程地址 automake语言国际化 最初工程目录结构 $ ls -l total 16 drwxrwxr-x. 2 fedora fedora 4096 May 10 10:38 build-aux ...