【Spring AOP 原理】

首先AOP跟OOP(面向对象编程)、IOC(控制反转)一样都是一种编程思想

跟OOP不同, AOP是面向切面编程, 面对多个不具备继承关系的对象同时需要引入一段公共逻辑的时候, OOP就显得有点笨重了, 而AOP就游刃有余, 一个切面可以横跨多个类或者对象去执行公共逻辑, 极大的提升了开发效率

完全没读过源码的朋友, 建议先浅读下这篇文章【spring的AOP】, 简单了解下SpringAop基础概念

本文会从三个方面讲清楚,Spring AOP到底是怎么回事

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的增强。
Spring AOP 原理

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对象
Spring AOP 原理
执行了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 -> 切入点(毒丸方法) 的增强
Spring AOP 原理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值