1. 什么是AOP(Aspect oriented programming)
1) 核心概念
- aspect:如果说class是OOP(Object Oriented Programming)中的一等公民,那么aspect就是AOP中的一等公民。aspect用于cross-cutting concern的模块化。
- cross-cutting concern: 个人理解,AOP是为cross-cutting concern而生的,对于这个相对抽象的概念,用举例来解释的话,就是transaction management了。
- join point: 程序执行中的某一个点,用于在该点插入advice。
- advice: aspect在某个join point进行的操作,有以下类型:around,before,after。通常advice又称为interception。
- pointcut: 用于匹配找到某个join point的条件表达式。
- AOP proxy: 用于实现aspect。
2. spring declarative transaction management
1)transaction is not only about DB, but also domain service.
transaction的概念,个人理解应该是始于database,为了保证数据库操作的原子性,但随着后来的发展,transaction的概念不仅限于数据库操作,更重要的用于service层面,用于保证service的原子性。比如银行卡取款,这可以理解为银行提供的一项service,该service的内部实现包括很多动作,比如在你的账户中扣除相应金额,以及将那些输出那些钱给你;可以想象,如果这样的service没有transaction的保护,就会出现问题了。相似的,很多service都需要包含这样的transaction特性。比如在我工作的项目中,就有domain service会用transaction包装起来。
2) spring declarative transaction management用起来貌似很简单。
spring的官方文档中说,spring提供的declarative transaction management很容易实现,只需要将那个class用@transactional annotation进行标注。同时在我们项目中,有一个domain service需要标记为transaction,因此我们就用@transaction标注该service。但是当我们运行相关测试的时候,问题出现了,error message显示没有interface与给domain service对应。这又是怎么回事呢?
pubic class CustomerService { @Transactional public Customer getCustomer(Integer customerId) { .......... } }
3)上面问题的奥妙在于AOP proxy。
针对上面问题,我们去查spring declarative transaction management的实现,发现原来spring transaction的实现依托于AOP proxy。spring中的AOP proxy包括JDK dynamic proxy和CGLIB proxy,其中默认使用JDK dynamic proxy。而JDK dynamic proxy只支持interface中提供方法的proxy而不支持具体的class,CGLIB则同时支持具体class中方法的proxy,但由于面向接口本来就是oop中推荐的方式,因此推荐令domain service实现接口,以实现对其进行transaction管理。然后我们的code就修改成了这个样子,错误就消失了:
pubic class DefaultCustomerService implements CustomerService{ @Override @Transactional public Customer getCustomer(Integer customerId) { .......... } }
4)AOP proxy是如何影响方法调用的。
在学习AOP proxy的同时,也解决了之前的另一个疑问。在尝试debug被spring transaction管理的domain service时,如果尝试dubug into该方法就会进入invoke方法。其实invoke方法也是由spring AOP提供的。
下图是POJO中提供的方法的调用:
从代码的角度来理解:
public class Main { public static void main(String[] args) { Pojo pojo = new SimplePojo(); // this is a direct method call on the ‘pojo‘ reference pojo.foo(); } }
下图是AOP proxy情形下的方法调用:
从代码的角度来理解:
public class Main { public static void main(String[] args) { ProxyFactory factory = new ProxyFactory(new SimplePojo()); factory.addInterface(Pojo.class); factory.addAdvice(new RetryAdvice()); Pojo pojo = (Pojo) factory.getProxy(); // this is a method call on the proxy! pojo.foo(); } }
关于transaction还有很多话可以讲,以后再讲吧:)