首先AOP跟OOP(面向对象编程)、IOC(控制反转)一样都是一种编程思想
跟OOP不同, AOP是面向切面编程, 面对多个不具备继承关系的对象同时需要引入一段公共逻辑的时候, OOP就显得有点笨重了, 而AOP就游刃有余, 一个切面可以横跨多个类或者对象去执行公共逻辑, 极大的提升了开发效率
完全没读过源码的朋友, 建议先浅读下这篇文章【spring的AOP】, 简单了解下SpringAop基础概念
本文会从三个方面讲清楚,Spring AOP到底是怎么回事
- 1、SpringAOP是如何生效的
- 2、代理对象是如何创建的
- 3、增强逻辑是怎样执行的
1、SpringAOP是如何生效的
- 使用Spring框架时, 我们需要引入spring-aop和aspectjweaver依赖, 然后在配置类上加上@EnableAspectJAutoProxy注解就可以开始使用aop了
- 使用SpringBoot框架时, 要简单一些, 只需要引入spring-boot-starter-aop依赖就可以开始使用aop了
那aop到底是如何生效的呢? 下面我们追踪源码看下。
首先我们看下@EnableAspectJAutoProxy注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {}
@Import
是不是很熟悉, 简单复习下它能干啥?
- 导入一个普通bean对象到IOC中
- 导入一个ImportSelector接口实现类, 将接口方法selectImports返回的数组中的全限定类名称对应的bean注册为到IOC中
- 导入一个 ImportBeanDefinitionRegistrar接口实现类, 接口方法registerBeanDefinitions可以将一批BeanDefinition注册到IOC中
显然AspectJAutoProxyRegistrar是ImportBeanDefinitionRegistrar接口实现类, 肯定是想在Spring启动过程中往IOC中注册BeanDefinition, 执此想法我们去看看Spring启动流程到底在哪一步做了这个事情。
(下面我看下关键代码, 一起探索一下!)
refresh()
方法不用多介绍吧, Spring启动流程就在此方法中完成, 主要看invokeBeanFactoryPostProcessors() 和 registerBeanPostProcessors()。
为啥看这俩呢, 浅读一下【SpringBoot自动配置原理】就了解了。
public void refresh()...{...try {...// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);...// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);...}
}
invokeBeanFactoryPostProcessors主要逻辑就是执行bean工厂的增强和BeanDefinitionRegistry的增强。
debug发现主要的逻辑都是ConfigurationClassPostProcessor类中完成, 这个类中执行了parse方法, 完成了配置类上的注解解析, 包括@EnableAspectJAutoProxy注解中的@Import(AspectJAutoProxyRegistrar.class), 感觉快到了, 继续追踪。
final class PostProcessorRegistrationDelegate {public static void invokeBeanFactoryPostProcessors(...) {// BeanDefinitionRegistry相关的增强invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);}private static void invokeBeanDefinitionRegistryPostProcessors(...) {for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {postProcessor.postProcessBeanDefinitionRegistry(registry);}}
}public class ConfigurationClassPostProcessor ...{public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {//到这里就开始熟悉起来了 解析主配置类上的所有注解parser.parse(candidates);}}
果然在这doProcessConfigurationClass中看到了对@Import注解的处理, candidate.isAssignable(ImportBeanDefinitionRegistrar.class)这个分支中将AspectJAutoProxyRegistrar类实例化并加入到了classConfig(importBeanDefinitionRegistrars)中, 至此, 这个类已经注册进来了, 那么后面肯定有执行AspectJAutoProxyRegistrar.registerBeanDefinitions()方法地方。
class ConfigurationClassParser {protected final SourceClass doProcessConfigurationClass(...) throws IOException {// Process any @Import annotations//果然追踪到这里看到了一行注释, 解析任何@Import注解, 就是这个无疑了processImports(configClass, sourceClass, getImports(sourceClass), true);}}private void processImports(...) {...if (candidate.isAssignable(ImportSelector.class)) {}else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {// Candidate class is an ImportBeanDefinitionRegistrar ->// delegate to it to register additional bean definitionsClass<?> candidateClass = candidate.loadClass();ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);ParserStrategyUtils.invokeAwareMethods(registrar, this.environment, this.resourceLoader, this.registry);configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());}}
}
继续往后追踪代码, 发现在reader.loadBeanDefinitions(configClasses)这个方法中执行了registerBeanDefinitions方法, 将AnnotationAwareAspectJAutoProxyCreator类封装成BeanDefinition注册进registry中了
public class ConfigurationClassPostProcessor ...{public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {//将解析出来的配置类 注册为BeanDefinitionthis.reader.loadBeanDefinitions(configClasses);}}class ConfigurationClassBeanDefinitionReader {public void loadBeanDefinitions(...) {...for (ConfigurationClass configClass : configurationModel) {loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);}}private void loadBeanDefinitionsForConfigurationClass(...) {...loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());//loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());}private void loadBeanDefinitionsFromRegistrars(...) {registrars.forEach((registrar, metadata) ->registrar.registerBeanDefinitions(metadata, this.registry));}
}
到这里就已经完成了AOP的注解解析, 继续再往后看registerBeanPostProcessors方法中执行了, getBean方法创建了AnnotationAwareAspectJAutoProxyCreator单例对象
public static void registerBeanPostProcessors(```) {```for (String ppName : orderedPostProcessorNames) {//在这里创建了AnnotationAwareAspectJAutoProxyCreator单例对象BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);}
}
同时在初始化化过程中进行Aware接口检查的时候, 将AspectJAdvisorFactory和BeanFactoryAspectJAdvisorsBuilder对象new出来注入到对应属性字段上了
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {super.initBeanFactory(beanFactory);if (this.aspectJAdvisorFactory == null) {this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);}this.aspectJAdvisorsBuilder = new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}
至此aop就可以使用了 , 那创建的这些对象到底有啥用呢? 往下看
2、代理对象是如何创建的
配置生效了, 那aop又是怎么帮我们创建代理对象的呢?
如果看过开篇那个文章应该知道, 创建代理的时机就是bean初始化完成后的后置增强postProcessAfterInitialization方法中
debug看下发现确实用到了AnnotationAwareAspectJAutoProxyCreator对象
执行了wrapIfNecessary方法, 创建出代理对象
public Object postProcessAfterInitialization(...) {if (bean != null) {Object cacheKey = getCacheKey(bean.getClass(), beanName);if (this.earlyProxyReferences.remove(cacheKey) != bean) {return wrapIfNecessary(bean, beanName, cacheKey);}}return bean;
}protected Object wrapIfNecessary(...) {...// 查找并封装所有匹配的增强方法Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(...);// 创建代理对象Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));...
}
创建代理对象时, 在getAdvicesAndAdvisorsForBean方法中查找出所有匹配的增强方法, 并封装为Advisor, 这里我们看到使用了BeanFactoryAspectJAdvisorsBuilder去构建Advisor对象
protected List<Advisor> findCandidateAdvisors() {List<Advisor> advisors = super.findCandidateAdvisors();if (this.aspectJAdvisorsBuilder != null) {//使用了advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());}return advisors;
}
拿到所有Advisor后, 就去创建代理对象, 核心代码如下, 能看到Spring Aop支持jdk和cglib两种代理 【Java的动态代理】
public AopProxy createAopProxy(...) throws AopConfigException {if (...) {//cglib代理return new ObjenesisCglibAopProxy(config);} else {//jdk代理return new JdkDynamicAopProxy(config);}
}
3、增强逻辑是怎样执行的
来个demo
@Aspect
@Component
public class LoggingAspect {@Pointcut("@annotation(com.test.springBoot.ann.AopAdvise)")public void pointCut() {}@Before("pointCut()")public void before() throws Throwable {System.out.println("增强方法之前");}@After("pointCut()")public void after() throws Throwable {System.out.println("增强方法之后");}}
同样debug的方式看下, 发现有三个增强方法, 这里拿到了所有的Advisor并封装为Interceptor, 第一个是pointCut, 第二个是after, 第三个是before, 这个顺序很重要, 后面会依赖于这个顺序做链式调用编排
又将chain封装到了CglibMethodInvocation对象中, 调用proceed做链式调用编排
class CglibAopProxy implements AopProxy, Serializable {public Object intercept(...) throws Throwable {//拿到了所有的Advisor并封装为InterceptorList<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);// 封装了CglibMethodInvocation对象, 调用proceed做链式调用编排retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();}}
主要是用下面两个对象进行编排的
- ReflectiveMethodInvocation 方法执行编排器
- MethodInterceptor 增强方法执行对象
public class ReflectiveMethodInvocation ... {public Object proceed() throws Throwable {// 判断 -1 = chain.size() - 1if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {return invokeJoinpoint();}//拿到当前的AdvisorObject interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {// 如果当前的Advisor是一个连接点 // 比如 before/after/afterReturn等, 就执行invoke方法...return dm.interceptor.invoke(this);...} else {// 否则就是切入点方法return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);}}
}
我们可以看到invoke把编排器传了进去, 还记的上面的顺序把, 按顺序依次去看实现类
ExposeInvocationInterceptor 中上来先调用下一个process
AspectJAfterAdvice 中上来先调用下一个process
MethodBeforeAdviceInterceptor 中, 执行了before增强方法, 调用下一process
再次进入process方法中 判断条件 -1 = chain.size() - 1 成立, 执行invokeJoinpoint(业务方法)
返回到MethodBeforeAdviceInterceptor执行完了
再返回到AspectJAfterAdvice执行after方法
再返回到ExposeInvocationInterceptor设置毒丸
public final class ExposeInvocationInterceptor implements MethodInterceptor...{@Overridepublic Object invoke(MethodInvocation mi) throws Throwable {MethodInvocation oldInvocation = invocation.get();invocation.set(mi);try {// 先调下一个增强return mi.proceed();} finally {// 最后设置毒丸invocation.set(oldInvocation);}}
}public class AspectJAfterAdvice implements MethodInterceptor... {@Overridepublic Object invoke(MethodInvocation mi) throws Throwable {try {//先调下一个增强return mi.proceed();} finally {// 最后执行after增强invokeAdviceMethod(...);}}
}public class MethodBeforeAdviceInterceptor implements MethodInterceptor... {private final MethodBeforeAdvice advice;@Overridepublic Object invoke(MethodInvocation mi) throws Throwable {// 执行before增强this.advice.before(...);// 继续调下一个增强return mi.proceed();}}
也就是说基于栈, 先入后出的特点, 实现了执行顺序 before -> 业务方法 -> after -> 切入点(毒丸方法) 的增强