SpringAOP中@EnableAspectJAutoProxy注解的作用

2023-05-16

文章目录

  • 前言
    • 从注解开始
    • Import注解
    • 封装对象、注入容器
  • AnnotationAwareAspectJAutoProxyCreator的作用
    • 类图
    • 回顾IOC对象初始化
    • 后置处理器
  • 总结

前言

如果要使用SpringAOP的功能,必须要添加一个@EnableAspectJAutoProxy注解,有了这个注解才能支持@Aspect等相关的一系列AOP注解的功能,这个注解就相当于在传统的xml配置文件中添加 <aop:aspectj-autoproxy>一样。

在学习SpringAOP相关的知识之前,建议一定要先搞清楚IOC相关的知识,如果不清楚的可以先阅读Spring专栏中IOC系列的文章。

从注解开始

接下来就来看一下@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}.
	 */
	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
	 */
	boolean exposeProxy() default false;

}

Import注解

看到@Import注解,直接跟进去。@Import注解不了解的可以看这篇文章,解析Spring中@Import的实现原理

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.
	 */
	// spring启动时,会调用到这个方法
	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		// 注册AnnotationAwareAspectJAutoProxyCreator
		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
		if (enableAspectJAutoProxy != null) {
			if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
			if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
				AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
			}
		}
	}

}
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
	return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}

@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
		BeanDefinitionRegistry registry, @Nullable Object source) {
	
	return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

封装对象、注入容器

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

	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

	if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
		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;
	}
	// 把AnnotationAwareAspectJAutoProxyCreator封装成RootBeanDefinition
	RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
	beanDefinition.setSource(source);
	beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
	beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
	// 把需要spring管理的bean放入beanDefinitionMap和beanDefinitionNames,分别是一个map和list容器。
	// spring在实例化bean时,就会遍历容器中的bean然后依次处理。
	registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
	return beanDefinition;
}

可以看出@EnableAspectJAutoProxy注解最主要的作用实际上就是通过@Import注解把AnnotationAwareAspectJAutoProxyCreator这个对象注入到spring容器中。

AnnotationAwareAspectJAutoProxyCreator的作用

类图

再看一下AnnotationAwareAspectJAutoProxyCreator类的结构图
在这里插入图片描述

AnnotationAwareAspectJAutoProxyCreator类间接的实现了BeanPostProcessor接口,实现这个接口的目的就是为了能够通过前置处理器、后置处理器完成一些事情。

回顾IOC对象初始化

这部分代码来自IOC初始化bean对象的过程

	protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			//调动前置处理器
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
			//调动后置处理器
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}
	@Override
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			//从刚刚的类图中可以看出AnnotationAwareAspectJAutoProxyCreator类或者继承类中,肯定有重写这个方法
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

后置处理器

分析一下这段流程,AnnotationAwareAspectJAutoProxyCreator因为间接继承了抽象类AbstractAutoProxyCreator,而这个抽象类又间接实现了BeanPostPorcessor接口,所以在每个bean对象最后初始化的时候,通过postProcessAfterInitialization方法完成了AOP相关的处理。

总结

本文就没有继续接着postProcessAfterInitialization方法继续深入,因为还是打算另起一篇文章着重分析,可以先下一个结论,这个方法就是扫描并解析aop注解的入口,如果当前bean对象符合配置的增加规则,最终就会返回实现增加方法的代理类。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SpringAOP中@EnableAspectJAutoProxy注解的作用 的相关文章

