文章目錄
一、前言
本文是筆者閱讀Spring源碼的記錄文章,由於本人技術水平有限,在文章中難免出現錯誤,如有發現,感謝各位指正。在閱讀過程中也創建了一些衍生文章,衍生文章的意義是因爲自己在看源碼的過程中,部分知識點並不瞭解或者對某些知識點產生了興趣,所以爲了更好的閱讀源碼,所以開設了衍生篇的文章來更好的對這些知識點進行進一步的學習。
全集目錄:Spring源碼分析:全集整理
本文前篇:
Spring源碼分析十一:@AspectJ方式的AOP
這個方法的實現在 AbstractAdvisorAutoProxyCreator
類中。getAdvicesAndAdvisorsForBean
的作用是獲取所有適用於當前Bean 的 Advisors 。因爲並不是所有的規則都適用於當前bean,所有會有一個篩選的過程。
這個方法的邏輯分爲兩步:
- 尋找所有的顧問(Advisors), 這個方法在Aop中被重寫了,爲了可以的動態生成 Advisor –
findCandidateAdvisors
- 尋找所有顧問(Advisors) 中適用於bean 的增強並應用 –
findAdvisorsThatCanApply
@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 主要邏輯還是在 findEligibleAdvisors 中完成。
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
//如果沒有增強點則不需要代理。
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
...
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 尋找所有的增強
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 尋找所有增強中適用於bean 的增強並應用
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
可以看到兩個核心方法 findCandidateAdvisors
和 findAdvisorsThatCanApply
。下面我們一個一個來分析。
二、尋找所有Advisors - findCandidateAdvisors
前文講過,Spring aop 注入的自動代理創建器是 AnnotationAwareAspectJAutoProxyCreator,所以AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
的代碼如下:
@Override
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
// 1. 這裏是從BeanFactory 中找出來 所有 Advisor 類型的bean。即找到所有配置的Advisor。
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
// 2. buildAspectJAdvisors() 從代碼中動態找到了需要的增強點
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
這裏來解釋一下這兩個方法的區別:
super.findCandidateAdvisors();
: 一般獲取的都是通過直接註冊的 Advisors。比如事務的顧問,直接通過 @Bean 注入到Spring容器中。
this.aspectJAdvisorsBuilder.buildAspectJAdvisors()
: 主要獲取我們通過註解方式動態註冊的 Advisors。比如 在 Aop 中根據不同的表達式,需要攔截的切面也不同,那就需要爲這些切面動態生成 Advisors。而不能直接注入。
1. super.findCandidateAdvisors();
super.findCandidateAdvisors();
這裏調用的實際上是AbstractAdvisorAutoProxyCreator 中的findCandidateAdvisors
方法。這一步最終會調用如下的findAdvisorBeans
方法。其作用根據註釋也能明白。獲取所有合格的 Advisor Bean(合格並不代表適用當前bean),忽略了FactoryBean 和創建中的bean。
/**
* Find all eligible Advisor beans in the current bean factory,
* ignoring FactoryBeans and excluding beans that are currently in creation.
* @return the list of {@link org.springframework.aop.Advisor} beans
* @see #isEligibleBean
*/
public List<Advisor> findAdvisorBeans() {
// Determine list of advisor bean names, if not cached already.
// 從緩存中獲取 advisorNames
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!
// 從 Spring 中獲取 Advisor 類型的 beanname 。這裏獲取到的一般都是硬編碼注入的 Advisors
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
// 如果沒有獲取到 Advisors ,直接返回
if (advisorNames.length == 0) {
return new ArrayList<>();
}
// 到這一步必定有Advisors ,我們需要通過name來獲取到bean的實例
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 {
// 根據name 和 類型獲取到 Advisor
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;
}
2. this.aspectJAdvisorsBuilder.buildAspectJAdvisors()
this.aspectJAdvisorsBuilder.buildAspectJAdvisors()
的作用就是 在當前的bean工廠中查找帶有AspectJ註解的 Aspect bean,並封裝成代表他們的Spring Aop Advisor,注入到Spring 中。
基本的思路如下:
- 獲取所有beanName,這一步所有在beanFactory中註冊的bean都會被提取出來
- 遍歷所有的beanName, 找出聲明AspectJ註解的類,進行進一步處理
- 對標記爲AspectJ註解的類進行Advisors 提取
- 將提取的結果保存到緩存中。
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<>();
// 1. 獲取所有的beanName。
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
// 遍歷beanname, 找出對應的增強方法
for (String beanName : beanNames) {
// 不合法的bean略過,由子類定義規則,默認true
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.
// 獲取對應bean 的類型
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
// 2. 如果存在AspectJ 註解,進一步處理
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);
// 3. 解析標記AspectJ註解中的增強方法,也就是被 @Before、@Around 等註解修飾的方法,並將其封裝成 Advisor
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 {
// Per target or per this.
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);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
// 4. 將所有的增強方法保存到緩存中。
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
2.1. this.advisorFactory.getAdvisors(factory);
在上述代碼中,最爲複雜的就是增強器(Advisors
)獲取,也就是 this.advisorFactory.getAdvisors(factory);
這一步,
具體的實現是在 ReflectiveAspectJAdvisorFactory#getAdvisors
中。下面我們具體來看代碼
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// 獲取標記爲 AspectJ 的類
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
// 獲取標記爲 AspectJ 的名字
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<>();
// 獲取 aspectClass 的所有方法,過濾掉了聲明爲 PointCut 的方法以及 !method.isBridge() && !method.isSynthetic() 的方法
for (Method method : getAdvisorMethods(aspectClass)) {
// 將方法封裝成 Advisor 。如果不滿足封裝條件,即沒有被 AspectJ 系列註解
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.
// 獲取 DeclaredParents 註解並處理。@DeclaredParents 註解可以實現指定某些代理類是某些接口的實現。
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
...
// 篩選出合適的方法,並封裝成 Advisor 。這裏返回的都是 InstantiationModelAwarePointcutAdvisorImpl
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 1. 切點信息的獲取
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
// 2. 根據切點信息封裝成增強器
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
這裏根據 切點信息來動態生成了增強器,也就是 Advisor。是根據AOP 的註解解析來的動態生成的。 可以看到,封裝的關鍵的操作還是在 getAdvisor
方法 中,下面我們來詳細分析:
2.1.1. 切點信息的獲取 - getPointcut
getPointcut 方法的實現很簡單,就是判斷方法上是否有 AspectJ系列的註解,有則封裝。
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
// 獲取方法上的註解,包括 Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// 到這裏必然有 AspectJ系列的註解了
// 使用 AspectJExpressionPointcut 實例封裝獲取的信息
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
// 提取出的得到的註解中的表達式
// 如 @Pointcut("execution(* com.kingfish.aopdemo.controller.AopController.hello(String))") 中的 execution(* com.kingfish.aopdemo.controller.AopController.hello(String))
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
if (this.beanFactory != null) {
ajexp.setBeanFactory(this.beanFactory);
}
return ajexp;
}
其中 AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
方法如下:
private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};
// 獲取指定方法上的註解並使用 AspectJAnnotation 封裝
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
if (foundAnnotation != null) {
return foundAnnotation;
}
}
return null;
}
2.1.2. 根據切點信息封裝成增強器 - InstantiationModelAwarePointcutAdvisorImpl
在 Aop 中所有的增強都由 Advisor 的實現類 InstantiationModelAwarePointcutAdvisorImpl
統一封裝。
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
this.declaredPointcut = declaredPointcut;
this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
this.methodName = aspectJAdviceMethod.getName();
this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
this.aspectJAdviceMethod = aspectJAdviceMethod;
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
this.aspectInstanceFactory = aspectInstanceFactory;
this.declarationOrder = declarationOrder;
this.aspectName = aspectName;
if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
// Static part of the pointcut is a lazy type.
Pointcut preInstantiationPointcut = Pointcuts.union(
aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
// Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
// If it's not a dynamic pointcut, it may be optimized out
// by the Spring AOP infrastructure after the first evaluation.
this.pointcut = new PerTargetInstantiationModelPointcut(
this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
this.lazy = true;
}
else {
// A singleton aspect.
this.pointcut = this.declaredPointcut;
this.lazy = false;
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
}
...
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);
}
在封裝過程中只是簡單的將信息封裝在類的實例中,所有的信息只是單純的賦值,在實例化過程中還完成了對於增強器的處理。因爲不同的增強體現的邏輯是不同的,簡單來說就是不同的切點信息的動作是不同的,比如 @Before
和 @After
註解的動作就不同, @Before
需要在切點方法前調用, @After
需要在切點方法後調用 。而根據註解中的信息初始化對應的增強器就是在instantiateAdvice 中實現。而instantiateAdvice 中主要還是調用了 this.aspectJAdvisorFactory.getAdvice
,因此我們來看 this.aspectJAdvisorFactory.getAdvice
的代碼:
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:
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;
}
可以看到,Spring會根據不同的註解生成不同的增強器(通知)。比如 AspectJAroundAdvice
、AspectJMethodBeforeAdvice
等,從而完成不同的註解所需的動作。
二、篩選合適的Advisors - findAdvisorsThatCanApply
經歷了第一步,也僅僅是將所有的顧問(Advisors),也就是增強器,全部查找出來。但是並非所有的Advisors 都適用於當前bean。所以這一步的目的是爲了過濾出適合當前bean的增強器。
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
可以看到關鍵內容還是在 AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
所以我們繼續往下看。AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
的代碼如下:
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
// 首先處理引介增強
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
// 引介增強已處理
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
// 對於普通bean 的處理
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
引介增強和普通的增強處理是不同的,所以需要分開處理。而通過上面的代碼,我們可以看到關鍵邏輯在 canApply
函數中,因此我們直接看這個函數。
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
// 獲取切點的方法匹配器
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set<Class<?>> classes = new LinkedHashSet<>();
if (!Proxy.isProxyClass(targetClass)) {
classes.add(ClassUtils.getUserClass(targetClass));
}
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
for (Class<?> clazz : classes) {
// 獲取當前bean的所有方法
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
// 在這裏判斷方法是否匹配
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
以上:內容部分參考
《Spring實戰》
《Spring源碼深度解析》
https://www.cnblogs.com/cheng21553516/p/12190008.html
https://blog.csdn.net/wyl6019/article/details/80136000
如有侵擾,聯繫刪除。 內容僅用於自我記錄學習使用。如有錯誤,歡迎指正