【Spring AOP】【四】Spring AOP源码解析-AOP代理时机
1 前言
我们分析了AOP不管是XML配置还是注解方式的解析过程,这篇我们简单来说下AOP在Spring中对bean对象生命周期的一个入场时机,其实我们在讲解IOC的时候,已经点了一下这篇我们再来简单说一下。
2 源码分析
切入时机准确的说有两个地方:
- createBean里的resolveBeforeInstantiation
- initializeBean里的applyBeanPostProcessorsAfterInitialization
2.1 resolveBeforeInstantiation
第一个时机resolveBeforeInstantiation:
try { // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. // 也就是说给当前bean的创建处理器的机会 判断当前bean能不能直接创建代理对象出来 Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean != null) { return bean; } }
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) { Object bean = null; /** * beforeInstantiationResolved 是否在Instantiation时解析 也就是你的beanDefinition里的beforeInstantiationResolved设置为true的情况下才有可能前置处理 */ if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) { // Make sure bean class is actually resolved at this point. /** * mbd.isSynthetic 是否是合成的 这个跟AOP有关系 因为我看到AOP的代理里才会把这个变为true 所以我们自己的一般都是false * hasInstantiationAwareBeanPostProcessors 是否有实现 这个肯定有 代理的核心类本身就实现了 */ if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { Class<?> targetType = determineTargetType(beanName, mbd); if (targetType != null) { bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName); if (bean != null) { bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); } } } mbd.beforeInstantiationResolved = (bean != null); } return bean; }
@Override 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; } // shouldSkip这里会获取所有的通知器 也就是说开始进入AOP的解析 解析有哪些通知器 if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return null; } } // targetSource 自定义源 也就是你的bean要自己创建 要有 customTargetSourceCreators // 这个我感觉有点像第三方包的意思或者自己提供创建的方法 自己创建 不走spring创建bean的生命周期 // Create proxy here if we have a custom TargetSource. // Suppresses unnecessary default instantiation of the target bean: // The TargetSource will handle target instances in a custom fashion. TargetSource targetSource = getCustomTargetSource(beanClass, beanName); if (targetSource != null) { 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; }
2.2 applyBeanPostProcessorsAfterInitialization
我们知道AOP有个核心类大哥AbstractAutoProxyCreator, 他实现了BeanPostProcessor的postProcessAfterInitialization方法,我们来看下源码:
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware { @Override // bean 初始化后置处理方法 public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (this.earlyProxyReferences.remove(cacheKey) != bean) { // 如果需要,为 bean 生成代理对象 return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; } }
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; } /* 如果是基础设施类(Pointcut、Advice、Advisor 等接口的实现类),或是应该跳过的类, 则不应该生成代理,此时直接返回 bean 也就是代理不能给自己再加代理 就是不套娃 */ if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { // 将 <cacheKey, FALSE> 键值对放入缓存中 缓存你懂的 this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // 为目标 bean 查找合适的通知器 // Create proxy if we have advice. Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); /* 若 specificInterceptors != null,即 specificInterceptors != DO_NOT_PROXY, 则为 bean 生成代理对象,否则直接返回 bean */ 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()); /* 返回代理对象,此时 IOC 容器输入 bean,得到 proxy。此时, beanName 对应的 bean 是代理对象,而非原始的 bean */ return proxy; } this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }
以上就是创建代理对象的方法分析,过程比较简单,这里简单总结一下:
- 若 bean 是 AOP 基础设施类型,则直接返回
- 为 bean 查找合适的通知器(因为第一个时机里已经解析过并缓存了, 所以查找通知器的时候,会直接使用缓存了)
- 如果通知器数组不为空,说明bean需要代理,则为 bean 生成代理对象,并返回代理对象
- 若数组为空,则返回原始 bean即自己
3 小结
本篇我们简单了解下AOP的入场时机,接下来我们就看看AOP是如何筛选通知器的,并如何串联编排多个通知器的,休息一下,我们再继续。