Spring(三)——AOP
AOP全名为Aspect-Oriented Programming,意思是面向横切面编程,前边我们有过介绍 面向横切面编程AOP的理解 ,我们通过这种编程思想很容易的扩展我们的应用程序。
一,如何实现AOP编程思想呢?实现这种编程思想的一个重要手段就是代理模式或者说模仿代理模式的运用。尤其是其中动态代理模式,JDK提供的Proxy的使用,这个在前边也总结:Proxy代理模式的应用 而这种动态代理是基于接口的,也就是说代理对象和目标对象实现了同一个接口。而假如我们应用中没有使用接口,就无法使用Proxy了。但是不要着急,CGLIB这个组件解决了这个问题,它正是弥补jdk中的不足,专门基于继承来实现动态代理,其中代理对象是继承目标对象进行扩展的。它和JDK提供的Proxy实现原理是非常类似的。这里看一下网上的资料吧:java动态代理(JDK和cglib)
二,事务(Trasaction)
这个在数据库中我们学习过,为什么在这里又提出来呢?因为Spring框架运用在我们的service层。而事务的应用正是用到一个业务当中,也就是我们的Service层,所以声明式事务在Spring框架中的应用,也是其实现AOP编程思想非常出色的地方。下边先看一下事务的基础知识。
1,事务的四大特性:
原子性:指的是数据库事务是一个不可分割的工作单元
一致性:指的是数据库事务不能破坏关系数据的完整性以及业务逻辑上的一致性。
隔离性:并发环境中,当不同的事务同时操作相同的数据时,每个事务都有各自的完整数据空间。
持久性:只有事务提交,数据就所做的更新操作必须永久保存下来。
2,多个事务嵌套时,几种设置方法:
方式 |
说明 |
REQUIRED: |
业务方法需要在一个事务中运行,如果方法运行时,已经存在一个事务中,那么加入到该事务,否则自己创建一个新事务。 |
SUPPORTS: |
如果存在一个事务,那么使用当前事务,如果没有事务,则不使用事务。 |
MANDATORY: |
如果有一个事务,则使用事务,如果没有可以使用的事务,则发生异常。 |
REQUIRESNEW: |
不管是否存在事务,业务方法总为自己发起一个新事务;如果方法已经运行在一个事务中,则原有事务会被挂起,新的事务会被创建,直到方法调用结束,新事务才结束,原先的事务再恢复执行。 |
NOT_SUPPORTED: |
声明方法不需要事务,如果方法没有关联到事务,容器不会为它开启事务,如果方法在一个事务中被调用,该事务会被挂起,在方法调用结束后,原先的事务便会恢复执行。 |
NEVER: |
业务方法绝对不能再事务范围内执行,如果方法在某个事务中执行,容器会抛出例外,只有业务方法没有关联到任何事务,方法才能够正常执行。 |
NESTED: |
如果一个活动的事务存在,则运行在一个嵌套的事务中,如果没有活动事务,则按照REQUIRED属性执行,它使用了一个单独的事务,这个事务有多个可以回滚的保存点,内部事务的回滚不会对外部事务产生影响。它只对DataSourceTransactionManager事务管理器有效。 |
3,事务的隔离级别:
级别 |
说明 |
ISOLATION_DEFAULT |
这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.另外四个与JDBC的隔离级别相对应 |
ISOLATION_READ_UNCOMMITTED |
这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读 |
ISOLATION_READ_COMMITTED(Oracle默认隔离级别) |
保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。 |
ISOLATION_REPEATABLE_READ(MySQL默认隔离级别) |
这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。 (行级锁 select。。。for update) |
ISOLATION_SERIALIZABLE |
这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。 |
三,声明式事务的使用:
Spring默认情况下是不支持AOP功能的,如果使用需要引入AspectJ jar包。AspectJ是专门来做AOP操作的框架,Spring可以利用AspectJ进行AOP编程。看一下步骤吧!
1,拷贝相应的jar包:
commons-logging.jar
spring.jar(Spring核心jar包,支持IoC的jar包)
SPRING_HOME\lib\aspectj\aspectjrt.jar
SPRING_HOME\lib\aspectj\aspectjweaver.jar(支持AOP的jar包)
SPRING_HOME\lib\cglib\cglib-nodep-2.1_3.jar(支持继承动态的jar包)
2,拷入的核心配置文件applicationContext.xml需要加入增加命名空间和约束文件:
<beans...
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
...
http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
3,核心配置文件中启用AOP功能:
<aop:aspectj-autoproxy/>
4, 定义目标类:
目标类可以有接口,如果有接口Spring使用jdk动态代理产生代理对象,完成功能扩展。也可以没有接口,如果没有接口,Spring使用cglib代理产生代理对象,完成功能扩展。
5,定义扩展对象,只是普通的javabean类,里边定义我们扩展的方法即可!
6,在核心配置文件中配置目标对象和代理对象,还有就是两者之间的关系,例如:
- <!-- 声明目标类对象 -->
- <bean id="targetDao" class="com.ljh.spring.aop.TargetDao"></bean>
- <!-- 声明扩展类对象,计算方法的执行时间 -->
- <bean id="timePrint" class="com.ljh.spring.aop.TimePrint"></bean>
- <!-- 组合目标对象和扩展对象的关系 -->
- <aop:config>
- <aop:aspect id="timeAspect" ref="timePrint">
- <aop:pointcut expression="execution(public * * (..))" id="timePoincat" isolation="DEFAULT" rollback-for="java.lang.Exception"/>
- <aop:before method="printStartTime" pointcut-ref="timePoincat" isolation="DEFAULT" rollback-for="java.lang.Exception"/>
- <aop:after method="printEndTime" pointcut-ref="timePoincat" isolation="DEFAULT" rollback-for="java.lang.Exception"/>
- </aop:aspect>
- </aop:config>
分析总结:这里需要注意组合关系的编写,例如匹配此事务的目标方法execution如何匹配,事务的隔离级别如何定义等。还需要注意的是,这里写了rollback-for="java.lang.Exception",因为Spring框架默认的是针对运行时异常进行回滚的,而对编译时异常不会回滚,所以在这里要进行声明。更多关于组合对象之间的关系,可以查看官网上的帮助文档,上边列举的例子较多。
综上为Spring框架中的关于AOP的相关知识,需要我们在实践中不断使用。当然了,Spring框架和其它框架集成起来了,才会更强大的。后边看框架的组合使用……