Spring - AOP/事务 实现原理

发布于:2024-03-30 ⋅ 阅读:(22) ⋅ 点赞:(0)

AOP 基本概念

  1. 官方文档: Aspect Oriented Programming with Spring

Spring AOP supports the following AspectJ pointcut designators (PCD) for use in pointcut expressions:

within - limits matching to join points within certain types (simply the execution of a method declared within a matching type when using Spring AOP):AOP学习之within

@within - limits matching to join points within types that have the given annotation (the execution of methods declared in types with the given annotation when using Spring AOP)

  1. What is the difference between Advisor and Aspect in AOP?

Most aspects are a combination of advice that defines the aspect’s behavior and a pointcut defining where the aspect should be executed.Spring recognizes this and offers advisors (such as PointcutAdvisor), which combine advice and pointcuts into one object.

public interface Advisor {
	Advice getAdvice();
}
public interface PointcutAdvisor extends Advisor {
	Pointcut getPointcut();
}

Advisor 是一个接口,实现该接口的类必须提供一个 Advice 实例。

  1. Pointcut vs Joinpoint

Join points are the options on the menu and pointcuts are the items you select. A joinpoint is an opportunity within code for you to apply an aspect…just an opportunity. Once you take that opportunity and select one or more joinpoints and apply an aspect to them, you’ve got a pointcut.

AOP 使用

通过在 Spring 配置组件类上增加 @EnableAspectJAutoProxy 即可开启 AOP 的使用

  1. Enables support for handling components marked with AspectJ’s {@code @Aspect} annotation.
  2. boolean proxyTargetClass() default false; // Indicate whether subclass-based (CGLIB) proxies are to be created as opposed to standard Java interface-based proxies.

注意:SpringBoot 通过 SPI 机制将 org.springframework.boot.autoconfigure.aop.AopAutoConfiguration 注入到 Spring 容器中,从而无需手动设置 @EnableAspectJAutoProxy 即自动支持 AOP 。原理为通过 AopAutoConfiguration 引入了 @EnableAspectJAutoProxy,从而开启了 AOP 功能,且默认使用 CGLib 代理

@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class, AnnotatedElement.class })
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

	@Configuration
	@EnableAspectJAutoProxy(proxyTargetClass = false)
	// 在配置参数 spring.aop.proxy-target-class 值被明确设置为 false 时生效
	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
			matchIfMissing = false)
	public static class JdkDynamicAutoProxyConfiguration {

	}

	@Configuration
	@EnableAspectJAutoProxy(proxyTargetClass = true)
	// 仅在属性 spring.aop.auto 【缺失】或者明确指定为 true 时生效
	// SpringBoot 默认使用 CGLib 实现 AOP
	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
			matchIfMissing = true)
	public static class CglibAutoProxyConfiguration {

	}
}

AOP 原理

概述

Spring的Aop实现原理,Spring AOP 与 AspectJ 的关系 转载

