Spring知识体系总结本文基于 Spring 框架核心原理系统整理 IOC、AOP、事务、循环依赖、SpringMVC 等核心知识点适合面试复习与源码学习。目录Spring知识体系总结一、Spring 核心概述1.1 配置方式与容器启动1.2 Spring 扫描机制1.3 BeanDefinition声明式 vs 编程式二、Bean 的生命周期从生成到销毁2.1 完整生命周期流程2.2 推断构造方法2.3 实例化方式2.4 Aware 接口2.5 Bean 的销毁三、依赖注入DI3.1 手动注入3.2 XML 的 autowire 自动注入3.3 Autowired 自动注入3.4 Resource 自动注入四、循环依赖与三级缓存4.1 问题出现4.2 三级缓存机制4.3 为什么需要三级缓存单级不能解决吗4.4 createBean 与 getBean 的相互调用4.5 关键源码方法五、Spring AOP5.1 核心概念5.2 动态代理方式5.3 CGLIB 原理5.4 代理工厂与实现方式5.5 Advisor六、Spring 事务6.1 事务本质6.2 基本执行原理6.3 事务传播机制6.4 事务失效场景七、Spring 整合 MyBatis7.1 整合核心思想7.2 Spring-MyBatis 执行流程7.3 一级缓存失效问题八、SpringMVC8.1 原生 MVC 弊端8.2 SpringMVC 核心组件8.3 父子容器九、手写 Spring 心得注解与工具9.1 Target 注解9.2 RetentionPolicy 保留策略9.3 Scope 作用域9.4 类型转化9.5 元数据读取器一、Spring 核心概述1.1 配置方式与容器启动两种配置方式AnnotationConfigApplicationContext注解配置可指定扫描路径、直接定义 BeanClassPathXmlApplicationContextXML 形式配置扫描路径ApplicationContext 继承体系类/接口功能ConfigurableApplicationContext增加事件监听器、BeanFactoryPostProcessor、Environment 设置AbstractApplicationContext实现 ConfigurableApplicationContextGenericApplicationContext继承 AbstractApplicationContext实现 BeanDefinitionRegistry可注册 BeanDefinitionAnnotationConfigRegistry处理Configuration、Bean支持扫描AnnotationConfigApplicationContext拥有以上全部功能核心功能扫描 Bean、构建容器、资源加载、获取运行时环境、事件发布。启动流程构造 BeanFactory解析配置ComponentScan等国际化初始化ApplicationEventMulticaster将ApplicationListener添加到ApplicationContext创建非懒加载的单例 Bean调用 Lifecycle Bean 的start()发布ContextRefreshedEvent事件1.2 Spring 扫描机制解析AppConfig.class得到扫描路径遍历扫描路径下的所有 Java 类发现Component、Service等注解则记录到BeanDefinitionMapSpring 根据规则生成 beanName 作为 key当前类作为 value为什么不使用多线程扫描扫描是一次性操作性能收益小风险大少量类提升不明显大量类受限于 I/O 或类加载器瓶颈Spring 启动瓶颈不在扫描而在类加载、Bean 实例化、注解解析、AOP 代理生成使用索引indexer、延迟加载、减少扫描范围等方式更有效1.3 BeanDefinition声明式 vs 编程式声明式定义使用Bean、Component等注解定义编程式定义用代码从上下文获取 Bean、用代码写事务无论哪种方式最终都会被 Spring 解析为 BeanDefinition 对象放入容器。生成 BeanDefinition 的过程Spring 扫描包路径读取 class 文件使用ASM 技术非 JVM 加载转化为元数据提取类名、接口名、注解等信息二、Bean 的生命周期从生成到销毁2.1 完整生命周期流程1. InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() [实例化前] 2. 实例化推断构造方法 3. MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition() 4. InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() [实例化后] 5. 自动注入 6. InstantiationAwareBeanPostProcessor.postProcessProperties() [处理属性] 7. Aware 接口回调BeanNameAware、BeanClassLoaderAware、BeanFactoryAware 8. BeanPostProcessor.postProcessBeforeInitialization() [初始化前] 9. 初始化PostConstruct → InitializingBean.afterPropertiesSet() → init-method 10. BeanPostProcessor.postProcessAfterInitialization() [初始化后AOP在此] 11. 使用 Bean 12. 销毁PreDestroy → DisposableBean.destroy() → destroy-method简化版[实例化] ↓ [Autowired 注入] ↓ [Aware 回调] ↓ [PostConstruct] ↓ [InitializingBean.afterPropertiesSet()] ↓ [initMethodName()] ↓ [BeanPostProcessor.afterInitialization()] ← AOP 在此阶段实现 ↓ [使用 Bean] ↓ [销毁]2.2 推断构造方法场景结果有默认构造选默认只有一个构造选唯一有多个构造且有默认无参选无参多个构造且无无参报错多个构造中某个有Autowired选该注解方法2.3 实例化方式Supplier创建对象工厂方法factory-bean/factory-method类似Bean推断构造方法最常用反射实例化若未找到构造方法则寻找Lookup注解获取实例2.4 Aware 接口Aware 接口作用BeanNameAware回传 beanNameBeanClassLoaderAware回传 classLoaderBeanFactoryAware回传 beanFactoryApplicationContextAware回传 ApplicationContext通过 ApplicationContextAwareProcessor 处理2.5 Bean 的销毁发布ContextClosedEvent事件通知容器即将关闭调用LifecycleProcessor.onClose()处理 SmartLifecycle Bean销毁单例 BeandisposableBean 从单例池移除调用destroy()方法按依赖顺序递归销毁清空用户手动设置的单例 Bean销毁时的设计模式Spring 使用DisposableBeanAdapter将DisposableBean、AutoCloseable等接口适配为统一的DisposableBean接口涉及适配器模式 策略模式 工厂模式。三、依赖注入DI3.1 手动注入set 方法注入构造方法注入3.2 XML 的 autowire 自动注入模式说明byType按类型注入byName按名称注入constructor构造方法注入default默认no不注入需要 set 方法构造方法注入相当于 byType byName。3.3 Autowired 自动注入Autowired是byType 和 byName 的结合位置规则属性上先根据属性类型找找到多个再根据属性名确定构造方法上先根据参数类型找找到多个再根据参数名确定set 方法上先根据参数类型找找到多个再根据参数名确定寻找注入点流程遍历当前类所有属性字段查看是否存在Autowired、Value、Inject存在则为注入点static 字段不注入static 属于类本身Spring 依赖注入面向对象无法设置类级别成员获取Autowired的 required 属性值构造AutowiredFieldElement存入currElements遍历所有方法判断是否是桥接方法找到原方法查看方法是否有注解static 不注入构造AutowiredMethodElement存入currElements遍历父类直到没有父类将currElements封装成InjectionMetadata缓存桥接方法Java 泛型通过类型擦除实现编译器为保证子类重写父类泛型方法的多态性会生成桥接方法。处理时需要找到对应的原方法。注入点注入字段注入字段封装为DependencyDescriptor→BeanFactory.resolveDependency()查找 → 反射赋值Set 方法注入参数封装为MethodParameter→DependencyDescriptor→resolveDependency()→ 反射执行方法3.4 Resource 自动注入特性AutowiredResource默认方式byTypebyName找不到匹配requiredfalse 注入 null否则抛异常回退到 byType流程判断 BeanFactory 中是否存在注入点名字对应的 Bean存在 → 按 name 注入不存在 → 判断是否指定了 name 属性指定了 → 按 name 注入未指定 → 和Autowired一致先 byType 后 byName四、循环依赖与三级缓存4.1 问题出现Spring 中循环依赖是问题因为 Bean 不是简单 new 出来的而是根据生命周期创建的ABean 创建 → 依赖 B 属性 → 触发 BBean 创建 → B 依赖 A 属性 → 需要 ABean但 A 还在创建中4.2 三级缓存机制缓存级别名称作用一级缓存singletonObjects已完成初始化的单例 Bean可直接使用二级缓存earlySingletonObjects提前暴露的早期 Bean已实例化但未填充属性三级缓存singletonFactories用于生成早期 Bean的工厂对象ObjectFactory循环依赖解决示例A 依赖 BB 又依赖 A创建 A实例化 A → 将 A 的工厂放入三级缓存注入 B发现需要 B转而创建 B创建 B实例化 B → 发现需要 A → 从三级缓存获取 A 的早期引用 → 移到二级缓存继续初始化 B完成注入 A返回继续初始化 A4.3 为什么需要三级缓存单级不能解决吗由于AOP 的存在循环依赖用单缓存无法解决代理对象的问题B 注入 A 的原始对象时若 A 经过 AOP会导致 B 里的 A 是原始对象而真正的 A 应该是代理后对象则 B 依赖的 A 和最终的 A不是同一个对象singletonFactories 的作用存的是ObjectFactory函数式接口支持 Lambda() → getEarlyBeanReference(beanName, mbd, bean)作用设置原始对象 →将原始对象进行 AOP 处理完整创建逻辑A 创建时A 原始对象存入singletonFactoriesA 创建需要 B去创建 B创建 B 需要 A根据 A 的 beanName 去singletonFactories获取ObjectFactory执行getEarlyBeanReference获取 A 原始对象的代理对象存入earlySingletonObjectsB 创建完成注入 A 的代理对象A 继续初始化由于参与过 AOP不会重复进行通过earlyProxyReferences判断最后将 A 放入singletonObjects4.4 createBean 与 getBean 的相互调用createBean() → 调用 getBean() → 注入依赖 ↑ ↓ 按需创建 ← getBean() 调用 createBean()createBean()调用getBean()为字段注入依赖getBean()调用createBean()Bean 未实例化时按需创建单例已创建则直接返回缓存三级缓存机制支持循环依赖的解决4.5 关键源码方法org.springframework.context.support.AbstractApplicationContext#refresh (入口) org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization org.springframework.beans.factory.config.ConfigurableListableBeanFactory#preInstantiateSingletons org.springframework.beans.factory.support.AbstractBeanFactory#getBean (万恶之源) org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingletonFactory org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean五、Spring AOP5.1 核心概念概念说明Aspect切面可以定义 PointcutJoin point连接点某个方法Advice通知连接点上的具体动作日志、异常处理等Pointcut切点匹配一个或多个连接点Introduction使用DeclareParents给匹配的类添加接口默认实现Target object目标对象被代理的对象AOP proxy代理对象Weaving织入创建代理对象的动作5.2 动态代理方式特性JDK 动态代理CGLIB 动态代理机制基于接口反射实现基于类继承机制实现适用对象必须实现至少一个接口不要求实现接口不能代理 final 方法/类性能足够好实现简单某些场景更高但代理对象更复杂灵活性基于接口更灵活基于继承可能受限Spring AOP 选择策略优先 JDK 动态代理目标对象没有实现接口则自动切换到 CGLIB。5.3 CGLIB 原理Enhancer是 CGLIB 提供的类用于运行时动态生成类的子类被代理类是父类代理类是子类代理对象就是代理类的实例常用于Spring AOP、事务管理、日志记录可配置多个回调自定义不同方法的回调规则代理的含义在不改变原始对象的前提下对其进行功能增强和行为拦截。CGLIB AOP 大致流程生成代理类UserServiceProxy继承UserService代理类重写父类方法如test()代理类包含target属性被代理对象执行代理方法逻辑Before切面逻辑 → 调用target.test()5.4 代理工厂与实现方式ProxyFactory封装了两种代理方式根据是否实现接口选择实现了用 JDK否则用 CGLIB。代理 Bean 的实现方式方式说明ProxyFactoryBean只针对单个 Bean 代理BeanNameAutoProxyCreator通过 bean 名字自动代理DefaultAdvisorAutoProxyCreator找所有 Advisor根据 PointCut 和 Advice 代理注解形式常用AspectComponent5.5 AdvisorPointcut指定代理规则匹配类中的方法AdviceBefore Advice方法之前执行After returning advicereturn 后执行After throwing advice抛异常后执行After (finally) advicefinally 后执行Around advice功能最强可自定义执行顺序六、Spring 事务6.1 事务本质Spring 事务基于AOP 实现失效原因核心在于未被成功代理就使用。EnableTransactionManagement作用AutoProxyRegistrar开启自动代理ProxyTransactionManagementConfiguration判断Transactional注解并进行代理6.2 基本执行原理Bean 执行创建生命周期匹配 AdvisorTransactional注解若存在Bean 需要动态代理产生代理对象代理对象执行再次匹配Transactional执行TransactionInterceptor.invoke()新建数据库连接修改autocommit为false执行业务方法无异常提交有异常回滚6.3 事务传播机制传播机制说明REQUIRED默认共享事务REQUIRES_NEW完全独立a、b 独立提交SUPPORTS存在事务则加入否则非事务运行REQUIRES_NEW 执行流程a() 调用 b()代理对象执行 a()事务管理器新建连接 a连接 a 的 autocommit 改成 false设置到 ThreadLocal执行 a() 中的 SQL执行 a() 调用 b() →挂起连接 a从 ThreadLocal 移除新建连接 bautocommit 改成 false设置到 ThreadLocal执行 b() 中的 SQLb() 执行完从 ThreadLocal 拿连接 b提交恢复连接 a挂起资源重新设置到 ThreadLocala() 执行完ThreadLocal 中连接 a提交6.4 事务失效场景类内部调用类本身调用Transactional方法未经代理直接调用事务失效其他待补充…七、Spring 整合 MyBatis7.1 整合核心思想将其他框架中所产生的对象放入 Spring 容器中。7.2 Spring-MyBatis 执行流程Spring 嵌入 MyBatis 部分通过MapperScan导入MapperScannerRegistrarMapperScannerRegistrar实现ImportBeanDefinitionRegistrarSpring 启动时调用registerBeanDefinitions注册MapperScannerConfigurer类型的 BeanDefinitionMapperScannerConfigurer实现BeanDefinitionRegistryPostProcessor调用postProcessBeanDefinitionRegistry生成ClassPathMapperScanner进行扫描扫描到的 BeanDefinition 修改为MapperFactoryBeanAutowireMode 调整为byTypeSpring 基于 BeanDefinition 创建 Bean每个 Mapper 对应一个 FactoryBeanMapperFactoryBean.getObject()调用getSqlSession()得到 sqlSession生成 Mapper 接口代理对象MyBatis 执行 SQL 部分开启事务塞入LinkedHashSet利用事务管理器创建数据库连接利用 MyBatis 生成的 Mapper 代理对象执行 SQL代理对象执行方法时进入SqlSessionTemplate的SqlSessionInterceptor取 sqlSession 对象若为空则在DefaultSqlSessionFactory创建判断是否开启事务若开启事务将 sqlSession 存入resourcesThreadLocal利用 sqlSession 执行 SQL7.3 一级缓存失效问题MyBatis 一级缓存基于sqlSession实现同一个 sqlSession 执行 SQL 可利用一级缓存Spring 整合后若方法上没有Transactional注解每执行一个 SQL 都会新生成一个 SqlSession一级缓存失效开启 Spring 事务时事务中的多个 SQL 使用同一个 sqlSession一级缓存生效不是 bug是机制没有事务则 SQL 单独执行生命周期过短八、SpringMVC8.1 原生 MVC 弊端JSP Servlet JavaBeanXML 配置 Servlet 映射开发效率低入侵性强分发给不同方法麻烦、参数解析麻烦、数据响应麻烦8.2 SpringMVC 核心组件组件作用DispatcherServlet前端调度器负责请求拦截分发到控制器HandlerMapping根据请求 URL 和RequestMapping映射HandlerAdapter调用 Handler 具体方法返回视图名ModelAndView封装视图名、request 域数据ViewResolver根据 ModelAndView 找具体 View 对象View视图渲染8.3 父子容器Spring 和 SpringMVC 整合涉及父子容器概念先去父容器找再找子容器父容器 service 无法访问子容器 controller子容器可以访问父容器面试题Spring 和 SpringMVC 一定需要父子容器吗不一定如 Spring Boot原因单一职责、规范架构、方便切换、节省重复 Bean 创建是否可以把所有 Bean 都通过 Spring 容器管理不可以会导致请求接口 404。SpringMVC 初始化时无法根据 Controller 注册 HandlerMethod没有查找父容器的 bean是否可以把所有 Bean 使用 SpringMVC 子容器管理可以但不推荐可能导致 AOP 误配失效九、手写 Spring 心得注解与工具9.1 Target 注解类型作用范围ElementType.TYPE类、接口、枚举、记录ElementType.FIELD字段、枚举常量ElementType.METHOD方法不含构造方法ElementType.PARAMETER方法或构造方法参数ElementType.CONSTRUCTOR构造方法ElementType.LOCAL_VARIABLE局部变量ElementType.ANNOTATION_TYPE注解接口ElementType.PACKAGE包声明ElementType.MODULE模块声明Java 9ElementType.RECORD_COMPONENTrecord 组件Java 169.2 RetentionPolicy 保留策略策略说明SOURCE仅保留在源文件编译后遗弃CLASS保留到 class 文件JVM 加载时遗弃默认RUNTIME保留到 class 文件JVM 加载后仍然存在9.3 Scope 作用域作用域说明singleton单例模式容器中只创建一次默认prototype原型模式每次请求都创建新实例request每个 HTTP 请求创建新实例Web 环境session每个 HTTP 会话创建新实例Web 环境工具方法beanName Introspector.decapitalize(clazz.getSimpleName())—— 首字母转小写9.4 类型转化Spring 注入Value(xxx)到private User user字段时字符串xxx是配置中的原始值Spring 检测到目标字段是 User 类型使用内部注册的ConversionService尝试转换如果存在ConverterString, User调用该转换器完成转换9.5 元数据读取器MetadataReader、ClassMetadata、AnnotationMetadata使用ASM 技术解析类的元数据类名、方法、注解等无需 JVM 加载类本文持续更新中如有错误或补充欢迎留言交流
Spring个人知识体系总结
Spring知识体系总结本文基于 Spring 框架核心原理系统整理 IOC、AOP、事务、循环依赖、SpringMVC 等核心知识点适合面试复习与源码学习。目录Spring知识体系总结一、Spring 核心概述1.1 配置方式与容器启动1.2 Spring 扫描机制1.3 BeanDefinition声明式 vs 编程式二、Bean 的生命周期从生成到销毁2.1 完整生命周期流程2.2 推断构造方法2.3 实例化方式2.4 Aware 接口2.5 Bean 的销毁三、依赖注入DI3.1 手动注入3.2 XML 的 autowire 自动注入3.3 Autowired 自动注入3.4 Resource 自动注入四、循环依赖与三级缓存4.1 问题出现4.2 三级缓存机制4.3 为什么需要三级缓存单级不能解决吗4.4 createBean 与 getBean 的相互调用4.5 关键源码方法五、Spring AOP5.1 核心概念5.2 动态代理方式5.3 CGLIB 原理5.4 代理工厂与实现方式5.5 Advisor六、Spring 事务6.1 事务本质6.2 基本执行原理6.3 事务传播机制6.4 事务失效场景七、Spring 整合 MyBatis7.1 整合核心思想7.2 Spring-MyBatis 执行流程7.3 一级缓存失效问题八、SpringMVC8.1 原生 MVC 弊端8.2 SpringMVC 核心组件8.3 父子容器九、手写 Spring 心得注解与工具9.1 Target 注解9.2 RetentionPolicy 保留策略9.3 Scope 作用域9.4 类型转化9.5 元数据读取器一、Spring 核心概述1.1 配置方式与容器启动两种配置方式AnnotationConfigApplicationContext注解配置可指定扫描路径、直接定义 BeanClassPathXmlApplicationContextXML 形式配置扫描路径ApplicationContext 继承体系类/接口功能ConfigurableApplicationContext增加事件监听器、BeanFactoryPostProcessor、Environment 设置AbstractApplicationContext实现 ConfigurableApplicationContextGenericApplicationContext继承 AbstractApplicationContext实现 BeanDefinitionRegistry可注册 BeanDefinitionAnnotationConfigRegistry处理Configuration、Bean支持扫描AnnotationConfigApplicationContext拥有以上全部功能核心功能扫描 Bean、构建容器、资源加载、获取运行时环境、事件发布。启动流程构造 BeanFactory解析配置ComponentScan等国际化初始化ApplicationEventMulticaster将ApplicationListener添加到ApplicationContext创建非懒加载的单例 Bean调用 Lifecycle Bean 的start()发布ContextRefreshedEvent事件1.2 Spring 扫描机制解析AppConfig.class得到扫描路径遍历扫描路径下的所有 Java 类发现Component、Service等注解则记录到BeanDefinitionMapSpring 根据规则生成 beanName 作为 key当前类作为 value为什么不使用多线程扫描扫描是一次性操作性能收益小风险大少量类提升不明显大量类受限于 I/O 或类加载器瓶颈Spring 启动瓶颈不在扫描而在类加载、Bean 实例化、注解解析、AOP 代理生成使用索引indexer、延迟加载、减少扫描范围等方式更有效1.3 BeanDefinition声明式 vs 编程式声明式定义使用Bean、Component等注解定义编程式定义用代码从上下文获取 Bean、用代码写事务无论哪种方式最终都会被 Spring 解析为 BeanDefinition 对象放入容器。生成 BeanDefinition 的过程Spring 扫描包路径读取 class 文件使用ASM 技术非 JVM 加载转化为元数据提取类名、接口名、注解等信息二、Bean 的生命周期从生成到销毁2.1 完整生命周期流程1. InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() [实例化前] 2. 实例化推断构造方法 3. MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition() 4. InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() [实例化后] 5. 自动注入 6. InstantiationAwareBeanPostProcessor.postProcessProperties() [处理属性] 7. Aware 接口回调BeanNameAware、BeanClassLoaderAware、BeanFactoryAware 8. BeanPostProcessor.postProcessBeforeInitialization() [初始化前] 9. 初始化PostConstruct → InitializingBean.afterPropertiesSet() → init-method 10. BeanPostProcessor.postProcessAfterInitialization() [初始化后AOP在此] 11. 使用 Bean 12. 销毁PreDestroy → DisposableBean.destroy() → destroy-method简化版[实例化] ↓ [Autowired 注入] ↓ [Aware 回调] ↓ [PostConstruct] ↓ [InitializingBean.afterPropertiesSet()] ↓ [initMethodName()] ↓ [BeanPostProcessor.afterInitialization()] ← AOP 在此阶段实现 ↓ [使用 Bean] ↓ [销毁]2.2 推断构造方法场景结果有默认构造选默认只有一个构造选唯一有多个构造且有默认无参选无参多个构造且无无参报错多个构造中某个有Autowired选该注解方法2.3 实例化方式Supplier创建对象工厂方法factory-bean/factory-method类似Bean推断构造方法最常用反射实例化若未找到构造方法则寻找Lookup注解获取实例2.4 Aware 接口Aware 接口作用BeanNameAware回传 beanNameBeanClassLoaderAware回传 classLoaderBeanFactoryAware回传 beanFactoryApplicationContextAware回传 ApplicationContext通过 ApplicationContextAwareProcessor 处理2.5 Bean 的销毁发布ContextClosedEvent事件通知容器即将关闭调用LifecycleProcessor.onClose()处理 SmartLifecycle Bean销毁单例 BeandisposableBean 从单例池移除调用destroy()方法按依赖顺序递归销毁清空用户手动设置的单例 Bean销毁时的设计模式Spring 使用DisposableBeanAdapter将DisposableBean、AutoCloseable等接口适配为统一的DisposableBean接口涉及适配器模式 策略模式 工厂模式。三、依赖注入DI3.1 手动注入set 方法注入构造方法注入3.2 XML 的 autowire 自动注入模式说明byType按类型注入byName按名称注入constructor构造方法注入default默认no不注入需要 set 方法构造方法注入相当于 byType byName。3.3 Autowired 自动注入Autowired是byType 和 byName 的结合位置规则属性上先根据属性类型找找到多个再根据属性名确定构造方法上先根据参数类型找找到多个再根据参数名确定set 方法上先根据参数类型找找到多个再根据参数名确定寻找注入点流程遍历当前类所有属性字段查看是否存在Autowired、Value、Inject存在则为注入点static 字段不注入static 属于类本身Spring 依赖注入面向对象无法设置类级别成员获取Autowired的 required 属性值构造AutowiredFieldElement存入currElements遍历所有方法判断是否是桥接方法找到原方法查看方法是否有注解static 不注入构造AutowiredMethodElement存入currElements遍历父类直到没有父类将currElements封装成InjectionMetadata缓存桥接方法Java 泛型通过类型擦除实现编译器为保证子类重写父类泛型方法的多态性会生成桥接方法。处理时需要找到对应的原方法。注入点注入字段注入字段封装为DependencyDescriptor→BeanFactory.resolveDependency()查找 → 反射赋值Set 方法注入参数封装为MethodParameter→DependencyDescriptor→resolveDependency()→ 反射执行方法3.4 Resource 自动注入特性AutowiredResource默认方式byTypebyName找不到匹配requiredfalse 注入 null否则抛异常回退到 byType流程判断 BeanFactory 中是否存在注入点名字对应的 Bean存在 → 按 name 注入不存在 → 判断是否指定了 name 属性指定了 → 按 name 注入未指定 → 和Autowired一致先 byType 后 byName四、循环依赖与三级缓存4.1 问题出现Spring 中循环依赖是问题因为 Bean 不是简单 new 出来的而是根据生命周期创建的ABean 创建 → 依赖 B 属性 → 触发 BBean 创建 → B 依赖 A 属性 → 需要 ABean但 A 还在创建中4.2 三级缓存机制缓存级别名称作用一级缓存singletonObjects已完成初始化的单例 Bean可直接使用二级缓存earlySingletonObjects提前暴露的早期 Bean已实例化但未填充属性三级缓存singletonFactories用于生成早期 Bean的工厂对象ObjectFactory循环依赖解决示例A 依赖 BB 又依赖 A创建 A实例化 A → 将 A 的工厂放入三级缓存注入 B发现需要 B转而创建 B创建 B实例化 B → 发现需要 A → 从三级缓存获取 A 的早期引用 → 移到二级缓存继续初始化 B完成注入 A返回继续初始化 A4.3 为什么需要三级缓存单级不能解决吗由于AOP 的存在循环依赖用单缓存无法解决代理对象的问题B 注入 A 的原始对象时若 A 经过 AOP会导致 B 里的 A 是原始对象而真正的 A 应该是代理后对象则 B 依赖的 A 和最终的 A不是同一个对象singletonFactories 的作用存的是ObjectFactory函数式接口支持 Lambda() → getEarlyBeanReference(beanName, mbd, bean)作用设置原始对象 →将原始对象进行 AOP 处理完整创建逻辑A 创建时A 原始对象存入singletonFactoriesA 创建需要 B去创建 B创建 B 需要 A根据 A 的 beanName 去singletonFactories获取ObjectFactory执行getEarlyBeanReference获取 A 原始对象的代理对象存入earlySingletonObjectsB 创建完成注入 A 的代理对象A 继续初始化由于参与过 AOP不会重复进行通过earlyProxyReferences判断最后将 A 放入singletonObjects4.4 createBean 与 getBean 的相互调用createBean() → 调用 getBean() → 注入依赖 ↑ ↓ 按需创建 ← getBean() 调用 createBean()createBean()调用getBean()为字段注入依赖getBean()调用createBean()Bean 未实例化时按需创建单例已创建则直接返回缓存三级缓存机制支持循环依赖的解决4.5 关键源码方法org.springframework.context.support.AbstractApplicationContext#refresh (入口) org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization org.springframework.beans.factory.config.ConfigurableListableBeanFactory#preInstantiateSingletons org.springframework.beans.factory.support.AbstractBeanFactory#getBean (万恶之源) org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingletonFactory org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean五、Spring AOP5.1 核心概念概念说明Aspect切面可以定义 PointcutJoin point连接点某个方法Advice通知连接点上的具体动作日志、异常处理等Pointcut切点匹配一个或多个连接点Introduction使用DeclareParents给匹配的类添加接口默认实现Target object目标对象被代理的对象AOP proxy代理对象Weaving织入创建代理对象的动作5.2 动态代理方式特性JDK 动态代理CGLIB 动态代理机制基于接口反射实现基于类继承机制实现适用对象必须实现至少一个接口不要求实现接口不能代理 final 方法/类性能足够好实现简单某些场景更高但代理对象更复杂灵活性基于接口更灵活基于继承可能受限Spring AOP 选择策略优先 JDK 动态代理目标对象没有实现接口则自动切换到 CGLIB。5.3 CGLIB 原理Enhancer是 CGLIB 提供的类用于运行时动态生成类的子类被代理类是父类代理类是子类代理对象就是代理类的实例常用于Spring AOP、事务管理、日志记录可配置多个回调自定义不同方法的回调规则代理的含义在不改变原始对象的前提下对其进行功能增强和行为拦截。CGLIB AOP 大致流程生成代理类UserServiceProxy继承UserService代理类重写父类方法如test()代理类包含target属性被代理对象执行代理方法逻辑Before切面逻辑 → 调用target.test()5.4 代理工厂与实现方式ProxyFactory封装了两种代理方式根据是否实现接口选择实现了用 JDK否则用 CGLIB。代理 Bean 的实现方式方式说明ProxyFactoryBean只针对单个 Bean 代理BeanNameAutoProxyCreator通过 bean 名字自动代理DefaultAdvisorAutoProxyCreator找所有 Advisor根据 PointCut 和 Advice 代理注解形式常用AspectComponent5.5 AdvisorPointcut指定代理规则匹配类中的方法AdviceBefore Advice方法之前执行After returning advicereturn 后执行After throwing advice抛异常后执行After (finally) advicefinally 后执行Around advice功能最强可自定义执行顺序六、Spring 事务6.1 事务本质Spring 事务基于AOP 实现失效原因核心在于未被成功代理就使用。EnableTransactionManagement作用AutoProxyRegistrar开启自动代理ProxyTransactionManagementConfiguration判断Transactional注解并进行代理6.2 基本执行原理Bean 执行创建生命周期匹配 AdvisorTransactional注解若存在Bean 需要动态代理产生代理对象代理对象执行再次匹配Transactional执行TransactionInterceptor.invoke()新建数据库连接修改autocommit为false执行业务方法无异常提交有异常回滚6.3 事务传播机制传播机制说明REQUIRED默认共享事务REQUIRES_NEW完全独立a、b 独立提交SUPPORTS存在事务则加入否则非事务运行REQUIRES_NEW 执行流程a() 调用 b()代理对象执行 a()事务管理器新建连接 a连接 a 的 autocommit 改成 false设置到 ThreadLocal执行 a() 中的 SQL执行 a() 调用 b() →挂起连接 a从 ThreadLocal 移除新建连接 bautocommit 改成 false设置到 ThreadLocal执行 b() 中的 SQLb() 执行完从 ThreadLocal 拿连接 b提交恢复连接 a挂起资源重新设置到 ThreadLocala() 执行完ThreadLocal 中连接 a提交6.4 事务失效场景类内部调用类本身调用Transactional方法未经代理直接调用事务失效其他待补充…七、Spring 整合 MyBatis7.1 整合核心思想将其他框架中所产生的对象放入 Spring 容器中。7.2 Spring-MyBatis 执行流程Spring 嵌入 MyBatis 部分通过MapperScan导入MapperScannerRegistrarMapperScannerRegistrar实现ImportBeanDefinitionRegistrarSpring 启动时调用registerBeanDefinitions注册MapperScannerConfigurer类型的 BeanDefinitionMapperScannerConfigurer实现BeanDefinitionRegistryPostProcessor调用postProcessBeanDefinitionRegistry生成ClassPathMapperScanner进行扫描扫描到的 BeanDefinition 修改为MapperFactoryBeanAutowireMode 调整为byTypeSpring 基于 BeanDefinition 创建 Bean每个 Mapper 对应一个 FactoryBeanMapperFactoryBean.getObject()调用getSqlSession()得到 sqlSession生成 Mapper 接口代理对象MyBatis 执行 SQL 部分开启事务塞入LinkedHashSet利用事务管理器创建数据库连接利用 MyBatis 生成的 Mapper 代理对象执行 SQL代理对象执行方法时进入SqlSessionTemplate的SqlSessionInterceptor取 sqlSession 对象若为空则在DefaultSqlSessionFactory创建判断是否开启事务若开启事务将 sqlSession 存入resourcesThreadLocal利用 sqlSession 执行 SQL7.3 一级缓存失效问题MyBatis 一级缓存基于sqlSession实现同一个 sqlSession 执行 SQL 可利用一级缓存Spring 整合后若方法上没有Transactional注解每执行一个 SQL 都会新生成一个 SqlSession一级缓存失效开启 Spring 事务时事务中的多个 SQL 使用同一个 sqlSession一级缓存生效不是 bug是机制没有事务则 SQL 单独执行生命周期过短八、SpringMVC8.1 原生 MVC 弊端JSP Servlet JavaBeanXML 配置 Servlet 映射开发效率低入侵性强分发给不同方法麻烦、参数解析麻烦、数据响应麻烦8.2 SpringMVC 核心组件组件作用DispatcherServlet前端调度器负责请求拦截分发到控制器HandlerMapping根据请求 URL 和RequestMapping映射HandlerAdapter调用 Handler 具体方法返回视图名ModelAndView封装视图名、request 域数据ViewResolver根据 ModelAndView 找具体 View 对象View视图渲染8.3 父子容器Spring 和 SpringMVC 整合涉及父子容器概念先去父容器找再找子容器父容器 service 无法访问子容器 controller子容器可以访问父容器面试题Spring 和 SpringMVC 一定需要父子容器吗不一定如 Spring Boot原因单一职责、规范架构、方便切换、节省重复 Bean 创建是否可以把所有 Bean 都通过 Spring 容器管理不可以会导致请求接口 404。SpringMVC 初始化时无法根据 Controller 注册 HandlerMethod没有查找父容器的 bean是否可以把所有 Bean 使用 SpringMVC 子容器管理可以但不推荐可能导致 AOP 误配失效九、手写 Spring 心得注解与工具9.1 Target 注解类型作用范围ElementType.TYPE类、接口、枚举、记录ElementType.FIELD字段、枚举常量ElementType.METHOD方法不含构造方法ElementType.PARAMETER方法或构造方法参数ElementType.CONSTRUCTOR构造方法ElementType.LOCAL_VARIABLE局部变量ElementType.ANNOTATION_TYPE注解接口ElementType.PACKAGE包声明ElementType.MODULE模块声明Java 9ElementType.RECORD_COMPONENTrecord 组件Java 169.2 RetentionPolicy 保留策略策略说明SOURCE仅保留在源文件编译后遗弃CLASS保留到 class 文件JVM 加载时遗弃默认RUNTIME保留到 class 文件JVM 加载后仍然存在9.3 Scope 作用域作用域说明singleton单例模式容器中只创建一次默认prototype原型模式每次请求都创建新实例request每个 HTTP 请求创建新实例Web 环境session每个 HTTP 会话创建新实例Web 环境工具方法beanName Introspector.decapitalize(clazz.getSimpleName())—— 首字母转小写9.4 类型转化Spring 注入Value(xxx)到private User user字段时字符串xxx是配置中的原始值Spring 检测到目标字段是 User 类型使用内部注册的ConversionService尝试转换如果存在ConverterString, User调用该转换器完成转换9.5 元数据读取器MetadataReader、ClassMetadata、AnnotationMetadata使用ASM 技术解析类的元数据类名、方法、注解等无需 JVM 加载类本文持续更新中如有错误或补充欢迎留言交流