首先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 definitions
Class<?> 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) {
//将解析出来的配置类 注册为BeanDefinition
this.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并封装为Interceptor
List<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() - 1
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
//拿到当前的Advisor
Object 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...{
@Override
public 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... {
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
//先调下一个增强
return mi.proceed();
} finally {
// 最后执行after增强
invokeAdviceMethod(...);
}
}
}
public class MethodBeforeAdviceInterceptor implements MethodInterceptor... {
private final MethodBeforeAdvice advice;
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
// 执行before增强
this.advice.before(...);
// 继续调下一个增强
return mi.proceed();
}
}
也就是说基于栈, 先入后出的特点, 实现了执行顺序 before -> 业务方法 -> after -> 切入点(毒丸方法) 的增强