Spring - AOP/事务 实现原理

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
  • Difference between Joint Point and Point Cut

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.

  • Spring AOP: What’s the difference between JoinPoint and PointCut?
    Joinpoints / Pointcut / Advice

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 {@Beanpublic FooRepository fooRepository() {// configure and return a class having @Transactional methodsreturn new JdbcFooRepository(dataSource());}@Beanpublic DataSource dataSource() {// configure and return the necessary JDBC DataSource}@Beanpublic 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> {@Overrideprotected 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) {// 类的全限定名 + .ORIGINALif (!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动态代理的速度快很多了?

  • The performance implications of Java reflection

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.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/770781.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Visual Studio项目编译和运行依赖第三方库的项目

1.创建项目&#xff0c;这里创建的项目是依赖于.sln的项目&#xff0c;非CMake项目 2.添加第三方库依赖的头文件和库文件路劲 3.添加第三方依赖库文件 4.项目配置有2个&#xff0c;一个是Debug&#xff0c;一个是Release&#xff0c;如果你只配置了Debug&#xff0c;编译和运行…

Unity 视频组件 VideoPlayer

组件添加&#xff1a; 在自己定义的组件下&#xff08;例如&#xff1a;Panel&#xff09; 点击 Inspector 面板中的 AddComponent &#xff0c;输入“VideoPlayer”。 资源 这里 视频资源有两种形式&#xff0c;第一种是 VideoClip &#xff0c;需要将视频文件拖拽到该属性字段…

喜报 | 聚合科技荣获江苏省数字经济学会科学技术奖

近日&#xff0c;江苏省数字经济学会公布了2023年度江苏省数字经济学会科学技术奖获奖名单。本次在全省范围内共评选出科学技术进步奖、科学技术创新奖、优秀成果奖获奖项目共计19项。“聚合数据资产服务API平台”凭借其前沿的创新性和优秀的应用前景成功获得科学技术创新奖二等…

说说Loader和Plugin的区别?编写Loader,Plugin的思路?

文章目录 一、区别二、编写loader三、编写plugin参考文献 一、区别 前面两节我们有提到Loader与Plugin对应的概念&#xff0c;先来回顾下 loader 是文件加载器&#xff0c;能够加载资源文件&#xff0c;并对这些文件进行一些处理&#xff0c;诸如编译、压缩等&#xff0c;最终…

基于TensorFlow的花卉识别(算能杯)%%%

Anaconda Prompt 激活 TensorFlow CPU版本 conda activate tensorflow_cpu //配合PyCharm环境 直接使用TensorFlow1.数据分析 此次设计的主题为花卉识别&#xff0c;数据为TensorFlow的官方数据集flower_photos&#xff0c;包括5种花卉&#xff08;雏菊、蒲公英、玫瑰、向日葵…

UI自动化_id 元素定位

## 导包selenium from selenium import webdriver import time1、创建浏览器驱动对象 driver webdriver.Chrome() 2、打开测试网站 driver.get("你公司的平台地址") 3、使浏览器窗口最大化 driver.maximize_window() 4、在用户名输入框中输入admin driver.find_ele…

RSTP环路避免实验(思科)

华为设备参考&#xff1a;RSTP环路避免实验&#xff08;华为&#xff09; 一&#xff0c;技术简介 RSTP (Rapid Spanning Tree Protocol) 是从STP发展而来 • RSTP标准版本为IEEE802.1w • RSTP具备STP的所有功能&#xff0c;可以兼容STP运行 • RSTP和STP有所不同 减少了…

MVC框架里的几种对象

Java语言是一门面向对象的编程语言&#xff0c;所有都用类表达&#xff0c;入口都是一个类&#xff0c;没有独立的main&#xff08;&#xff09;函数&#xff0c;类的实例化就是对象。 简单来讲类包括数据和方法&#xff0c;方法就是操作&#xff0c;是实现业务逻辑的地方&…

Facebook是什么?有什么功能?如何利用Facebook运营?

Facebook&#xff0c;也常被人们称为“脸书”、“脸谱”等&#xff0c;是美国的社交网络服务及社会化媒体网站&#xff0c;拥有超过20亿的月活跃用户&#xff0c;对于众多商家而言&#xff0c;Facebook以其广泛的用户基础和强大的社交影响力&#xff0c;成为了一个理想的社媒营…

视频推拉流EasyDSS点播平台云端录像播放异常的问题排查与解决

视频推拉流EasyDSS视频直播点播平台可提供一站式的视频转码、点播、直播、视频推拉流、播放H.265视频等服务&#xff0c;搭配RTMP高清摄像头使用&#xff0c;可将无人机设备的实时流推送到平台上&#xff0c;实现无人机视频推流直播、巡检等应用。 有用户反馈&#xff0c;项目现…

2.7、创建列表(List)

概述 列表是一种复杂的容器&#xff0c;当列表项达到一定数量&#xff0c;内容超过屏幕大小时&#xff0c;可以自动提供滚动功能。它适合用于呈现同类数据类型或数据类型集&#xff0c;例如图片和文本。在列表中显示数据集合是许多应用程序中的常见要求&#xff08;如通讯录、…

LeetCode 面试经典150题 392.判断子序列

题目&#xff1a; 给定字符串 s 和 t &#xff0c;判断 s 是否为 t 的子序列。 字符串的一个子序列是原始字符串删除一些&#xff08;也可以不删除&#xff09;字符而不改变剩余字符相对位置形成的新字符串。&#xff08;例如&#xff0c;"ace"是"abcde"…

基于深度学习的OCR,如何解决图像像素差的问题?

基于深度学习的OCR技术在处理图像像素差的问题时确实面临一定的挑战。图像像素差可能导致OCR系统无法准确识别文本&#xff0c;从而影响其精度和可靠性。尽管已经有一些方法如SRN-Deblur、超分SR和GAN系列被尝试用于解决这个问题&#xff0c;但效果并不理想。然而&#xff0c;这…

安防监控视频汇聚平台EasyCVR在银河麒麟V10系统中的启动异常及解决方法

安防监控视频平台EasyCVR具备较强的兼容性&#xff0c;它可以支持国标GB28181、RTSP/Onvif、RTMP&#xff0c;以及厂家的私有协议与SDK&#xff0c;如&#xff1a;海康ehome、海康sdk、大华sdk、宇视sdk、华为sdk、萤石云sdk、乐橙sdk等。平台兼容性强&#xff0c;支持Windows系…

容器镜像加速指南:探索 Kubernetes 缓存最佳实践

介绍 将容器化应用程序部署到 Kubernetes 集群时&#xff0c;由于从 registry 中提取必要的容器镜像需要时间&#xff0c;因此可能会出现延迟。在应用程序需要横向扩展或处理高速实时数据的情况下&#xff0c;这种延迟尤其容易造成问题。幸运的是&#xff0c;有几种工具和策略…

政安晨:【TensorFlow与Keras实战演绎机器学习】专栏 —— 目录

政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: TensorFlow与Keras实战演绎机器学习 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 本篇是作者政安晨的专栏《TensorFlow与Keras…

文献阅读笔记(Transformer)

文献阅读笔记&#xff08;Transformer&#xff09; 摘要Abstract1、文献阅读1.1 文献题目1.2 文献摘要1.3 研究背景1.4 模型架构1.4.1 Encoder-Decoder1.4.2 注意力机制1.4.3 多头注意力1.4.4 Position-wise Feed-Forward Networks1.4.5 Embeddings and Softmax1.4.6 Positiona…

大小端字节序和字节序的判断+有符号整形和无符号整形的取值范围

大小端存在的意义 大小端字节存储方式&#xff08;Big-Endian 和 Little-Endian&#xff09;的存在主要是由于不同计算机体系结构和网络通信标准对数据表示方式的差异所导致的。大小端字节存储方式的存在具有以下意义&#xff1a; 1. 兼容性&#xff1a;不同的计算机系统和网络…

javaWeb网上订餐管理系统

一、简介 在当今社会&#xff0c;随着互联网的普及&#xff0c;网上订餐已经成为了人们生活中不可或缺的一部分。为了方便用户点餐&#xff0c;同时也方便商家管理订单&#xff0c;我设计了一个基于JavaWeb的网上订餐管理系统。该系统分为前台和后台两部分&#xff0c;前台包括…

ChatGPT助力论文写作:详细步骤解析

前言 在论文写作过程中&#xff0c;尽管人工智能工具如ChatGPT能为我们提供有效的辅助&#xff0c;但我们必须铭记&#xff0c;这些工具并不能完全取代我们的思考与判断能力。本指南将详尽地展示如何利用ChatGPT辅助论文写作的全过程&#xff0c;旨在帮助您更高效地完成学术任…