spring2--aop及事务高级特性

https://segmentfault.com/a/1190000022694615

一、AOP实现原理

1、定义

AOP:【动态代理】
指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式;

2、步骤

1、导入aop模块;Spring AOP:(spring-aspects)
2、定义一个业务逻辑类(MathCalculator);在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、方法出现异常,xxx)
3、定义一个日志切面类(LogAspects):切面类里面的方法需要动态感知MathCalculator.div运行到哪里然后执行;
通知方法:
前置通知(@Before):logStart:在目标方法(div)运行之前运行
后置通知(@After):logEnd:在目标方法(div)运行结束之后运行(无论方法正常结束还是异常结束)
返回通知(@AfterReturning):logReturn:在目标方法(div)正常返回之后运行
异常通知(@AfterThrowing):logException:在目标方法(div)出现异常以后运行
环绕通知(@Around):动态代理,手动推进目标方法运行(joinPoint.procced())
4、给切面类的目标方法标注何时何地运行(通知注解);
5、将切面类和业务逻辑类(目标方法所在类)都加入到容器中;
6、必须告诉Spring哪个类是切面类(给切面类上加一个注解:@Aspect)
7、给配置类中加 @EnableAspectJAutoProxy 【开启基于注解的aop模式】
在Spring中很多的 @EnableXXX;

三步:
1)、将业务逻辑组件和切面类都加入到容器中;告诉Spring哪个是切面类(@Aspect
2)、在切面类上的方法上标注通知注解,告诉Spring何时何地运行(@Pointcut切入点表达式
3)、开启基于注解的aop模式;@EnableAspectJAutoProxy
在这里插入图片描述

3、AOP原理:

【看给容器中注册了什么组件,这个组件什么时候工作,这个组件的功能是什么?】

1、@EnableAspectJAutoProxy是什么?
@Import(AspectJAutoProxyRegistrar.class):给容器中导入AspectJAutoProxyRegistrar
利用AspectJAutoProxyRegistrar自定义给容器中注册bean;BeanDefinetion
internalAutoProxyCreator=AnnotationAwareAspectJAutoProxyCreator

2、继承关系 AnnotationAwareAspectJAutoProxyCreator:
AnnotationAwareAspectJAutoProxyCreator
->AspectJAwareAdvisorAutoProxyCreator
->AbstractAdvisorAutoProxyCreator
->AbstractAutoProxyCreator
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
关注后置处理器(在bean初始化完成前后做事情)、自动装配BeanFactory

4、流程

1)、传入配置类,创建ioc容器
2)、注册配置类,调用refresh()刷新容器;
3)、registerBeanPostProcessors(beanFactory);注册bean的后置处理器来方便拦截bean的创建;
	1)、先获取ioc容器已经定义了的需要创建对象的所有BeanPostProcessor
	2)、给容器中加别的BeanPostProcessor
	3)、优先注册实现了PriorityOrdered接口的BeanPostProcessor;
	4)、再给容器中注册实现了Ordered接口的BeanPostProcessor;
	5)、注册没实现优先级接口的BeanPostProcessor;
	6)、注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中;
		创建internalAutoProxyCreator的BeanPostProcessor【AnnotationAwareAspectJAutoProxyCreator】
		1)、创建Bean的实例
		2)、populateBean;给bean的各种属性赋值
		3)、initializeBean:初始化bean;
				1)、invokeAwareMethods():处理Aware接口的方法回调
				2)、applyBeanPostProcessorsBeforeInitialization():应用后置处理器的postProcessBeforeInitialization()
				3)、invokeInitMethods();执行自定义的初始化方法
				4)、applyBeanPostProcessorsAfterInitialization();执行后置处理器的postProcessAfterInitialization();
		4)、BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功;--》aspectJAdvisorsBuilder
	7)、把BeanPostProcessor注册到BeanFactory中;
		beanFactory.addBeanPostProcessor(postProcessor);
=======以上是创建和注册AnnotationAwareAspectJAutoProxyCreator的过程========
	AnnotationAwareAspectJAutoProxyCreator => InstantiationAwareBeanPostProcessor
4)、finishBeanFactoryInitialization(beanFactory);完成BeanFactory初始化工作;创建剩下的单实例bean
	1)、遍历获取容器中所有的Bean,依次创建对象getBean(beanName);
		getBean->doGetBean()->getSingleton()->
	2)、创建bean
		【AnnotationAwareAspectJAutoProxyCreator在所有bean创建之前会有一个拦截,InstantiationAwareBeanPostProcessor,会调用postProcessBeforeInstantiation()】
		1)、先从缓存中获取当前bean,如果能获取到,说明bean是之前被创建过的,直接使用,否则再创建;
			只要创建好的Bean都会被缓存起来
		2)、createBean();创建bean;
			AnnotationAwareAspectJAutoProxyCreator 会在任何bean创建之前先尝试返回bean的实例
			【BeanPostProcessor是在Bean对象创建完成初始化前后调用的】
			【InstantiationAwareBeanPostProcessor是在创建Bean实例之前先尝试用后置处理器返回对象的】
			1)、resolveBeforeInstantiation(beanName, mbdToUse);解析BeforeInstantiation
				希望后置处理器在此能返回一个代理对象;如果能返回代理对象就使用,如果不能就继续
				1)、后置处理器先尝试返回对象;
					bean = applyBeanPostProcessorsBeforeInstantiation():
						拿到所有后置处理器,如果是InstantiationAwareBeanPostProcessor;
						就执行postProcessBeforeInstantiation
					if (bean != null) {
					bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
				}
			2)、doCreateBean(beanName, mbdToUse, args);真正的去创建一个bean实例;和3.6流程一样;

流程总结

1)、@EnableAspectJAutoProxy 开启AOP功能
2)、@EnableAspectJAutoProxy 会给容器中注册一个组件 AnnotationAwareAspectJAutoProxyCreator
3)、AnnotationAwareAspectJAutoProxyCreator是一个后置处理器;
4)、容器及bean的创建流程:
	1)、传入配置类,创建ioc容器
	2)、注册配置类,调用refresh()刷新容器;
	3)、registerBeanPostProcessors()注册后置处理器;创建AnnotationAwareAspectJAutoProxyCreator对象
	4)、finishBeanFactoryInitialization()初始化剩下的单实例bean
		1)、创建业务逻辑组件和切面组件
		2)、AnnotationAwareAspectJAutoProxyCreator拦截组件的创建过程
		3)、组件创建完之后,判断组件是否需要增强
			是:切面的通知方法,包装成增强器(Advisor);给业务逻辑组件创建一个代理对象(cglib);
5)、执行目标方法(调用该方法时才会执行):
	1)、代理对象执行目标方法
	2)、CglibAopProxy.intercept();
		1)、得到目标方法的拦截器链(增强器包装成拦截器MethodInterceptor)
		2)、利用拦截器的链式机制,依次进入每一个拦截器进行执行;
		3)、效果:
			正常执行:前置通知-》目标方法-》后置通知-》返回通知
			出现异常:前置通知-》目标方法-》后置通知-》异常通知

5、拦截器链(责任链模式)

代理对象+拦截器
代理对象的目标方法要执行了,拦截器链就开始工作。
事务拦截器工作时也一样,只不过事务拦截器链只有一个拦截器
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

6、实现方式

1)JDK动态代理和CGLIB动态代理:

JDK动态代理只提供接口的代理,不支持类的代理。
核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例, 生成目标类的代理对象。

如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。

CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。	CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

2)静态代理与动态代理区别
在于生成AOP代理对象的时机不同,相对来说AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理。

二、spring 声明式事务

1、步骤:

 1、导入相关依赖
 		数据源、数据库驱动、Spring-jdbc模块
 2、配置数据源、JdbcTemplate(Spring提供的简化数据库操作的工具)操作数据
 3、给方法上标注 @Transactional 表示当前方法是一个事务方法;
 4、 @EnableTransactionManagement 开启基于注解的事务管理功能;
 		@EnableXXX
 5、配置事务管理器来控制事务;
		@Bean
 		public PlatformTransactionManager transactionManager()

2、代码原理

在这里插入图片描述

3、Spring事务的实现方式和实现原理

Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。

4、Spring的事务传播行为

① PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。
② PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。
③ PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
④ PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。
⑤ PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
⑥ PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
⑦ PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。

5、 spring 的事务隔离?

spring 有五大隔离级别,默认值为 ISOLATION_DEFAULT(使用数据库的设置),其他四个隔离级别和数据库的隔离级别一致:

ISOLATION_DEFAULT:用底层数据库的设置隔离级别,数据库设置的是什么我就用什么;
ISOLATION_READ_UNCOMMITTED:未提交读,最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读);
ISOLATION_READ_COMMITTED:提交读,一个事务提交后才能被其他事务读取到(会造成幻读、不可重复读),SQL server 的默认级别;
ISOLATION_REPEATABLE_READ:可重复读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读),MySQL 的默认级别;
ISOLATION_SERIALIZABLE:序列化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读。

6、Spring框架的事务管理有哪些优点?

1)为不同的事务API 如 JTA,JDBC,Hibernate,JPA 和JDO,提供一个不变的编程模式。
2)支持声明式事务管理。
3)和Spring各种数据访问抽象层很好得集成

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值