欢迎大家关注github.com/hsfxuebao,希望对大家有所协助,要是觉得能够的话费事给点一下Star哈
1. 事例(注解版)
- 引进依赖
build.gradle文件:
dependencies { api(project(":spring-context")) api(project(":spring-aspects")) //引进aop&切面模块 api(project(":spring-jdbc")) //引进jdbc模块 // https://mvnrepository.com/artifact/c3p0/c3p0 implementation group: 'c3p0', name: 'c3p0', version: '0.9.1.2' // https://mvnrepository.com/artifact/mysql/mysql-connector-java implementation group: 'mysql', name: 'mysql-connector-java', version: '8.0.18' // https://mvnrepository.com/artifact/org.projectlombok/lombok compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.14' }
- 注解版装备文件
@ComponentScan("com.hsf.spring.tx")
@Configuration
@EnableTransactionManagement
public class TxConfig {
@Bean
public DataSource dataSource() throws Exception {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser("root");
dataSource.setPassword("hsfxuebao");
dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/spring_tx");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate() throws Exception {
// Spring对@Configuration类会特殊处理,给容器中加组件的办法,多次调用都只是从容器中找组件
return new JdbcTemplate(dataSource());
}
// 注册业务管理器
@Bean
public PlatformTransactionManager transactionManager() throws Exception {
return new DataSourceTransactionManager(dataSource());
}
}
- 实例类
@Repository
public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public void insert() {
String sql = "INSERT INTO user(name,age) values(?,?)";
String name = UUID.randomUUID().toString().substring(0, 5);
jdbcTemplate.update(sql, name, 19);
}
}
@Service
public class UserInfoService {
public void test() {
System.out.println("UserInfoService.test()");
}
}
@Service
public class UserService {
@Autowired
private UserDao userDao;
// 不主动注入,模仿空指针反常
private UserInfoService userInfoService;
@Transactional()
public void insertUser() {
userDao.insert();
System.out.println("插入完结");
// 模仿空指针反常
userInfoService.test();
}
}
- 测验类
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(TxConfig.class);
// 业务
UserService userService = context.getBean(UserService.class);
userService.insertUser();
}
2. @EnableTransactionManagement
咱们第1末节中开端业务管理很简单,运用 @EnableTransactionManagement
注解即可。那么也就说明 @EnableTransactionManagement
是咱们剖析的进口了。
@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 Ordered.LOWEST_PRECEDENCE;
}
很明显了@Import(TransactionManagementConfigurationSelector.class)
指向咱们去看
去看 TransactionManagementConfigurationSelector
的完结。
2.1 TransactionManagementConfigurationSelector
能够看到,TransactionManagementConfigurationSelector
直接完结了 ImportSelector
接口,ImportSelector
会依据 selectImports
回来的字符串数组(一般是类的全路径名) 经过反射加载该类并注册到Spring容器中
。
所以咱们这儿必定来看一下 selectImports
办法了,ImportSelector#selectImports
的完结在其父类AdviceModeImportSelector#selectImports
:
@Override
public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
// 获取注解类型, 这儿是 EnableTransactionManagement
Class<?> annType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class);
Assert.state(annType != null, "Unresolvable type argument for AdviceModeImportSelector");
// 解分出 @EnableTransactionManagement 注解的参数
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
if (attributes == null) {
throw new IllegalArgumentException(String.format(
"@%s is not present on importing class '%s' as expected",
annType.getSimpleName(), importingClassMetadata.getClassName()));
}
// 获取mode特点。EnableTransactionManagement 默许mode = AdviceMode.PROXY
AdviceMode adviceMode = attributes.getEnum(getAdviceModeAttributeName());
// 调用 TransactionManagementConfigurationSelector#selectImports
String[] imports = selectImports(adviceMode);
if (imports == null) {
throw new IllegalArgumentException("Unknown AdviceMode: " + adviceMode);
}
return imports;
}
...
@Nullable
protected abstract String[] selectImports(AdviceMode adviceMode);
能够知道了 这儿是将 protected abstract String[] selectImports(AdviceMode adviceMode);
回来的值回来给 Spring。这儿咱们看看在 TransactionManagementConfigurationSelector
中的 selectImports(AdviceMode adviceMode)
办法的完结。
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
@Override
protected String[] selectImports(AdviceMode adviceMode) {
// 默许值 是 PROXY。个人猜测是经过 署理形式完结业务,假如是 ASPECTJ 则是经过 ASPECTJ的办法完结,AspectJ 需求独自引进编译
switch (adviceMode) {
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {determineTransactionAspectClass()};
default:
return null;
}
}
private String determineTransactionAspectClass() {
return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
}
}
到这儿就能够看到了,默许状况下,咱们引进了两个类,AutoProxyRegistrar
和ProxyTransactionManagementConfiguration
。
-
AutoProxyRegistrar
: 首要是注册了InfrastructureAdvisorAutoProxyCreator
主动署理创立器。而InfrastructureAdvisorAutoProxyCreator
的逻辑根本上和 Aop 的逻辑相同 -
ProxyTransactionManagementConfiguration
: 注册了业务完结的中心 Bean,包括BeanFactoryTransactionAttributeSourceAdvisor
、TransactionAttributeSource
、TransactionInterceptor
等
3. AutoProxyRegistrar
AutoProxyRegistrar
完结了 ImportBeanDefinitionRegistrar
接口,所以咱们要去看看他的registerBeanDefinitions
办法的完结。
AutoProxyRegistrar#registerBeanDefinitions
代码如下:
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
// 获取 当时类上的一切注解
Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
for (String annType : annTypes) {
// 获取注解的一切特点
AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
if (candidate == null) {
continue;
}
// 获取mode、proxyTargetClass 特点
Object mode = candidate.get("mode");
Object proxyTargetClass = candidate.get("proxyTargetClass");
if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
Boolean.class == proxyTargetClass.getClass()) {
candidateFound = true;
// 判别假如是 Proxy 形式,也便是默许形式,注册主动署理创立器
if (mode == AdviceMode.PROXY) {
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
// 假如需求署理方针列,则强制主动署理创立者运用类署理
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
... 省掉日志打印
}
在这儿咱们能够看到,registerBeanDefinitions
办法中解析了 业务注解
,并注册了主动署理创立器
。这儿主动署理创立器咱们在Aop 源码中提到过,是Aop 创立的中心。
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)
这一步最首要的效果将主动署理创立器 InfrastructureAdvisorAutoProxyCreator
注册到了 Spring容器中。
经过数次跳转,咱们来到了 AopConfigUtils#registerOrEscalateApcAsRequired
。其中这
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";
private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3);
static {
// Set up the escalation list...
// 业务运用
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
// Spring aop 运用
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}
....
public static BeanDefinition registerAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}
...
// 这儿的 cls 是 InfrastructureAdvisorAutoProxyCreator .class
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
// 假如有注册,则判别优先级,将优先级的高的保存
// 假如现已纯在了主动署理创立器,且存在的主动署理创立器与现在的并不共同,那么需求依据优先级来判别到底要运用哪个
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) {
// 改动bean所对应的className 特点
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;
}
...
// 能够看到,所谓的优先级次序实际上是在 APC_PRIORITY_LIST 调集的次序
public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
// 设置 proxyTargetClass 特点
definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
}
}
...
public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
// 设置 exposeProxy 特点
definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
}
}
到这儿咱们根本能够断定和 Aop 的逻辑根本相同了,只不过业务默许主动注入的主动署理创立器是 InfrastructureAdvisorAutoProxyCreator
类型。
留意:
- 在AOP 中咱们知道 Aop创立的主动署理创立器类型是
AnnotationAwareAspectJAutoProxyCreator
,而业务创立的类型是InfrastructureAdvisorAutoProxyCreator
。 - 这儿之所以
beanName (AUTO_PROXY_CREATOR_BEAN_NAME)
和 bean的类型并不相同,是因为这个beanName 特指内部的主动署理创立器,但是主动创立署理器会对应多种不同的完结办法。比如在默许的业务中,注入的bean类型却为InfrastructureAdvisorAutoProxyCreator
,而AOP的完结却是AnnotationAwareAspectJAutoProxyCreator
。 - 关于主动署理创立器优先级的问题,咱们能够看到
APC_PRIORITY_LIST
调集的次序,下标越大,优先级越高
。因而能够得知优先级的次序应该是InfrastructureAdvisorAutoProxyCreator < AspectJAwareAdvisorAutoProxyCreator < AnnotationAwareAspectJAutoProxyCreator
3.1 InfrastructureAdvisorAutoProxyCreator
上面咱们能够知道,业务将主动署理创立器 InfrastructureAdvisorAutoProxyCreator
注册到了 Spring容器中。这儿就跟Aop 根本相同了,下面咱们来看看 InfrastructureAdvisorAutoProxyCreator
的内容
能够看到 InfrastructureAdvisorAutoProxyCreator
并没有完结什么逻辑,首要逻辑在其父类 AbstractAutoProxyCreator
中。咱们在Aop 中提到过, AbstractAutoProxyCreator
是主动署理创立器的根底。绝大部分逻辑都是在其中完结的。(AbstractAutoProxyCreator 是AbstractAdvisorAutoProxyCreator 的父类,是 InfrastructureAdvisorAutoProxyCreator 的 “爷爷”类)。
public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {
@Nullable
private ConfigurableListableBeanFactory beanFactory;
@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.initBeanFactory(beanFactory);
this.beanFactory = beanFactory;
}
@Override
// 校验bean是否合格
protected boolean isEligibleAdvisorBean(String beanName) {
return (this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) &&
this.beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE);
}
}
关于 AbstractAutoProxyCreator
的剖析量非常巨大,这儿不再重写剖析一遍,详细内容能够去看 AOP剖析文章的 AbstractAutoProxyCreator
部分。
3.2 业务中的 findCandidateAdvisors 办法
在这儿,咱们能够发现的是: Aop 的运用的是 AnnotationAwareAspectJAutoProxyCreator
主动署理创立器;业务运用的是InfrastructureAdvisorAutoProxyCreator
主动署理创立器。而Aop署理创立的要害逻辑就主动署理创立器中。
咱们对比后两种主动署理创立器后,惊奇的发现,其实际逻辑根本共同。最大的不同之处在于,Aop 重写了
AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
办法。而业务并没有重写这一部分。所以业务调用的实际上是 AbstractAdvisorAutoProxyCreator#findCandidateAdvisors
。即下面一部分
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
return this.advisorRetrievalHelper.findAdvisorBeans();
}
而Spring aop调用的则是重写后的 AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
:
@Override
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
能够清楚的看到,Aop 的重写是加了this.aspectJAdvisorsBuilder.buildAspectJAdvisors()
办法调用,也便是动态生成 Advisor
的部分。
关于 getAdvicesAndAdvisorsForBean
的源码剖析能够看Spring5源码13-AOP源码剖析(上)
到这儿咱们知道了 相较于 Aop 的 ,业务的 InfrastructureAdvisorAutoProxyCreator
,不仅没有添加新逻辑(要害逻辑),还砍掉了动态生成Advisor 的逻辑。
3.3 为什么业务完结不需求动态生成Advisor 部分?
个人了解是因为因为事物的切入点并不像AOP那样如此多变。
- 何为Aop的切入点多变,即Pointcut的定义规则由代码掌握,咱们经过
@Pointcut
注解 能够定义一个匹配一切办法的切面,也能够定义一个匹配到指定的办法的切面,关于Spring来说,Spring无法经过一个Advisor
满意许多Pointcut 条件,而为了满意这个条件所以需求经过代码来动态解析一切的Pointcut 来封装成一个一个的 Advisor,随后便能够经过 Advisor 来判别该办法是否满意某个 Advisor 的切入要求。 - 而关于业务来说,启用业务的办法有必要要运用
@Transactional
来润饰办法(也能够润饰在类上,但这儿为了便利描绘直接说办法上,而且在类上运用更符合编程习气)。也便是说对Spring来说,判别一个办法是否启用业务的依据便是该办法上是否运用了@Transactional
注解。也便是说,咱们仅需求一个Advisor
,其判别条件是办法是否被@Transactional
注解润饰即可。而已然知道了Pointcut
条件,咱们就能够完结编写好满意这个逻辑的 Advisor,在Spring发动时分直接将这个条件的 Advisor 注入到容器中直接运用。 - 综上,业务并不需求去动态注入
Advisor
,而Spring aop 则需求动态注入。
经过上面的剖析,咱们判别,业务的Advisor 现已事前注入了,然后咱们回头看到TransactionManagementConfigurationSelector
中注入的另一个类 ProxyTransactionManagementConfiguration
。在 ProxyTransactionManagementConfiguration
中果不其然发现了Advisor 的踪迹。
4. ProxyTransactionManagementConfiguration
ProxyTransactionManagementConfiguration
代码如下,并没有逻辑,便是将几个Bean注入的到容器中。不过这几个bean可都是要害bean,所以咱们需求对其中的bean进行剖析。
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource);
advisor.setAdvice(transactionInterceptor);
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
BeanFactoryTransactionAttributeSourceAdvisor
: 业务的增强器,该办法是否开端业务,是否需求署理该类都在该类中判别
-
TransactionAttributeSource
: 保存了业务相关的一些信息资源。 -
TransactionInterceptor
: 业务拦截器,业务生成署理类时运用的署理拦截器,编写了业务的规则
4.1 BeanFactoryTransactionAttributeSourceAdvisor
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
@Nullable
private TransactionAttributeSource transactionAttributeSource;
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@Override
@Nullable
protected TransactionAttributeSource getTransactionAttributeSource() {
return transactionAttributeSource;
}
};
/**
* Set the transaction attribute source which is used to find transaction
* attributes. This should usually be identical to the source reference
* set on the transaction interceptor itself.
* @see TransactionInterceptor#setTransactionAttributeSource
*/
public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
this.transactionAttributeSource = transactionAttributeSource;
}
/**
* Set the {@link ClassFilter} to use for this pointcut.
* Default is {@link ClassFilter#TRUE}.
*/
public void setClassFilter(ClassFilter classFilter) {
this.pointcut.setClassFilter(classFilter);
}
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
}
这个依据上面的剖析,咱们能够知道这个是业务判别的中心,BeanFactoryTransactionAttributeSourceAdvisor
是Advisor
子类,那么咱们能够知道其中有两个要害特点: Pointcut
(判别是否能够效果于当时办法) 和 Advice
(效果于当时办法的详细逻辑)。
经过 Aop文章的剖析咱们能够知道,Advisor
判别一个办法是否匹配,是经过其 Pointcut.matchs
特点来判别的。然后咱们经过上面的代码,发现其 Pointcut
的完结类是 TransactionAttributeSourcePointcut
,也便是说,一个办法是否需求运用业务,是经过 TransactionAttributeSourcePointcut#matches
办法判别的。
4.1.1. TransactionAttributeSourcePointcut
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
protected TransactionAttributeSourcePointcut() {
setClassFilter(new TransactionAttributeSourceClassFilter());
}
@Override
public boolean matches(Method method, Class<?> targetClass) {
// 调用 TransactionAttributeSource.getTransactionAttribute办法来匹配
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
... 省掉一些无关代码
/**
* Obtain the underlying TransactionAttributeSource (may be {@code null}).
* To be implemented by subclasses.
*/
@Nullable
protected abstract TransactionAttributeSource getTransactionAttributeSource();
/**
* {@link ClassFilter} that delegates to {@link TransactionAttributeSource#isCandidateClass}
* for filtering classes whose methods are not worth searching to begin with.
*/
private class TransactionAttributeSourceClassFilter implements ClassFilter {
@Override
public boolean matches(Class<?> clazz) {
// 假如是一些根底类,则回来false
if (TransactionalProxy.class.isAssignableFrom(clazz) ||
PlatformTransactionManager.class.isAssignableFrom(clazz) ||
PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) {
return false;
}
// 调用 TransactionAttributeSource.isCandidateClass 办法来匹配
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.isCandidateClass(clazz));
}
}
}
Aop中咱们总结了 Pointcut
匹配的需求满意下面两个条件:
-
pc.getClassFilter().matches(targetClass)
回来true -
pc.getMethodMatcher().matches(method, targetClass)
回来true
如下图,详细完结在 AopUtils#canApply(org.springframework.aop.Pointcut, java.lang.Class<?>, boolean)
中,这儿第二点不考虑,因为在这儿不会为True
经过 TransactionAttributeSourcePointcut
的代码咱们能够发现,上面两个条件的要害
能够转换成
- 调用
TransactionAttributeSource.isCandidateClass
办法来匹配 :TransactionAttributeSourceClassFilter#matches
中调用了该办法 - 调用
TransactionAttributeSource.getTransactionAttribute
办法来匹配
而 TransactionAttributeSource
正是咱们在 ProxyTransactionManagementConfiguration
中注入的 AnnotationTransactionAttributeSource
。
4.2 AnnotationTransactionAttributeSource
经过上面的剖析,咱们知道了首要逻辑在 isCandidateClass
和 getTransactionAttribute
办法中,也便是一个Bean 是否需求业务署理需求经过下面两个办法的校验。因而咱们下面来看看这两个办法的完结
4.2.1 AnnotationTransactionAttributeSource#isCandidateClass
isCandidateClass
首要是 判别是否是候选类
,即当时的的注解解析器annotationParsers
是否能够解析当时类。annotationParsers
的初始化在其结构函数中,在初始化的进程中中添加了 SpringTransactionAnnotationParser
,咱们后面的业务注解解析便是经过 SpringTransactionAnnotationParser
进行的解析。
这儿annotationParsers 有三种解析类型:
-
SpringTransactionAnnotationParser
:即咱们默许的业务解析器,解析的注解是org.springframework.transaction.annotation.Transactional
-
JtaTransactionAnnotationParser
:解析的注解是javax.transaction.Transactional
-
Ejb3TransactionAnnotationParser
:解析的注解是javax.ejb.TransactionAttribute
private final Set<TransactionAnnotationParser> annotationParsers;
...
public AnnotationTransactionAttributeSource() {
this(true);
}
...
public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
this.publicMethodsOnly = publicMethodsOnly;
// 能够看到,无论什么场景 SpringTransactionAnnotationParser 都是必定存在的解析器
if (jta12Present || ejb3Present) {
this.annotationParsers = new LinkedHashSet<>(4);
this.annotationParsers.add(new SpringTransactionAnnotationParser());
if (jta12Present) {
this.annotationParsers.add(new JtaTransactionAnnotationParser());
}
if (ejb3Present) {
this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
}
}
else {
this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
}
}
@Override
public boolean isCandidateClass(Class<?> targetClass) {
for (TransactionAnnotationParser parser : this.annotationParsers) {
// 这儿是SpringTransactionAnnotationParser 类型, SpringTransactionAnnotationParser#isCandidateClass 中判别了方针类是否存在 org.springframework.transaction.annotation.Transactional 注解
if (parser.isCandidateClass(targetClass)) {
return true;
}
}
return false;
}
在 SpringTransactionAnnotationParser#isCandidateClass
中判别了方针类是否存在 org.springframework.transaction.annotation.Transactional
注解,假如存在,这儿会回来true,经过校验
4.2.2 AbstractFallbackTransactionAttributeSource#getTransactionAttribute
getTransactionAttribute
办法的完结在其父类AbstractFallbackTransactionAttributeSource
中 完结的:
// 获取业务特点,假如
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// 判别声明类是否是 Object
if (method.getDeclaringClass() == Object.class) {
return null;
}
// First, see if we have a cached value.
// 测验从缓冲中获取
Object cacheKey = getCacheKey(method, targetClass);
TransactionAttribute cached = this.attributeCache.get(cacheKey);
if (cached != null) {
// Value will either be canonical value indicating there is no transaction attribute,
// or an actual transaction attribute.
if (cached == NULL_TRANSACTION_ATTRIBUTE) {
return null;
}
else {
return cached;
}
}
else {
// We need to work it out.
// 没有缓存,则开端解析
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
// Put it in the cache.
// 获取
if (txAttr == null) {
// 放入缓存中
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
}
else {
// 获取适宜的办法称号
String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
if (txAttr instanceof DefaultTransactionAttribute) {
((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
}
if (logger.isTraceEnabled()) {
logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
}
this.attributeCache.put(cacheKey, txAttr);
}
return txAttr;
}
}
...
// 解析业务注解特点
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// Don't allow no-public methods as required.
// 假如只允许解析public 办法 && 当时办法不是 publissh
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
// The method may be on an interface, but we need attributes from the target class.
// If the target class is null, the method will be unchanged.
// method 代表接口中的办法,specificMethod 办法代表完结类中的办法
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
// First try is the method in the target class.
// 寻觅完结类办法的业务特点,即类办法是否有声明业务特点
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
// Second try is the transaction attribute on the target class.
// 在完结类上是否有业务特点的声明
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
// 假如存在接口办法,则从接口办法中测验去获取业务特点
if (specificMethod != method) {
// Fallback is to look at the original method.
txAttr = findTransactionAttribute(method);
if (txAttr != null) {
return txAttr;
}
// Last fallback is the class of the original method.
txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
}
// 都没得到则回来没有得到
return null;
}
这儿的逻辑仍是很清楚的
- 从完结类办法上获取业务注解,若获取到则回来
- 从完结类上获取业务注解,若获取到则回来
- 假如存在接口办法,则从接口办法中获取业务注解,若获取到则回来
- 若仍未获取到,则回来null,以为当时办法没有被注解润饰
AnnotationTransactionAttributeSource#findTransactionAttribute(java.lang.reflect.Method)
在上面的代码中,咱们留意到一个办法 findTransactionAttribute
。上面代码便是经过 findTransactionAttribute
办法来寻觅业务注解特点的。而findTransactionAttribute 的完结在 AnnotationTransactionAttributeSource
中。其完结代码如下
protected TransactionAttribute findTransactionAttribute(Method method) {
return determineTransactionAttribute(method);
}
...
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
for (TransactionAnnotationParser parser : this.annotationParsers) {
TransactionAttribute attr = parser.parseTransactionAnnotation(element);
if (attr != null) {
return attr;
}
}
return null;
}
能够看到 AnnotationTransactionAttributeSource
中获取 业务注解是经过 TransactionAnnotationParser#parseTransactionAnnotation
办法去解析的,而一开端咱们就说过annotationParsers
在结构函数中添加了SpringTransactionAnnotationParser
。咱们来看看 SpringTransactionAnnotationParser
进行了怎么样的解析。到这儿,咱们终于看到了业务注解的描绘,这儿便是解析业务注解的各种特点信息了.
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
// 获取业务注解的特点信息
AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
element, Transactional.class, false, false);
if (attributes != null) {
return parseTransactionAnnotation(attributes);
}
else {
return null;
}
}
....
// 解析业务注解,并回来
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"));
List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
rollbackRules.add(new RollbackRuleAttribute(rbRule));
}
for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
rollbackRules.add(new RollbackRuleAttribute(rbRule));
}
for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
}
for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
}
rbta.setRollbackRules(rollbackRules);
return rbta;
}
咱们的剖析到这儿,就现已能够知道了Spring 中对业务注解的解析进程,逻辑根本和 Spring Aop 类似。
@EnableTransactionManagement
经过引进 TransactionManagementConfigurationSelector
注册了 AutoProxyRegistrar
和 ProxyTransactionManagementConfiguration
两个类。
-
AutoProxyRegistrar
中注册了 InfrastructureAdvisorAutoProxyCreator 主动署理创立器 InfrastructureAdvisorAutoProxyCreator 中拦截bean的创立进程,经过 BeanFactoryTransactionAttributeSourceAdvisor 来判别bean中是否有业务注解,有则进行署理。 在上面的逻辑中,咱们好像没有发现Spring业务署理的详细进程,实际上署理的进程是在TransactionInterceptor
中。
4.3 TransactionInterceptor
在 Aop 的剖析文章中,咱们知道了无论是 Jdk署理仍是 Cglib署理,其增强完结都是调用 Advisor
中的Advice
完结。BeanFactoryTransactionAttributeSourceAdvisor
作为 Advisor 的完结类,天然要遵从 Advisor 的处理办法,当署理被调用时会调用这个类的增强办法,也便是此bean 的Advice ,而在解析业务标签是,咱们把 TransactionInterceptor
注入到了 BeanFactoryTransactionAttributeSourceAdvisor
中,所以调用业务增强器增强署理类的时会首先履行TransactionInterceptor
进行增强,同时也便是 TransactionInterceptor#invoke
完结了整个业务的逻辑。
所以咱们这儿天然要看 TransactionInterceptor#invoke 办法。
public Object invoke(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...
// todo 在业务润饰下履行办法
return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {
@Override
@Nullable
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
@Override
public Object getTarget() {
return invocation.getThis();
}
@Override
public Object[] getArguments() {
return invocation.getArguments();
}
});
}
能够看到中心逻辑都在 invokeWithinTransaction
办法中,这儿调用的 invokeWithinTransaction
办法 实际是TransactionAspectSupport#invokeWithinTransaction
办法。所以下面咱们来看看 TransactionAspectSupport#invokeWithinTransaction
办法的详细完结
TransactionAspectSupport#invokeWithinTransaction
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
// 获取业务数据源,这儿获取的数据源便是在 TransactionInterceptor 注入的时分的设置的特点transactionAttributeSource = AnnotationTransactionAttributeSource。
// 在 ProxyTransactionManagementConfiguration 中完结
TransactionAttributeSource tas = getTransactionAttributeSource();
// 1. 获取对应的业务特点
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
// 2. 获取一个适宜的 TransactionManager
final TransactionManager tm = determineTransactionManager(txAttr);
// 3. 关于反应式业务的处理
// 从Spring Framework 5.2 M2开端,Spring经过ReactiveTransactionManagerSPI 支撑响应式/反应式业务管理
if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {
if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) {
throw new TransactionUsageException(
"Unsupported annotated transaction on suspending function detected: " + method +
". Use TransactionalOperator.transactional extensions instead.");
}
ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(method.getReturnType());
if (adapter == null) {
throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " +
method.getReturnType());
}
return new ReactiveTransactionSupport(adapter);
});
return txSupport.invokeWithinTransaction(
method, targetClass, invocation, txAttr, (ReactiveTransactionManager) tm);
}
// 判别 tm是否是 PlatformTransactionManager 类型,是则强转,不是则抛出反常
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
// 结构办法的唯一标识( 全路径了类名.办法)
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
// 4. 对不同业务情景的处理
// 声明式业务的处理
// 假如txAttr为空或者tm 属于非CallbackPreferringPlatformTransactionManager,履行方针增强
// 在TransactionManager上,CallbackPreferringPlatformTransactionManager完结PlatformTransactionManager接口,暴露出一个办法用于履行业务处理中的回调
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
// 5.假如有必要,创立业务信息。首要因为业务的传达特点,所以这儿并不一定会创立业务
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
Object retVal;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
// 6. 履行被增强的办法
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
// 7. 反常回滚
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
// 8. 提交之前铲除业务信息
cleanupTransactionInfo(txInfo);
}
if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// Set rollback-only in case of Vavr failure matching our rollback rules...
TransactionStatus status = txInfo.getTransactionStatus();
if (status != null && txAttr != null) {
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
}
// 9.提交业务
commitTransactionAfterReturning(txInfo);
return retVal;
}
// 编程式业务(CallbackPreferringPlatformTransactionManager)的处理。这儿的逻辑根本都被封装了
else {
final ThrowableHolder throwableHolder = new ThrowableHolder();
try {
// 直接调用execute 办法。因为业务的提交回滚等操作都现已封装好了,所以这儿并没有对业务进行详细的操作。
Object result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> {
// 准备业务信息
TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status);
try {
// 履行办法
Object retVal = invocation.proceedWithInvocation();
if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// Set rollback-only in case of Vavr failure matching our rollback rules...
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
return retVal;
}
catch (Throwable ex) {
if (txAttr.rollbackOn(ex)) {
// A RuntimeException: will lead to a rollback.
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}
else {
throw new ThrowableHolderException(ex);
}
}
else {
// A normal return value: will lead to a commit.
throwableHolder.throwable = ex;
return null;
}
}
finally {
// 铲除业务信息
cleanupTransactionInfo(txInfo);
}
});
// Check result state: It might indicate a Throwable to rethrow.
if (throwableHolder.throwable != null) {
throw throwableHolder.throwable;
}
return result;
}
catch (ThrowableHolderException ex) {
throw ex.getCause();
}
catch (TransactionSystemException ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
ex2.initApplicationException(throwableHolder.throwable);
}
throw ex2;
}
catch (Throwable ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
}
throw ex2;
}
}
}
从上面的代码中,咱们能够知道Spring支撑声明式业务和编程式业务
两种处理。两者的完结本质根本相同。在invoke办法中咱们也能够看到这两种办法的完结,通常咱们运用的都是经过 @Transactional
注解润饰的声明式业务,所以咱们下面首要剖析 声明式业务 的处理进程。
-
获取业务特点
TransactionAttribute
,TransactionAttribute
中包括 传达特点,timeout
等业务特点信息。假如是运用@Transactional
注解,这个解析进程是在AnnotationTransactionAttributeSource#findTransactionAttribute(java.lang.reflect.Method)
中完结。 -
加载装备中的
TrancationManager
, 业务管理器,是业务完结的根底,咱们这儿获取到的是DataSourceTransactionManager
。 -
对反应式业务的处理。
-
不同业务处理办法运用不同的逻辑。在上面的代码中首要是两种状况,一是声明式业务,这种状况是经过
@Transactional
注解润饰办法来表示开启业务。另一种状况是编程式业务,即能够经过xml办法或者装备类办法来进行完结业务功用,其实TransactionTemplate 的完结便是编程式业务,但经过TransactionTemplate
并不会走到这个逻辑,这儿的编程式业务应该独自是经过xml或者装备类办法来装备的。- 关于声明式业务的处理和编程式业务的处理,差异首要在两点。一是业务特点上,因为编程式业务是不需求业务特点的,二是
TransactionManager
的不同,CallbackPreferringPlatformTransactionManager
完结了PlatformTransactionManager
接口,暴露了一个办法用于履行业务处理中的回调。所以这两种办法都能够作为业务处理办法的判别。
- 关于声明式业务的处理和编程式业务的处理,差异首要在两点。一是业务特点上,因为编程式业务是不需求业务特点的,二是
-
在方针办法履行前获取业务并搜集业务信息。
- 业务信息与业务特点并不相同,也便是
TransactionInfo
和TransactionAttribute
并不相同,TransactionInfo
中包括TransactionAttribute
信息,而且处理TransactionAttribute
之外还有其他事物信息,比如PlatformTransactionManager
以及TransactionStatus
相关信息。
- 业务信息与业务特点并不相同,也便是
-
履行方针办法
-
假如出现反常,则进行回滚。这儿需求留意,默许的状况下只有
RuntimeException
反常才会履行回滚。能够经过@Transactional(rollbackFor = Exception.class)
的办法来指定触发回滚的反常 -
提交业务前的业务信息铲除
-
提交业务
-
若是 编程式业务,则直接履行execute办法即可,这儿就不再解说。
注:
PlatformTransactionManager
和ReactiveTransactionManager
二者都是为了完结业务,PlatformTransactionManager
在内部进行业务履行流程的封装,而且暴露出来一个execute
办法用于履行业务的详细信息,TransactionTemplate
的声明式业务便是基于此完结的。而ReactiveTransactionManager
则是比较原始的,需求咱们自己来完结业务的整个逻辑。
上面比较笼统的讲了业务的完结,下面们首要剖析以下三个办法,也是业务的的要害流程:
- 业务的创立 –
createTransactionIfNecessary
- 业务的回滚 –
completeTransactionAfterThrowing
- 业务的提交 –
commitTransactionAfterReturning
参阅文章
Spring5源码注释github地址
Spring源码深度解析(第2版)
spring源码解析
Spring源码深度解析笔记
Spring注解与源码剖析
Spring注解驱动开发B站教程