曹工說Spring Boot原始碼(22)-- 你說我Spring Aop依賴AspectJ,我依賴它什麼了
If alwaysMatches is true, then maybeMatches is always true.
Default is {@link FilterType#ANNOTATION}. * @see #classes * @see #pattern */ // 講解點1 FilterType type() default FilterType.ANNOTATION; ... /** * The pattern (or patterns) to use for the filter, as an alternative * to specifying a Class {@link #value}. *
If {@link #type} is set to {@link FilterType#ASPECTJ ASPECTJ},
* this is an AspectJ type pattern expression. If {@link #type} is
* set to {@link FilterType#REGEX REGEX}, this is a regex pattern
* for the fully-qualified class names to match.
* @see #type
* @see #classes
*/
String[] pattern() default {};
}
```
其中,講解點1,可以看到,裡面預設是ANNOTATION型別,實際還有其他型別;
講解點2,如果type選擇ASPECTJ,則這裡寫AspectJ語法的切點表示式即可。
```java
public enum FilterType {
/**
* Filter candidates marked with a given annotation.
* @see org.springframework.core.type.filter.AnnotationTypeFilter
*/
ANNOTATION,
/**
* Filter candidates assignable to a given type.
* @see org.springframework.core.type.filter.AssignableTypeFilter
*/
ASSIGNABLE_TYPE,
/**
* 講解點1
* Filter candidates matching a given AspectJ type pattern expression.
* @see org.springframework.core.type.filter.AspectJTypeFilter
*/
ASPECTJ,
/**
* Filter candidates matching a given regex pattern.
* @see org.springframework.core.type.filter.RegexPatternTypeFilter
*/
REGEX,
/** Filter candidates using a given custom
* {@link org.springframework.core.type.filter.TypeFilter} implementation.
*/
CUSTOM
}
```
縱觀以上幾點,可以發現,Spring Aop整合AspectJ,只是把切點這一套語法、@Aspect這類註解、切點的解析,都直接使用AspectJ的,沒有自己另起爐灶。但是核心呢,是沒有使用AspectJ的編譯期注入和ltw的。
下面我們仔細講解,上面的第二點,這也是最重要的一點。
# Spring Aop是在實現aop時(上面第二點),如何整合AspectJ
這裡不會講aop的實現流程,大家可以去翻前面幾篇,從這篇往下的幾篇。
[曹工說Spring Boot原始碼(16)-- Spring從xml檔案裡到底得到了什麼(aop:config完整解析【上】)](https://www.cnblogs.com/grey-wolf/p/12314954.html)
##解析xml或註解,獲取AspectJExpressionPointcut
在aop解析xml或者@Aspect時,最終切點是用AspectJExpressionPointcut 型別來表示的,且被註冊到了ioc容器,後續可以通過getBean直接獲取該切點
##AspectJAwareAdvisorAutoProxyCreator 後置處理器,判斷切點是否匹配,來生成代理
在AspectJAwareAdvisorAutoProxyCreator 這個BeanPostProcessor對target進行處理時,會先判斷該target是否需要生成代理,此時,就會使用到我們前面講解的東西。
判斷該target是否匹配切點,如果匹配,則生成代理;否則不生成。
```java
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
...
// 獲取能夠匹配該target bean的攔截器,即aspect切面
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;
}
```
我們主要看getAdvicesAndAdvisorsForBean:
```java
@Override
protected Object[] getAdvicesAndAdvisorsForBean(Class beanClass, String beanName, TargetSource targetSource) {
List advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List findEligibleAdvisors(Class beanClass, String beanName) {
// 講解點1
List candidateAdvisors = findCandidateAdvisors();
// 講解點2
List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
return eligibleAdvisors;
}
```
講解點1,獲取全部的切面集合;
講解點2,過濾出能夠匹配target bean的切面集合
```java
protected List findAdvisorsThatCanApply(
List candidateAdvisors, Class beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
```
```java
public static List findAdvisorsThatCanApply(List candidateAdvisors, Class> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
for (Advisor candidate : candidateAdvisors) {
// canApply就是判斷切面和target的class是否匹配
if (canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
```
所以,重點就來到了canApply方法:
```java
public static boolean canApply(Advisor advisor, Class> targetClass, boolean hasIntroductions) {
if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
//講解點1
return canApply(pca.getPointcut(), targetClass);
}
else {
// It doesn't have a pointcut so we assume it applies.
return true;
}
}
```
講解點1,就是首先pca.getPointcut()獲取了切點,然後呼叫瞭如下方法:
```java
org.springframework.aop.support.AopUtils#canApply
public static boolean canApply(Pointcut pc, Class> targetClass, boolean hasIntroductions) {
//講解點1
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
MethodMatcher methodMatcher = pc.getMethodMatcher();
// 講解點2
Set