以下观点,是个人对AOP底层实现的理解。由于个人知识的局限性,难免有错误,仅
供参考。
我们以Spring的事务管理机制为切入点,来进行说明。并且,以下所有观点,都是建
立在2个前提条件下:
1,Spring是在程序运行期间,把事务控制代码添加到委托类的字节码文件中的。
2,Spring具有修改字节码文件的能力。
首先,我们来回顾一下Spring的事务控制。Spring为我们提供了编程式的事务控制和
申明式的事务控制。而申明式事务控制的实现依赖的就是我们今天要讨论的AOP。编程式
事务,就是直接把事务控制代码写在java类中,事务的开启和提交,都要显示的写在java
代码中。申明式事务是通过配置的方式,申明哪些DAO层的方法会进行事务控制。Spring
会根据我们的配置文件,拦截所有我们配置的方法,然后进行事务控制。看下面的代码,
这就是我们常见的申明式事务配置文件的关键代码:
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transactionManager" />
<property name="transactionAttributes">
<props>
<prop key="query*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="save*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="delete*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="update*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
这段代码,我们在大部分使用了Spring框架的实际项目中,都可以看到。虽然不是
完全一致,基本上都是大同小异。毕竟,使用的都是Spring的声明式事务。
那么,在程序运行期间,AOP是如何进行事务控制的呢?当用户点击了一个按钮,进
行查询操作时,在后台,Spring的拦截器就会进行拦截。拦截到这个方法queryAll()以
后,Spring会根据这个方法配置的事务传播机制(比如是PROPAGATION_REQUIRED,
readOnly),去生成对应的事务控制字节码。然后,把生成的字节码添加到queryAll()
所对应的字节码文件中。最后,把修改以后的字节码文件装载到JVM执行。这里有一个
关键点就是,queryAll()方法(或者说queryAll()所在的类)是在项目编译阶段生成
的。
这就是Spring中的动态代理的实现方式。这里的“动态”,指的就是在程序运行期
间,生成字节码文件。关于Spring中动态代理的实现细节,业界的看法是一致的:融合
供参考。
我们以Spring的事务管理机制为切入点,来进行说明。并且,以下所有观点,都是建
立在2个前提条件下:
1,Spring是在程序运行期间,把事务控制代码添加到委托类的字节码文件中的。
2,Spring具有修改字节码文件的能力。
首先,我们来回顾一下Spring的事务控制。Spring为我们提供了编程式的事务控制和
申明式的事务控制。而申明式事务控制的实现依赖的就是我们今天要讨论的AOP。编程式
事务,就是直接把事务控制代码写在java类中,事务的开启和提交,都要显示的写在java
代码中。申明式事务是通过配置的方式,申明哪些DAO层的方法会进行事务控制。Spring
会根据我们的配置文件,拦截所有我们配置的方法,然后进行事务控制。看下面的代码,
这就是我们常见的申明式事务配置文件的关键代码:
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transactionManager" />
<property name="transactionAttributes">
<props>
<prop key="query*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="save*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="delete*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="update*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
这段代码,我们在大部分使用了Spring框架的实际项目中,都可以看到。虽然不是
完全一致,基本上都是大同小异。毕竟,使用的都是Spring的声明式事务。
那么,在程序运行期间,AOP是如何进行事务控制的呢?当用户点击了一个按钮,进
行查询操作时,在后台,Spring的拦截器就会进行拦截。拦截到这个方法queryAll()以
后,Spring会根据这个方法配置的事务传播机制(比如是PROPAGATION_REQUIRED,
readOnly),去生成对应的事务控制字节码。然后,把生成的字节码添加到queryAll()
所对应的字节码文件中。最后,把修改以后的字节码文件装载到JVM执行。这里有一个
关键点就是,queryAll()方法(或者说queryAll()所在的类)是在项目编译阶段生成
的。
这就是Spring中的动态代理的实现方式。这里的“动态”,指的就是在程序运行期
间,生成字节码文件。关于Spring中动态代理的实现细节,业界的看法是一致的:融合
了JDK的动态代理和CGLIB的动态代理。