前言
spring的aop的源码相对来说比较少。但是很多细节想要弄懂,还是要在debug的世界里遨游很长一段时间。这里我分享一下我理解的aop的主要流程,希望对大家有所帮助。如有错误,请不吝指正。
核心原理
原理很简单,利用beanPostProcessor的postProcessAfterInitialization方法,在每一个bean初始化完成以后。判断当前bean是否有aop增强。如果有,则返回一个代理类作为bean。
@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;
}
看起来是不是瞬间懂了,但是我们要弄懂的地方还有很多。
是哪个beanPostProcessor
这一段代码是AbstractAutoProxyCreator类里的代码,真正执行这一段代码的是AnnotationAwareAspectJAutoProxyCreator,继承关系如下图所示:
什么时候注入到ioc容器的beanPostProcessors缓存的
这个AnnotationAwareAspectJAutoProxyCreator是什么时候被注入到ioc容器的。要分为两种情况
第一种,自动配置或者注解的形式
@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class,
AnnotatedElement.class })
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true",
matchIfMissing = true)
public class AopAutoConfiguration {
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class",
havingValue = "false", matchIfMissing = false)
public static class JdkDynamicAutoProxyConfiguration {
}
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class",
havingValue = "true", matchIfMissing = true)
public static class CglibAutoProxyConfiguration {
}
}
在springboot的自动配置的包下,有一个AopAutoConfiguration配置,根据@ConditionalOnClass条件可以看到,当有@EnableAspectJAutoProxy注解,@Aspect注解, 实现了Advice接口的容器类时。aop注解自动开启。所以没必要非得在启动类上加@EnableAspectJAutoProxy注解,存在@Aspect的切面,并且这个切面注入到ioc容器,也就是加上@Component注解,aop就已经开启了。当然,也可以配置里配置开启。
条件满足,就会注册AopAutoConfiguration,然后,在@EnableAspectJAutoProxy注解里,会@Import(AspectJAutoProxyRegistrar.class),之后AspectJAutoProxyRegistrar会把AnnotationAwareAspectJAutoProxyCreator注册到beanDefinitionMap。
第二种方式 xml配置的方式
当在xml文件里配置了
@Override
public void init() {
// In 2.0 XSD as well as in 2.1 XSD.
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
// Only in 2.0 XSD: moved to context namespace as of 2.1
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
然后在AspectJAutoProxyBeanDefinitionParser的parse()方法里,会把AnnotationAwareAspectJAutoProxyCreator注册到beanDefinitionMap。
实例化
接下来,在ioc容器执行registerBeanPostProcessors(beanFactory)方法时,把AnnotationAwareAspectJAutoProxyCreator实例化并放到beanPostProcessors缓存中。
这里有个地方要注意,初始化的时候因为也实现了BeanFactoryAware接口,所以会触发setBeanFactory()方法,在setBeanFactory()方法里又initBeanFactory((ConfigurableListableBeanFactory) beanFactory),初始化了advisorRetrievalHelper和aspectJAdvisorsBuilder。但是aop的各类缓存里是没有一起初始化的,只是个空壳子。
如何生成代理类
wrapIfNecessary
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 这个是为了防止循环依赖重复aop代理
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 判断当前bean是否已经处理过
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 这个缓存是缓存了bean是否需要代理,key为beanName,value是boolean值
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;
}
// 根据beanName拿到需要增强的点
// 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;
}
getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
最终后走到这个地方,为了篇幅,中间的代码有的会省略,建议打开源码和文章一起看
@Override
protected List findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
// 查找当前 bean 工厂中所有符合条件的 Advisor bean,忽略 FactoryBeans 并排除当前正在创建的 bean。这里其实找不到啥。重点是下面
List advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
// 这个里面缓存了增强的点。
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
buildAspectJAdvisors
这段代码很简单。拿出所有的beanName,一个一个判断是不是被@Aspect修饰,如果是,拿出所有的method,然后判断是不是@before,@after,@around。是就封装,然后以类为单位放到缓存,key是beanName,value是增强的方法数组。
public List buildAspectJAdvisors() {
List aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
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);
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) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
List 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 advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
List 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;
}
代码走到这里并不奇怪,但是奇怪的是,代码第一次走进来,advisorsCache和aspectBeanNames缓存里已经有值了,等于直接从缓存拿的,那么肯定是有一个执行了这个方法。通过调用链我们发现,shouldSkip()方法也执行了这段逻辑,那么问题就知道了,是在第一次执行shouldSkip()方法是,初始化了缓存。
shouldSkip()
问题又来了,第一次执行shouldSkip()是在哪?通过调用链我们发现,AnnotationAwareAspectJAutoProxyCreator还继承了InstantiationAwareBeanPostProcessor,这个BeanPostProcessor可以在bean实例化前后做一些逻辑。
最终,我们找到在第一次调用resolveBeforeInstantiation()的时候,触发了aop的初始化,具体在哪个时候呢,就是第一个创建bean调用到createBean()方法的时候,注意,并不是第一个bean创建的时候,有的bean创建可能不走createBean()方法。
createProxy()
有空再写。。。。