Spring Aop 源码分析实现原理(JDK动态代理)
Spring 开启Aop
引入Aspectj库
Spring 开启aop得先引入Aspectj的库,因为Spring用到了aspectj的注释。在Spring之前的几个版本中,想要用到Spring aop的话,得写许多得代码。为了简化流程,Spring就引用了aspectj的注解来进行自身的开发,最终实现还是由Spring自己来完成的。
compile group: ‘org.aspectj’, name: ‘aspectjweaver’,version:‘1.9.5’
开启aop功能
然后在一个配置类上标注@EnableAspectJAutoProxy开启Aop功能。这个注解的主要用途就是向Spring导入了一个类------AspectJAutoProxyRegistrar。
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
由于AspectJAutoProxyRegistrar类实现了ImportBeanDefinitionRegistrar接口,在Spring在扫描的时候就会将ImportBeanDefinitionRegistrar的registerBeanDefinitions这个方法给执行。
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
注册BeanDefinition
这个registerBeanDefinitions方法会将SpringAop的一个类给转化为BeanDefinition,从而将这个类给注册到Spring的BeanDefinitionMap当中。
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
---------------------------
//最终会到这个方法当中,这个方法就是将AnnotationAwareAspectJAutoProxyCreator注册到Spring的BeanDefinitionMap中。
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
------------------------
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
/**
*中间是一些判断
*
*/
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
//这里就是将AnnotationAwareAspectJAutoProxyCreator这个类个注册到Spring的BeanDefinitionMap中,方便后面生成Bean
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
添加后置处理器
上面注册到Spring的bdMap中的类就是实现了BeanPostProcessor后置处理器的接口,在refresh方法中,有一个registerBeanPostProcessors方法,是专门用来将bdMap中的后置处理器实例化,然后添加到Spring的后置处理器集合里,方便在下面实例化Bean的时候进行一系列的操作。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
..........
// 注册(实例化后置处理器并添加到工厂的后置处理器集合里)
registerBeanPostProcessors(beanFactory);
.........
}
在这个方法内部,就进行一系列的操作,先是对后置处理器进行分类,然后按照优先级排序来分别创建Bean和注册到Spring的后置处理器集合里。
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
//首先先从bdMap中获取实现了BeanPostProcessor接口的类。
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
//新建四个集合,两个是已经变成Bean得后置处理器集合,还有两个是后置处理器得名字。
//之所以要弄两个不同种类得集合是因为在Spring内部实现了priorityOrdered这个接口的 //BeanPostProcessor的类有两个,分别是CommonAnnotitionBeanPostProcessor和 //AutoWiredAnnotitionBeanPostProcessor,这两个类与Spring的依赖注入有着相当大的关系。先 //往后置处理器注册这两个类是为了开发者扩展Spring的时候,能够互相调用类的关系。
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
//内置了CommonAnnotition和AutoWiredAnnntition这两个后置处理器
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
//生成Bean,并且添加到集合里,在下面注册到Spring的后置处理器中
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
//找到实现了ordered接口的类
orderedPostProcessorNames.add(ppName);
}
else {
//没有实现Ordered的类
nonOrderedPostProcessorNames.add(ppName);
}
}
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
//将priorityOrderedPostProcessors集合中的Bean注册到后置处理器中
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
//在这里,Spring在生成Aop的配置类的Bean(就是上面添加到bdMap的类)后,添加到Spring的后置处理器集合中。下面的就是依次生成Bean,然后注册到后置处理器中。
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// Now, register all regular BeanPostProcessors.
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
// Finally, re-register all internal BeanPostProcessors.
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
// Re-register post-processor for detecting inner beans as ApplicationListeners,
// moving it to the end of the processor chain (for picking up proxies etc).
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
扫描切面
当我们在一个配置类上标注了@Aspect注解的时候,这个配置类就变成了一个切面类了。与此同时,在配置类中的切点表达式和通知将会在扫描的时候一并扫描到。
postProcessBeforeInstantiation—后置处理器
扫描切面配置类的入口是findCandidateAdvisors这个方法,这个方法被许多方法给调用。最先调用这个方法是从后置处理器的postProcessBeforeInstantiation方法,这也是为什么Aop的实现类要实现BeanPostProcessor这个接口的原因。
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
//简单的判断,是否为空
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
/**
* 第一次调用这个方法时,当判断不是aop的配置类的话,就会进行第二部分的扫描了。
* shouldSkip里面就有调用findCandidateAdvisors这个方法,也是第一遍调用这个方法。
*/
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
}
----------------------------------
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
/**
* 找到候选的切面
*/
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
//当前的类是否是一个spring的切面类
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}
findCandidateAdvisors 扫描切面类
protected List<Advisor> findCandidateAdvisors() {
/**
* 获取实现了Advisor这个接口的类 // 调用父类方法从容器中查找所有的通知器
* 先调用父类的扫描方法---父类的方法是直接从bdMap中查看有没有实现了Advisor这个接口的类,正常情况来讲都
*是没有的,实现Aop用的大部分都是通过注解的方式。所以调用父类的扫描得出的是一个空集合。
*/
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
//获得aop的切点通知
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
从上面看来,因为父类得到的结果是一个空集合。所以,扫描切面类就是通过这一个方法实现了 —this.aspectJAdvisorsBuilder.buildAspectJAdvisors()。
/**
* 创建用@Aspect注解标注的类的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<>();
//从bdMap中获取全部的名字
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
//获得bean的类型
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
//判断是不是一个切面类,不是就继续遍历
if (this.advisorFactory.isAspect(beanType)) {
//将名字添加到切面名字集合里,方便以后的调用
aspectNames.add(beanName);
//将当前切面类的类型和名字封装成一个切面元数据类,方便使用
AspectMetadata amd = new AspectMetadata(beanType, beanName);
//判断切面类的使用范围是不是单例的
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
//将Spring的bean工厂和切面类的元数据封装成切面工厂
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
//获得该切面类的切点通知
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
//在bean工厂中判断是不是单例的切面类,是的话就放入缓存中,不是的话就将封装好的切面工厂放入缓存中
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();
}
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;
}
buildAspectJAdvisors这个方法主要是解析由Aspect这个注解标注类,将其转化为Spring得Advisor切面类。
getAdvisors 获得切面类
这个方法就是真正意义上的扫描了,在上面我们已经获得了切面类了,现在我们要做的就是扫描这个配置类中的有关Aop的内容了。
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
//getAdvisorMethods(aspectClass)获得除了标注了@Pointcut注解的方法,下面再进行判断
for (Method method : getAdvisorMethods(aspectClass)) {
/**
* 对方法进行遍历,找到当前切面的通知。
* 注意,在这里,Spring是不会扫描到切点的。
* 关于切点的扫描Spring交给了AspectJ来处理了。
*/
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, 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.
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
getAdvisorMethods方法首先获取Aop配置类中除去标注了Pointcut的全部方法,再对方法进行筛选,然后将方法转换为Spring中的通知。
//这个方法比较简单,就是去除了Pointcut这个标注的方法,然后判断是不是一个中间的方法
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
final List<Method> methods = new ArrayList<>();
ReflectionUtils.doWithMethods(aspectClass, method -> {
// Exclude pointcuts 把没有@Pointcut注解的方法获取到
if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
methods.add(method);
}
}, ReflectionUtils.USER_DECLARED_METHODS);
if (methods.size() > 1) {
methods.sort(METHOD_COMPARATOR);
}
return methods;
}
-----------
public static final MethodFilter USER_DECLARED_METHODS =
(method -> !method.isBridge() && !method.isSynthetic());
重要的来了,在上面我们已经获得到了除去Pointcut标注的方法集了。接下来,我们通过getAdvisor方法对方法集继续二次筛选,进一步得到我们想要得通知了。
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
//传入方法和切面类,返回方法上的aop注解和注解的值然后封装成切点表达式
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
//封装返回带有切点方法、切点内容、切面名字、切面实例工厂的对象
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
---------------------
getPointcut方法是先看类方法上的注解是不是和Aop相关的注解,符合就获得注解上的信息,封装成AspectJAnnotation类并返回,否则就返回空。
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
//找到带有aop注解的方法 Pointcut Before After AfterReturning AfterThrowing这五个注解标注的方法。
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
//AspectJ切点表达式,并非获取到切点方法上的值,只是获取了切点方法的方法名。
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;
}
------------------------
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
//ASPECTJ_ANNOTATION_CLASSES的值是
private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};
----------------
for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
if (foundAnnotation != null) {
return foundAnnotation;
}
}
return null;
}
=--------------------
private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) {
A result = AnnotationUtils.findAnnotation(method, toLookFor);
if (result != null) {
//封装成AspectJAnnotation类
return new AspectJAnnotation<>(result);
}
else {
return null;
}
}
----------------------
现在,我们已经从getPointcut方法获得了通知方法上注解的值了。Spring就会将注解的值,一般情况下也就是切点的方法名给获取到。将类和切点的方法名赋值给一个封装的类,再二次封装成最终的切面类。
获得切点对象
至此,Spring已经将我们配置好的切面类给扫描完成了。扫描之后要做的就是要分清楚哪些类中的方法要用到上面扫描得到的通知进行Aop增强。
创建代理对象
创建代理对象是在Bean的生命周期的初始化后置方法里(有时候在循环依赖里完成)
图片上的applyBeanPostProcessorsAfterInitialization方法就是Spring 实现Aop的入口了,也是重写了后置处理器中的方法,使得能在Bean的生命周期中修改Bean。
wrapIfNecessary方法
applyBeanPostProcessorsAfterInitialization最终会执行的是Aop中的wrapIfNecessary方法,这个方法就是Aop最重要的方法。
wrapIfNecessary方法中也有扫描通知的方法,不过由于已经扫描过一遍了,所以是直接从缓存里拿到数据的。
getAdvicesAndAdvisorsForBean方法就是获得有关该Bean的通知。
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
//找到符合该类的通知
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
--------------
//最终还是会到findEligibleAdvisors方法来进行逻辑的处理
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
//找到候选的切点通知,就是扫描全部的通知的方法。在上面已经扫描过了
List<Advisor> candidateAdvisors = findCandidateAdvisors();
//找到符合该类的通知
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
//线程共享
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
findAdvisorsThatCanApply 找到符合的切面
从这个方法一直点进去就会跳转到一个判断的方法中了—canApply,canApply方法主要是对通知和类的方法进行匹配。在上面我们仅仅只是获取到了切点方法的方法名,现在我们就要通过切点方法的方法名来获得切点方法上注解的值,也就是获得自己写的切点表达式的值了。在这一步里,Spring交给了Aspectj来获取。
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
//在这里,就是先交给Aspectj来获取ClassFilter类匹配器,然后再对类进行匹配
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) {
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;
}
我们先来看看getClassFilter这个方法,这个方法尤为重要,其中处理了获得@Pointcut注解上我们定义的切入点,并将其转换为一个Aspej库中的PointcutExpressionImpl类,方便对不同的类进行方法的匹配。
//也就是一个空壳方法
public ClassFilter getClassFilter() {
obtainPointcutExpression();
return this;
}
-------------
private PointcutExpression obtainPointcutExpression() {
if (getExpression() == null) {
throw new IllegalStateException("Must set property 'expression' before attempting to match");
}
if (this.pointcutExpression == null) {
this.pointcutClassLoader = determinePointcutClassLoader();
//在这个方法里就是获取Aspectj库中得切点类了。
this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
}
return this.pointcutExpression;
}
buildPointcutExpression 创建切点表达式
这个方法里的逻辑十分复杂,本文章只讲解Aspectj是怎么获得切点表达式的,其他判断逻辑则略过。
private PointcutExpression buildPointcutExpression(@Nullable ClassLoader classLoader) {
PointcutParser parser = initializePointcutParser(classLoader);
PointcutParameter[] pointcutParameters = new PointcutParameter[this.pointcutParameterNames.length];
for (int i = 0; i < pointcutParameters.length; i++) {
pointcutParameters[i] = parser.createPointcutParameter(
this.pointcutParameterNames[i], this.pointcutParameterTypes[i]);
}
//通过通知上带的参数和通知所在的类(切面)以及 切点参数 获得Aspectj的切点表达式类 !!!!扫描得到得定义对象(DeferredResolvedPointcutDefinition)
return parser.parsePointcutExpression(replaceBooleanOperators(resolveExpression()),
this.pointcutDeclarationScope, pointcutParameters);
}
--------------------------------------------------------------------
/**
* 从这里开始,就进入到了Aspectj的逻辑里面了
*/
public PointcutExpression parsePointcutExpression(String expression, Class<?> inScope, PointcutParameter[] formalParameters)
throws UnsupportedPointcutPrimitiveException, IllegalArgumentException {
PointcutExpressionImpl pcExpr = null;
try {
//在这个方法里获取了切点表达式,可是先不进行属性的填充
Pointcut pc = resolvePointcutExpression(expression, inScope, formalParameters);
//在这里进行了属性的填充了。
pc = concretizePointcutExpression(pc, inScope, formalParameters);
validateAgainstSupportedPrimitives(pc, expression); // again, because we have now followed any ref'd pcuts
//将获得的Aspectj的切点表达式和切点方法,参数等二次封装。
pcExpr = new PointcutExpressionImpl(pc, expression, formalParameters, getWorld());
} catch (ParserException pEx) {
throw new IllegalArgumentException(buildUserMessageFromParserException(expression, pEx));
} catch (ReflectionWorld.ReflectionWorldException rwEx) {
throw new IllegalArgumentException(rwEx.getMessage());
}
return pcExpr;
}
--------------------------------------------------------------------
protected Pointcut resolvePointcutExpression(String expression, Class<?> inScope, PointcutParameter[] formalParameters) {
try {
//创建一个解析对象用来解析类上的方法
PatternParser parser = new PatternParser(expression);
//设置适配器
parser.setPointcutDesignatorHandlers(pointcutDesignators, world);
//初步解析Pointcut
Pointcut pc = parser.parsePointcut(); // more correctly: parsePointcut(true)
//验证
validateAgainstSupportedPrimitives(pc, expression);
IScope resolutionScope = buildResolutionScope((inScope == null ? Object.class : inScope), formalParameters);
//生成切点表达式,但不放入
pc = pc.resolve(resolutionScope);
return pc;
} catch (ParserException pEx) {
throw new IllegalArgumentException(buildUserMessageFromParserException(expression, pEx));
}
}
第一次调用resolvePointcutExpression 解析切点方法
这个方法在整个的解析过程中调用了两遍,第二遍调用的时机是在第一遍调用的pc.resolvede的方法的getDeclaredPointcuts这个方法中,其中不一样的是初步解析得到的Pointcut对象和最后调用resolve方法的类不一样。
第一遍是解析方法名,通过方法名先获得方法注解上的值,第二遍则是解析方法上的注解的值,使其转化为一个切点对象。
第一遍通过parse对象解析切点方法名获得的是ReferencePointcut类,第二遍parse解析切点方法注解上的值获得是的KindedPointcut对象。由于两个Pointcut对象不一样,导致调用pc.resolve的结果也不一样,第一遍调用的结果是将第二遍调用的结果给放入。
resolve
在经历上面的代码逻辑之后,进入到了resolve这个方法来准备解析了。
public final Pointcut resolve(IScope scope) {
//Aspectj自定义的断言
assertState(SYMBOLIC);
Bindings bindingTable = new Bindings(scope.getFormalCount());
IScope bindingResolutionScope = scope;
if (typeVariablesInScope.length > 0) {
bindingResolutionScope = new ScopeWithTypeVariables(typeVariablesInScope, scope);
}
//进入到这个这个方法来进行解析
this.resolveBindings(bindingResolutionScope, bindingTable);
bindingTable.checkAllBound(bindingResolutionScope);
this.state = RESOLVED;
return this;
}
--------------------------------------------------------------
public void resolveBindings(IScope scope, Bindings bindings) {
省略掉了许多的无关代码了,我们把眼光放到这个方法里,findPointcut找到切入点。
ResolvedPointcutDefinition pointcutDef = searchType.findPointcut(name);
// if we're not a static reference, then do a lookup of outers
}
findPointcut方法
不要看到这个方法就几行代码就觉得蛮简单的。可是实际上,这个方法调用了非常之多的自定义迭代器为前提,在迭代器里调用实际的操作方法。个人的理解是,之所以调用了这么多的迭代器,是因为要在用到迭代器的基础上,保证遍历出来的结果不重复。
public ResolvedPointcutDefinition findPointcut(String name) {
for (Iterator<ResolvedMember> i = getPointcuts(); i.hasNext();) {
ResolvedPointcutDefinition f = (ResolvedPointcutDefinition) i.next();
// the ResolvedPointcutDefinition can be null if there are other problems that prevented its resolution
if (f != null && name.equals(f.getName())) {
return f;
}
}
// pr120521
if (!getOutermostType().equals(this)) {
ResolvedType outerType = getOutermostType().resolve(world);
ResolvedPointcutDefinition rpd = outerType.findPointcut(name);
return rpd;
}
return null; // should we throw an exception here?
}
内置的自定义迭代器
让我们看看getPointcuts这个方法先,这个方法返回的就是一个自定义的迭代器。其中,又有一个recur方法对Iterators类中的Getter类进行了处理,返回的还是一个自定义的迭代器。所以getPointcuts方法返回的迭代器的方法中存在着一个迭代器。Aspectj自定义的迭代器都不支持remove方法的。迭代器的处理,我打算再新开一篇文章来仔细介绍,因为实在是非常复杂。
public Iterator<ResolvedMember> getPointcuts() {
final Iterators.Filter<ResolvedType> dupFilter = Iterators.dupFilter();
// same order as fields
Iterators.Getter<ResolvedType, ResolvedType> typeGetter = new Iterators.Getter<ResolvedType, ResolvedType>() {
@Override
public Iterator<ResolvedType> get(ResolvedType o) {
return dupFilter.filter(o.getDirectSupertypes());
}
};
return Iterators.mapOver(Iterators.recur(this, typeGetter), PointcutGetterInstance);
}
--------------------------------------------------------------
public static <A> Iterator<A> recur(final A a, final Getter<A, A> g) {
return new Iterator<A>() {
Iterator<A> delegate = one(a);
public boolean hasNext() {
return delegate.hasNext();
}
public A next() {
A next = delegate.next();
delegate = append(g.get(next), delegate);
return next;
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
真正获取切入点的表达式
直接跳到获取切点表达式的逻辑里,是在Java15ReflectionBasedReferenceTypeDelegate#getDeclaredPointcuts的方法中。
至于调用过程可以看看Debug的过程。
在这个getDeclaredPointcuts方法中,先是从这个类中获得所以切点方法组成的切点数组。然后,创建一个缓存,在经历下面的逻辑处理后放入缓存。
public ResolvedMember[] getDeclaredPointcuts() {
if (pointcuts == null) {
//获取切点方法组成的数组。
Pointcut[] pcs = this.myType.getDeclaredPointcuts();
//作为缓存
pointcuts = new ResolvedMember[pcs.length];
InternalUseOnlyPointcutParser parser = null;
World world = getWorld();
if (world instanceof ReflectionWorld) {
parser = new InternalUseOnlyPointcutParser(classLoaderReference.getClassLoader(), (ReflectionWorld) getWorld());
} else {
parser = new InternalUseOnlyPointcutParser(classLoaderReference.getClassLoader());
}
Set additionalPointcutHandlers = world.getRegisteredPointcutHandlers();
for (Iterator handlerIterator = additionalPointcutHandlers.iterator(); handlerIterator.hasNext();) {
PointcutDesignatorHandler handler = (PointcutDesignatorHandler) handlerIterator.next();
parser.registerPointcutDesignatorHandler(handler);
}
for (int i = 0; i < pcs.length; i++) {
AjType<?>[] ptypes = pcs[i].getParameterTypes();
UnresolvedType[] weaverPTypes = new UnresolvedType[ptypes.length];
for (int j = 0; j < weaverPTypes.length; j++) {
weaverPTypes[j] = this.typeConverter.fromType(ptypes[j].getJavaClass());
}
//将类型,切点方法名封装成PointcutDefinition对象
pointcuts[i] = new DeferredResolvedPointcutDefinition(getResolvedTypeX(), pcs[i].getModifiers(), pcs[i].getName(),
weaverPTypes);
}
PointcutParameter[][] parameters = new PointcutParameter[pcs.length][];
//设置切点属性
for (int i = 0; i < pcs.length; i++) {
AjType<?>[] ptypes = pcs[i].getParameterTypes();
String[] pnames = pcs[i].getParameterNames();
if (pnames.length != ptypes.length) {
pnames = tryToDiscoverParameterNames(pcs[i]);
if (pnames == null || (pnames.length != ptypes.length)) {
throw new IllegalStateException("Required parameter names not available when parsing pointcut "
+ pcs[i].getName() + " in type " + getResolvedTypeX().getName());
}
}
parameters[i] = new PointcutParameter[ptypes.length];
for (int j = 0; j < parameters[i].length; j++) {
parameters[i][j] = parser.createPointcutParameter(pnames[j], ptypes[j].getJavaClass());
}
//先获取@pointcut注解上的值
String pcExpr = pcs[i].getPointcutExpression().toString();
//调用第二遍resolvePointcutExpression方法,将类似方法上注解的值解析成一个aspectj的切点对象。
org.aspectj.weaver.patterns.Pointcut pc = parser.resolvePointcutExpression(pcExpr, getBaseClass(), parameters[i]);
//设置参数名
((ResolvedPointcutDefinition) pointcuts[i]).setParameterNames(pnames);
//设置切点
((ResolvedPointcutDefinition) pointcuts[i]).setPointcut(pc);
}
for (int i = 0; i < pointcuts.length; i++) {
ResolvedPointcutDefinition rpd = (ResolvedPointcutDefinition) pointcuts[i];
//再次设置切点表达式,其实就是修改了Pointcut的状态
rpd.setPointcut(parser.concretizePointcutExpression(rpd.getPointcut(), getBaseClass(), parameters[i]));
}
}
return pointcuts;
}
第二次调用resolvePointcutExpression 解析切点注解上的值
在调用parse解析注解上的值就获得了初步的Pointcut对象了,最后调用resolve则也是修改Pointcut对象的状态。
再次设置切点
在进行第二次调用resolvePointcutExpression后,将切点对象返回,并将切点对象设置在原本的Pointcut对象中。
最后调用concretizePointcutExpression方法,修改切点对象状态。
左边为第一次解析后的切点对象,右边为最后填充的切点对象。本质上是一样的,就是两个对象的状态不一样。
在上面,我们已经获得了切点方法的Definition对象了,然后回到findPointcut方法里,就方法进行验证后进行返回。
public ResolvedPointcutDefinition findPointcut(String name) {
for (Iterator<ResolvedMember> i = getPointcuts(); i.hasNext();) {
//得到解析后的PointcutDefinition对象
ResolvedPointcutDefinition f = (ResolvedPointcutDefinition) i.next();
// the ResolvedPointcutDefinition can be null if there are other problems that prevented its resolution
//判断方法名是否一样
if (f != null && name.equals(f.getName())) {
return f;
}
}
// pr120521
if (!getOutermostType().equals(this)) {
ResolvedType outerType = getOutermostType().resolve(world);
ResolvedPointcutDefinition rpd = outerType.findPointcut(name);
return rpd;
}
return null; // should we throw an exception here?
}
concretizePointcutExpression 具体化切点表达式
让我们回到最开始的parsePointcutExpression方法,到现在这一步,我们已经获取了切点表达式了,也执行了两遍resolvePointcutExpression方法,通过解析方法名来调用第二遍来解析方法注解上的值。在调用concretizePointcutExpression之前,pc的值还是没填充解析的值,调用之后才填充的。
public PointcutExpression parsePointcutExpression(String expression, Class<?> inScope, PointcutParameter[] formalParameters)
throws UnsupportedPointcutPrimitiveException, IllegalArgumentException {
PointcutExpressionImpl pcExpr = null;
try {
//在这个方法里获取了切点表达式,可是先不进行属性的填充
Pointcut pc = resolvePointcutExpression(expression, inScope, formalParameters);
//在这里进行了属性的填充了。
pc = concretizePointcutExpression(pc, inScope, formalParameters);
validateAgainstSupportedPrimitives(pc, expression); // again, because we have now followed any ref'd pcuts
//将获得的Aspectj的切点表达式和切点方法,参数等二次封装。
pcExpr = new PointcutExpressionImpl(pc, expression, formalParameters, getWorld());
} catch (ParserException pEx) {
throw new IllegalArgumentException(buildUserMessageFromParserException(expression, pEx));
} catch (ReflectionWorld.ReflectionWorldException rwEx) {
throw new IllegalArgumentException(rwEx.getMessage());
}
return pcExpr;
}
-----------------------
protected Pointcut concretizePointcutExpression(Pointcut pc, Class<?> inScope, PointcutParameter[] formalParameters) {
ResolvedType declaringTypeForResolution = null;
if (inScope != null) {
//获取类型
declaringTypeForResolution = getWorld().resolve(inScope.getName());
} else {
declaringTypeForResolution = ResolvedType.OBJECT.resolve(getWorld());
}
IntMap arity = new IntMap(formalParameters.length);
for (int i = 0; i < formalParameters.length; i++) {
arity.put(i, i);
}
return pc.concretize(declaringTypeForResolution, declaringTypeForResolution, arity);
}
---------------------
public final Pointcut concretize(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
// !!! add this test -- assertState(RESOLVED);
Pointcut ret = this.concretize1(inAspect, declaringType, bindings);
if (shouldCopyLocationForConcretize()) {
ret.copyLocationFrom(this);
}
ret.state = CONCRETE;
// copy the unbound ignore list
ret.m_ignoreUnboundBindingForNames = m_ignoreUnboundBindingForNames;
return ret;
}
concretize1 方法
在这个方法内部,有一个方法我们很熟悉就是findPointcut。这个方法很长,我只截取了我debug所运行的代码。
public Pointcut concretize1(ResolvedType searchStart, ResolvedType declaringType, IntMap bindings) {
try {
concretizing = true;
ResolvedPointcutDefinition pointcutDec;
//获取上面解析完的PointcutDefinition对象
pointcutDec = declaringType.findPointcut(name);
newBindings.copyContext(bindings);
newBindings.pushEnclosingDefinition(pointcutDec);
try {
//获取的切点对象
Pointcut ret = pointcutDec.getPointcut();
if (typeVariableMap != null && !hasBeenParameterized) {
ret = ret.parameterizeWith(typeVariableMap, searchStart.getWorld());
ret.hasBeenParameterized = true;
}
//再次调用concretize方法
return ret.concretize(searchStart, declaringType, newBindings);
} finally {
newBindings.popEnclosingDefinitition();
}
} finally {
concretizing = false;
}
}
KindedPointcut类型调用concretize方法
由于两次调用concretize1方法的类型不一样,进而方法也是不一样的。第一次是还是ReferencePointcut类型,第二次是KindedPointcut类型。
public final Pointcut concretize(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
// !!! add this test -- assertState(RESOLVED);
Pointcut ret = this.concretize1(inAspect, declaringType, bindings);
if (shouldCopyLocationForConcretize()) {
ret.copyLocationFrom(this);
}
ret.state = CONCRETE;
// copy the unbound ignore list
ret.m_ignoreUnboundBindingForNames = m_ignoreUnboundBindingForNames;
return ret;
}
方法还是一样的,就是里面调用concretize1方法的类型不一样。
又新建了一个KindedPointcut的类,将其返回。然后在concretize方法里改变Pointcut的状态,变更为CONCRETE具体的。
封装切点
public PointcutExpression parsePointcutExpression(String expression, Class<?> inScope, PointcutParameter[] formalParameters)
throws UnsupportedPointcutPrimitiveException, IllegalArgumentException {
PointcutExpressionImpl pcExpr = null;
try {
//在这个方法里获取了切点表达式,可是先不进行属性的填充
Pointcut pc = resolvePointcutExpression(expression, inScope, formalParameters);
//在这里进行了属性的填充了。
pc = concretizePointcutExpression(pc, inScope, formalParameters);
validateAgainstSupportedPrimitives(pc, expression); // again, because we have now followed any ref'd pcuts
//将获得的Aspectj的切点表达式和切点方法,参数等二次封装。
pcExpr = new PointcutExpressionImpl(pc, expression, formalParameters, getWorld());
} catch (ParserException pEx) {
throw new IllegalArgumentException(buildUserMessageFromParserException(expression, pEx));
} catch (ReflectionWorld.ReflectionWorldException rwEx) {
throw new IllegalArgumentException(rwEx.getMessage());
}
return pcExpr;
}
至此,我们通过从通知上注解所带的值,也就是切点方法的名称,经历多个步骤,将其解析成为一个Aspectj中的pointcutExpression对象。
匹配切点
现在,我们已经获得了通知,切点,和切面。我们要做的就是找到与切点相匹配的类。我们从通过getClassFilter方法获得了切点,然后就从切点出发匹配切点所属的类。
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) {
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;
}
-------------------------
public boolean matches(Class<?> targetClass) {
PointcutExpression pointcutExpression = obtainPointcutExpression();
/**
* 判断该类与切点表达式是否一致
*/
try {
try {
return pointcutExpression.couldMatchJoinPointsInType(targetClass);
}
return false;
}
couldMatchJoinPointsInType 能不能匹配的类型
public boolean couldMatchJoinPointsInType(Class aClass) {
//获得当前需要匹配的类
ResolvedType matchType = world.resolve(aClass.getName());
if (matchType.isMissing() && (world instanceof ReflectionWorld)) {
// Class is a generated class that cannot be 'looked up' via getResource.
// For example a proxy or lambda.
// Use the class itself in this case
matchType = ((ReflectionWorld)world).resolveUsingClass(aClass);
}
//封装成一个匹配信息对象
ReflectionFastMatchInfo info = new ReflectionFastMatchInfo(matchType, null, this.matchContext, world);
//进入匹配,执行fastmacth返回的是一个FuzzyBoolean对象,再调用maybeTrue方法返回True/False
boolean couldMatch = pointcut.fastMatch(info).maybeTrue();
if (MATCH_INFO) {
System.out.println("MATCHINFO: fast match for '" + this.expression + "' against '" + aClass.getName() + "': "
+ couldMatch);
}
return couldMatch;
}
fastMatch 快速匹配
这个方法的原理是,先从解析完的切点取出切点的类型。判断切点是那一种类型的,大多数的方法直接执行(method-execution),并且info中kind的值是空的,就进入到下一步的判断中,
这个方法返回的是一个对象,Aspectj的内置对象----FuzzyBoolean。可以通过调用这个对象的方法返回一个布尔值,进一步确定匹配是否成功。
public FuzzyBoolean fastMatch(FastMatchInfo info) {
// info.getKind()==null means all kinds
if (info.getKind() != null) {
if (info.getKind() != kind) {
return FuzzyBoolean.NO;
}
}
//默认为True
if (info.world.optimizedMatching) {
// 类型为方法执行和初始化(Spring中不支持初始化类型)就进入逻辑
if ((kind == Shadow.MethodExecution || kind == Shadow.Initialization) && info.getKind() == null) {
//判断info中,实际上就是判断当前的类是不是一个切面
boolean fastMatchingOnAspect = info.getType().isAspect();
//是的化就返回 MaybeFuzzyBoolean类型得类
if (fastMatchingOnAspect) {
return MAYBE;
}
//判断切点是不是精准匹配的。
if (this.getSignature().isExactDeclaringTypePattern()) {
//取得当前切点匹配的类型
ExactTypePattern typePattern = (ExactTypePattern) this.getSignature().getDeclaringType();
// 获得精准配置的类
ResolvedType patternExactType = typePattern.getResolvedExactType(info.world);
//判断切点匹配类是否接口,一般情况来说不会在接口上使用Aop。
if (patternExactType.isInterface()) {
//获得当前判断的类
ResolvedType curr = info.getType();
Iterator<ResolvedType> hierarchyWalker = curr.getHierarchy(true, true);
boolean found = false;
while (hierarchyWalker.hasNext()) {
curr = hierarchyWalker.next();
if (typePattern.matchesStatically(curr)) {
found = true;
break;
}
}
if (!found) {
return FuzzyBoolean.NO;
}
//不是接口就会进入到一个普遍类上的判断
} else if (patternExactType.isClass()) {
ResolvedType curr = info.getType();
do {
//进入静态匹配的方法
if (typePattern.matchesStatically(curr)) {
break;
}
//获得父类继续循环。
curr = curr.getSuperclass();
} while (curr != null);
//如果到最后循环到为空了还是没能跳出循环就放回一个No对象
if (curr == null) {
return FuzzyBoolean.NO;
}
}
//一般情况下,也是buhui进入这个判断的,故不作分析
} else if (this.getSignature().getDeclaringType() instanceof AnyWithAnnotationTypePattern) {
// aim here is to say NO if the annotation is not possible in the hierarchy here
ResolvedType type = info.getType();
AnnotationTypePattern annotationTypePattern = ((AnyWithAnnotationTypePattern) getSignature().getDeclaringType())
.getAnnotationPattern();
if (annotationTypePattern instanceof ExactAnnotationTypePattern) {
ExactAnnotationTypePattern exactAnnotationTypePattern = (ExactAnnotationTypePattern) annotationTypePattern;
if (exactAnnotationTypePattern.getAnnotationValues() == null
|| exactAnnotationTypePattern.getAnnotationValues().size() == 0) {
ResolvedType annotationType = exactAnnotationTypePattern.getAnnotationType().resolve(info.world);
if (type.hasAnnotation(annotationType)) {
return FuzzyBoolean.MAYBE;
}
if (annotationType.isInheritedAnnotation()) {
// ok - we may be picking it up from further up the hierarchy (but only a super*class*)
ResolvedType toMatchAgainst = type.getSuperclass();
boolean found = false;
while (toMatchAgainst != null) {
if (toMatchAgainst.hasAnnotation(annotationType)) {
found = true;
break;
}
toMatchAgainst = toMatchAgainst.getSuperclass();
}
if (!found) {
return FuzzyBoolean.NO;
}
} else {
return FuzzyBoolean.NO;
}
}
}
}
}
}
//返回Maybe对象
return FuzzyBoolean.MAYBE;
}
matchesStatically 静态判断
这个方法就是主要的判断方法之一了,要是判断成立,就进行再次的验证,不成功则直接退出。
public boolean matchesStatically(ResolvedType type) {
if (includeSubtypes) {
return matchesSubtypes(type);
} else {
//类型模式匹配
return matchesExactly(type);
}
}
----------------------
protected boolean matchesExactly(ResolvedType matchType) {
//判断传入的类与切点类是否一致,最后作为一个判断的条件
boolean typeMatch = this.type.equals(matchType);
//判断是不是一个参数化类型和一个泛型
if (!typeMatch && (matchType.isParameterizedType() || matchType.isGenericType())) {
typeMatch = this.type.equals(matchType.getRawType());
}
//是不是一个类型变量类
if (!typeMatch && matchType.isTypeVariableReference()) {
typeMatch = matchesTypeVariable((TypeVariableReferenceType) matchType);
}
//到这一步了,typematch还是为false的话就返回fasle,既不将该通知作为该类的扩展。
if (!typeMatch) {
return false;
}
//进行注解模式得匹配
annotationPattern.resolve(matchType.getWorld());
boolean annMatch = false;
if (matchType.temporaryAnnotationTypes != null) {
annMatch = annotationPattern.matches(matchType, matchType.temporaryAnnotationTypes).alwaysTrue();
} else {
//一般情况下,上面通过了,这个也是会成立得
annMatch = annotationPattern.matches(matchType).alwaysTrue();
}
return (typeMatch && annMatch);
}
当返回得对象调用maybeTrue方法得到的布尔值是false的话就结束判断,跳到下一个通知继续判断。要是返回的是true的话,继续进行下面的判断。
methodMatcher.matches
回到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) {
//获取类中所有方法
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;
}
从上面的代码逻辑我们可以看出,就是获取所有与候选类相关的类以及所有的方法,再和切点中的方法匹配器(就是切点本身),再进行匹配。
match 方法匹配
public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
obtainPointcutExpression();
//获得一个Aspectj库中的结果对象,就是方法和类与切面的匹配结果
ShadowMatch shadowMatch = getTargetShadowMatch(method, targetClass);
// Special handling for this, target, @this, @target, @annotation
// in Spring - we can optimize since we know we have exactly this class,
// and there will never be matching subclass at runtime.
//这个对象我们要关注的是match属性的值
if (shadowMatch.alwaysMatches()) {
return true;
}
else if (shadowMatch.neverMatches()) {
return false;
}
else {
// the maybe case
if (hasIntroductions) {
return true;
}
// A match test returned maybe - if there are any subtype sensitive variables
// involved in the test (this, target, at_this, at_target, at_annotation) then
// we say this is not a match as in Spring there will never be a different
// runtime subtype.
RuntimeTestWalker walker = getRuntimeTestWalker(shadowMatch);
return (!walker.testsSubtypeSensitiveVars() || walker.testTargetInstanceOfResidue(targetClass));
}
}
-------------------------------
private ShadowMatch getTargetShadowMatch(Method method, Class<?> targetClass) {
Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
//看方法的所属的类是不是一个接口
if (targetMethod.getDeclaringClass().isInterface()) {
Set<Class<?>> ifcs = ClassUtils.getAllInterfacesForClassAsSet(targetClass);
if (ifcs.size() > 1) {
try {
Class<?> compositeInterface = ClassUtils.createCompositeInterface(
ClassUtils.toClassArray(ifcs), targetClass.getClassLoader());
targetMethod = ClassUtils.getMostSpecificMethod(targetMethod, compositeInterface);
}
catch (IllegalArgumentException ex) {
// Implemented interfaces probably expose conflicting method signatures...
// Proceed with original target method.
}
}
}
//进入到调用方法中
return getShadowMatch(targetMethod, method);
}
----------------------
private ShadowMatch getShadowMatch(Method targetMethod, Method originalMethod) {
// Avoid lock contention for known Methods through concurrent access...
//先从缓存里面找
ShadowMatch shadowMatch = this.shadowMatchCache.get(targetMethod);
if (shadowMatch == null) {
synchronized (this.shadowMatchCache) {
// Not found - now check again with full lock...
PointcutExpression fallbackExpression = null;
//再次确认缓存中没有
shadowMatch = this.shadowMatchCache.get(targetMethod);
if (shadowMatch == null) {
Method methodToMatch = targetMethod;
try {
try {
//获得结果对象
shadowMatch = obtainPointcutExpression().matchesMethodExecution(methodToMatch);
}
-----
中间都是一些判断的代码,抛出异常啥的
-----
if (shadowMatch == null) {
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
}
else if (shadowMatch.maybeMatches() && fallbackExpression != null) {
shadowMatch = new DefensiveShadowMatch(shadowMatch,
fallbackExpression.matchesMethodExecution(methodToMatch));
}
this.shadowMatchCache.put(targetMethod, shadowMatch);
}
}
}
return shadowMatch;
}
进入到obtainPointcutExpression().matchesMethodExecution(methodToMatch)这个方法中,其实就是调用切点的matchesMethodExecution方法获得一个也是Aspectj库中的类。
最终会在matchesExecution中的getShadowMatch方法中填充match属性
private ShadowMatch matchesExecution(Member aMember) {
//先获得一个基本的Shadow类
Shadow s = ReflectionShadow.makeExecutionShadow(world, aMember, this.matchContext);
//传入Shadow,这里面处理获得一个ShadowMatchImpl 类
ShadowMatchImpl sm = getShadowMatch(s);
sm.setSubject(aMember);
sm.setWithinCode(null);
sm.setWithinType(aMember.getDeclaringClass());
return sm;
}
---------
private ShadowMatchImpl getShadowMatch(Shadow forShadow) {
//调用切点的match方法,得到一个FuzzyBoolean类,也就是上面切点匹配类中也用到过的类。
org.aspectj.util.FuzzyBoolean match = pointcut.match(forShadow);
Test residueTest = Literal.TRUE;
ExposedState state = getExposedState();
if (match.maybeTrue()) {
residueTest = pointcut.findResidue(forShadow, state);
}
ShadowMatchImpl sm = new ShadowMatchImpl(match, residueTest, state, parameters);
sm.setMatchingContext(this.matchContext);
return sm;
}
match方法中,会进入到matchInternal方法,这个方法是通过判断传入shaow中kind的值和切点中kind的值,也就是切点指示符。然后返回一个判断类的子类。
protected FuzzyBoolean matchInternal(Shadow shadow) {
//因为我们标注到切点注解上的值得execution开头的指示符,所以Shadow和切点中kind的值是“method-execution”。
//下面的判读都不会进入的
if (shadow.getKind() != kind) {
return FuzzyBoolean.NO;
}
if (shadow.getKind() == Shadow.SynchronizationLock && kind == Shadow.SynchronizationLock) {
return FuzzyBoolean.YES;
}
if (shadow.getKind() == Shadow.SynchronizationUnlock && kind == Shadow.SynchronizationUnlock) {
return FuzzyBoolean.YES;
}
if (!signature.matches(shadow.getMatchingSignature(), shadow.getIWorld(), this.kind == Shadow.MethodCall)) {
if (kind == Shadow.MethodCall) {
warnOnConfusingSig(shadow);
// warnOnBridgeMethod(shadow);
}
return FuzzyBoolean.NO;
}
//返回一个判断类的YES子类
return FuzzyBoolean.YES;
}
在这里,我们获得了match方法中判断的关键shadowMatch对象中的match的值,也就是Aspectj中判断类的YES子类。回到match方法中,由于match的值是YES子类,所以调用alwaysMatches的结果的是true,返回一个true出去。
public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
//获得切点
obtainPointcutExpression();
ShadowMatch shadowMatch = getTargetShadowMatch(method, targetClass);
if (shadowMatch.alwaysMatches()) {
return true;
}
else if (shadowMatch.neverMatches()) {
return false;
}
else {
// the maybe case
if (hasIntroductions) {
return true;
}
// A match test returned maybe - if there are any subtype sensitive variables
// involved in the test (this, target, at_this, at_target, at_annotation) then
// we say this is not a match as in Spring there will never be a different
// runtime subtype.
RuntimeTestWalker walker = getRuntimeTestWalker(shadowMatch);
return (!walker.testsSubtypeSensitiveVars() || walker.testTargetInstanceOfResidue(targetClass));
}
}
至此,我们已经分析完了Spring中Aop是如何判断一个通知要不要作用到一个类上的。主要是有两个判断,都涉及到了Aspectj库中的方法。
当然了,在进行两个判断之前,还先需要通过通知获得通知所属的切点。获取切点的顺序是,先从通知上得到通知所对应的切点方法名,然后在通知所属的类中找到与切点方法名一致的方法,再解析方法得到方法上切点注解的值,获得注解上的值后,解析值,得到一个Aspectj库中的切点类。
两个判断则是先判断候选类与切点中标注的类是否一致,然后再判断类中的方法和切点中标注的方法是否吻合,两个判断都成功,就表明,这个通知可以作用在当前候选类上。
创建代理对象
在获得了属于候选类的通知后,我们就可以为候选类创建代理对象了。创建代理对象是在获得通知之后进行的。用到AbstractAutoProxyCreator中的createProxy方法。
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
/**
* 获取该类得通知(切面)
*/
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;
}
createProxy 创建代理对象
在这里,先是将代理前的Class类保存在mergeBdMap中的bd的属性中,方便之后查看。然后就是创建代理工厂,对工厂的值进行赋值,之后判断是否需要强制开启CGLIB代理。
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
//在merge合并后的BeanDefinitionMap中找到该Bd添加一个属性(把原本的未进行代理的类保存下来)
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
//创建代理工厂
ProxyFactory proxyFactory = new ProxyFactory();
//将Aop的属性复制到新的代理工厂
proxyFactory.copyFrom(this);
//判断代理工厂是不是一个代理的目标类
if (!proxyFactory.isProxyTargetClass()) {
//判断当前传入的类是不是一个需要代理的目标类(判断bd中包不包含一个属性并且属性的值是True)是的话就强制开启CGLIB代理
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
//判断候选类是否实现接口,不实现接口或者接口是某个值就转化为CGLIB代理
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
//将传进来的切面转化为一个数组
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
//设置通知
proxyFactory.addAdvisors(advisors);
//目标类
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
//设置是不是已经经过筛选
proxyFactory.setPreFiltered(true);
}
return proxyFactory.getProxy(getProxyClassLoader());
}
之后就进入到获取代理类的阶段了,在对类进行代理的过程中,需要判断代理的工厂是什么。JDK动态代理还是CGLIB代理呢,就要进入到获取哪种代理的判断当中。
createAopProxy 创建Aop代理工厂
在这里就是判断究竟是是用哪一种的代理模式的。其实判断方法挺简单的,其实就是看看在配置@EnableAspectJAutoProxy注解的时候有没有将boolean proxyTargetClass() default false;的值给赋值上,这个值默认的false的。或者的需要代理的类有没有实现接口,没有得话就默认开启JDK的动态代理了。
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
//第一个条件不是很懂,接下来就是判断是不是应该进行优化或者是否强制使用CGLIB代理或者是候选类是否实现了接口或者只实现了一个继承了SpringProxy接口的接口
//都不是就创建JDK动态代理对象
if (!IN_NATIVE_IMAGE &&
(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.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
本文是讲解JDK动态代理的代理模式,暂不描述CGLIB的代理模式。
getProxy 获得代理对象
在这个方法里,我们就看到了熟悉的**Proxy.newProxyInstance(classLoader, proxiedInterfaces, this)**方法。其实就是调this的invoke方法来增强目标类中的方法。
invoke
在这个方法里大致分为了三个阶段,第一个阶段是判断增强的方法是不是Equals、HashCode方法和方法所属的类是不是DecoratingProxy类和方法的所属的类是不是继承了Advised类。第二个阶段则是将符合该类的切面中的通知转化为一个个拦截器。第三个阶段就是将获得的拦截器集合变成一个拦截器链,然后实现方法的增强。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
// 如果 expose-proxy 属性为 true,则暴露代理对象
if (this.advised.exposeProxy) {
// Make invocation available if necessary. 向 AopContext 中设置代理对象
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
//获得未代理的对象
target = targetSource.getTarget();
//候选类对象
Class<?> targetClass = (target != null ? target.getClass() : null);
// 获取适合当前方法的切面(通过advice转换)
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
// 如果拦截器链为空,则直接执行目标方法
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
// 通过反射执行目标方法
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
/**
* 将获得的拦截器组装成拦截器链
*/
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
/**
* 真正上将通知运用在方法上下 aop的具体实现
*/
retVal = invocation.proceed();
}
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
获得拦截器
转换切面中的通知的方法是这个方法
List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
这个方法先是获得存入代理工厂的切面,然后遍历每一个切面。因为在上面已经通过了匹配,所以这里要做的就是将通知转化为一个个拦截器。
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
//获取之前存进工厂的切面
Advisor[] advisors = config.getAdvisors();
List<Object> interceptorList = new ArrayList<>(advisors.length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
//遍历所有切面
for (Advisor advisor : advisors) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
//是否经过筛选或者切点的类过滤器是否匹配(也就是上面匹配的过程)
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
if (mm instanceof IntroductionAwareMethodMatcher) {
if (hasIntroductions == null) {
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
//这个匹配是获得ShadowMatch中match也是上面经历过的
match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
}
else {
match = mm.matches(method, actualClass);
}
if (match) {
//获得由切面中的通知转化的拦截器
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
//添加到集合中
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
转化的方法是这个:
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<>(3);
Advice advice = advisor.getAdvice();
if (advice instanceof MethodInterceptor) {
//实现了拦截器接口的通知直接添加
interceptors.add((MethodInterceptor) advice);
}
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {
/**
* 在这里把没有实现拦截器接口的通知转化成拦截器类添加
*/
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[0]);
}
获得拦截器集合后,Spring就将代理后的对象、代理前的对象、方法、参数、拦截器集合封装成一个方法调用类**(MethodInvocation)**
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
增强方法
获得调用类用,调用proceed方法就进入到了围绕着目标方法进行增强的步骤了。
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
/**
* 判断当前拦截器的指针和拦截链的大小是否一致,一致相当于已经完成拦截链的拦截,准备执行原方法
*/
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
/**
* 获得一个拦截器,并在下面实现他的源码
*/
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
//针对动态方法拦截器,我们基本使用的都不是动态方法拦截器
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
//所以就会跳到这里来执行拦截器的invoke方法
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
当前这个方法增强的只有两个通知,一个是前置通知,一个是后置通知,还有一个是Spring自己添加进的共享线程的通知。
首先,调用的一定是ExposeInvocationInterceptor这个拦截器,这个拦截器是在findEligibleAdvisors方法中的extendAdvisors添加进去的。在我认为,其实这个拦截器就是用来共享当前这个链接器链的调用的。
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
//找到候选的切点通知
List<Advisor> candidateAdvisors = findCandidateAdvisors();
//找到符合该类的通知
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
//线程共享
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
------------------------------------------
protected void extendAdvisors(List<Advisor> candidateAdvisors) {
AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
}
------------------------------------------
public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
// Don't add advisors to an empty list; may indicate that proxying is just not required
if (!advisors.isEmpty()) {
boolean foundAspectJAdvice = false;
for (Advisor advisor : advisors) {
// Be careful not to get the Advice without a guard, as this might eagerly
// instantiate a non-singleton AspectJ aspect...
if (isAspectJAdvice(advisor)) {
foundAspectJAdvice = true;
break;
}
}
//添加ExposeInvocationInterceptor到切面的首位置
if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
return true;
}
}
return false;
}
private static final ThreadLocal invocation =
new NamedThreadLocal<>(“Current AOP method invocation”);
这个就是调用的第一个拦截器,ExposeInvocationInterceptor这个拦截器的invoke方法,可以看到,其实就是往ThreadLocal设置了当前的调用类。然后继续调用调用类的proceed方法,来一个一个调用拦截器的invoke方法。
第二个拦截器是前置通知拦截器,其实就是调用了通知中的方法而已。
public Object invoke(MethodInvocation mi) throws Throwable {
/**
* 前置通知 @Before
*/
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
-----------------
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
------------------
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
Object[] actualArgs = args;
if (this.aspectJAdviceMethod.getParameterCount() == 0) {
actualArgs = null;
}
try {
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
// TODO AopUtils.invokeJoinpointUsingReflection
//通过反射进行方法调用
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("Mismatch on arguments to advice method [" +
this.aspectJAdviceMethod + "]; pointcut expression [" +
this.pointcut.getPointcutExpression() + "]", ex);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
当Before方法执行完成后,又会去调用调用类的proceed方法。
这次调用的是后置通知,执行后置通知其实就是使用到了JAVA的finally代码块而已。
在后置通知中,先是回到proceed方法继续调用接下来的逻辑代码。由于本次案例,我只用了两个通知,所以回到proceed方法中调用的就是被增强的方法本身了,然后执行完方法本身后,就又会回到After通知中,执行finally代码块中的代码。finally中的代码给Before的方法是一样的。都是通过反射调用方法的。
总结
至此,Spring Aop的使用逻辑和底层的代码也讲解完成了,由于这篇文章是回到学校后断断续续开始写的,所以可能有些地方上的语言会不通,也欢迎大家指出。
另外,这篇文章还有几个点是没有讲到的,一个是Aspectj是怎么把传进来的切点表达式给解析成一个切点的,一个是Aspectj内置的迭代器都有什么作用都没有讲清楚。
我打算有时间在另外讲清楚,也需要等我自己足够理解了才会开始写吧。
另外,谢谢大家能看完这么长的一篇文章,谢谢了!