Spring

Spring AOP 处理流程概述

Spring AOP 处理流程概述

D瓜哥
AOP 是 Spring 框架的最核心的两个功能之一,在前面的 Spring 启动流程概述 和 Spring Bean 生命周期概述 两篇文章中,分别介绍了 Spring 启动过程和 Spring Bean 的生命周期,对 IoC 有了一个细致介绍。这里来细致分析一下 Spring AOP 的实现原理和处理流程。 基本概念 先来了解几个基本概念,D瓜哥私以为这些概念是 AOP 中最核心的内容,了解了基本概念,可以说基本上掌握了一半的 AOP 内容。 学习概念最权威的地方,当然就是官方文档。所以,这些概念可以在 Spring Framework Documentation: AOP Concepts 中看到最权威的介绍。 Join point(连接点): 所谓的连接点是指那些被拦截到的点。在 Spring 中,连接点指的是方法,因为 Spring 只支持方法类型的连接点。在 Spring 中,使用 Pointcut(切入点): 所谓的切入点,是指要对哪些 Join point(连接点) 进行拦截的定义。如果 Join point(连接点) 是全集,那么 Pointcut(切入点) 就是被选中的子集。写 AOP 代码的时候,一般是用 Pointcut(切入点) 表达式进行对 Join point(连接点) 进行选择。 Advice(通知/增强): 所谓的通知就是指拦截到 Join point(连接点) 之后所要做的事情。通知根据作用位置不同,又细分为: Before advice(前置通知): 在 Join point(连接点) 之前运行的通知。这种通知,不能阻止执行流程继续到 Join point(连接点)。
Spring Bean 生命周期概述

Spring Bean 生命周期概述

D瓜哥
在 Spring 启动流程概述 中,分析了 Spring 的启动流程。本文就来说明一下 Spring Bean 整个生命周期。如果有不清楚的地方,可以参考上文的“附录:启动日志”。 直接上图:Spring Bean 生命周期流程图。内容较多,图片文字偏小,请放大看(矢量图,可以任意放大): 图 1. Spring Bean 生命周期流程图 下面是文字说明。 Bean 生命周期简述 调用 InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation,主要是判断 AnnotationAwareAspectJAutoProxyCreator 是否可以生成代理。 调用构造函数 调用 MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition,主要是通过 CommonAnnotationBeanPostProcessor、 AutowiredAnnotationBeanPostProcessor 收集依赖信息。 InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation,这步什么也没做。 调用 InstantiationAwareBeanPostProcessor#postProcessProperties,主要是完成依赖注入。 调用 AutowiredAnnotationBeanPostProcessor#setBeanFactory,注入 BeanFactory 等相关信息。 调用 BeanPostProcessor#postProcessBeforeInitialization,主要是注入 ApplicationContext 等相关信息。 调用 InitializingBean#afterPropertiesSet、 init-method 方法 调用 BeanPostProcessor#postProcessAfterInitialization,主要是生成 AOP 代理类。 Bean 生命周期详解 从 getBean() 方法获取 Bean 时,如果缓存中没有对应的 Bean,则会创建 Bean,整个流程如下: InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation — 目前有如下四个: ImportAwareBeanPostProcessor — 继承父类实现,无所事事。 AnnotationAwareAspectJAutoProxyCreator — 继承父类实现,判断是否属于基础切面类,如果有指定的 Target 则生成代理。
Spring 启动流程概述

Spring 启动流程概述

D瓜哥
对于 Spring 启动流程和 Bean 的生命周期,总有一些小地方搞的不是很清楚,干脆直接通过修改代码增加日志输出,使用断点单步调试,把整个流程捋顺了一点点的。 除了加载配置文件或者基础配置类外,Spring 的启动过程几乎都被封装在 AbstractApplicationContext#refresh 方法中,可以说弄清楚了这个方法的执行过程,就摸清楚了 Spring 启动全流程,下面的流程分析也是以这个方法为骨架来展开的。 流程概要 下面完整流程有些太复杂,所以,提炼一个简要的过程,方便糊弄面试官,哈哈哈😆 创建容器,读取 applicationContext.register(Config.class) 指定的配置。 准备 BeanFactory,注册容器本身和 BeanFactory 实例,以及注册环境配置信息等。 执行 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry 注册 BeanDefinition。有三点需要注意: 目前只有一个 ConfigurationClassPostProcessor 实现类,Spring 中大量的 Bean 都是在这一步被该类注册到容器中的。 执行顺序是 ① PriorityOrdered ② Ordered ③ 普通的顺序来执行 在执行上一步时,如果发现注册了 BeanDefinitionRegistryPostProcessor 类型的 Bean,就会在循环里继续调用 postProcessBeanDefinitionRegistry 方法。MyBATIS 和 Spring 整合的 MapperScannerConfigurer 类就是在这一步执行的。 执行 BeanFactoryPostProcessor#postProcessBeanFactory 方法。目前只有一个 ConfigurationClassPostProcessor 实现类。 注册 CommonAnnotationBeanPostProcessor 和 AutowiredAnnotationBeanPostProcessor 为 BeanPostProcessor。 注册 ApplicationEventMulticaster,用于广播事件的。 注册 ApplicationListener 预加载以及注册所有非懒加载的 Bean 启动时序图 Spring 启动流程的时序图如下: 图 1.
Spring 扩展点实践:整合 MyBATIS

Spring 扩展点实践:整合 MyBATIS

D瓜哥
在上一篇文章 Spring 扩展点概览及实践 中介绍了 Spring 内部存在的扩展点。学以致用,现在来分析一下 Spring 与 MyBATIS 的整合流程。 示例程序 为了方便分析源码,先根据官方文档 mybatis-spring – MyBatis-Spring | Getting Started 搭建起一个简单实例。 数据库方面,直接使用功能了 MySQL 示例数据库: MySQL : Employees Sample Database,需要的话,自行下载。 package com.diguage.truman.mybatis; import com.mysql.cj.jdbc.Driver; import com.zaxxer.hikari.HikariDataSource; import org.apache.ibatis.session.Configuration; import org.junit.jupiter.api.Test; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import javax.sql.DataSource; /** * @author D瓜哥, https://www.diguage.com/ * @since 2020-05-29 17:11 */ public class MybatisTest { @Test public void test() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.
Spring 扩展点概览及实践

Spring 扩展点概览及实践

D瓜哥
学习 Spring 代码,最重要的是掌握 Spring 有哪些扩展点,可以利用这些扩展点对 Spring 做什么扩展操作。说得更具体一点,如果自己开发一个框架,如何与 Spring 进行整合,如果对 Spring 的扩展点有一个比较清晰的认识,势必会事半功倍。 @Import 先来看一下 @Import 注解的定义: @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Import { /** * {@link Configuration @Configuration}, {@link ImportSelector}, * {@link ImportBeanDefinitionRegistrar}, or regular component classes to import. */ Class<?>[] value(); } 从声明可以看出,使用时,只需要指定 Class 实例即可;从方法的文档中可以看出,Class 实例可以分为三种:ImportSelector、ImportBeanDefinitionRegistrar 和常规组件类。示例如下: @Configuration @Import(LogImportSelector.class) public static class Config { } 在 org.springframework.context.annotation.ConfigurationClassParser#processImports 方法中,集中了对 @Import 注解的处理。从代码可以非常清晰地看出,分了三种情况进行处理: ImportSelector ImportBeanDefinitionRegistrar 常规组件 Class 下面分别对其进行介绍。 ImportSelector 先来看一下 ImportSelector 接口的定义: