上一篇文章主要介绍了Spring AOP一些简单用法,当然如果要了解更多,可以选择再去看看Spring 文档。
博主还是喜欢从源码中知其所以然嘿嘿。
spring-boot-starter-aop
博主以 Spring-boot-starter-aop
为例,开始分析。
在spring boot
中使用 aop
,我们只需要引入 spring-boot-starter-aop
即可定义注解进行操作:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.1.7.RELEASE</version>
</dependency>
从spring-boot-starter-aop
反编译后的依赖来看,这个项目里面并没有任何代码:
没有任何代码,那么里面是怎么引入的呢?抱着这个想法,博主下载了Spring Boot
项目源码查看,不过里面确实没有java
代码,只有一个gradle
依赖。
dependencies {
api(platform(project(":spring-boot-project:spring-boot-dependencies")))
api(project(":spring-boot-project:spring-boot-starters:spring-boot-starter"))
api("org.springframework:spring-aop")
api("org.aspectj:aspectjweaver")
}
在 spring-boot-starter-aop
项目中,引入了一些依赖,包括 spring-aop
和 ajpectjweaver
,以及当前spring-boot
项目的starter
。
经过前面文章也有个大概了解,spring-aop
项目中应该只是一些类,而没有注入到Spring
容器中,那么 spring-aop
的引线在哪里呢?
首先要使用spring-boot-starter-aop
,首先得是一个spring-boot
架构项目,而 spring-boot
项目引入依赖的一个途径是通过增加Spring SPI
配置文件: spring.factories
,有加载 @EnableAutoConfiguration
进行加载,但很明显,spring-boot-starter-aop
不属于这一类。
在针对 @SpringBootApplication
进行更细致分析,它在 spring-boot-autoconfigure
包下面:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
...
}
上面 SpringBootApplication
注解中,使用 @ComponentScan
对当前包下进行进一步扫描,此时可以看到有个aop
的子包,下面有个配置类 AopAutoConfiguration
。没错,这就是 spring-boot
中,spring-aop
的入口:
@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)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
matchIfMissing = false)
public static class JdkDynamicAutoProxyConfiguration {
}
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
public static class CglibAutoProxyConfiguration {
}
}
@Configuration
说明是配置类,会被spring
扫描到@ConditionalOnClass
即当前classpath下面,有这几个类EnableAspectJAutoProxy
、Aspect
、Advice
、AnnotatedElement
才回去加载该类,通俗说就是 即有spring-aop
依赖才会加载。@ConditionalOnProperty
在上一步,再一步对配置进行条件判断,即判断是否有spring.aop.auto
=true
则加载。matchIfMissing = true
或者没有该配置,则默认加载配置。
类上注解分析完,下面看内部类注解:- spring 代理方式有两种,一种是jdk代理(需要有接口方式进行代理),一种是cglib方式(不需要接口,以子类方式,但是无法代理final方法)。如上面配置,默认下是使用 cglib进行代理。
下面看两个子类都有的注解 @EnableAspectJAutoProxy
。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
除了两个属性外,还引入了一个 AspectJAutoProxyRegistrar
。 AspectJAutoProxyRegistrar
则为一个 ImportBeanDefinitionRegistrar
,它将重写 registerBeanDefinitions
来注册自己的bean。
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 注册 AnnotationAwareAspectJAutoProxyCreator
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
// 设置 EnableAspectJAutoProxy 来的两个属性 proxyTargetClass 和 exposeProxy 到 AnnotationAwareAspectJAutoProxyCreator 中
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
- 注册
AnnotationAwareAspectJAutoProxyCreator
,这是spring-aop
的核心入口类。 - 设置
EnableAspectJAutoProxy
来的两个属性proxyTargetClass
和exposeProxy
到AnnotationAwareAspectJAutoProxyCreator
中。
AnnotationAwareAspectJAutoProxyCreator
排除众多类结构,发现 AnnotationAwareAspectJAutoProxyCreator
是一个 SmartInstantiationAwareBeanPostProcessor
,和解析@Autowired
的类实现同一个接口,大概能猜到,在spring
容器初始化bean
时候,对对应类进行代理操作 。
实现 SmartInstantiationAwareBeanPostProcessor
接口,需要实现以下方法(当然全部有默认接口):
Class<?> predictBeanType(Class<?> beanClass, String beanName)
:预测bean类型Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName)
解析获取候选构造方法Object getEarlyBeanReference(Object bean, String beanName)
获取bean实例,主要目的是解决spring循环依赖Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName)
实例前处理boolean postProcessAfterInstantiation(Object bean, String beanName)
实例后处理PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
设置一些属性PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
设置一些属性值Object postProcessBeforeInitialization(Object bean, String beanName)
实例化前处理Object postProcessAfterInitialization(Object bean, String beanName)
实例化后处理
在 AnnotationAwareAspectJAutoProxyCreator
主要对以下几个方法有具体实现:
predictBeanType
在AbstractAutoProxyCreator
有实现getEarlyBeanReference
在AbstractAutoProxyCreator
有实现postProcessBeforeInstantiation
在AbstractAutoProxyCreator
有实现postProcessAfterInitialization
在AbstractAutoProxyCreator
有实现
下面从spring容器执行方法先后顺序,结合例子具体分析spring-aop
原理。
postProcessBeforeInstantiation
在实例化前进行调用:
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
// 获取即将缓存名字,有beanName,则返回beanName,如果为FactoryBean类型,则加上FactoryBean&前缀;没有beanName,则直接返回beanClass
Object cacheKey = getCacheKey(beanClass, beanName);
// 如果没有beanName,或者不在 targetSourcedBeans中
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
// 如果已包含该key,则说明已经处理过了
return null;
}
// 如果该bean是spring-aop的框架内部bean,即 Advice,Pointcut,Advisor,AopInfrastructureBean 几种bean。或者有@Aspect注解,或者,这个bean类,本身就是aspectj创建。 则加入到advisedBeans bean 并跳过。
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// 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;
}
return null;
}
- 获取即将缓存名字,有beanName,则返回beanName,如果为FactoryBean类型,则加上FactoryBean&前缀;没有beanName,则直接返回beanClass。
- 对bean进行处理,判断是否需要跳过。
isInfrastructureClass
逻辑主要是要跳过以下几种类型:
- Advice,Pointcut,Advisor,AopInfrastructureBean 几种bean类型。或者有@Aspect注解,或者,这个bean类,本身就是aspectj创建。
而shouldSkip
主要有以下几种判断: - 获取advisor过程,这个看下一小节
- 如果有一种类型为
AspectJPointcutAdvisor
则直接跳过 - 执行父类的
shouldSkip
方法,父类主要是 判断 跳过original instance
类型bean
- 如果有配置
targetSource
,则调用getAdvicesAndAdvisorsForBean
获取代理接口,并调用创建代理类接口。
findCandidateAdvisors
findCandidateAdvisors
是获取Advisor
过程:
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;
}
看父类的 AbstractAdvisorAutoProxyCreator
中方法:
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
return this.advisorRetrievalHelper.findAdvisorBeans();
}
具体使用 BeanFactoryAdvisorRetrievalHelper
的 findAdvisorBeans
,这个方法主要目的是找到所有 资格的 Advisor
bean类,该方法会忽略 FactoryBean
类型,以及排除 正在创建的bean。
public List<Advisor> findAdvisorBeans() {
// Determine list of advisor bean names, if not cached already.
String[] advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the auto-proxy creator apply to them!
// 直接从beanFactory中获取所有Advisor类。
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
if (advisorNames.length == 0) {
return new ArrayList<>();
}
List<Advisor> advisors = new ArrayList<>();
for (String name : advisorNames) {
if (isEligibleBean(name)) {
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isTraceEnabled()) {
logger.trace("Skipping currently created advisor '" + name + "'");
}
}
else {
try {
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
String bceBeanName = bce.getBeanName();
if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
if (logger.isTraceEnabled()) {
logger.trace("Skipping advisor '" + name +
"' with dependency on currently created bean: " + ex.getMessage());
}
// Ignore: indicates a reference back to the bean we're trying to advise.
// We want to find advisors other than the currently created bean itself.
continue;
}
}
throw ex;
}
}
}
}
return advisors;
}
在Spring中,也可以直接使用@Aspect注解,当从 findAdvisorBeans
没有获取到信息是,会尝试调用 BeanFactoryAspectJAdvisorsBuilder
的 buildAspectJAdvisors()
获取注解。
public List<Advisor> buildAspectJAdvisors() {
// 读取缓存
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
// 获取所有实例,即Object子类。
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
// 判断是否已经制定表达式过滤
continue;
}
// We must be careful not to instantiate beans eagerly as in this case they
// would be cached by the Spring container but would not have been weaved.
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
if (this.advisorFactory.isAspect(beanType)) {
// 如果是 @Aspect注解且不是aspectj动态产生的。那额
aspectNames.add(beanName);
// 构造 Aspect 元数据
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
// 如果改AspectJ 注解 是单例模型
// 构造一个 BeanFactoryAspectInstanceFactory
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
// 获取在Advice 中配置的Advisor,即PointCut信息。
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
// 单例
this.advisorsCache.put(beanName, classAdvisors);
}
else {
// 非单例
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
// 非单例模型
if (this.beanFactory.isSingleton(beanName)) {
// 再一次检查
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
// 构造MetadataAwareAspectInstanceFactory 并缓存
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
List<Advisor> advisors = new ArrayList<>();
// 从获取到的有Aspecj 注解的类,进行获取其 Advisor过程
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
// 构造 MetadataAwareAspectInstanceFactory 并加入
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
整个 findCandidateAdvisors
方法有点长,但是代码逻辑还是挺容易理解的
- 调用父类方法
findCandidateAdvisors
获取Advisor
类型类,即实现了Advisor
接口类。Advisor
是Advice
的一个点,实际上为Advice
的一个切点(JoinPoint)。这个接口一般不建议给Spring 使用者用,而提供给Spring 所需要的的维护者使用。 - 再从
BeanFactoryAspectJAdvisorsBuilder
的buildAspectJAdvisors
中,将所有切面@Advice
从beanFactory解析出,并且分别解析其PointCut
,每个拦截方法,使用Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class
注解,就是一个Advisor
。
this.advisorFactory.getAdvisors(factory)
往下看 this.advisorFactory.getAdvisors(factory)
具体内容:
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// 获取目标代理类
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
// 获取切面名字
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
// 判断是否为懒加载切面
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
for (Method method : getAdvisorMethods(aspectClass)) {
// 获取该切面类的切点信息
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// If it's a per target aspect, emit the dummy instantiating aspect.
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
// 对 @DeclareParent 注解进行处理
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
上面代码中,看对普通增强器获取,主要方法为: getAdvisor
:
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;
}
// 包装一层 InstantiationModelAwarePointcutAdvisorImpl
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
其实对于普通使用 @Aspectj
切面的处理,就是将其切点信息PointCut
获取出来并处理:
@Nullable
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
// 获取Pointcut, Around, Before, After, AfterReturning, AfterThrowing
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// 设置poincut信息后取出。
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
if (this.beanFactory != null) {
ajexp.setBeanFactory(this.beanFactory);
}
return ajexp;
}
上面代码片段中,对每个方法进行获取增强器操作,而后封装为 InstantiationModelAwarePointcutAdvisorImpl
返回。
InstantiationModelAwarePointcutAdvisorImpl
的构造方法,则是普通信息的填充,而主要是其内部的 instantiateAdvice
,对信息进行初始化过程。
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
return (advice != null ? advice : EMPTY_ADVICE);
}
再看 ReflectiveAspectJAdvisorFacotory
的 getAdvice
方法:
@Override
@Nullable
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
// 切面类
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
// 获取方法上面注解
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// If we get here, we know we have an AspectJ method.
// Check that it's an AspectJ-annotated class
if (!isAspect(candidateAspectClass)) {
throw new AopConfigException("Advice must be declared inside an aspect type: " +
"Offending method '" + candidateAdviceMethod + "' in class [" +
candidateAspectClass.getName() + "]");
}
if (logger.isDebugEnabled()) {
logger.debug("Found AspectJ method: " + candidateAdviceMethod);
}
AbstractAspectJAdvice springAdvice;
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
case AtAround:
// candidateAdviceMethod 为候选方法,expressionPointcut 为注解上面切点信息, aspectInstanceFactory 为
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter:
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing:
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
// Now to configure the advice...
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
根据不同类型AspectJ注解,Spring 封装了不同类返回。
主要有以下几种:
@Around
:AspectJAroundAdvice
@Before
:AspectJMethodBeforeAdvice
@After
:AspectJAfterAdvice
@AfterReturning
:AspectJAfterReturningAdvice
@AfterThrowing
:AspectJAfterThrowingAdvice
小结
本文主要分析Spring AOP入口,以及postProcessBeforeInstantiation
部分内容,下文将针对 具体 createProxy
具体分析
觉得博主写的有用,不妨关注博主公众号: 六点A君。
哈哈哈,一起研究Spring: