3.springboot创建代理

1.概述

本文介绍配置切面后,动态代理创建器自动创建动态代理的过程。有些名称先统一,可先看看前一篇:
原始bean: 需要被动态代理的对象,一般是我们用户编写的java类;
代理bean: spring为原始bean创建的代理对象,可在执行原始bean的方法时,添加额外的逻辑;
Advice: 通知,代理bean为原始bean添加的额外执行逻辑。一个Advice处理一种逻辑,比如事务注解和缓存注解会有两个Advice;
Advisor: 顾问,是对Advice(通知)的封装,通常内部会持有一个Advice对象;

代理方式实现方式
接口代理jdk动态代理
目标类代理cglib动态代理

2.结论(重点)

代理bean的创建过程:
A.入口是SmartInstantiationAwareBeanPostProcessor的生命周期管理方法(如实例化前置处理器postProcessBeforeInstantiation),创建每个bean时都会调用此方法,在这些方法中可以对bean进行修改。而创建代理就是判断bean是否需要使用代理bean,如果需要就创建代理bean代替原始bean;
B.判断原始bean是否能封装为TargetSource,不能则不创建代理bean;
C.获取原始bean配置的顾问和通知(AdvicesAndAdvisors);

根据获取方式的不同可以分成两类: 普通的Advisor和AspectJ切面;
a.普通的Advisor: 本身就是Advisor的实例 ,可直接使用beanFactory.getBean(Class requiredType)获取;
b.AspectJ注解切面: 本身只是只是标注了@Aspect的普通类,并不是Advisor的子类。需要根据bean方法上的切面注解(如@Around)封装为Advisor;
找到所有的Advisor后,然后根据Advisor提供的过滤方法判断是否能适用于原始bean;

D.根据原始bean,TargetSource和顾问和通知列表,创建代理bean;

根据原始bean的的配置和代理的限制,选择为bean创建jdk代理还是cglib代理。springboot默认proxyTargetClass=true,所以默认为cglib代理;

使用jdk动态代理的场景使用cglib动态代理的场景
proxyTargetClass=false & 原始bean存在有效的接口proxyTargetClass=true
proxyTargetClass=true & Interface(targetClass.isInterface())proxyTargetClass=false & 原始bean强制使用cglib代理
proxyTargetClass=true & Proxy(Proxy.isProxyClass(targetClass))proxyTargetClass=false & 原始bean没有有效的接口
proxyTargetClass=true & Lambda(ClassUtils.isLambdaClass(targetClass))

3.原理

核心类图

类体系分成两部分:

  • AbstractAutoProxyCreator及其父类/父接口主要负责处理生成代理相关的配置的逻辑;
  • AbstractAdvisorAutoProxyCreator及其子类主要负责检索原始bean的顾问和通知;
