SpringAop源码分析(基于注解)一

一、AOP原理

关于Aop的原理,简单来讲无非就是用代理模式为目标对象生产代理对象,对原有的方法进行增强。看上去挺简单,但在Spring中,有许多细节是要注意到的。比如:

  • AOP是怎么触发的?
  • 代理对象是什么时候生成的?
  • 怎么发现目标对象?
  • 怎么判断目标对象的哪些方法需要增强?
  • 怎么实现前置通知,后置通知,环绕通知?
  • 一个方法有多个切面代理怎么处理?

我们可以带着这些疑问来看源码,有助于我们的理解。

二、AOP术语

AOP的术语有很多并且很重要,看源码之前还是要对术语有所了解,这里就不一一介绍了

三、demo

先来一个注解方式实现AOP的demo,然后我们后面根据这个demo来分析源码。

@Aspect
@Component
@EnableAspectJAutoProxy
public class LogAspect {

	@Before("execution(* com.mydemo.work.StudentController.getName(..))")
	public void doBefore() {
		System.out.println("========before");
	}

	@After("execution(* com.mydemo.work.StudentController.getName(..))")
	public void doAfter() {
		System.out.println("========after");
	}
}

这是一个简单的日志AOP,对StudentController类的getName(..)方法进行增强,在这个方法执行前后会打印不同的信息。

四、准备

可以看到,在最开始的demo工程中,为了开启AOP功能,我使用了一个@EnableAspectJAutoProxy注解,代码如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

	/**
	 * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
	 * to standard Java interface-based proxies. The default is {@code false}.
	 */
	//代理的实现方式,true为CGLIB,false为JDK,默认false
	boolean proxyTargetClass() default false;

	/**
	 * Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
	 * for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
	 * Off by default, i.e. no guarantees that {@code AopContext} access will work.
	 * @since 4.3.1
	 */
	//代理的暴露方式,解决内部调用不能使用代理的场景,默认为false
	boolean exposeProxy() default false;

}

可以看到这个注解有2个属性proxyTargetClassexposeProxy。除此之外还使用@Import注解引入了一个配置类AspectJAutoProxyRegistrar。 我们来看下这个关键的类:

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

/**
 * Register, escalate, and configure the AspectJ auto proxy creator based on the value
 * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
 * {@code @Configuration} class.
 */
@Override
public void registerBeanDefinitions(
		AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

<1>     //注册一个专门管理AOP的Bean到IOC容器中
	AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

	//获取@EnableAspectJAutoProxy注解
<2>	AnnotationAttributes enableAspectJAutoProxy =
			AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
	if (enableAspectJAutoProxy != null) {
		//处理该注解的2个属性
		if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
			AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
		}
		if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
			AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
		}
	}
	}

}

这段代码看起来不难,我们肯定要有一个处理AOP逻辑的代码类,那在Spring中就要把这个类交给Spring容器来管理,所以有了第<1>步。我们来看下详细逻辑, 直接追踪到最后调用的地方:

//AopConfigUtils.java

/**
 * The bean name of the internally managed auto-proxy creator.
 */
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
			"org.springframework.aop.config.internalAutoProxyCreator";

@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry,
		@Nullable Object source) {

	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
	
	//检查容器中是否已经注册过该Bean
	if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
		//注册过,判断Bean的ClassName是否为AnnotationAwareAspectJAutoProxyCreator
		BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
		if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
			int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
			int requiredPriority = findPriorityForClass(cls);
			if (currentPriority < requiredPriority) {
				apcDefinition.setBeanClassName(cls.getName());
			}
		}
		return null;
	}
	//没有注册过,则注册
	//cls = AnnotationAwareAspectJAutoProxyCreator.class
	RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
	beanDefinition.setSource(source);
	beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
	beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
	registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
	return beanDefinition;
}

这段代码就是把AnnotationAwareAspectJAutoProxyCreator这个类注册到SpringIOC容器中,实际上AnnotationAwareAspectJAutoProxyCreator这个类的BeanName就是org.springframework.aop.config.internalAutoProxyCreator

五、注册BeanPostProcessor

现在我们已经有了处理AOP的类AnnotationAwareAspectJAutoProxyCreator, 先来看下这个类的继承图:

可以看出,这个类间接实现了BeanPostProcessor接口,这个接口大家应该很熟悉,是Spring的一个后置处理器接口。

public interface BeanPostProcessor {

	//在Bean的初始化前回调
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	
	//在Bean的初始化之后回调
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

}

BeanPostProcessor 可以理解为是 Spring 的一个工厂钩子(其实 Spring 提供一系列的钩子,如 Aware 、InitializingBean、DisposableBean),它是 Spring 提供的对象实例化阶段强有力的扩展点,允许 Spring 在实例化 bean 的前后对其进行修改,比较常见的使用场景是处理标记接口实现类或者为当前对象提供代理实现(例如 AOP)。 一般普通的 BeanFactory 是不支持自动注册 BeanPostProcessor 的,需要我们手动调用addBeanostProcessor()方法进行注册。如下:

beanFactory.addBeanPostProcessor(BeanPostProcessor beanPostProcessor)

注册后的 BeanPostProcessor 适用于所有该 BeanFactory 创建的 bean,但是 ApplicationContext 可以在其 bean 定义中自动检测所有的 BeanPostProcessor 并自动完成注册,同时将他们应用到随后创建的任何 Bean 中。

在这里我们的容器是ApplicationContext,所以会自动检测所有BeanPostProcessor并完成注册。接下来我们就看下自动注册的逻辑。

我们都知道在 ApplicationContext 中有一个重要的方法refresh(),会在容器启动时执行,代码如下:

//AbstractApplicationContext.java

public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
	// Prepare this context for refreshing.
	//1、调用spring容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识
	prepareRefresh();

	// Tell the subclass to refresh the internal bean factory.
	//2、创建并初始化 BeanFactory   ---->  获取IOC容器
	ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

	// Prepare the bean factory for use in this context.
	//3、填充BeanFactory功能。    配置容器特性,例如类加载器、事件处理器等
	prepareBeanFactory(beanFactory);

	try {
		// Allows post-processing of the bean factory in context subclasses.
		//4、提供子类覆盖的额外处理,即子类处理自定义的BeanFactoryPostProcess
		postProcessBeanFactory(beanFactory);

		// Invoke factory processors registered as beans in the context.
		//5、激活各种BeanFactory处理器。 调用所有注册的BeanFactoryPostProcessor的Bean
		invokeBeanFactoryPostProcessors(beanFactory);

		// Register bean processors that intercept bean creation.
		//6、注册BeanPostProcessor后置处理器.
		//AutowiredAnnotationBeanPostProcessor(处理被@Autowired注解修饰的bean并注入)
		//RequiredAnnotationBeanPostProcessor(处理被@Required注解修饰的方法)
		//CommonAnnotationBeanPostProcessor(处理@PreDestroy、@PostConstruct、@Resource等多个注解的作用)等
		//AutoProxyCreator(aop代理 @Aspect)
		registerBeanPostProcessors(beanFactory);

		// Initialize message source for this context.
		//7、初始化信息源,和国际化相关.
		initMessageSource();

		// Initialize event multicaster for this context.
		//8、初始化容器事件传播器.
		initApplicationEventMulticaster();

		// Initialize other special beans in specific context subclasses.
		//9、调用子类的某些特殊Bean初始化方法
		onRefresh();

		// Check for listener beans and register them.
		//10、为事件传播器注册事件监听器.
		registerListeners();

		// Instantiate all remaining (non-lazy-init) singletons.
		//11、初始化剩下的单例Bean(非延迟加载的)
		finishBeanFactoryInitialization(beanFactory);

		// Last step: publish corresponding event.
		//12、初始化容器的生命周期事件处理器,并发布容器的生命周期事件
		finishRefresh();
	}

	catch (BeansException ex) {
		if (logger.isWarnEnabled()) {
			logger.warn("Exception encountered during context initialization - " +
					"cancelling refresh attempt: " + ex);
		}

		// Destroy already created singletons to avoid dangling resources.
		//13、销毁已创建的Bean
		destroyBeans();

		// Reset 'active' flag.
		//14、取消refresh操作,重置容器的同步标识。
		cancelRefresh(ex);

		// Propagate exception to caller.
		throw ex;
	}

	finally {
		// Reset common introspection caches in Spring's core, since we
		// might not ever need metadata for singleton beans anymore...
		//15、重设公共缓存
		resetCommonCaches();
	}
	}
	}