随机推荐

  • VS2019中编写C语言

    建立C 43 43 控制台程序 xff0c 将main函数所在的文件后缀名从cpp改成c xff0c 然后复制下列模板即可 xff1b 模板如下 xff1a dsa zju cpp 此文件包含 34 main 34 函数 程序执行将在此处开
  • CMake编译工程/第一个CMakeLists.txt(最详细案例演示)

    目录 在 linux 平台下使用 CMake 构建C C 43 43 工程的流程 当前项目目录结构 最小CMake工程 进入文件夹5 3 1 xff0c VScode打开项目文件5 3 1 在项目5 3 1顶层目录中 xff0c New F
  • 数据分析岗-机器学习相关知识

    1 解释共线性 我们进行回归分析需要了解每个自变量对因变量的单纯效应 xff0c 多重共线性就是说自变量间存在某种函数关系 xff0c 如果你的两个自变量间 xff08 X1和X2 xff09 存在函数关系 xff0c 那么X1改变一个单位
  • make,Makefile简易教程

    一 概述 make是一个类UNIX系统下的编译命令 xff0c 也可以理解为一个项目管理工具 xff0c 通过make可以按照自己指定的编译命令编译整个项目 xff0c 相当于将在命令行的编译命令按序执行 xff0c 省去了反复键入编译命令
  • @Transactional注解事务失效的七种原因分析

    64 Transactional是一种基于注解管理事务的方式 xff0c spring通过动态代理的方式为目标方法实现事务管理的增强 64 Transactional使用起来方便 xff0c 但也需要注意引起 64 Transactiona
  • C头文件相互包含

    今天遇见一个很头疼的事 xff0c 就是1 h头文件包含2 h xff0c 但是1 h里面却找不到2 h定义的一个结构体变量 最后排查发现是2 h里面又包含了1 h导致的 C语言中头文件包含的处理原则 之前一直以为 xff0c 一个 c文件
  • spring-kafka通过@KafkaListener实现消费者监听流程分析

    文章目录 主流程处理EnableKafka注解实现BeanPostProcessor接口postProcessAfterInitialization扫描 64 KafkaListenerregisterListenerContainer注册
  • c语言strrchr函数,strrchr_字符串 | Strings_C_参考手册_非常教程

    strrchr 在头文件中定义 char strrchr const char str xff0c int ch 通过 str 指向的以空字符结尾的字节字符串 每个字符解释为无符号字符 查找 ch 的最后一次出现 在转换为 char 之后
  • cmake中多级CMakeLists.txt调用

    文章目录 一 工程目录结构二 工程源代码2 1 上层目录2 1 1 cmaketest CMakeLists txt2 1 2 cmaketest main cpp2 1 3 cmaketest inc func1 hpp2 1 4 cma
  • c++ 函数后面加一个冒号的含义

    转载自 xff1a https www cnblogs com Allen rg p 11529949 html 冒号后面跟的是赋值 xff0c 这种写法是C 43 43 的特性 括号赋值只能在变量定义并初始化中 不能用在变量定义后再赋值
  • 理解死锁产生的四个必要条件

    死锁的定义 死锁是指两个或两个以上的进程在执行过程中 xff0c 由于竞争资源或者由于彼此通信而造成的一种阻塞的现象 xff0c 若无外力作用 xff0c 它们都将无法推进下去 此时称系统处于死锁状态或系统产生了死锁 xff0c 这些永远在
  • c++ error 2064: term does not evaluate to a function taking 1 arguments解决方法

    首先来看一个简单的示例 xff1a class T public T 61 default T 61 default int convertToInt double x return ceil x void doSomething vect
  • SZU_OnlineJudge_C++多态实验总结

    父类和子类的赋值问题 1 子类可以直接赋值给父类 如Cpoint 61 CRect 2 通过强制类型转换 xff0c 可以让父类赋值给子类 如 Cpoint Crect 61 cpoint 3 派生类对象指针 或引用 可以赋值给基类对象指针
  • 奇偶校验码原来这样算!!!

    数据传输的正误 数据发出方A像数据接收方B发送一串加密过后的情书 但是信息在传输过程中可能发生错误 比如某人截获并修改内容 一段美好的爱情就结束了 手动狗头 在电路传输中 电信号很容易受到干扰 电梯打电话你就知道了 于是我们要在原有的信息之
  • 手把手教你打造自己的4G数传模块

    如何低成本打造自己的4G数传模块 大家好 xff0c 现在给大家介绍一种简单的方法打造自己的4G数传 目录 一 背景 1 二 材料清单 2 2 1 G43模块 2 2 2 PSHAT接口板 5 三 使用方法 5 3 1 硬件连接 6 3 2
  • .error: C++ requires a type specifier for all declarations

    error C 43 43 requires a type specifier for all declarations 出错原因 xff1a 代码片段没有写在函数中 解决方法 xff1a 将代码片段写进函数中
  • 4g图传数传实测

    又一位客户极高的评价 xff0c 为了反馈大家 xff0c 从文章看到的并且加我qq1767893964 xff0c 备注gslink购买者 xff0c 毕淘宝搜索下单的有很大的优惠哦 下面是客户的测试 xff1a 最近南京天气开始变暖 x
  • Unable to locate package错误解决办法

    Ubuntu下执行apt install python pip得到如下错误提示 xff1a Reading package lists Done Building dependency tree Reading state informat
  • 树莓派编译卡死用交换空间问题的解决

    今天在树莓派编译一个ros包时发现 xff0c 每次编译到后速度会特别慢并且卡死 xff0c 经过各种尝试 xff0c 增加2G交换空间后才解决问题 xff0c 编译只花了不到10s xff0c 之前折腾了大半天啊 树莓派3B默认的swap
  • SpringAOP中@EnableAspectJAutoProxy注解的作用

    文章目录 前言从注解开始Import注解封装对象 注入容器 AnnotationAwareAspectJAutoProxyCreator的作用类图回顾IOC对象初始化后置处理器 总结 前言 如果要使用SpringAOP的功能 xff0c 必