之前,在研究了代理对象创建的原理以及如何包装advice通知之后,再来看一个例子:@Transactional注解
1.什么是@Transactional注解
举个例子:我们要往mysql数据库批量添加一些用户,比如说是2条,
定义一个controller层的方法:testAddUsers,
@PostMapping("/test") public String testAddUsers(){ userService.testAddUsers(); return "testAddUsers OK!"; }
userserviceimpl的方法:
@Override @Transactional public void testAddUsers() { List<User> userList=new ArrayList<>(); userList.add(new User().setUsername("mawebchao").setPassword("123")); userList.add(new User().setUsername("mawebchao").setPassword("123")); for (int i = 0; i < userList.size(); i++) { try { userMapper.insert(userList.get(i)); if(i%2==0){ System.out.println(1/0); } } catch (Exception e) { e.printStackTrace(); throw e; } } }
因为加了Transactional注解,当方法体抛出异常之后,事务会回滚。这就是@Transactional注解的用处,它将整个方法体看作一个事务。
2.SpringTransactionAnnotationParser在什么时机去解析@Transactional注解的?猜测:spring容器refresh的时候
3.@Transactional注解加在方法上的时候,跟踪方法应该会成为一个advice,方法所在的类应该会成为一个代理对象,跟踪代理对象里的这个方法,和别的方法有什么区别
4.@EnableTransactionManagement配置类标识事务并运行方法和启动运用了事务的spring项目的时候,都会去执行SpringTransactionAnnotationParser的parseTransactionAnnotation方法,分别是为了干什么?
首先,执行 SpringTransactionAnnotationParser.parseTransactionAnnotation()方法,归根结底还是为了创建bean:
创建bean->判断是否需要生成代理对象->查找有没有符合的advisors->检查transactional注解
spring项目中和普通项目:
加了@Springbootapplication注解后,在注解内部,spring自动定义了开启事务管理,而一旦开启了事务管理,事务管理的本质是方法的加强,所以和原始的aop一样,在容器中会多出一个transactionaladvice这个bean,这个只与是否开启事务有关。而普通项目没有加springbootapplication注解的话,可以加上@EnableTransactionManagement注解开启事务管理,起到的效果是一样的。但这里还有一个很大的区别在于,spring项目在refresh的regisBeanPostProcessor方法中就在做@Transactional注解的解析了,而普通方法中却是在finishBeanFactoryInitialization(创建剩余单例对象)的时候去解析的,这是为什么呢?
在spring项目中,在创建objectMapperConfigurer这个bean的时候,会去判断这个对象是否需要变成代理对象(所有对象创建的时候都要进行判断(wrapifnecessary方法)),而在加载objectMapperConfigurer它的预选advisors的时候把transactionaladvice给加进去了,所以需要判断
transactionaladvice是不是这个类的advice,所以才会去解析transactional注解(parseTransactionAnnotation方法)。所以为啥要解析@transactional注解呢,是为了判断当前这个类是否需要transactionaladvice对他进行加强。
那根据常理,一个类需要被transactionaladvice加强为代理对象的条件是什么?那最常用的就是它内部的某个方法或是某些方法加了@Transactional注解啊,所以看源码:
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass){// First try is the method in the target class. //找到目标类里被@Transactional注解的方法 TransactionAttribute txAttr = findTransactionAttribute(specificMethod);// Second try is the transaction attribute on the target class. //找到目标类里被@Transactional注解的属性 txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());}
这里怎么找呢,首先要遍历类里所有的方法,再有parseTransactionAnnotation这个方法了------解析@Transactional注解,给他传递一个参数就是类里的方法method,那很显然objectMapperConfigurer这个类内部没有方法标注了@Transactional注解,所以First try的结果为null。Second try就更不用看了,肯定没有。。
那为什么会在创建objectMapperConfigurer这个bean的时候,预选者advisors里多了这个transactionaladvice呢?因为在objectMapperConfigurer的resolveBeforeInstantiation方法中已经间接创建了这个transactionaladvice了。。。