«Interface»
AopInfrastructureBean
//**基础设施标记接口
ProxyConfig
//**代理配置
- boolean proxyTargetClass//**是否启用cglib代理
- boolean optimize //**是否优化,true:使用cglib代理
< boolean opaque
< boolean exposeProxy //**是否暴露代理
- boolean frozen //**是否冻结
+//**复制代理配置()
+void copyFrom(ProxyConfig config)
ProxyProcessorSupport
//**代理创建器通用功能基类
//**主要用于classLoader管理和计算原始类的接口
- boolean classLoaderConfigured //**是否设置了classLoader
- ClassLoader<?> proxyClassLoader//**classLoader
+//**两个都是设置classLoader,setProxyClassLoader优先度更高()
+void setBeanClassLoader(ClassLoader)
+void setProxyClassLoader(ClassLoader)
#计算原始类是否包合理的接口。否则设置proxyTargetClass=true()
#void evaluateProxyInterfaces(Class<?>, ProxyFactory)
«Interface»
SmartInstantiationAwareBeanPostProcessor
//**智能实例化处理器
+//**预测bean的class类型()
+Class~?~ predictBeanType(Class<?>, String)
+//**确定bean的class类型()
+Class~?~ determineBeanType(Class<?>, String)
+//**获取提前暴露的bean引用()
+Object getEarlyBeanReference(Object, String)
+//**实例化前置处理器()
+Object postProcessBeforeInstantiation(Class<?>, String)
+//**初始化后置处理器()
+Object postProcessAfterInitialization(Object, String)
«Abstract»
AbstractAutoProxyCreator
//**创建代理对象的主要逻辑
//**子类只需要实现getAdvicesAndAdvisorsForBean获取原始bean需要绑定的通知和顾问
- TargetSourceCreator[] customTargetSourceCreators //**TargetSource创建器
- String[] interceptorNames //**拦截器bean名称数组
- AdvisorAdapterRegistry advisorAdapterRegistry //**advisor适配器注册,SPI接口
- Map<Object, Boolean> advisedBeans //**key:bean名称,vlue:是否使用代理
- Map<Object, Class> proxyTypes //**key:bean名称,vlue:代理bean的class对象
- Map<Object, Object> earlyProxyReferences //**key:bean名称,vlue:原始bean
- Set<String> targetSourcedBeans //**能获取targetSource的bean名称
- boolean applyCommonInterceptorsFirst //**是否首先应用公共Interceptor
# Object[] DO_NOT_PROXY //**常量,标记getAdvicesAndAdvisorsForBean方法没有代理时的返回值
+//**springbean的生命周期管理的5个方法,创建bean动态代理的入口()
+//**1.预测bean的class类型()
+Class~?~ predictBeanType(Class<?>, String)
+//**2.确定bean的class类型.创建代理的class对象()
+Class~?~ determineBeanType(Class<?>, String)
+//**3.获取提前暴露的bean引用,没有则创建代理对象()
+Object getEarlyBeanReference(Object, String)
+//**4.实例化前置处理器.创建代理对象()
+Object postProcessBeforeInstantiation(Class<?>, String)
+//**5.初始化后置处理器,上一步没有创建代理对象,则在这里创建代理对象()
+Object postProcessAfterInitialization(Object, String)
#//**创建代理对象()
#Object createProxy(Class<?>, String, Object[], TargetSource)
#//**获取bean配置的通知和顾问,需要子类实现()
#Object[] getAdvicesAndAdvisorsForBean(Class<?>, String, TargetSource)
#//**开放的钩子,允许用户对ProxyFactory进行自定义操作。暂无实现()
#void customizeProxyFactory(ProxyFactory)
#//**如果需要则创建代理,否则使用原始bean()
#Object wrapIfNecessary(Object, String, Object)
#//**是否应该跳过,不创建代理对象()
#boolean shouldSkip(Class<?>, String)
#//**是否强制使用cglib代理()
#boolean shouldProxyTargetClass(Class<?>, String)
#//**根据拦截器构建顾问()
#Advisor[] buildAdvisors(String, Object[])
-//**创建代理bean的class对象()
-Class~?~ createProxyClass(Class<?>, String?, Object[]?, TargetSource)
#//**根据拦截器解析顾问()
-Advisor[] resolveInterceptorNames()
-//**构建代理对象,创建代理对的主要逻辑()
-Object buildProxy(Class<?>, String?, Object[]?, TargetSource, boolean)
«Abstract»
AbstractAdvisorAutoProxyCreator
//**主要功能是获取标准的顾问Advisor,并找出可应用于指定bean的顾问
//**子类可实现extendAdvisors添加除了非标准顾问其它的准顾
- BeanFactoryAdvisorRetrievalHelper advisorRetrievalHelper //**检索标准Advisor的助手
#//**实现了此方法,委托findEligibleAdvisors找出可应用于指定bean的顾问()
#Object[] getAdvicesAndAdvisorsForBean(Class<?>, String, TargetSource)
#//**找出可应用于指定bean的顾问,主要逻辑在此()
#List~Advisor~ findEligibleAdvisors(Class<?>, String)
#//**获取所有标准的顾问Advisor()
#List~Advisor~ findCandidateAdvisors()
#//**从上面所有标准顾问Advisor中,找出可应用于指定bean的顾问()
#List~Advisor~ findAdvisorsThatCanApply(List<Advisor>, Class<?>, String)
#//**可过滤指定的标准顾问()
#boolean isEligibleAdvisorBean(String)
#//**可对指定bean的顾问列表排序()
#sortAdvisors(List<Advisor>)
#//**可扩展添加其它的顾问()
#extendAdvisors(List<Advisor>)
DefaultAdvisorAutoProxyCreator
//**默认的自动代理创建器
//**使用指定前缀过滤标准顾问
//**通常用于一个Advisor类有多个实例的场景
- boolean usePrefix //**是否使用前缀
- String advisorBeanNamePrefix //**前缀
#//**过滤bean名称不包含指定前缀的标准顾问()
#boolean isEligibleAdvisorBean(String)
InfrastructureAdvisorAutoProxyCreator
//**基础设施自动代理创建器
//**查找基础设施标准顾问
#//**过滤非ROLE_INFRASTRUCTURE的标准顾问()
#boolean isEligibleAdvisorBean(String)
AspectJAwareAdvisorAutoProxyCreator
//**AspectJ自动代理创建器
//**增加对AspectJ切面的支持
#//**添加DefaultPointcutAdvisor()
#void extendAdvisors(List<Advisor>)
#//**跳过AspectJPointcutAdvisor()
#boolean shouldSkip(Class<?>, String)
#**使用新的排序规则排序()
#List~Advisor~ sortAdvisors(List<Advisor>)
AnnotationAwareAspectJAutoProxyCreator
//**注解@AspectJ自动代理创建器
//**增加对@Aspect切面的支持
- List<Pattern> includePatterns
+//**支持配置全局正则过滤@AspectJ切面()
+void setIncludePatterns(List<String>)
#boolean isEligibleAspectBean(String)
#//**添加所有配置@AspectJ的顾问()
#List~Advisor~ findCandidateAdvisors()

核心类说明

A.ProxyConfig

代理配置类,提供了代理相关的配置属性。其中proxyTargetClass表示是否启用目标类代理,而不使用接口代理。目标类代理的实现方式是使用cglib代理;

B.ProxyProcessorSupport

代理创建器通用功能基类,提供一些工具方法;

  • 1.用于classLoader管理;
  • 2.计算原始类是否存在有效的接口(计算规则如下)。如果不存在有效的接口则设置proxyTargetClass=true;
//**1.接口的方法数量 > 1
ifc.getMethods().length > 0//**2.非如下回调接口
protected boolean isConfigurationCallbackInterface(Class<?> ifc) {return (InitializingBean.class == ifc || DisposableBean.class == ifc || Closeable.class == ifc ||AutoCloseable.class == ifc || ObjectUtils.containsElement(ifc.getInterfaces(), Aware.class));
}//**3.非如下外部语言接口
protected boolean isInternalLanguageInterface(Class<?> ifc) {return (ifc.getName().equals("groovy.lang.GroovyObject") ||ifc.getName().endsWith(".cglib.proxy.Factory") ||ifc.getName().endsWith(".bytebuddy.MockAccess"));
}	

C.SmartInstantiationAwareBeanPostProcessor

智能实例化处理器,管理bean的生命周期;

D.AbstractAutoProxyCreator

自动代理创建器抽象类,创建代理对象的主要逻辑。获取原始bean的所有AdvicesAndAdvisors(通知和顾问),封装成ProxyFactory,然后创建动态代理bean代替原始bean。其中获取原始bean所有AdvicesAndAdvisors的方法getAdvicesAndAdvisorsForBean委托子类实现;

  • 实现了SmartInstantiationAwareBeanPostProcessor的5个生命周期管理接口。用于在bean生命周期的各个阶段返回的是代理bean,而不是返回原始bean。SmartInstantiationAwareBeanPostProcessor以前介绍过,这里就不展开了;
