曹工说Spring Boot源码(22)-- 你说我Spring Aop依赖AspectJ,我依赖它什么了
三国梦回 人气:0If alwaysMatches is true, then maybeMatches is always true.
*/ boolean maybeMatches(); /** * True iff the pointcut expression can never match any join point at this * shadow (for example, the pointcut will never match a call to the given * method). */ boolean neverMatches(); ... } ``` 这个接口就是告诉你,匹配了切点后,你可以找它拿结果,结果可能是:总是匹配;总是不匹配;可能匹配。 什么情况下,会返回可能匹配,我目前还没试验出来。 我跟过AspectJ的代码,发现解析处主要在以下方法: org.aspectj.weaver.patterns.SignaturePattern#matchesExactlyMethod 有兴趣的小伙伴可以看下,方法很长,以下只是一部分。 ```java private FuzzyBoolean matchesExactlyMethod(JoinPointSignature aMethod, World world, boolean subjectMatch) { if (parametersCannotMatch(aMethod)) { // System.err.println("Parameter types pattern " + parameterTypes + " pcount: " + aMethod.getParameterTypes().length); return FuzzyBoolean.NO; } // OPTIMIZE only for exact match do the pattern match now? Otherwise defer it until other fast checks complete? if (!name.matches(aMethod.getName())) { return FuzzyBoolean.NO; } // Check the throws pattern if (subjectMatch && !throwsPattern.matches(aMethod.getExceptions(), world)) { return FuzzyBoolean.NO; } // '*' trivially matches everything, no need to check further if (!declaringType.isStar()) { if (!declaringType.matchesStatically(aMethod.getDeclaringType().resolve(world))) { return FuzzyBoolean.MAYBE; } } ... } ``` 这两部分,代码就讲到这里了。我的demo源码在: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
加载全部内容