本文,从代码来解析AOP的一些概念、源码、流程等…
首先需要对spring AOP 的一些概念需要有一些了解…
Aspect (切面)Advice(通知)Pointcut(切入点)Advisor(增强器、顾问)我比较喜欢称之为增强器,如果注释中存在增强器指的就是这个…Target (目标对象)简单说,一个切面定义了 切入点和通知
而 Advisor(顾问、增强器)将切面的里面的 切入点和通知进行了一个包装
也就说 我们的AOP 什么时候去使用的?我们知道 当一个Bean注册的时候会对Bean 做一些列操作 ,简单说也就是 相关 BeanPostProcessor,而我们通过接口分析得知AnnotationAwareAspectJAutoProxyCreator最终是实现了SmartInstantiationAwareBeanPostProcessor、InstantiationAwareBeanPostProcessor也就是说基本是 执行 BeanPostProcessor的时候去进行处理的,在通过源码了解到 BeanPostProcessor 是贯穿了我们 Bean 的生命周期的,那其实我们想知道这个什么时候起的作用,只需要知道实现的这几个方法什么时候执行的即可
单从结果上看 仅仅只有 AbstractAutoProxyCreator 去实现了这些方法,子类并没有重新和覆盖
调用时机可参考 InstantiationAwareBeanPostProcessor
由AbstractAutoProxyCreator 去实现了这些方法
调用时机可参考 BeanPostProcessor
由 AbstractAutoProxyCreator去实现了这些方法
当创建一个 Bean 的时候,也就说只有2个地方可能会返回代理对象,一个是直接返回代理对象,根本不给机会去创建对象,另一个是走完初始化方法调用后返回代理对象
主流程指的是DBUG线程调用的地方方法~~,也就说每一次的Bean 创建都会走这里…
refresh();finishBeanFactoryInitialization(beanFactory);beanFactory.preInstantiateSingletons();getBean(beanName);doGetBean()getSingleton()createBean()给 BeanPostProcessors 一个 机会 返回 一个代理替换这个目标 Bean 的 实例,简单来说,直接就通过代理返回结果了
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) { Object bean = null; // beforeInstantiationResolved 可能是 null 、true、false // null 代表 bean 没有走过 resolveBeforeInstantiation 这个方法 // true 代表 bean 已经走过 resolveBeforeInstantiation 这个方法 // false 代表 bean 不需要走 resolveBeforeInstantiation 这个方法 // 这里是为了一个效率的存在,当如果 这个 BeanDefinition 已经走过一边后,并且返回了 false 后下次就不会继续走了 if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) { // 1. 判断是不是 合成 Bean // 2. 判断有没有 实现了 InstantiationAwareBeanPostProcessor 这个接口的 BeanPostProcessors if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { Class<?> targetType = determineTargetType(beanName, mbd); if (targetType != null) { // 执行前置方法 bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName); // 如果不是 null 就代表已经返回对象了,则会去执行后置方法 if (bean != null) { // 执行后置方法 bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); } } } // bean != null 返回 true 代表 bean 已经被创建 // bean != null 返回 false 代表 bean 不需要进行代理.. mbd.beforeInstantiationResolved = (bean != null); } return bean; }这里可以看到一个细节就是 BeanDefinition. beforeInstantiationResolved 这个属性 是为了缓存结果,简单来说当走完所有的 InstantiationAwareBeanPostProcessors 后如果都是不创建那就会定义为 false,也就是说在 多例(原型)的情况下这里的代码如果第一次走完后,下次如果是false就会直接返回.
这里简单说就是获取增强器,可以通过XML、接口、注解方式进行配置,来让我们一步一步的将他吃透…大致是这些流程…
AbstractAutoProxyCreator.postProcessBeforeInstantiation
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) { // 获取 一个用于缓存 key 其实就是 BeanName Object cacheKey = getCacheKey(beanClass, beanName); // 判断 targetSourcedBeans 不包含这个 bean if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) { // 判断需要增强的 Bean 是否包含这个 Bean // advisedBeans 包含所有 切面Bean 和 增强Bean if (this.advisedBeans.containsKey(cacheKey)) { return null; } //1. 判断是不是 基础类型,也就说判断是不是 实现了这些接口 Advice、Pointcut、Advisor、AopInfrastructureBean、 //2. 还会判断是不是 有没有 @Aspect 注解 // isInfrastructureClass 执行方法,主要注意的是 this 的指向是 AnnotationAwareAspectJAutoProxyCreator, // 所以执行 AnnotationAwareAspectJAutoProxyCreator.isInfrastructureClass() // 这段逻辑是处理如果是基础类、切面类、原始类 都不会进行代理 if (isInfrastructureClass(beanClass) || // 所以执行 AnnotationAwareAspectJAutoProxyCreator.shouldSkip() // 判断是不是需要跳过,如果返回true则就会将 这个 name 进行缓存 shouldSkip(beanClass, beanName)) { // 这里其实是将 切面 Bean 的BeanName 缓存起来,代表这个 Bean 不进行 增强操作 this.advisedBeans.put(cacheKey, Boolean.FALSE); return null; } } // 如果我们有自定义的TargetSource,请在此处创建代理。 // 禁止目标Bean的不必要的默认实例化: TargetSource 将以自定义方式处理目标实例。 TargetSource targetSource = getCustomTargetSource(beanClass, beanName); if (targetSource != null) { // 这个 BeanName 是正常的 if (StringUtils.hasLength(beanName)) { this.targetSourcedBeans.add(beanName); } Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource); //创建代理对象 Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } return null; }isInfrastructureClass 执行方法,主要注意的是 this 的指向是 AbstractAutoProxyCreator, 所以会执行AnnotationAwareAspectJAutoProxyCreator.shouldSkip()
protected boolean shouldSkip(Class<?> beanClass, String beanName) { // 找到候选的 增强器,也就是说是切面里面的通知方法 List<Advisor> candidateAdvisors = findCandidateAdvisors(); // 循环所有 增强器 for (Advisor advisor : candidateAdvisors) { //判断我们的增强器是不是 AspectJPointcutAdvisor 这个类型 if (advisor instanceof AspectJPointcutAdvisor && // 并且 增强的名称和我们的BeanName 是一致 ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) { return true; } } // 这里基本返回 false.. return super.shouldSkip(beanClass, beanName); } // 父类的方法 protected boolean shouldSkip(Class<?> beanClass, String beanName) { // 判断是不是 原始的实例,也就是说是不需要进行代理的实例 return AutoProxyUtils.isOriginalInstance(beanName, beanClass); } static boolean isOriginalInstance(String beanName, Class<?> beanClass) { // 如果 BeanName 不正常 返回 false // beanName 的长度不是 bean全限定类名+ ORIGINAL_INSTANCE_SUFFIX(原始后缀),也返回 false // 也就是说这里基本会返回 false 那什么时候返回 True 呢 当我们的Bean 是全限定类名 + ORIGINAL_INSTANCE_SUFFIX 的时候... // 这里可以去手动注册一个 这样的Bean,演示DEMO 在下面~~~ if (!StringUtils.hasLength(beanName) || beanName.length() != beanClass.getName().length() + AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX.length()) { return false; } return (beanName.startsWith(beanClass.getName()) && beanName.endsWith(AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX)); } //-----------------------------DEMO // @EnableAspectJAutoProxy // @ComponentScan // public class IsOriginalInstanceContext { // public static void main(String[] args) { // AnnotationConfigApplicationContext value = new AnnotationConfigApplicationContext(); // value.register(IsOriginalInstanceContext.class); // value.registerBeanDefinition(IsOriginalInstanceBean.class.getName() // + AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX, // BeanDefinitionBuilder.genericBeanDefinition(IsOriginalInstanceBean.class).getBeanDefinition() // ); // value.refresh(); // } // } //----------------------------这里也是同理,会调用AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors()
这里逻辑分为两步
调用父类的findCandidateAdvisors()方法获取的是 实现了 Advisor 接口的Bean获取的是注解 切面里面所有的 Advisor protected List<Advisor> findCandidateAdvisors() { // 获取所有 实现 Advisor 接口的类,这里的代码就不贴了.. 自己可以去看看比如自己转配一个 Bean 去实现这个 Advisor 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; }从这里可以看出 Advisor 指的就是 切入点和通知的集合
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrderInAspect, String aspectName) { // 校验... validate(aspectInstanceFactory.getAspectMetadata().getAspectClass()); // 获取 切入点 AspectJExpressionPointcut expressionPointcut = getPointcut( candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass()); if (expressionPointcut == null) { return null; } // 在创建 InstantiationModelAwarePointcutAdvisorImpl 的时候 里面有一个 instantiateAdvice--> getAdvice 比较重要需要看一下 // 将切入点和通知包装成一个 增强器 return new InstantiationModelAwarePointcutAdvisorImpl( expressionPointcut, //切入点表达式 candidateAdviceMethod, //通知方法 this, aspectInstanceFactory, // 切面实例的工厂.. declarationOrderInAspect, //0 aspectName //切面名称 ); }获取Pointcut(切入点),需要说明的是这里如果使用的 @Pointcut 定义的切入点… 并没有进行解析,简单说 AspectJExpressionPointcut 的 Pointcut 仅仅是 @Pointcut的方法名…
@Nullable private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) { // 获取方法的(通知) // Pointcut.class, // Around.class, // Before.class, // After.class, // AfterReturning.class, // AfterThrowing.class AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod); if (aspectJAnnotation == null) { return null; } // 构建一个 切点 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; }1
这个单独领出来说,是这里…想要进入条件比较刻薄
protected TargetSource getCustomTargetSource(Class<?> beanClass, String beanName) { // customTargetSourceCreators 不为空 // beanFactory 不为空 // bean 存在 spring容器中 if (this.customTargetSourceCreators != null && this.beanFactory != null && this.beanFactory.containsBean(beanName)) { for (TargetSourceCreator tsc : this.customTargetSourceCreators) { TargetSource ts = tsc.getTargetSource(beanClass, beanName); if (ts != null) { // Found a matching TargetSource. if (logger.isTraceEnabled()) { logger.trace("TargetSourceCreator [" + tsc + "] found custom TargetSource for bean with name '" + beanName + "'"); } return ts; } } } // No custom TargetSource found. return null; }整个上面的所有代码都是获取 Aspect 和 Advice 和 Pointcut
缓存了 实现了 Advisor 接口 Bean 的name缓存了 @Aspect 注解的 Bean 的name缓存了 切面 Bean 下面的所有 Advisor(Advice、Pointcut)为什么这么做… 为了效率,因为每一次都会去拦截,每次都会去走一遍,对其数据进行缓存,其实随处可见的细节太多了…
根据主流程~~ 继续DBUG,也就是说没有直接返回代理对象~~这里的代码就不贴了,直接贴核心代码
doCreateBeaninitializeBeanapplyBeanPostProcessorsAfterInitialization这里的细节点是 可以看到 advisedBeans.put(cacheKye,Boolean.FALSE) 或者ture ,其实为了就是效率…
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { // 判断 beanName是正常的 并且 targetSourcedBeans 已经存在则会直接返回 if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { return bean; } //判断 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. // 创建代理对象 // 1. 获取当前Bean 的所有增强器(通知方法) Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); // 如果不是 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; } // 如果不需要代理则设置为 False 当下次进来的时候会直接返回(细节) this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }解析切入点表达式…为过滤做准备
public ClassFilter getClassFilter() { obtainPointcutExpression(); return this; }去解析表达式…
private PointcutExpression buildPointcutExpression(@Nullable ClassLoader classLoader) { // 初始化基础的Aspect切入点解析器 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]); } // 这里嵌套了3个方法....而且还异常复杂我都不忍心看... return parser.parsePointcutExpression(replaceBooleanOperators(resolveExpression()), this.pointcutDeclarationScope, pointcutParameters); }这里仅仅是去匹配当前类是否符合规则
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); //根据切入点和 目标类,判断类 package 是否匹配 boolean couldMatch = pointcut.fastMatch(info).maybeTrue(); return couldMatch; }上面一大串代码都是为了去进行匹配,当匹配成功的时候才会去创建代理对象
创建代理对象
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 = new ProxyFactory(); // 将当前类的一些配置进行 复制 ,简单来说就是获取 XML 或者注解配置的属性.. // 这里可以参考一下: proxyFactory.copyFrom(this); // 判断是否是通过接口 默认是 False if (!proxyFactory.isProxyTargetClass()) { //根据最开始@EnableAspectJAutoProxy注解中的proxyTargetClass参数判断是否应该使用cglib代理 if (shouldProxyTargetClass(beanClass, beanName)) { //标识 使用cglib动态代理 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); } return proxyFactory.getProxy(getProxyClassLoader()); }取决于 createAopProxy 返回的是 CGlib 还是JDK 代理