代码很长,其他的暂时先不管,直接看第6步registerBeanPostProcessors(beanFactory),这行代码是需要我们关注的,它就是对 BeanPostProcessors 进行自动注册的方法。

//PostProcessorRegistrationDelegate.java

public static void registerBeanPostProcessors(
		ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

<1>	//获取容器中所有的BeanPostProcessor名称
	String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

	// Register BeanPostProcessorChecker that logs an info message when
	// a bean is created during BeanPostProcessor instantiation, i.e. when
	// a bean is not eligible for getting processed by all BeanPostProcessors.
	int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
	//注册BeanPostProcessorChecker到容器中
	beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

	// Separate between BeanPostProcessors that implement PriorityOrdered,
	// Ordered, and the rest.
	List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
	List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
	List<String> orderedPostProcessorNames = new ArrayList<>();
	List<String> nonOrderedPostProcessorNames = new ArrayList<>();
<2>	//遍历所有BeanPostProcessor名称
	for (String ppName : postProcessorNames) {
		//判断当前BeanPostProcessor是否实现PriorityOrdered接口
		if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			priorityOrderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		//判断当前BeanPostProcessor是否实现Ordered接口
		else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
			orderedPostProcessorNames.add(ppName);
		}
		else {
			nonOrderedPostProcessorNames.add(ppName);
		}
	}

	// First, register the BeanPostProcessors that implement PriorityOrdered.
<3>	//对实现PriorityOrdered接口的BeanPostProcessors进行排序
	sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
	//注册
	registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

	// Next, register the BeanPostProcessors that implement Ordered.
	List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
	for (String ppName : orderedPostProcessorNames) {
		BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
		orderedPostProcessors.add(pp);
		if (pp instanceof MergedBeanDefinitionPostProcessor) {
			internalPostProcessors.add(pp);
		}
	}
<4>	//对实现Ordered接口的BeanPostProcessors进行排序
	sortPostProcessors(orderedPostProcessors, beanFactory);
	//注册
	registerBeanPostProcessors(beanFactory, orderedPostProcessors);

	// Now, register all regular BeanPostProcessors.
	List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
	for (String ppName : nonOrderedPostProcessorNames) {
		BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
		nonOrderedPostProcessors.add(pp);
		if (pp instanceof MergedBeanDefinitionPostProcessor) {
			internalPostProcessors.add(pp);
		}
	}
<5>	//注册没有实现排序接口的BeanPostProcessors
	registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

	// Finally, re-register all internal BeanPostProcessors.
<6>	//排序并注册内部BeanPostProcessors
	sortPostProcessors(internalPostProcessors, beanFactory);
	registerBeanPostProcessors(beanFactory, internalPostProcessors);

	// Re-register post-processor for detecting inner beans as ApplicationListeners,
	// moving it to the end of the processor chain (for picking up proxies etc).
	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
	}
//PostProcessorRegistrationDelegate.java

//具体注册方法
private static void registerBeanPostProcessors(
		ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {

	for (BeanPostProcessor postProcessor : postProcessors) {
	        //核心
		beanFactory.addBeanPostProcessor(postProcessor);
	}
}

这段代码看起来很长,但其实很简单。

  • <1>处,先从容器中获取所有BeanPostProcessors类型的BeanName。 在上一步我们已经通过@EnableAspectJAutoProxy注解把处理AOP的Bean->internalAutoProxyCreator给注册到容器中了,所以这里可以拿到。
  • <2>处,遍历所有BeanName,进行分类,分为4类。
    • 实现PriorityOrdered接口的BeanPostProcessors
    • 实现Ordered接口的BeanPostProcessors
    • 没有实现排序接口的BeanPostProcessors
    • Spring内部的BeanPostProcessors

    我们通过@EnableAspectJAutoProxy注解注册的internalAutoProxyCreator是属于第2类。

  • <3>处,排序并注册实现PriorityOrdered接口的BeanPostProcessors
  • <4>处,排序并注册实现Ordered接口的BeanPostProcessors
  • <5>处,注册没有实现排序接口的BeanPostProcessors
  • <6>处,排序并注册Spring内部的BeanPostProcessors

至此,我们已经把所有的BeanPostProcessors注册到了容器ApplicationContext中,包括我们专门处理AOP的BeanPostProcessors,接下来就可以使用了。

总结

总结一下到目前位置的步骤:

  • 通过@EnableAspectJAutoProxy注解把专门处理AOP的Bean注册到IOC容器中
  • 通过ApplicationContext.refresh()方法把专门处理AOP的BeanPostProcessors注册到IOC容器中。

那这两步之间有什么关联呢?

  • 首先,我们要把专门处理AOP的Bean注册到IOC容器中,交给spring来管理。-->@EnableAspectJAutoProxy
  • 然后,通过IOC容器的getBean()方法生成实例AnnotationAwareAspectJAutoProxyCreator。-->refresh()
  • 最后,因为该实例间接实现了BeanPostProcessors,而BeanPostProcessors想起作用的话,必须要调用beanFactory.addBeanPostProcessor()方法注册到容器中。-->refresh()

下篇文章我们将分析AnnotationAwareAspectJAutoProxyCreator类是怎么起作用的。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏IT那个小笔记

Spring基本使用

他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。

10820
来自专栏眯眯眼猫头鹰的小树杈

Mockito入门:如何在Spring中Mock部分对象

随着分布式应用的开发逐渐成为标配,多个微服务团队合作来完成垂直业务的开发成为了一种常态。微服务使得团队可以专注于自己的业务逻辑,在和下游依赖和上游对接的团队聚焦...

58010
来自专栏温安适的blog

Spring源码学习(四)在单值注入时如何按类型查找匹配的Bean 原

不知你是否也好奇,Spring是如果找到AService类型的Bean的呢?,此文,我们就聊聊这个->单值注入时如何按类型查找匹配的Bean.

8010
来自专栏happyJared

Spring Bean 作用域详解

在 Spring 中,那些组成应用程序的主体,以及由 Spring IOC 容器所管理的对象,被称之为 bean。简单地讲,bean 就是由 IOC 容器初始化...

9320
来自专栏软件开发-青出于蓝

Feign源码分析之FeignClientFactoryBean

     springcloud-openfeign-core-2.1.1.release.

9810
来自专栏IT大咖说

你以为反射真的不能为所欲为?至少JDK8以后很强

这里就不在赘述如何通过Method对象调用方法了。文章末尾会给出上一章节的地址。今天我们要研究的是Method如何获取方法参数这一块。看似简单却又是那么的传奇。...

8220
来自专栏Java架构学习路线

Spring、SpringMVC、SpringBoot、SpringCloud的区别与联系

Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。Spring使你能够编写更干净、更可管理、并且更易于测试的代码。

11030
来自专栏算法与编程之美

Java|怎样快速搭建一个spring boot项目

当我在网站搭建学习到一定阶段的时候,我们就会学习到springboot框架,我们怎么利用IDEA快速搭建一个spring boot项目呢?

12420
来自专栏知了一笑

Spring 框架基础(03):核心思想 IOC 容器总结,案例演示

7720
来自专栏SpringBoot 核心技术

MinBox Logging v1.0.0 使用文档

MinBox Logging是一款分布式、零侵入式的链路日志分析框架,支持SpringCloud微服务架构下配置使用,内部封装了RestTemplate、Ope...

7920

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励