AOP中有三个重要的概念:advisor(切面)、切点(pointcut)、advice(通知)
spring会对有切面的类生成代理
@EnableAspectJAutoProxy开启切面功能
在AspectJAutoProxyRegistrar中注册aop的入口类
上图将AnnotationAwareAspectJAutoProxyCreator注册到BeanDefinitionRegistry中,看继承关系如图所示:
所以AnnotationAwareAspectJAutoProxyCreator继承了AbstractAutoProxyCreator。在进行属性注入完成之后,会走到initializeBean方法,这是aop的入口
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
.....
//这里不是合成的
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
.....
}
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
获取BeanPostProcessor ,并循环调用postProcessAfterInitialization方法,通过继承关系知道AnnotationAwareAspectJAutoProxyCreator继承了AbstractAutoProxyCreator,所以这里会调到AbstractAutoProxyCreator的postProcessAfterInitialization方法,如图所示:
找切面的过程:
看getAdvicesAndAdvisorsForBean方法,找到合适的切面
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();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
//寻找有@Aspectj注解,把所有有这个注解的类封装成Advisor返回
List<Advisor> candidateAdvisors = findCandidateAdvisors();
//判断候选的切面是否作用在当前beanClass上面,匹配判断
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
//对有@Aspect注解切面添加了一个默认的切面 DefaultPointcutAdvisor
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
//对有@Order@Priority进行排序
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
寻找合格切面的过程:
1、寻找有@Aspectj注解的类,把所有有这个注解的类封装成Advisor返回
2、判断候选的切面是否作用在当前beanClass上面
3、对有@Aspect注解切面添加了一个默认的切面 DefaultPointcutAdvisor
4、对切面进行排序
看寻找合格切面过程的第一步findCandidateAdvisors方法
上图中第一步找自定义advisor过程比较简单,这里不赘述,看收集有@Aspect注解的buildAspectJAdvisors方法
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
.....
//获取spring容器中的所有bean的名称BeanName
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
.....
//判断类上是否有@Aspect注解
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
//创建获取有@Aspect注解类的实例工厂,负责获取有@Aspect注解类的实例
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
//创建切面advisor对象
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
.....
advisors.addAll(classAdvisors);
}
.....
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
.....
return advisors;
}
上面代码中创建获取有@Aspect注解类的实例工厂,负责获取有@Aspect注解类的实例。
看这个方法具体的实现:
上图中循环的是类中没有pointcut的方法,也就是advice方法,将advice方法传入构造advisor切面,看上图的构造切面的getAdvisor方法
看上图获取pointcut对象的方法
至此,pointcut创建好了,由之前传过来的advice方法构造完成advisor切面,如图所示:
在getAdvice方法中会获取advice方法上面的注解,根据注解的不同,构造不同的advice
至此,切面中两个必备的元素pointcut和advice都已经具备,一个advisor切面就创建好了。
创建完所有的切面后,接下来过滤出匹配的切面,如图所示:
会调到canApply方法中进行类和方法的匹配:
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
//调用ClassFilter的matches方法,判断类是否匹配
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;
}
过滤出匹配的切面之后,接下来针对@Aspect注解切面添加了一个默认的切面 DefaultPointcutAdvisor。
然后对所有匹配到的advisor进行排序后返回。
如果返回的advisor数组不为空,则生成代理对象。
切面收集总结:
-
寻找有@Aspect注解,把所有有这个注解的类封装成Advisor返回。
1)找到自定义的advisor,即实现了Advisor接口的 2)找到有@Aspect注解的类,生成切面 构造切面:循环没有@PoinitCut注解的方法,也就是advice方法 构造pointcut对象,从advice方法的注解中拿到表达式, 并设置到pointcut对象中 构造advice对象,根据advice方法上不同的注解类型,构造不同的advice
-
判断候选的切面是否作用在当前beanClass上面,匹配判断,需要类和方法都匹配。
循环找到的所有切面,判断当前beanClass上是否有切面,先进行类的匹配 1)类匹配 在进行类匹配的时候, 根据advice中的表达式,找到@PointCut注解的方法, 然后将pointcut对象中的表达式的值替换成@PointCut注解中的表达式, 然后判断当前beanClass是否在表达式中 2)方法匹配
-
对有@Aspect注解切面添加了一个默认的切面 DefaultPointcutAdvisor
-
对切面进行排序
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/13824.html