//**springbean的生命周期管理的5个方法,创建bean动态代理的入口()
//**1.预测bean的class类型()
public Class<?> predictBeanType(Class<?>, String)
//**2.确定bean的class类型.创建代理的class对象()
public Class<?> determineBeanType(Class<?>, String)
//**3.获取提前暴露的bean引用,没有则创建代理对象()
public Object getEarlyBeanReference(Object, String)
//**4.实例化前置处理器.创建代理对象()
public Object postProcessBeforeInstantiation(Class<?>, String)
//**5.初始化后置处理器,上一步没有创建代理对象,则在这里创建代理对象()
public Object postProcessAfterInitialization(Object, String)
  • 5个方法创建代理bean的的逻辑都差不多,我们重点看下postProcessBeforeInstantiation(实例化前置处理器):
    核心逻辑就是查找原始bean是否需要代理,如果需要则获取所的AdvicesAndAdvisors(通知和顾问),并创建并返回代理对象,不需要则返回null;
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {\//**获取缓存的keyObject cacheKey = getCacheKey(beanClass, beanName);//**如果beanName为空 || 原始bean不能封装为TargetSourceif (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {//**如果是重复处理的bean,不处理,直接返回空(advisedBeans缓存了已经处理过的bean)if (this.advisedBeans.containsKey(cacheKey)) {return null;}//**如果是基础设置类 || 应该跳过,则不使用代理并返回空。并缓存在advisedBeans中if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return null;}}//**尝试把原始beab封装为TargetSourceTargetSource targetSource = getCustomTargetSource(beanClass, beanName);//**如果能封装为TargetSourceif (targetSource != null) {//**缓存到targetSourcedBeans中if (StringUtils.hasLength(beanName)) {this.targetSourcedBeans.add(beanName);}//**获取原始bean的AdvicesAndAdvisorsObject[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);//**创建代理对象Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);//**缓存在proxyTypes中this.proxyTypes.put(cacheKey, proxy.getClass());//**返回代理对象return proxy;}//**返回空return null;
}
  • 在看下创建代理的核心代码:
    核心逻辑就是根据原始bean的class对象&名称&通知和顾问&TargetSource创建ProxyFactory对象。然后调用ProxyFactory的getProxy方法获取代理对象;
private Object buildProxy(Class<?> beanClass, @Nullable String beanName,@Nullable Object[] specificInterceptors, TargetSource targetSource, boolean classOnly) {//**如果beanFactory是ConfigurableListableBeanFactory,把原始类信息写到BeanDefinition的originalTargetClass属性中if (this.beanFactory instanceof ConfigurableListableBeanFactory clbf) {AutoProxyUtils.exposeTargetClass(clbf, beanName, beanClass);}//**创建ProxyFactory,并初始化基础配置ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.copyFrom(this);//**虽然proxyTargetClass=true,但是原始bean是Proxy || 是Lambda,则仍然会使用jdk动态代理,需要配置接口if (proxyFactory.isProxyTargetClass()) {if (Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {for (Class<?> ifc : beanClass.getInterfaces()) {proxyFactory.addInterface(ifc);}}} else {//**proxyTargetClass=false,但原始bean强制了使用目标类代理,则仍然需要设置proxyTargetClass=trueif (shouldProxyTargetClass(beanClass, beanName)) {proxyFactory.setProxyTargetClass(true);}else {//**proxyTargetClass=false,如果原始bean存在有效的接口,则使用jdk动态代理,否则仍然使用目标类代理evaluateProxyInterfaces(beanClass, proxyFactory);}}//**对通知和顾问进行处理和转换//**1.添加常用的通知和顾问,并排序//**2.如果是通知(advice),封装成顾问(Advisor),前面一直都是AdvicesAndAdvisors(通知和顾问),到这里时必须全部是AdvisorAdvisor[] advisors = buildAdvisors(beanName, specificInterceptors);proxyFactory.addAdvisors(advisors);//**设置TargetSourceproxyFactory.setTargetSource(targetSource);//**开放的钩子,允许用户对ProxyFactory进行自定义操作。暂无实现customizeProxyFactory(proxyFactory);proxyFactory.setFrozen(this.freezeProxy);if (advisorsPreFiltered()) {proxyFactory.setPreFiltered(true);}ClassLoader classLoader = getProxyClassLoader();if (classLoader instanceof SmartClassLoader smartClassLoader && classLoader != beanClass.getClassLoader()) {classLoader = smartClassLoader.getOriginalClassLoader();}//**调用ProxyFactory的getProxy方法获取代理对象return (classOnly ? proxyFactory.getProxyClass(classLoader) : proxyFactory.getProxy(classLoader));
}
  • 创建代理是ProxyFactory(AdvisedSupport的子类)实现的,我们会有专门的篇章介绍AdvisedSupport。这里先简单看一下创建代理的核心代码:
    核心逻辑就是根据原始bean的的配置和代理的限制,选择为bean创建jdk接口代理还是cglib目标类代理;
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {//**如果原始bean 需要优化 || proxyTargetClass=true || 没有有效的接口if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {Class<?> targetClass = config.getTargetClass();if (targetClass == null) {throw new AopConfigException("TargetSource cannot determine target class: " +"Either an interface or a target is required for proxy creation.");}//**原则上满足上述条件是需要使用目标类代理的,但是原始bean是接口 || 是Proxy || 是Lambda,则仍然使用jdk动态代理if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {return new JdkDynamicAopProxy(config);}//**使用目标类代理(cglib代理)return new ObjenesisCglibAopProxy(config);}else {//**使用jdk动态代理return new JdkDynamicAopProxy(config);}
}