Aop源码大概分为以下几步:

  1. spring boot 自动配置AopAutoConfiguration类中带有@EnableAspectJAutoProxy,项目启动即开启对spring AOP的支持,该注解注册了AnnotationAwareAspectJAutoProxyCreator 类,该类实现了bean的后置处理器,可以在类创建过程中做一些其他操作
  2. 在bean后置处理器的 postProcessBeforeInstantiation方法中,解析切面类,把通知封装成Advisor,并放入缓存advisorsCache中!
  3. 在创建每一个bean时,在bean的后置处理器中的postProcessAfterInitialization方法中,拿到缓存中所有的Advisor,根据切入点PointCut与当前bean做匹配,匹配成功与否决定是否需要创建动态代理!如果匹配到了,则根据实际情况(调用 AbstractAutoProxyCreator#wrapIfNecessary 方法)创建动态代理。
  4. 调用目标方法时,会调用经过动态代理增强的方法逻辑 !

AnnotationAwareAspectJAutoProxyCreator

@EnableAspectJAutoProxy 向 Spring 容器中注入了实现 AOP 的关键类AnnotationAwareAspectJAutoProxyCreator(名为 internalAutoProxyCreator 的 BeanDefinition 实例)

在这里插入图片描述

AnnotationAwareAspectJAutoProxyCreator 继承体系为:
AnnotationAwareAspectJAutoProxyCreator 继承关系

注意 InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation 是在 Bean 对象创建之前被调用用来尝试生成 Bean 实例的代理对象,而 BeanPostProcessor#postProcessBeforeInitialization 则是在 Bean 对象创建完成后,初始化前被执行。

AnnotationAwareAspectJAutoProxyCreator 则会在 Spring 刷新容器(执行 AbstractApplicationContext#refreshrefresh() 方法)时,通过

// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory); 

注入将到 Spring 后置处理器集合中(将 BeanDefinition 转换为具体的实例),其注入的核心代码为:

// 代码来自 PostProcessorRegistrationDelegate#registerBeanPostProcessors 方法
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);


// 代码来自:PostProcessorRegistrationDelegate#registerBeanPostProcessors 方法
for (BeanPostProcessor postProcessor : postProcessors) {
	beanFactory.addBeanPostProcessor(postProcessor);
}

生效流程

动态代理增强 Bean 功能的入口:InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation 方法的调用:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean,该方法的调用发生在 Spring 容器刷新的最后一个阶段 finishBeanFactoryInitialization 中的 beanFactory.preInstantiateSingletons() 中的 AbstractBeanFactory#createBean

在这里插入图片描述
然后执行 AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation 遍历执行所有的 InstantiationAwareBeanPostProcessor (AOP 代理创建类 AnnotationAwareAspectJAutoProxyCreator 就是实现了该接口)实例

protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
	for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
		Object result = bp.postProcessBeforeInstantiation(beanClass, beanName);
		if (result != null) {
			return result;
		}
	}
	return null;
}

如果当前类没有经过 TargetSource 处理,则会继续执行AbstractAutoProxyCreator#postProcessAfterInitialization,最终通过 AbstractAutoProxyCreator#wrapIfNecessary,为被 AOP 拦截的 Bean 类生成代理对象。

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
	if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
		return bean;
	}
	if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
		return bean;
	}
	if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

	// Create proxy if we have advice.
	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());
		return proxy;
	}

	this.advisedBeans.put(cacheKey, Boolean.FALSE);
	return bean;
}
文章索引
  1. 视频讲解 - 结合 Spring 创建 Bean 流程梳理 AOP 实现原理
  2. Spring AOP的原理讲解以及源码分析

AOP 通知类型

通过 org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory

private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
		Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};

可以看出 Spring AOP 主要支持以下几种 AOP 类型(按执行顺序列出):

目标方法无异常时
①:前置通知
②:环绕通知的调用目标方法之前的代码
③:目标方法
④:环绕通知的调用目标方法之后的代码
⑤:返回通知
⑥:后置通知
在目标方法抛出异常的情况下
①:前置通知
②:环绕通知的调用目标方法之前的代码
③:目标方法(抛出异常)
④:异常通知
⑤:后置通知

@After 是如何实现的?

AspectJAfterAdvice#invoke

public Object invoke(MethodInvocation mi) throws Throwable {
	try {
		return mi.proceed();
	}
	finally {
		// 由于执行逻辑放到了 finally 块中,目标 bean 对象的方法被执行后,一定会执行该段代码
		invokeAdviceMethod(getJoinPointMatch(), null, null);
	}
}

AOP 核心组件

Pointcut:

public interface Pointcut {
	ClassFilter getClassFilter();
	MethodMatcher getMethodMatcher();
}

可以看出 Spring AOP 只能选择 class 或 method 作为切入点。

良好设计

Pointcut 之间支持逻辑运算,Spring 提供的工具类 MethodMatchers 与 ComposablePointcut 具有良好的设计体系,即抽象了逻辑运算过程,分别定义了 与运算类 和 或运算类,从而将复杂的逻辑运算变为两类对象的组合,这样在提高代码可读性(比如 IntersectionClassFilter 从名字上可以看出,其下的所有 classFilter 都满足时才为真)的同时,也加强了代码的复用性(不需要在每个需要实现 与运算 的类中再次定义一个集合,以及重复书写遍历集合的代码),值得思考和学习。

类层级体系(MethodMathcer)

MethodMathcer 相关类

可视化调用过程(ClassFilter)

调用栈可视化

Advice

其顶级标签接口为:Advice,其主要类层级结构为:
Advice 继承体系
可以看出 Spring 可以分为五种类型的增强:BeforeAdvice、AfterAdvice、Interceptor、DynamicIntroductionAdvice、AbstractAspectJAdvice

Interceptor

A generic interceptor can intercept runtime events that occur within a base program. Those events are materialized by (reified in) join points. Runtime joinpoints can be invocations, field access, exceptions… This interface is not used directly. Use the sub-interfaces to intercept specific events.

注意这里的 Interceptor 定义在 spring-aop 包中,spring-mvc 中也有一个 Interceptor 概念:HandlerInterceptor

MethodInterceptor

Intercepts calls on an interface on its way to the target. These are nested “on top” of the target. The user should implement the invoke(MethodInvocation) method to modify the original behavior.
MethodInterceptor

Aspect

Spring AOP 是借助 BeanPostProcessor 来实现的,其抽象过程封装在 org.springframework.aop.framework.AbstractAdvisingBeanPostProcessor

  1. 定义 PointcutAdvisor(封装了 Pointcut 和 Advice)
  2. 通过 isEligible 判断(判断逻辑封装在 Pointcut 中),是否为当前 bean 执行增强代理
protected boolean isEligible(Class<?> targetClass) {
	Boolean eligible = this.eligibleBeans.get(targetClass);
	if (eligible != null) {
		return eligible;
	}
	if (this.advisor == null) {
		return false;
	}
	//
	eligible = AopUtils.canApply(this.advisor, targetClass);
	this.eligibleBeans.put(targetClass, eligible);
	return eligible;
}
  1. 构造 ProxyFactory 对象,选择 JdkDynamicAopProxy 或 ObjenesisCglibAopProxy 创建出代理对象

其它组件

TargetSource

在计算机世界,如果问题难以解决,可以想着多抽象出一层来解决该问题。

AOP 的抽象模板流程预留了一个提前创建代理对象的钩子 TargetSource,其代码如下:

// 代码来自:AbstractAutoProxyCreator#postProcessBeforeInstantiation

// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
	if (StringUtils.hasLength(beanName)) {
		this.targetSourcedBeans.add(beanName);
	}
	Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
	Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
	this.proxyTypes.put(cacheKey, proxy.getClass());
	return proxy;
}

创建的代理对象代理的不是 Bean 类的实例,而是持有 Bean 类的实例的 TargetSource 。(多抽出来的一层)体系为:
TargetSource 体系
为了解决依赖注入的循环依赖问题,Spring 可以在 Bean 对象初始化之前提前创建出代理对象
提前创建代理对象

TargetSource 类型
SingletonTargetSource

This is the default implementation of the TargetSource interface, as used by the Spring AOP framework.

SingletonTargetSource

LazyInitTargetSource

lazily accesses a singleton bean from a {@link org.springframework.beans.factory.BeanFactory}. Useful when a proxy reference is needed on initialization but the actual target object should not be initialized until first use.

该类对象通过 LazyInitTargetSourceCreator 创建出

文章索引
  1. Spring AOP 中 TargetSource 的作用及原理分析
  2. spring通过TargetSourceCreator提前生成代理

在 spring aop 中,如果我们的类符合如下条件:被切面的 pointcut 匹配到、或者属于自定义的 Advisor 接口实现类,那么 spring 在 bean 完成实例化之后,会在 bean 的初始化阶段 (AbstractAutowireCapableBeanFactory#initializeBean 方法中调用 postProcessAfterInitialization) 为类生成代理对象。这是众所周知的 aop 流程。此外,spring还为我们提供了TargetSourceCreator接口,该接口的功能是:在bean实例化之前,就为类生成代理。

  1. Spring扩展点-TargetSource
  1. 我们可以看到它是在doGetBean调用之前去进行的干预,而如果有TargetSource,那么它直接完成代理返回了,后续的所有Bean的创建和初始化逻辑都不走了!这些逻辑都不走有什么问题吗?代表了XXXAware接口所有都不会生效,@Autowired/@Resource/@Value这些注解标注的属性赋值,都不会走!
  2. 执行目标方法的目标Bean,是从TargetSource隔离的BeanFactory当中去获取对象的,而隔离的BeanFactory中AOP相关的组件已经被移除了,因此不会存在getTarget获取到代理对象的可能性(如果获取到的是代理对象,那么很明显会出现StackOverFlow,因此不断的调用代理方法,没有尽头)。

动态代理类型

JdkDynamicAopProxy、DefaultAopProxyFactory(CGLib 动态代理)
Spring 动态代理继承体系

// DefaultAopProxyFactory#createAopProxy
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
	// 注意:当 @EnableAspectJAutoProxy(proxyTargetClass = true) 时,则只用 CGLib 动态代理
	if (!NativeDetector.inNativeImage() &&
			(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 动态代理:被代理类是 interface 或 是 Proxy 的子类
		if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
			return new JdkDynamicAopProxy(config);
		}
		return new ObjenesisCglibAopProxy(config);
	}
	else { // 当目标对象实现了自定义接口时,使用 JDK 动态代理
		return new JdkDynamicAopProxy(config);
	}
}

注意:当 @EnableAspectJAutoProxy(proxyTargetClass = true) 时,则只用 CGLib 动态代理。

why spring AOP use JDK Dynamic proxy?

Cglib is an external dependeny (…) Relying on third-party software is always a gamble, so it is best when as few people as possible rely on it." I.e., if you have a Spring application with very clean design, always programming against interfaces instead of directly against classes, you do not need CGLIB at all.

Spring 3.2 以后,spring-core 直接就把 CGLIB 和 ASM 的源码包括进来了,这也是为什么我们不需要显式的引入这两个依赖。即在 3.2 之前,程序员无需引入 CGLib 也可以使用 AOP 特性。

事务使用

@Configuration
@EnableTransactionManagement
public class AppConfig {

   @Bean
   public FooRepository fooRepository() {
       // configure and return a class having @Transactional methods
       return new JdbcFooRepository(dataSource());
   }

   @Bean
   public DataSource dataSource() {
       // configure and return the necessary JDBC DataSource
   }

   @Bean
   public PlatformTransactionManager txManager() {
       return new DataSourceTransactionManager(dataSource());
   }
}

注意事项: spring事务是基于spring aop实现的,采用的代理机制,所以一个类调用自己类的方法是不会走代理的,也就是即使被调用的方法声明了@Transaction,也不会开启事务。

事务原理

实现

TransactionInterceptor 和 Advice

@Configuration 类上有 @EnableTransactionManagement 注解后,在 ApplicationContext refresh 时,会调用 ConfigurationClassPostProcessor, ConfigurationClassPostProcessor 会在 postProcessBeanDefinitionRegistry 方法中处理 @EnableTransactionManagement 注解上的 TransactionManagementConfigurationSelector。

@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
    boolean proxyTargetClass() default false;
    AdviceMode mode() default AdviceMode.PROXY;
    int order() default Ordered.LOWEST_PRECEDENCE;
}

