初衷
日常開發中經常用到@Transaction註解,那你知道它是怎麼應用到你的業務程式碼中的嗎?本篇文章將從以下兩個方面闡述Spring事務實現原理:
- 解析並載入事務配置:本質上是解析xml檔案將標籤載入成 BeanDefinition 物件;
- 生成事務代理物件並執行:本質上是Spring AOP在事務這塊的應用,將業務Bean替換成事務代理物件(JdkDynamicAopProxy:JDK代理,CglibAopProxy:CGLIB代理);
本文使用的原始碼版本是Spring 4.3.18.RELEASE,使用的是XML開啟事務。
關鍵類
這裡列出幾個核心類,提前留個印象,後面會講解什麼時候呼叫
- XmlBeanDefinitionReader 載入XML定義的Bean入口
- TxNamespaceHandler 解析XML中的事務標籤: advice、annotation-driven等;
- InfrastructureAdvisorAutoProxyCreator 該類實現了 BeanPostProcessor 介面(可以在Bean初始化後進行替換),是生成事務代理類並替換的關鍵類;
- AnnotationTransactionAttributeSource 用來解析業務方法使用註解 @Transaction 上的配置,提供給 TransactionInterceptor 使用;
- TransactionInterceptor 事務攔截類:真正處理事務的類,開啟、回滾事務,可以理解成切面中的通知:做什麼;
- BeanFactoryTransactionAttributeSourceAdvisor 實現了Advisor介面,可以理解為切面:切點(TransactionAttributeSourcePointcut) + 通知(TransactionInterceptor)。
示例程式碼:
public class TransactionService {
@Transactional(rollbackFor = Throwable.class)
public void testTransaction(){
System.out.println("方法邏輯");
}
}
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("config.xml");
TransactionService transactionService = context.getBean(TransactionService.class);
transactionService.testTransaction();
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd">
<bean id="transactionService" class="com.yangwq.spring.transaction.TransactionService"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/blog"/>
<property name="username" value="root"/>
<property name="password" value="11"/>
</bean>
<!-- 定義事務管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--使用註釋事務 -->
<tx:annotation-driven/>
</beans>
1. 解析並載入事務配置
載入的入口(同時也是Spring容器載入的核心程式碼):
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// 重點,這裡是Spring初始化預設的容器,在這一步會通過解析配置檔案將定義的bean轉換為 BeanDefinition,
// 儲存在 beanDefinitionMap 中
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// 重點,初始化所有非懶載入bean的方法,也可以理解為根據特定規則將 BeanDefinition 轉成 Bean物件的方法
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
事務配置的解析在上面的obtainFreshBeanFactory,由於我們使用的是ClassPathXmlApplicationContext 作為容器,它的解析類為:XmlBeanDefinitionReader;核心方法:
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
// 讀取 config.xml 檔案
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
// 開始載入 config.xml 檔案中定義的bean,這裡只是載入成BeanDefinition,初始化在另外的方法
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
doLoadBeanDefinitions 具體解析的方法是在org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions 中進行,該方法如下
protected void doRegisterBeanDefinitions(Element root) {
// Any nested <beans> elements will cause recursion in this method. In
// order to propagate and preserve <beans> default-* attributes correctly,
// keep track of the current (parent) delegate, which may be null. Create
// the new (child) delegate with a reference to the parent for fallback purposes,
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isInfoEnabled()) {
logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
preProcessXml(root);
// 真正解析config.xml檔案
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
// 判斷根節點是不是預設的節點,實際通過判斷根節點的 namespaceURI 屬性是不是 http://www.springframework.org/schema/beans ,
// 我們這裡的配置檔案宣告的正好是這個屬性,所以返回的是true,注意bean標籤也是預設標籤
if (delegate.isDefaultNamespace(root)) {
// 獲取子節點
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
// 判斷子節點是不是標籤
if (node instanceof Element) {
Element ele = (Element) node;
// bean標籤的解析
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
// 重點:tx標籤在這裡進行
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
// 解析非bean的標籤
public BeanDefinition parseCustomElement(Element ele) {
return parseCustomElement(ele, null);
}
// 解析非預設標籤方法
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
// 這裡是Spring使用了策略模式解析配置,通過namespaceUri匹配對應的處理類,也就是上面的關鍵類 TxNamespaceHandler,
// 這裡的resolve運用了懶載入,在獲取對映關係handlerMappings屬性為null時會從META-INF/spring.handlers 下面獲取對映關係,
// 由於IDEA debug的時候預設會呼叫getHandlerMappings方法,所以使用debug的時候會發現一開始就有值
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
// 獲取到處理類後,讓處理類開始解析配置
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
TxNamespaceHandler 最終交給類 AnnotationDrivenBeanDefinitionParser 進行解析事務配置;
public BeanDefinition parse(Element element, ParserContext parserContext) {
// 註冊一個事務工廠事件,允許我們自定義監聽事務的提交等操作
registerTransactionalEventListenerFactory(parserContext);
String mode = element.getAttribute("mode");
// 如果使用的是 aspectj 方式,走這個方法
if ("aspectj".equals(mode)) {
// mode="aspectj"
registerTransactionAspect(element, parserContext);
}
else {
// 預設使用的是代理模式
// mode="proxy"
AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
}
return null;
}
/**
* Inner class to just introduce an AOP framework dependency when actually in proxy mode.
*/
private static class AopAutoProxyConfigurer {
public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
// 重點,註冊 InfrastructureAdvisorAutoProxyCreator 的 BeanDefinition,這個是個關鍵類,代理業務bean的操作都靠它了
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
Object eleSource = parserContext.extractSource(element);
// 重點,註冊一個全域性的 TransactionAttributeSource 的BeanDefinition ,用於解析 @Transaction 定義的後設資料
RootBeanDefinition sourceDef = new RootBeanDefinition(
"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
sourceDef.setSource(eleSource);
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
// 重點,註冊 TransactionInterceptor 的BeanDefinition,這個就是事務真正執行的類,可以理解為是事務切面上的通知
RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
interceptorDef.setSource(eleSource);
interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registerTransactionManager(element, interceptorDef);
interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
// 重點,註冊 BeanFactoryTransactionAttributeSourceAdvisor 的BeanDefinition,可以理解為事務的切面,
// 包含了切點(TransactionAttributeSourcePointcut) + 通知(TransactionInterceptor),儲存在 ProxyFactory 中,用於生成代理物件
RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
advisorDef.setSource(eleSource);
advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
if (element.hasAttribute("order")) {
advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
}
parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));
parserContext.registerComponent(compositeDef);
}
}
}
到這裡,事務配置的載入就結束了,上面的步驟只是將事務的關鍵類變成 BeanDefinition,實際上還沒有生成Bean物件的,下面我們看下BeanDefinition 是如何變成Bean的(這一個步驟不是Spring事務獨有的,是所有BeanDefinition 的共同邏輯),然後是如何生成業務bean代理物件並替換業務bean的。
2. 生成事務代理物件
入口在 1.解析並載入事務配置 列舉的finishBeanFactoryInitialization(beanFactory) 方法中:
/**
* Finish the initialization of this context's bean factory,
* initializing all remaining singleton beans.
*/
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// Register a default embedded value resolver if no bean post-processor
// (such as a PropertyPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
@Override
public String resolveStringValue(String strVal) {
return getEnvironment().resolvePlaceholders(strVal);
}
});
}
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null);
// Allow for caching all bean definition metadata, not expecting further changes.
beanFactory.freezeConfiguration();
// 重點,開始初始化所有非懶載入的bean
beanFactory.preInstantiateSingletons();
}
beanFactory.preInstantiateSingletons() 具體方法如下:
public void preInstantiateSingletons() throws BeansException {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.將所有註冊的BeanDefinition 名稱儲存到起來
List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
// 獲取 BeanDefinition
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// bean定義不是抽象、懶載入而且是單例bean
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 工廠bean特有邏輯,這不是我們的關注點,我們關注點是else的 getBean(beanName);
if (isFactoryBean(beanName)) {
final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
return ((SmartFactoryBean<?>) factory).isEagerInit();
}
}, getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
else {
// 重點,將 BeanDefinition 建立成bean的核心方法,同時也是執行 BeanPostProcessor 的入口
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
smartSingleton.afterSingletonsInstantiated();
return null;
}
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
getBean(beanName) 方法比較複雜,這裡只列舉出關鍵點:AbstractAutowireCapableBeanFactory 的 initializeBean方法,所有bean的建立都繞不開這個方法,這個方法是執行實現了 BeanPostProcessor 的bean的邏輯:
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 執行 BeanPostProcessor 的 postProcessBeforeInitialization 方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// 重點,InfrastructureAdvisorAutoProxyCreator 實現了BeanPostProcessor 介面,所以這裡會呼叫 InfrastructureAdvisorAutoProxyCreator 的postProcessBeforeInitialization 方法,
// wrappedBean 是生成代理後物件,wrappedBean 會替換掉傳入的bean,如果當前bean需要事務,wrappedBean就是被JDK或者CGLIB代理後的bean
wrappedBean = postProcessAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
InfrastructureAdvisorAutoProxyCreator 的 postProcessAfterInitialization 定義在父類:AbstractAutoProxyCreator,AbstractAutoProxyCreator這個類同時是Spring AOP處理的入口,並不是說事務處理獨有的,具體實現如下:
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
// 重點,AOP生成代理物件的入口,這裡也會生成事務代理物件
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
// 從Spring容器中獲取所有切面bean,並判斷是否在切面中,如果是的話生成一個代理物件,怎麼代理由具體的切面定義
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 這裡就是用來判斷當前bean 能不能代理
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 首先查詢切面Bean,對於本篇文章就是我們上面定義的 BeanFactoryTransactionAttributeSourceAdvisor 的 BeanDefinition,注意:實際應用場景肯定不僅只有一個切面的。
// spring現在只有BeanDefinition,這個方法先通過獲取切面 beanNames ,然後再呼叫上面的 getBean 方法生成 BeanFactoryTransactionAttributeSourceAdvisor bean物件
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 需要代理,生成代理物件
if (specificInterceptors != DO_NOT_PROXY) {
// 加入快取中
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 真正生成代理的地方
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
// 返回代理後的bean
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
// 不代理,返回原始bean
return bean;
}
// 獲取切面bean,先通過獲取切面BeanNames ,然後通過獲取bean
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 這個方法就是獲取切面bean,首先從容器中獲取實現了 Advisor 的beanNames,然後通過beanName再獲取Bean,
// 對於本篇文章只定義了一個事務切面,所以這裡返回的結果是 BeanFactoryTransactionAttributeSourceAdvisor Bean物件
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 判斷當前bean是否能被切面應用,判斷規則在下面有說明
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
// findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName) 具體實現邏輯在org.springframework.aop.support.AopUtils#findAdvisorsThatCanApply
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
// 請注意,這個方法是AOP通用判斷是否能應用切面的方法,不是事務處理獨有的
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
// 首先判斷類能不能匹配上,匹配不上就返回false, BeanFactoryTransactionAttributeSourceAdvisor 的切點類:
// TransactionAttributeSourcePointcut,預設ClassFilter 返回true,所以這裡不會進if
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
// 然後判斷方法匹配,TransactionAttributeSourcePointcut 通過繼承關係可以看到不是 MethodMatcher.TRUE,所以不會進if
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
// 判斷是不是引介方法匹配,什麼是引介增強:為目標類追加方法,屬於類的增強,
// 而 PointcutAdvisor 屬於攔截目標類的方法並增強,TransactionAttributeSourcePointcut 是 PointcutAdvisor 的子類,不屬於引介增強
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
// 開始讀取目標類的每一個方法,判斷是否在切面中
Set<Class<?>> classes = new LinkedHashSet<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
classes.add(targetClass);
for (Class<?> clazz : classes) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
// 對於事務而言,判斷條件重點在 TransactionAttributeSourcePointcut 的 matches 方法
if ((introductionAwareMethodMatcher != null &&
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
// TransactionAttributeSourcePointcut 的 matches 方法核心邏輯在 SpringTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement)
// 注意:只會判斷 public 的方法,判斷有沒有 Transactional 註解;判斷的順序為:先判斷方法上面有沒有,再判斷類上面有沒有。
// 判斷核心就是看方法或類上面有沒有 Transactional 註解,有這個註解就解析這個註解的後設資料
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ae, Transactional.class);
if (attributes != null) {
return parseTransactionAnnotation(attributes);
}
else {
return null;
}
}
// 解析 Transactional 註解後設資料
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
Propagation propagation = attributes.getEnum("propagation");
rbta.setPropagationBehavior(propagation.value());
Isolation isolation = attributes.getEnum("isolation");
rbta.setIsolationLevel(isolation.value());
rbta.setTimeout(attributes.getNumber("timeout").intValue());
rbta.setReadOnly(attributes.getBoolean("readOnly"));
rbta.setQualifier(attributes.getString("value"));
ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<RollbackRuleAttribute>();
Class<?>[] rbf = attributes.getClassArray("rollbackFor");
for (Class<?> rbRule : rbf) {
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
String[] rbfc = attributes.getStringArray("rollbackForClassName");
for (String rbRule : rbfc) {
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
Class<?>[] nrbf = attributes.getClassArray("noRollbackFor");
for (Class<?> rbRule : nrbf) {
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
String[] nrbfc = attributes.getStringArray("noRollbackForClassName");
for (String rbRule : nrbfc) {
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
rbta.getRollbackRules().addAll(rollBackRules);
return rbta;
}
// 以上就是 findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName) 的邏輯
// 下面回到wrapIfNecessary方法,如果當前bean需要生成代理物件,會呼叫下面的這個方法
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
// 建立代理工廠,用於建立代理bean
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
// 判斷是否配置了代理目標類,配置了這個選項會全部使用cglib代理
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 把所有的切面類放入 ProxyFactory
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 開始建立代理bean
return proxyFactory.getProxy(getProxyClassLoader());
}
proxyFactory.getProxy(getProxyClassLoader()) 方法實現:
public Object getProxy(ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
// createAopProxy方法邏輯,config 其實就是上面的 proxyFactory 物件,這個物件包含了目標物件以及切面類:
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// optimize:代理是否應該執行優化,一般用不上
// proxyTargetClass:這個屬性為treu時,不管目標類是不是實現的介面,都使用cglib代理
// hasNoUserSuppliedProxyInterfaces:是否只使用了Spring支援的代理介面,如果使用者自定義了代理介面不能進行cglib代理
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
// 如果目標類是介面或者已經被jdk代理過了,使用jdk代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 其他情況使用CGLIB代理
return new ObjenesisCglibAopProxy(config);
}
// 使用JDK代理
else {
return new JdkDynamicAopProxy(config);
}
}
// ObjenesisCglibAopProxy 的 getProxy(classLoader) 方法,cglib是使用Enhancer建立代理物件的 :
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
}
try {
// 獲取目標類
Class<?> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
// 代理類的父類,預設是目標類
Class<?> proxySuperClass = rootClass;
// 如果目標類以及是cglib代理類,
if (ClassUtils.isCglibProxyClass(rootClass)) {
// 取cglib代理類的父類作為代理類的父類
proxySuperClass = rootClass.getSuperclass();
// 獲取代理類的介面追加到當前類的介面集合中
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
// 驗證目標類是否能被代理,僅僅是列印日誌,不做其他處理
validateClassIfNecessary(proxySuperClass, classLoader);
// 使用Enhancer 來構造cglib代理物件
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
// 重點,設定回撥的類,很重要的一個類 DynamicAdvisedInterceptor,這個類就是應用AOP 通知的地方,對於本篇文章就是應用TransactionInterceptor
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// 建立代理類的位元組碼,並建立例項,例項設定回撥
return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
": Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
": Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Throwable ex) {
// TargetSource.getTarget() failed
throw new AopConfigException("Unexpected AOP exception", ex);
}
}
// JdkDynamicAopProxy 的 getProxy(classLoader) 方法:
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
通過2. 生成事務代理物件,此時建立的bean就是以及被JDK或者CGLIB代理的類,這一步是Spring AOP通用的處理邏輯,那具體是怎麼執行的呢?
JDK動態代理執行:
// 本質是呼叫org.springframework.aop.framework.JdkDynamicAopProxy#invoke方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Class<?> targetClass = null;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be null. Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
// 獲取方法的攔截器鏈,對於本篇文章就是關鍵類:BeanFactoryTransactionAttributeSourceAdvisor
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 將所有引數:代理物件,目標物件,方法,引數,攔截器鏈封裝到一個ReflectiveMethodInvocation物件中
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 然後呼叫ReflectiveMethodInvocation的proceed方法,會執行攔截器
retVal = invocation.proceed();
}
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
org.springframework.aop.framework.ReflectiveMethodInvocation#proceed 方法:
public Object proceed() throws Throwable {
// 所有攔截器呼叫完成,一般情況是沒有匹配到任意的攔截器,這裡會執行目標類本身的方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 獲取攔截器鏈中的第一個攔截器
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// 通知器或通知是動態匹配方法攔截器型別,對於本篇文章,interceptorOrInterceptionAdvice 是TransactionInterceptor物件,
// 所有走的是else,直接執行TransactionInterceptor的invoke方法
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// 動態匹配方法攔截器
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
// 匹配成功就執行對應的攔截器
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// 如果不匹配,就跳過此攔截器,遞迴執行下一個攔截器
return proceed();
}
}
else {
// 如果是一個interceptor,直接呼叫這個interceptor對應的方法
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
CGLIB代理執行:
// 其實就是建立代理物件時設定的回撥類DynamicAdvisedInterceptor
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
private final AdvisedSupport advised;
public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
}
// 主要是這個方法執行攔截,處理邏輯大致和JDK動態代理差不多,都是獲取攔截器鏈,
// 然後構建ReflectiveMethodInvocation的子類CglibMethodInvocation物件,
// 執行ReflectiveMethodInvocation的proceed方法
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Class<?> targetClass = null;
Object target = null;
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be null. Get as late as possible to minimize the time we
// "own" the target, in case it comes from a pool...
target = getTarget();
if (target != null) {
targetClass = target.getClass();
}
// 獲取方法的攔截器鏈,對於本篇文章就是關鍵類:BeanFactoryTransactionAttributeSourceAdvisor
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// We can skip creating a MethodInvocation: just invoke the target directly.
// Note that the final invoker must be an InvokerInterceptor, so we know
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// 將引數封裝成CglibMethodInvocation物件並執行proceed方法,CglibMethodInvocation 其實是ReflectiveMethodInvocation的子類,可以理解為ReflectiveMethodInvocation是模板類,CglibMethodInvocation通過重寫了部分方法,proceed是兩種代理處理的共同邏輯
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null) {
releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
@Override
public boolean equals(Object other) {
return (this == other ||
(other instanceof DynamicAdvisedInterceptor &&
this.advised.equals(((DynamicAdvisedInterceptor) other).advised)));
}
/**
* CGLIB uses this to drive proxy creation.
*/
@Override
public int hashCode() {
return this.advised.hashCode();
}
protected Object getTarget() throws Exception {
return this.advised.getTargetSource().getTarget();
}
protected void releaseTarget(Object target) throws Exception {
this.advised.getTargetSource().releaseTarget(target);
}
}
事務的最終執行類 TransactionInterceptor 的invoke 方法:
public Object invoke(final MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {@code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
@Override
public Object proceedWithInvocation() throws Throwable {
// 事務執行完畢後呼叫鏈繼續向下執行
return invocation.proceed();
}
});
}
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
throws Throwable {
// 獲取當前方法的事務屬性
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
// 獲取事務管理器
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
// 方法名
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
// 如果方法沒有事務或者事務管理器不屬於CallbackPreferringPlatformTransactionManager,CallbackPreferringPlatformTransactionManager需要回撥函式來實現事務流程,而我們常用的DataSourceTransactionManager就不是CallbackPreferringPlatformTransactionManager
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// 建立TransactionInfo事務物件,事務的管理都是通過TransactionInfo物件來完成,這裡建立事務會使用到Spring的事務隔離級別,具體的邏輯可以自行檢視
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// 攔截器鏈繼續向下執行
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 丟擲異常時提交或者回滾事務
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
// 重置TransactionInfo 的 ThreadLocal
cleanupTransactionInfo(txInfo);
}
// 提交/回滾事務
commitTransactionAfterReturning(txInfo);
return retVal;
}
// else使用的是CallbackPreferringPlatformTransactionManager,
else {
// .......略
}
}
總結
以上就是事務應用到業務場景中的原理,可以簡單理解:Spring事務是在Spring AOP的基礎上開發的,關注關鍵類:TransactionInterceptor 的實現就行了,不管是JDK動態代理還是CGLIB代理都是要用到這個類去提交/回滾事務的。如有錯誤歡迎指出。