E.AbstractAdvisorAutoProxyCreator

自动代理创建器第二个抽象类,它的它的子类实现了getAdvicesAndAdvisorsForBean方法,负责检索原始bean的顾问和通知,并提供了一些方法扩展该功能;

  • 实现的功能: 提供了查找标准顾问和通知的功能;
    每个需使用代理实现的功能都会注册一个Advisor,比如声明式事物如下:
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {//**注册名为org.springframework.transaction.config.internalTransactionAdvisor的Advisor@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;}
}
  • 提供的扩展:
    • 过滤isEligibleAdvisorBean(String)
    • 排序sortAdvisors(List)
    • 自定义extendAdvisors(List)
//**扩展的调用逻辑
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {//**查找所有类型为Advisor的bean,会调用isEligibleAdvisorBean过滤List<Advisor> candidateAdvisors = findCandidateAdvisors();//**从上面所有标准顾问Advisor中,找出可应用于原始定bean的顾问List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);//**添加自定义的AdvisorextendAdvisors(eligibleAdvisors);//**排序,执行时会按照此顺序执行if (!eligibleAdvisors.isEmpty()) {eligibleAdvisors = sortAdvisors(eligibleAdvisors);}return eligibleAdvisors;
}

F.DefaultAdvisorAutoProxyCreator

默认的自动代理创建器。重写了isEligibleAdvisorBean(String),支持使用指定前缀过滤标准顾问,通常用于一个Advisor类有多个实例的场景。实际上很少会使用;

//**只支持使用这3个自动代理创建器
static {APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}

G.InfrastructureAdvisorAutoProxyCreator

基础设施自动代理创建器。重写了isEligibleAdvisorBean(String),会过滤掉BeanDefinition中role!=ROLE_INFRASTRUCTURE的Advisor。通常Spring自带的标准功能会注册InfrastructureAdvisorAutoProxyCreator,如@EnableTransactionManagement和@EnableCaching等;

@Override
protected boolean isEligibleAdvisorBean(String beanName) {return (this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) &&this.beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE);
}

H.AspectJAwareAdvisorAutoProxyCreator

AspectJ自动代理创建器。重写了extendAdvisors(List)和sortAdvisors(List),对AspectJ切面进行支持;

  • 重写sortAdvisors(List),支持对AspectJ调用排序;
    • 如果A和B在不同的切面中定义,那么优先级是由切面的order值决定;
    • 如果A和B在同一个切面中定义:
      • 如果A或B是后置通知(after advice),那么后声明的通知具有高优先级;
      • 如果A和B都不是后置通知,那么先声明的通知具有高优先级;
  • 重写extendAdvisors(List),添加ExposeInvocationInterceptor到首位,以暴露AspectJ调用上下文;
//**如果包含AspectJ相关的Advice/Advisor,则自动添加DefaultPointcutAdvisor,并且添加到首位
public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) { is just not requiredif (!advisors.isEmpty()) {boolean foundAspectJAdvice = false;for (Advisor advisor : advisors) {if (isAspectJAdvice(advisor)) {foundAspectJAdvice = true;break;}}if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {advisors.add(0, ExposeInvocationInterceptor.ADVISOR);return true;}}return false;
}