默认的 PROXY 模式下,会引入 AutoProxyRegistrar 和 ProxyTransactionManagementConfiguration。

  • 通过 AutoProxyRegistrar 为 Spring 容器导入了 InfrastructureAdvisorAutoProxyCreator,利用后置处理器返回一个增强代理类
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

    @Override
    protected String[] selectImports(AdviceMode adviceMode) {
        switch (adviceMode) {
            case PROXY:
                return new String[] {AutoProxyRegistrar.class.getName(),
                        ProxyTransactionManagementConfiguration.class.getName()};
            case ASPECTJ:
                return new String[] {determineTransactionAspectClass()};
            default:
                return null;
        }
    }
}    
  • 通过 ProxyTransactionManagementConfiguration 会向 Spring 容器添加 BeanFactoryTransactionAttributeSourceAdvisor、TransactionAttributeSource、TransactionInterceptor 几个 Bean。
    • BeanFactoryTransactionAttributeSourceAdvisor 是用于 aop 的 Advisor
    • TransactionInterceptor 是 MethodIntercetor 的实现类。
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

    @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
        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() {
        TransactionInterceptor interceptor = new TransactionInterceptor();
        interceptor.setTransactionAttributeSource(transactionAttributeSource());
        if (this.txManager != null) {
            interceptor.setTransactionManager(this.txManager);
        }
        return interceptor;
    }

}

TransactionInterceptor 中定义了代理的实现 invoke 方法,从这里能看到 spring 事务的执行逻辑。

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...
    return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}

invokeWithinTransaction 实现在父类 TransactionAspectSupport 中。
invokeWithinTransaction 的执行逻辑为,先开启事务,然后保存到 ThreadLocal 中,执行被代理的方法,然后提交事务,并重置 ThreadLocal 的值然后提交事务。

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
        final InvocationCallback invocation) throws Throwable {

    // If the transaction attribute is null, the method is non-transactional.
    TransactionAttributeSource tas = getTransactionAttributeSource();
    final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
    final PlatformTransactionManager tm = determineTransactionManager(txAttr);
    final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

    if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
        // Standard transaction demarcation with getTransaction and commit/rollback calls.
        TransactionInfo txInfo = createTransactionIfNecessary(tm, 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.
            retVal = invocation.proceedWithInvocation();
        }
        catch (Throwable ex) {
            // target invocation exception
            // 执行业务逻辑遇到异常时,通过 事务管理器(PlatformTransactionManager)回滚事务
            completeTransactionAfterThrowing(txInfo, ex);
            throw ex;
        }
        finally {
            cleanupTransactionInfo(txInfo);
        }
		// 执行业务逻辑遇到异常时,通过 事务管理器(PlatformTransactionManager)提交事务
        commitTransactionAfterReturning(txInfo);
        return retVal;
    } else {
        final ThrowableHolder throwableHolder = new ThrowableHolder();

        // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
        try {
            Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status -> {
                TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
                try {
                    return invocation.proceedWithInvocation();
                }
                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;
        }
    }
}

BeanFactoryTransactionAttributeSourceAdvisor 类定义了 aop 的 Advisor,Pointcut 为TransactionAttributeSource,是有 @Transactional 注解的方法。 Advisor 的 advice 为上面的 TransactionInterceptor。

验证 @Transactional 注解修改生效的示例

文章索引

  1. Spring 源码解析:如何保证事务
  2. ThreadLocal与Spring 事务管理
  3. spring jdbcTemplate 事务:从 Connection 到 Spring @Transactional

拓展

  1. java中什么是bridge method(桥接方法)
    桥接方法字节码反编译示例
    博客中的错误:桥接方法方法的出现并不是为了兼容 JDK 1.5-,而是为了实现泛型。

  2. Type Erasure

Generics were introduced to the Java language to provide tighter type checks at compile time and to support generic programming. To implement generics, the Java compiler applies type erasure to:

  1. Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.
  2. Insert type casts if necessary to preserve type safety.
  3. Generate bridge methods to preserve polymorphism in extended generic types. After type erasure, the method signatures do not match; the Node.setData(T) method becomes Node.setData(Object). As a result, the MyNode.setData(Integer) method does not override the Node.setData(Object) method.
  1. org.springframework.beans.factory.config.AutowireCapableBeanFactory#ORIGINAL_INSTANCE_SUFFIX

Suffix for the “original instance” convention when initializing an existing bean instance: to be appended to the fully-qualified bean class name, e.g. “com.mypackage.MyClass.ORIGINAL”, in order to enforce the given instance to be returned, i.e. no proxies etc.

切面类
声明 bean 对象
非目标 bean 的代理对象
约定命名的解析代码:org.springframework.aop.framework.autoproxy.AutoProxyUtils#isOriginalInstance

static boolean isOriginalInstance(String beanName, Class<?> beanClass) {
	// 类的全限定名 + .ORIGINAL
	if (!StringUtils.hasLength(beanName) || beanName.length() !=
			beanClass.getName().length() + AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX.length()) {
		return false;
	}
	return (beanName.startsWith(beanClass.getName()) &&
			beanName.endsWith(AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX));
}

注意:@Bean 的第一个 name 非 aop.spring.OriginalBeanClass.ORIGINAL 时,则从容器中拿到的依然是目标 bean 的代理对象。
目标 bean 的代理对象
在 Bean 有多个名字(比如:A、B)时,Spring 会拿 bean 的第一个名字(比如:A)将 Bean 对象注册到容器中,使用其它名字(比如:B)调用 getBean 方法试图拿到 Bean 对象时,会先将其转换为容器中实际存储的名字(比如:A),然后再去容器中查找。org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

public String canonicalName(String name) {
	String canonicalName = name;
	// Handle aliasing...
	String resolvedName;
	do {
		resolvedName = this.aliasMap.get(canonicalName);
		if (resolvedName != null) {
			canonicalName = resolvedName;
		}
	}
	while (resolvedName != null);
	return canonicalName;
}
  1. Spring Boot 中的 AOP,到底是 JDK 动态代理还是 Cglib 动态代理?
  1. Spring 中的 AOP,有接口就用 JDK 动态代理,没有接口就用 Cglib 动态代理。
  2. Spring Boot 中的 AOP,2.0 之前和 Spring 一样;2.0 之后首选 Cglib 动态代理,如果用户想要使用 JDK 动态代理,需要自己手动配置。
  1. Spring AOP中的JDK和CGLib动态代理哪个效率更高?

在1.6和1.7的时候,JDK动态代理的速度要比CGLib动态代理的速度要慢,但是并没有教科书上的10倍差距,在JDK1.8的时候,JDK动态代理的速度已经比CGLib动态代理的速度快很多了?

This code contains an if block that will be entered after an invocation threshold is reached, such as after the reflective method has been called a certain number of times. If the invocation threshold has not yet been reached, the code proceeds with the native call.

Once the threshold has been reached, NativeMethodAccessorImpl will use a code generation factory, contained in MethodAccessorGenerator.generateMethod(), to create a custom class that contains bytecode that calls the target of the reflective call.

After creating an instance of this dynamically created class, the call to setDelegate() uses an uplevel reference to the parent accessor to replace the current object with acc, the newly created custom object.

For technical reasons related to class verification, the JVM must be aware of the special nature of the reflective accessor classes. For this reason, there is a special accessor class in the inheritance hierarchy that acts as a marker for the JVM. The precise details of this need not concern you, so don’t worry.

Overall, the mechanism as described represents a performance trade-off—some reflective calls are made only a few times, so the code generation process could be very expensive or wasteful. On the other hand, switching from Java into a native call is slower than remaining in pure Java. This approach allows the runtime to avoid code generation until it seems likely that the reflective call will be made relatively often.

As a result, the costs of code generation can then be amortized over the lifetime of the program, while still providing better performance for later calls than the native implementation can achieve.

本文含有隐藏内容,请 开通VIP 后查看