摘要:
對SpringBoot
有多了解,其實就是看你對Spring Framework
有多熟悉~ 比如SpringBoot
大量的模塊裝配的設計模式,其實它屬於Spring Framework提供的能力。SpringBoot大行其道的今天,基於XML
配置的Spring Framework的使用方式注定已成為過去式。注解驅動應用,面向元數據編程已然成受到越來越多開發者的偏好了,畢竟它的便捷程度、優勢都是XML方式不可比擬的。
@Configuration
@ConditionalOnClass({PlatformTransactionManager.class})
@AutoConfigureAfter({JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, Neo4jDataAutoConfiguration.class})
@EnableConfigurationProperties({TransactionProperties.class})
public class TransactionAutoConfiguration {
public TransactionAutoConfiguration() {
}
@Bean
@ConditionalOnMissingBean
public TransactionManagerCustomizers platformTransactionManagerCustomizers(ObjectProvider<PlatformTransactionManagerCustomizer<?>> customizers) {
return new TransactionManagerCustomizers((Collection)customizers.orderedStream().collect(Collectors.toList()));
}
@Configuration
@ConditionalOnBean({PlatformTransactionManager.class})
@ConditionalOnMissingBean({AbstractTransactionManagementConfiguration.class})
public static class EnableTransactionManagementConfiguration {
public EnableTransactionManagementConfiguration() {
}
@Configuration
@EnableTransactionManagement(
proxyTargetClass = true
)
@ConditionalOnProperty(
prefix = "spring.aop",
name = {"proxy-target-class"},
havingValue = "true",
matchIfMissing = true
)
//默認采用cglib代理
public static class CglibAutoProxyConfiguration {
public CglibAutoProxyConfiguration() {
}
}
@Configuration
@EnableTransactionManagement(
proxyTargetClass = false
)
@ConditionalOnProperty(
prefix = "spring.aop",
name = {"proxy-target-class"},
havingValue = "false",
matchIfMissing = false
)
public static class JdkDynamicAutoProxyConfiguration {
public JdkDynamicAutoProxyConfiguration() {
}
}
}
@Configuration
//當PlatformTransactionManager類型的bean存在並且當存在多個bean時指定為Primary的 PlatformTransactionManager存在時,該配置類才進行解析
@ConditionalOnSingleCandidate(PlatformTransactionManager.class)
public static class TransactionTemplateConfiguration {
private final PlatformTransactionManager transactionManager;
public TransactionTemplateConfiguration(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
// 由於TransactionAutoConfiguration是在DataSourceTransactionManagerAutoConfiguration之后才被解析處理的,而在DataSourceTransactionManagerAutoConfiguration中配置了transactionManager,因此, TransactionTemplateConfiguration 會被處理.
@Bean
@ConditionalOnMissingBean
public TransactionTemplate transactionTemplate() {
return new TransactionTemplate(this.transactionManager);
}
}
}
PlatformTransactionManager后續章節會分析
提示:使用@EnableTransactionManagement
注解前,請務必保證你已經配置了至少一個PlatformTransactionManager
的Bean,否則會報錯。(當然你也可以實現TransactionManagementConfigurer
來提供一個專屬的,只是我們一般都不這么去做~~~)
開啟注解驅動
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({TransactionManagementConfigurationSelector.class})
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default 2147483647;
}
簡直和@EnableAsync
注解的一模一樣。不同之處只在於@Import
導入器導入的這個類.
對比一下
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {
// 支持自定義注解類型 去支持異步~~~
Class<? extends Annotation> annotation() default Annotation.class;
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
TransactionManagementConfigurationSelector
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
public TransactionManagementConfigurationSelector() {
}
protected String[] selectImports(AdviceMode adviceMode) {
switch(adviceMode) {
case PROXY:
return new String[]{AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[]{this.determineTransactionAspectClass()};
default:
return null;
}
}
private String determineTransactionAspectClass() {
return ClassUtils.isPresent("javax.transaction.Transactional", this.getClass().getClassLoader()) ? "org.springframework.transaction.aspectj.AspectJJtaTransactionManagementConfiguration" : "org.springframework.transaction.aspectj.AspectJTransactionManagementConfiguration";
}
}
依然可以看出和@EnableAsync
導入的AsyncConfigurationSelector
如出一轍,都繼承自AdviceModeImportSelector
,畢竟模式一樣,觸類旁通,一通百通~
AdviceModeImportSelector
目前所知的三個子類是:AsyncConfigurationSelector
、TransactionManagementConfigurationSelector
、CachingConfigurationSelector
。由此可見后面還會着重分析的Spring
的緩存體系@EnableCaching
,模式也是和這個極其類似的~~~
AutoProxyRegistrar
它是個ImportBeanDefinitionRegistrar
,可以實現自己向容器里注冊Bean的定義信息
// @since 3.1
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
private final Log logger = LogFactory.getLog(this.getClass());
public AutoProxyRegistrar() {
}
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
// 這里面需要特別注意的是:這里是拿到所有的注解類型~~~而不是只拿@EnableAspectJAutoProxy這個類型的
// 原因:因為mode、proxyTargetClass等屬性會直接影響到代理得方式,而擁有這些屬性的注解至少有:
// @EnableTransactionManagement、@EnableAsync、@EnableCaching等~~~~
// 甚至還有啟用AOP的注解:@EnableAspectJAutoProxy它也能設置`proxyTargetClass`這個屬性的值,因此也會產生關聯影響~
Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
Iterator var5 = annTypes.iterator();
while(var5.hasNext()) {
String annType = (String)var5.next();
AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
if (candidate != null) {
Object mode = candidate.get("mode");
Object proxyTargetClass = candidate.get("proxyTargetClass");
// 如果存在mode且存在proxyTargetClass 屬性
// 並且兩個屬性的class類型也是對的,才會進來此處(因此其余注解相當於都擋外面了~)
if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() && Boolean.class == proxyTargetClass.getClass()) {
candidateFound = true;
if (mode == AdviceMode.PROXY) {
// 它主要是注冊了一個`internalAutoProxyCreator`,但是若出現多次的話,這里不是覆蓋的形式,而是以優先級的形式
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
//看要不要強制使用CGLIB的方式(由此可以發現 這個屬性若出現多次,是會是覆蓋的形式)
if ((Boolean)proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
}
if (!candidateFound && this.logger.isInfoEnabled()) {
String name = this.getClass().getSimpleName();
this.logger.info(String.format("%s was imported but no annotations were found having both 'mode' and 'proxyTargetClass' attributes of type AdviceMode and boolean respectively. This means that auto proxy creator registration and configuration may not have occurred as intended, and components may not be proxied as expected. Check to ensure that %s has been @Import'ed on the same class where these annotations are declared; otherwise remove the import of %s altogether.", name, name, name));
}
}
}
跟蹤AopConfigUtils
的源碼你會發現,事務這塊向容器注入的是一個InfrastructureAdvisorAutoProxyCreator
,並且看看是采用CGLIB
還是JDK
代理。它主要是讀取Advisor
類,並對符合的bean進行二次代理。
ProxyTransactionManagementConfiguration
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
public ProxyTransactionManagementConfiguration() {
}
@Bean(
name = {"org.springframework.transaction.config.internalTransactionAdvisor"}
)
@Role(2)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(this.transactionAttributeSource());
advisor.setAdvice(this.transactionInterceptor());
if (this.enableTx != null) {
// 順序由@EnableTransactionManagement注解的Order屬性來指定 默認值為:Ordered.LOWEST_PRECEDENCE
advisor.setOrder((Integer)this.enableTx.getNumber("order"));
}
return advisor;
}
@Bean
@Role(2)
// TransactionAttributeSource 這種類特別像 `TargetSource`這種類的設計模式
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
@Bean
@Role(2)
// 事務攔截器,它是個`MethodInterceptor`,它也是Spring處理事務最為核心的部分
// 請注意:你可以自己定義一個TransactionInterceptor(同名的),來覆蓋此Bean
public TransactionInterceptor transactionInterceptor() {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(this.transactionAttributeSource());
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
@Configuration
public abstract class AbstractTransactionManagementConfiguration implements ImportAware {
@Nullable
protected AnnotationAttributes enableTx;
// 此處:注解的默認的事務處理器(可議通過實現接口TransactionManagementConfigurer來自定義配置)
// 因為事務管理器這個東西,一般來說全局一個就行,但是Spring也提供了定制化的能力~~~
@Nullable
protected PlatformTransactionManager txManager;
public AbstractTransactionManagementConfiguration() {
}
public void setImportMetadata(AnnotationMetadata importMetadata) {
this.enableTx = AnnotationAttributes.fromMap(importMetadata.getAnnotationAttributes(EnableTransactionManagement.class.getName(), false));
//這個注解@EnableTransactionManagement是必須的~~~~~~~~~~~~~~~~否則報錯了
if (this.enableTx == null) {
throw new IllegalArgumentException("@EnableTransactionManagement is not present on importing class " + importMetadata.getClassName());
}
}
@Autowired(
required = false
)
// 這里和@Async的處理一樣,配置文件可以實現這個接口。然后給注解驅動的給一個默認的事務管理器~~~~
void setConfigurers(Collection<TransactionManagementConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
// 同樣的,最多也只允許你去配置一個~~~
if (configurers.size() > 1) {
throw new IllegalStateException("Only one TransactionManagementConfigurer may exist");
} else {
TransactionManagementConfigurer configurer = (TransactionManagementConfigurer)configurers.iterator().next();
this.txManager = configurer.annotationDrivenTransactionManager();
}
}
}
@Bean(
name = {"org.springframework.transaction.config.internalTransactionalEventListenerFactory"}
)
@Role(2)
public static TransactionalEventListenerFactory transactionalEventListenerFactory() {
return new TransactionalEventListenerFactory();
}
}
BeanFactoryTransactionAttributeSourceAdvisor
TransactionAttributeSourcePointcut
這個就是事務的匹配Pointcut
切面,決定了哪些類需要生成代理對象從而應用事務。
// 首先它的訪問權限事default 顯示是給內部使用的
// 首先它繼承自StaticMethodMatcherPointcut 所以`ClassFilter classFilter = ClassFilter.TRUE;` 匹配所有的類
// 並且isRuntime=false 表示只需要對方法進行靜態匹配即可~~~~
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
// 方法的匹配 靜態匹配即可(因為事務無需要動態匹配這么細粒度~~~)
@Override
public boolean matches(Method method, Class<?> targetClass) {
// 實現了如下三個接口的子類,就不需要被代理了 直接放行
// TransactionalProxy它是SpringProxy的子類。 如果是被TransactionProxyFactoryBean生產出來的Bean,就會自動實現此接口,那么就不會被這里再次代理了
// PlatformTransactionManager:spring抽象的事務管理器~~~
// PersistenceExceptionTranslator對RuntimeException轉換成DataAccessException的轉換接口
if (TransactionalProxy.class.isAssignableFrom(targetClass) ||
PlatformTransactionManager.class.isAssignableFrom(targetClass) ||
PersistenceExceptionTranslator.class.isAssignableFrom(targetClass)) {
return false;
}
// 重要:拿到事務屬性源~~~~~~
// 如果tas == null表示沒有配置事務屬性源,那是全部匹配的 也就是說所有的方法都匹配~~~~(這個處理還是比較讓我詫異的~~~)
// 或者 標注了@Transaction這樣的注解的方法才會給與匹配~~~
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
...
// 由子類提供給我,告訴事務屬性源~~~
@Nullable
protected abstract TransactionAttributeSource getTransactionAttributeSource();
}
@Transactional
這個事務注解可以用在類上,也可以用在方法上。
- 將事務注解標記到服務組件類級別,相當於為該服務組件的每個服務方法都應用了這個注解
- 事務注解應用在方法級別,是更細粒度的一種事務注解方式
注意 : 如果某個方法和該方法所屬類上都有事務注解屬性,優先使用方法上的事務注解屬性。
另外,Spring 支持三個不同的事務注解 :
- Spring 事務注解
org.springframework.transaction.annotation.Transactional
- JTA事務注解 ·javax.transaction.Transactional·
- EJB 3 事務注解 ·javax.ejb.TransactionAttribute·
自定義TransactionManagementConfigurer
@Configuration
@EnableTransactionManagement
public class MyTransactionManagementConfigurer implements TransactionManagementConfigurer {
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(dataSource);
return dataSourceTransactionManager;
}
@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
return null;
}
}
@EnableAspectJAutoProxy和@EnableTransactionManagement優先級?
@EnableAspectJAutoProxy
會像容器注入AnnotationAwareAspectJAutoProxyCreator
@EnableTransactionManagement
會像容器注入InfrastructureAdvisorAutoProxyCreator
public abstract class AopConfigUtils {
...
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
// 可以發現這里有一個很巧妙的處理:會對自動代理創建器進行升級~~~~
// 所以如果你第一次進來的是`InfrastructureAdvisorAutoProxyCreator`,第二次進來的是`AnnotationAwareAspectJAutoProxyCreator`,那就會取第二次進來的這個Class
// 反之則不行。這里面是維護的一個優先級順序的,具體參看本類的static代碼塊,就是順序 最后一個`AnnotationAwareAspectJAutoProxyCreator`才是最為強大的
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
...
}
從上面的分析可以知道:無論你的這些注解有多少個,無論他們的先后順序如何,它內部都有咯優先級提升的機制來保證向下的覆蓋兼容。因此一般情況下,我們使用的都是最高級的AnnotationAwareAspectJAutoProxyCreator
這個自動代理創建器~~~