I.AnnotationAwareAspectJAutoProxyCreator

AspectJ注解自动代理创建器,重写了findCandidateAdvisors(),查找AspectJ配置,支持@Aspect注解切面。支持配置全局正则过滤@AspectJ切面;

  • 查找AspectJ配置bean的核心代码:
    核心逻辑就是查找所有的bean,然后判断是否匹配全局正则,是否为AspectJ相关的bean,符合条件则封装为Advisor对象,添加到Advisor列表;
    如何区分AspectJ相关的bean: AnnotationUtils.findAnnotation(clazz, Aspect.class) != null && !compiledByAjc(clazz);包含@Aspect注解,并且不是ajc编译器编译(compiledByAjc是一个编译时生成的标志,当类被AspectJ 编译器织入切面时,会在类文件的元数据中添加这个标志。这个标志的存在表明该类已经被AspectJ处理,切面代码已经被织入到类中。);
if (aspectNames == null) {List<Advisor> advisors = new ArrayList<>();aspectNames = new ArrayList<>();//**查找所有的beanString[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);for (String beanName : beanNames) {if (!isEligibleBean(beanName)) {//**全局正则过滤continue;}//**获取bean的class对象Class<?> beanType = this.beanFactory.getType(beanName, false);if (beanType == null) {continue;}//**如果bean的类型为AspectJ类型(AnnotationUtils.findAnnotation(clazz, Aspect.class) != null)if (this.advisorFactory.isAspect(beanType)) {aspectNames.add(beanName);AspectMetadata amd = new AspectMetadata(beanType, beanName);if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {MetadataAwareAspectInstanceFactory factory =new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);//**把标注@Aspect的bean封装成AdvisorList<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);//**缓存起来,如果bean的作用域为单例,则直接缓存Advisor对象,否则缓存创建Advisor的工厂(后续用缓存的工厂创建实例)if (this.beanFactory.isSingleton(beanName)) {this.advisorsCache.put(beanName, classAdvisors);}else {this.aspectFactoryCache.put(beanName, factory);}advisors.addAll(classAdvisors);}else {...}}}this.aspectBeanNames = aspectNames;return advisors;
}
  • 根据AspectJ配置创建Advisor的核心代码:
    先查找AspectJ配置的方法,然后获取Pointcut,最后创建Advisor实例(InstantiationModelAwarePointcutAdvisorImpl);
//**1.查找AspectJ方法的逻辑,查找标注@Aspect注解的bean中不包修@Pointcut的方法
ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter);
MethodFilter adviceMethodFilter = ReflectionUtils.USER_DECLARED_METHODS.and(method -> (AnnotationUtils.getAnnotation(method, Pointcut.class) == null));//**2.获取Pointcut的逻辑,查找上一步结果的方法中的如下注解
Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};
AspectJAnnotation<?> aspectJAnnotation =AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);//**3.创建Advisor实例的逻辑,根据上面两步获取方法和Pointcut创建Advisor
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,int declarationOrderInAspect, String aspectName) {validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());AspectJExpressionPointcut expressionPointcut = getPointcut(candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());if (expressionPointcut == null) {return null;}//**创建了Advisor的子类InstantiationModelAwarePointcutAdvisorImplreturn new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
  • 创建Advice的核心代码:
    Advice才是真正添加的额外逻辑,Advisor只是对Advice的封装。最终切面的方法会转换为Advice,看下转换的核心逻辑;
//**根据通知的类型,创建对应的通知对象
switch (aspectJAnnotation.getAnnotationType()) {case AtPointcut -> {if (logger.isDebugEnabled()) {logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");}return null;}//**创建环绕通知case AtAround -> springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);//**创建前置通知case AtBefore -> springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);//**创建后置通知case AtAfter -> springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);case AtAfterReturning -> {springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();if (StringUtils.hasText(afterReturningAnnotation.returning())) {springAdvice.setReturningName(afterReturningAnnotation.returning());}}case AtAfterThrowing -> {springAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {springAdvice.setThrowingName(afterThrowingAnnotation.throwing());}}default -> throw new UnsupportedOperationException("Unsupported advice type on method: " + candidateAdviceMethod);
}
`

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

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

相关文章

手动仿射变换

开发环境&#xff1a; Windows 11 家庭中文版Microsoft Visual Studio Community 2019VTK-9.3.0.rc0vtk-example参考代码目的&#xff1a;学习与总结 demo解决问题&#xff1a;通过仿射控件vtkAffineWidget对目标actor进行手动的拖拽的仿射变换 关键类&#xff1a;vtkAffineWi…

LSF 守护程序和进程、集群通信路径和安全模型

LSF 细观 了解在 LSF 主机上运行的各种守护进程&#xff0c;LSF 集群通信路径&#xff0c;以及 LSF 如何容许集群中的主机故障。 1、LSF 守护程序和进程 集群中的每个主机上都运行多个 LSF 进程。 正在运行的进程的类型和数量&#xff0c;取决于主机是主节点还是计算节点。 主…

WINCC7.5-根据时间跨度选择趋势

yyyy-MM-dd hh:mm:ss “yyyy”&#xff1a;表示四位数的年份&#xff0c;例如&#xff1a;2022。 “MM”&#xff1a;表示两位数的月份&#xff0c;从01到12。 “dd”&#xff1a;表示两位数的日期&#xff0c;从01到31。 “hh”&#xff1a;表示12小时制的小时数&#xff0c;从…

HackTheBox-Starting Point--Tier 1---Tactics

文章目录 一 题目二 实验过程三 Psexec工具使用 一 题目 Tags Network、Protocols、SMB、Reconnaissance、Misconfiguration译文&#xff1a;网络、协议、中小企业、侦察、配置错误Connect To attack the target machine, you must be on the same network.Connect to the S…

重要—01:Redis

目录 一、什么是Redis&#xff1f; 二、Redis如何实现高可用 三、缓存与数据库不一致问题 四、Redis持久化方式 五、6种淘汰策略 六、缓存穿透和缓存雪崩 七、Redis实现分布式锁 八、Redis.conf 配置文件详解 九、常用命令 一、什么是Redis&#xff1f; Redis&#xf…

TypeScript面试知识点?

以下是一些常见的TypeScript面试知识点,可能会在TypeScript相关的面试中被问到: 1:TypeScript的优势和用途: 解释TypeScript相对于JavaScript的优势,如静态类型检查、提供更好的开发工具支持、增加代码可读性和可维护性等。描述在什么情况下选择使用TypeScript,并举例说…

rcore 笔记 批处理系统 邓氏鱼

批处理系统 批处理系统 (Batch System) &#xff0c;它可用来管理无需或仅需少量用户交互即可运行的程序&#xff0c;在资源允许的情况下它可以自动安排程序的执行&#xff0c;这被称为“批处理作业”。 特权机制 实现特权级机制的根本原因是应用程序运行的安全性不可充分信…

docker安装Kafka,SpringBoot整合Kafka

#拉取镜像 docker pull wurstmeister/zookeeper #运行容器 docker run --restartalways --name zookeeper -p 2181:2181 \ -v /etc/localtime:/etc/localtime -d wurstmeister/zookeeper#拉取镜像 docker pull wurstmeister/kafka#运行容器 docker run --restartalways --name …

Apache POI及easyExcel读取及写入excel文件

目录 1.excel 2.使用场景 3.Apache POI 4.easyExcel 5.总结 1.excel excel分为两版&#xff0c;03版和07版。 03版的后缀为xls&#xff0c;最大有65536行。 07版的后缀为xlsx&#xff0c;最大行数没有限制。 2.使用场景 将用户信息导出到excel表格中。 将excel中的数…

用pd.DataFrame.to_sql方法插入万行数据耗时21秒

to_sql是Pandas中用于将DataFrame数据写入数据库的方法&#xff0c;可以将DataFrame转换为SQL语句&#xff0c;方便我们将数据存入数据库中&#xff0c;以便进行后续的操作。 to_sql方法中包含多个参数&#xff0c;比较常用的参数有name&#xff08;表名&#xff09;、con&…

【算法挑战】用栈实现队列(含解析、源码)

232.用栈实现队列 https://leetcode-cn.com/problems/implement-queue-using-stacks/ 232.用栈实现队列 题目描述方法 1 思路复杂度代码 方法 2 思路复杂度代码(JavaScript/C) 题目描述 使用栈实现队列的下列操作&#xff1a;push(x) -- 将一个元素放入队列的尾部。 pop(…

系统架构设计师-第15章-面向服务架构设计理论与实践-软考学习笔记

面向服务的体系结构&#xff08;Service-Oriented Architecture, SOA) 面向服务的体系结构&#xff08;Service-Oriented Architecture, SOA&#xff09;是一种软件架构模式&#xff0c;它将应用程序的不同功能组织为一组可重用的、松耦合的、自治的服务&#xff0c;这些服务通…

在前端实现小铃铛上展示消息

点击铃铛显示如下消息框&#xff1a; 如果点击消息&#xff0c;可以实现消息从列表中移除,并从铃铛总数上进行扣减对应的已读消息数。 关于以上功能的实现方式&#xff1a; <!-- 铃铛位置 --><i class"el-icon-bell" click"showPopover true"&…

ubuntu启动报错error: proc_thermal_add, will cont

如题&#xff0c;ubuntu启动报错error: proc_thermal_add, will cont 截图如下&#xff1a; 困扰了我很久&#xff0c;差点就打算重装系统&#xff0c;准备放弃了&#xff0c;但是感谢国外的老哥&#xff0c;写了一篇非常详细的解决方案&#xff0c;我搬过来。 解决方案&#…

03-对象

对象 对象1.对象的创建字面量模式构造函数模式 2.对象的访问3.新增删除对象中的属性4.Object显示类型转换(强制类型转换)ECMAScript中可用的3种强制类型转换如下&#xff1a;Boolean(value)String(value)Number(value)Object类型到Boolean类型Object类型转String类型转换规则&a…

Redis通过复制rdb文件方式同步线上数据到本地以及提示:Can‘t handle RDB format version 9解决

场景 Redis的持久化机制-RDB方式和AOF方式&#xff1a; Redis的持久化机制-RDB方式和AOF方式_rdb 和ao-CSDN博客 Redis持久化机制导致服务自启动后恢复数据过长无法使用以及如何关闭&#xff1a; Redis持久化机制导致服务自启动后恢复数据过长无法使用以及如何关闭_霸道流氓…

mysql数据表设计

命名 mysql表名的命名规范为表名可以用 t_ 、tb_的前缀&#xff0c;或者是业务模块前缀。比如t_order。 有些项目也会使用 tt_、tm_、 ts_ 等前缀&#xff0c;根据项目的习惯命名就好了。 主键&#xff1a; AUTO_INCREMENT 表示自增&#xff0c;UNSIGNED 表示无符号&#xf…

【算法专题】双指针—盛最多水的容器

一、题目解析 分析这个题目不难得出一个容积公式 二、算法原理 解法一&#xff1a;暴力枚举&#xff08;超时&#xff09; 套用上述的容积公式&#xff0c;使用两个for循环来枚举出所有可能的情况&#xff0c;再挑出最大值即可&#xff0c;但是这种写法会超时&#xff0c;导致…

数据结构-初识泛型

写在前&#xff1a; 这一篇博客主要来初步的记录以下泛型的相关内容&#xff0c;内容比较琐碎&#xff0c;就不进行目录的整合&#xff0c;后续可能会对泛型这里进行系统性的梳理&#xff0c;此篇博客主要是对泛型有一个简单的认识与理解&#xff0c;需要知晓的内容。 当我调用…

2. 网络之网络编程

网络编程 文章目录 网络编程1. UDP1.1 DatagramSocket1.1.1 DatagramSocket 构造方法1.1.2 DatagramSocket 方法&#xff1a; 1.2 DatagramPacket1.2.1 DatagramPacket构造方法1.2.2 DaragramPacket方法1.2.3InetSocketAddress API 1.3 UDP回显服务器1.3.1 框架结构1.3.2 读取请…