交流
商城
MCN
登入
注册
首页
提问
分享
讨论
建议
公告
动态
发表新帖
发表新帖
aop第4 章:AnnotationAwareAspectJAutoProxyCreator
分享
未结
0
865
李延
LV6
2021-05-16
悬赏:20积分
# 总体说明 前面已经说明了aop是如何加载的。通过前面分析,我们知道:最终springboot是通过加载一个BeanPostprocessor类:AnnotationAwareAspectJAutoProxyCreator。在bean创建的时候生成代理的。那么下面我们将解释这个类,详细说明代理生成的过程。 # 继承关系  我们看到继承主要分为3个分支 1. BeanPostProcessor bean的后置处理器。代理的创建也在其方法的相关实现中,我们也将重点分析这些方法。 2. Aware 接口 3. Proxy 相关接口。我们也将以此继承关系为顺序分析源码 ## ProxyConfig 定义 代理相关配置 具体相关内容在使用是介绍 ## ProxyProcessorSupport 主要方法:evaluateProxyInterfaces ### evaluateProxyInterfaces 查询代理对象的父接口,当有接口时,将接口添加到ProxyConfig的Interface中,如果没有接口。则设置ProxyTargetClass为true。源码如下: ```java protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) { 查询到所有的父接口 Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader()); boolean hasReasonableProxyInterface = false; //判断是否有符合要求的接口 for (Class<?> ifc : targetInterfaces) { if (!isConfigurationCallbackInterface(ifc) && !isInternalLanguageInterface(ifc) && ifc.getMethods().length > 0) { hasReasonableProxyInterface = true; break; } } //有时,添加接口到proxyFacotry中 if (hasReasonableProxyInterface) { // Must allow for introductions; can't just set interfaces to the target's interfaces only. for (Class<?> ifc : targetInterfaces) { proxyFactory.addInterface(ifc); } } //没有时,使用class代理ß else { proxyFactory.setProxyTargetClass(true); } } ``` ## AbstructAutoProxyCreator 因为aop时通过继承BeanPostProcessor。在bean创建的过程中创建代理的。所以本抽象类就时关于BeanPostProcessor的相关实现,具体如下: ### postProcessBeforeInstantiation 没有找到具体在哪使用了。暂时不做解析,后面遇到再说。 ### getEarlyBeanReference 当bean被提起依赖时执行,代码如下: ```java @Override public Object getEarlyBeanReference(Object bean, String beanName) { Object cacheKey = getCacheKey(bean.getClass(), beanName); this.earlyProxyReferences.put(cacheKey, bean); return wrapIfNecessary(bean, beanName, cacheKey); } ``` 一共就3步: 1. 获取隐藏的名称,也就是当对象为BeanFactory时,获取的是BeanFactory对象。 2. 缓存当前对象到earlyProxyReferences中 3. 创建代理。 我们继续跟进wrapIfNecessary方法 ```java protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { //对于在targetSourcedBeans处理过的对象不做处理 if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { return bean; } //advisedBeans是缓存的所有与代理组件相关的类型,对于这些类步进行代理 if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } //判断是否时代理组建相关类,如果是,进行缓存,并不做代理 //主要有2方面判断。 //1 isInfrastructureClass 通过接口判断不是Advice Pointcut Advisor AopInfrastructureBean 相关子类 //2 shouldSkip 主要在子类实现逻辑,排除被@Aspect 标注的类 if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } //判断当前对象是否有Advices Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); //当有Advices时,说明当前类需要被代理。创建代理对象 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; } ``` 1. 首先判断当前是否为与aop相关组件的类型。如果是则不进行代理。判断的方式主要有:是否为指定的子类;是否被@Aspect 注释。(子类实现逻辑) 2. 判断是否有符合当前类的切面。 3. 如果有切面创建代理。 上面中的shouldSkip与getAdvicesAndAdvisorsForBean为子类实现在子类进行解析。我们继续跟进createProxy方法 ```java protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) { if (this.beanFactory instanceof ConfigurableListableBeanFactory) { AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); } //创建ProxyFactory对象 ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.copyFrom(this); //判断使用那种代理 if (!proxyFactory.isProxyTargetClass()) { if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } else { 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); } //通过ProxyFactory创建代理 return proxyFactory.getProxy(getProxyClassLoader()); } ``` 上面代码中我们看到首先创建了ProxyFactory对象,并对ProxyFactory进行配置。最后通过ProxyFactory的getProxy方法创建代理对象。对于ProxyFactory类在其文章中进行解析。 ### postProcessAfterInitialization 在bean初始化完成后执行 ```java @Override public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (this.earlyProxyReferences.remove(cacheKey) != bean) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; } ``` 我们看到postProcessAfterInitialization方法同样也是调用了wrapIfNecessary方法 **总结** 当前类主要是实现了BeanPostProcessor的几个方法。大致实现了代理创建的过程。 但是对于细节部分比如: 1. 如何判断哪些时切面类 2. 如何哪些类应该被代理 这些过程没有具体的实现,我们将在子类中说明。 ## AbstrcaAdvisiorAutoProxyCreator 主要是实现父类的getAdvicesAndAdvisorsForBean方法,获取当前类的aop切面 ```java @Override @Nullable 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(); } /** * Find all eligible Advisors for auto-proxying this class. * @param beanClass the clazz to find advisors for * @param beanName the name of the currently proxied bean * @return the empty List, not {@code null}, * if there are no pointcuts or interceptors * @see #findCandidateAdvisors * @see #sortAdvisors * @see #extendAdvisors */ protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { //获取所有的切面Advisor对象 List<Advisor> candidateAdvisors = findCandidateAdvisors(); //筛选出符合当前类的切面 List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); //扩展却面 extendAdvisors(eligibleAdvisors); //排序 if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; } ``` 上面代码中我们看到主要为一下逻辑: 1. 获取所有的切面 2. 筛选处符合要求的切面 3. 排序并返回 下面逐个解析 ### findCandidateAdvisors 获取系统中所有切面 ```java /** * Find all candidate Advisors to use in auto-proxying. * @return the List of candidate Advisors */ protected List<Advisor> findCandidateAdvisors() { Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available"); return this.advisorRetrievalHelper.findAdvisorBeans(); } ``` 我们看到查询是交给了advisorRetrievalHelper来实现。而这个对象是当前类的内部类,代码如下: ```java /** * Subclass of BeanFactoryAdvisorRetrievalHelper that delegates to * surrounding AbstractAdvisorAutoProxyCreator facilities. */ private class BeanFactoryAdvisorRetrievalHelperAdapter extends BeanFactoryAdvisorRetrievalHelper { public BeanFactoryAdvisorRetrievalHelperAdapter(ConfigurableListableBeanFactory beanFactory) { super(beanFactory); } @Override protected boolean isEligibleBean(String beanName) { return AbstractAdvisorAutoProxyCreator.this.isEligibleAdvisorBean(beanName); } } ``` 我们下面解析BeanFactoryAdvisorRetrievalHelper的findAdvisorBeans方法,看一下是如何获取到所有的切面的 ```java public List<Advisor> findAdvisorBeans() { // Determine list of advisor bean names, if not cached already. 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! advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Advisor.class, true, false); this.cachedAdvisorBeanNames = advisorNames; } if (advisorNames.length == 0) { return new ArrayList<>(); } 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 { 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; } ``` 我们看到就是直接用beanFactory中获取Advisor.class类型的bean。但是对于注解的处理是没有的,也就是说可能在子类中,我们在下面解析。 ### findAdvisorsThatCanApply 寻找到符合当前要求的切面,代码如下: ```java /** * Search the given candidate Advisors to find all Advisors that * can apply to the specified bean. * @param candidateAdvisors the candidate Advisors * @param beanClass the target's bean class * @param beanName the target's bean name * @return the List of applicable Advisors * @see ProxyCreationContext#getCurrentProxiedBeanName() */ 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方法: ```java 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; } if (canApply(candidate, clazz, hasIntroductions)) { eligibleAdvisors.add(candidate); } } return eligibleAdvisors; } /** * Can the given advisor apply at all on the given class? * This is an important test as it can be used to optimize * out a advisor for a class. * @param advisor the advisor to check * @param targetClass class we're testing * @return whether the pointcut can apply on any method */ public static boolean canApply(Advisor advisor, Class<?> targetClass) { return canApply(advisor, targetClass, false); } /** * Can the given advisor apply at all on the given class? * <p>This is an important test as it can be used to optimize out a advisor for a class. * This version also takes into account introductions (for IntroductionAwareMethodMatchers). * @param advisor the advisor to check * @param targetClass class we're testing * @param hasIntroductions whether or not the advisor chain for this bean includes * any introductions * @return whether the pointcut can apply on any method */ public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) { if (advisor instanceof IntroductionAdvisor) { return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass); } else if (advisor instanceof PointcutAdvisor) { PointcutAdvisor pca = (PointcutAdvisor) advisor; return canApply(pca.getPointcut(), targetClass, hasIntroductions); } else { // It doesn't have a pointcut so we assume it applies. return true; } } ``` 我们看到最终将advisor 分为3类, 1. IntroductionAdvisor 2. PointcutAdvisor 3. 其他情况 对于普通类型无条件返回true。 我们这里主要关注PointcutAdvisor的处理。但过程比较繁琐,暂时不解析 ## AspectJAwareAdvisiorAutoProxyCreator 这个类比较简单。只有2个比较重要的方法 ```java @Override protected void extendAdvisors(List<Advisor> candidateAdvisors) { AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors); } @Override protected boolean shouldSkip(Class<?> beanClass, String beanName) { // TODO: Consider optimization by caching the list of the aspect names List<Advisor> candidateAdvisors = findCandidateAdvisors(); for (Advisor advisor : candidateAdvisors) { if (advisor instanceof AspectJPointcutAdvisor && ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) { return true; } } return super.shouldSkip(beanClass, beanName); } ``` extendAdvisors 方法 在代理的切面最前面添加ExposeInvocationInterceptor.ADVISOR 实现shouldSkip方法。逻辑为排除到所有为切面的类型。 ## AnnotationAwareAspcetJAutoProxyCreator 到上面为止。基本上已经实现了aop的所有逻辑。这个类主要时扩展了注解功能。 主要方法为重写findCandidateAdvisors方法,在父类中只是识别了Advisor.class类型的切面。而当前方法中,将注解的切面也加入了进来。 ```java @Override protected List<Advisor> findCandidateAdvisors() { // Add all the Spring advisors found according to superclass rules. List<Advisor> advisors = super.findCandidateAdvisors(); // Build Advisors for all AspectJ aspects in the bean factory. if (this.aspectJAdvisorsBuilder != null) { advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); } return advisors; } ``` 我们看到具体也是通过aspectJAdvisorsBuilder来实现,而aspectJAdvisorsBuilder初始化如下: ```java @Override protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) { super.initBeanFactory(beanFactory); if (this.aspectJAdvisorFactory == null) { this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory); } this.aspectJAdvisorsBuilder = new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory); } ``` 跟进buildAspectJAdvisors方法如下: ```java 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<>(); //获取所有的bean名称 String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Object.class, true, false); //循环所有 for (String beanName : beanNames) { 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. Class<?> beanType = this.beanFactory.getType(beanName, false); if (beanType == null) { continue; } //通过advisorFactory的isAspect判断是否为切面类 if (this.advisorFactory.isAspect(beanType)) { aspectNames.add(beanName); //将切面信息封装为对象amd AspectMetadata amd = new AspectMetadata(beanType, beanName); //单例判断 if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) { //分装为BeanFactoryAspectInstanceFactory对象。并通过advisorFactory获取切面 MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName); 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(); } 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; } ``` 在上面代码中,我们看到。其实spring时获取到所有的bean逐个进行判断的,而判断是否为切面类,和分装获取切面都交给了advisorFactory处理。我们在AspectInstanceFactory文章中说明。 # 总结 通过上面的分析。我们知道大部分的代理创建是在bean初始化完成后执行的。而所有的代理都是通过ProxyFactory来执行。而ProxyFactory需要切面Advisor来提供切面。同时又是通过AspectInstanceFactory来判断哪些时切面类和生成Advisor对象。
回帖
消灭零回复
提交回复
热议榜
java 相关知识分享
8
好的程序员与不好的程序员
6
写给工程师的十条精进原则
5
spring boot以jar包运行配置的logback日志文件没生成
5
一步一步分析SpringBoot启动源码(一)
5
MockMvc测试
5
【吐槽向】是不是有个吐槽的板块比较好玩
4
logstash jdbc同步mysql多表数据到elasticsearch
3
IntelliJ IDEA 优质License Server
3
.gitignore忽略规则
3
SpringBoot启动源码分析
3
一步一步分析SpringBoot启动源码(三)
3
2
一步一步分析SpringBoot启动源码(二)
2
积分不够将无法发表新帖
2
官方产品
Meta-Boot - 基于MCN
MCN - 快速构建SpringBoot应用
微信扫码关注公众号