权限、事务、日志处理如果混杂在业务代码之中会使整个代码变得非常复杂而且可读性很差,难以修改重构。
面向对象的分析和设计引入了继承、抽象和多态等概念,由此为我们提供了降低软件复杂性的工具。但是,开发人员在软件设计过程中仍然经常会面对无法用面向对象软件开发技术轻易解决的问题。这些问题之一就是如何处理应用程序中的横切关注点(Cross-cutting concerns)。
1、横切关注点
关注点就是设计人员感兴趣的某一概念或区域。例如,在一个订货系统中,核心关注点可能是订单处理和生产,而系统关注点可能是事务处理和安全管理。
横切关注点是影响多个类或模块的关注点,即未能很好地局部化和模块化的关注点。
横切关注点的表现有:
·代码纠结—当一个模块或代码段同时管理多个关注点时发生这种情况。
·代码分散—当一个关注点分布在许多模块中并且未能很好地局部化和模块化时发生这种情况。
这些现象会从几个方面影响软件;例如,它们会导致软件难以维护和重用,并且难以编写和理解。
2、关注点的隔离
面向方面编程试图通过引入“关注点的隔离”这一概念来解决这些问题。采用这一概念,可以以一种模块化而且适当局部化的方式实现关注点。AOP解决这个问题的办法是在设计空间中增加额外一维,并且引入了一些构造,这些构造使我们能够定义横切关注点,将它们转移进新的维,并且以模块化方式将它们打 包。
声明式的AOP事务配置如下:
<bean id="nodeTarget"
class="com.daosheng.service.impl.NodeManagerImpl"
singleton="true"
lazy-init="default"
autowire="default" dependency-check="default">
<property
name="dao">
<ref
local="nodeDAO" />
</property>
</bean>
<bean
id="nodeManager"
class="com.daosheng.cms.right.RightTransactionProxyFactoryBean"
singleton="true"
lazy-init="default" autowire="default"
dependency-check="default">
<property
name="transactionManager">
<ref
local="transactionManager" />
</property>
<property
name="target">
<ref
local="nodeTarget" />
</property>
<property
name="transactionAttributes">
<props>
<prop
key="insert*">
PROPAGATION_REQUIRED,-ApplicationException
</prop>
<prop
key="update*">
PROPAGATION_REQUIRED,-ApplicationException
</prop>
</props>
</property>
</bean>
|
其实在注册nodeManager时注册的实际类不是自己开发的NodeManagerImpl类而是注册的RightTransactionProxyFactoryBean代理工厂类。在其它类里调用的nodeManager方法实际上是先调用的此代理工厂类的加入横切点代码(事务处理代码)然后在调用的NodeManagerImpl的相应方法,这样就实现了NodeManagerImpl类里不用操心事务问题,而实际的事务由加入在切点的Advice来完成。其在真正方法执行前启动事务,执行后提交事务(commit),如果出现异常则回滚(rollback)。
代理工厂类是采用jdk4以上自带的动态代理机制实现的。
框架的AOP中提供了4种处理切入类型:around,before,after,introduction.顾名思义,
1) around是针对具体的某个切入点的方法(比如,现在有个OrderBook方法,around的切入类型是就这个方法的内部调用,是通过java的元
数据,在运行时通过Method.invoke来调用,具有返回值,当发生意外的时候会终止.记住的一点是,返回值.);
2)before是在方法调用前调用(在OrderBook方法前调用,但是没有返回值,同时在通常意外情况下,会继续运行下一步方法.记住的一点是没有返回值);
3)after和before刚好相反,没有什么特别的地方.
4)introduction是一个更加特殊的,但功能更加强大的切入类型.比如(你现在有Book对象,Computer对象,还有几十个这种业务对象,现在你希望在每个这样的对象中都加入一个记录最后修改的时间.但是你又不希望对每个类都进行修改,因为太麻烦了,同时更重要的一点,破坏了对象的完整性,说不定你以后又不需要这个时间数据了呢.框架AOP为了专门实现这种思想提供了一个切入处理,那就是introduction.introduction可以为动态加入某些方法,这样可以在运行时,强制转换这些对象,进行插入时间数据的动作,更深的内幕就是C++虚函数中的vtable思想).
下面时序图为事务在整个各层代码协作过程中启动和提交的过程。每个Manager或者DAO实体可能是开发的实际类也可以是代理类。