当前位置: 首页 > news >正文

Spring底层核心原理解析

Spring简介

ClassPathXmlApplicationContext context = new classPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) context.getBean("userService");
userService.test();

上面一段代码是我们开始学习spring时看到的,光看这三行代码,其实并不能体现出来Spring的强大之处

但其实ClassPathXmlApplicationContext早已经过时,新版的Spring MVC和SpringBoot的底层中主要用的都是AnnotationConfigApplication,例如:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
//ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) context.getBean("userService");
userService.test();

两者写法基本类似,区别在于前者需要传入的是一个xml文件,后者传入的是一个class。都可以指定扫描路径,也可以定义Bean。例如:

spring.xml文件样例:

<context:component-scan base-package="com.zhouyu"/>
<bean id="userService" class="com.zhouyu.service.UserService"/>

AppConfig.java文件样例:

@ComponentScan("com.zhouyu")
public class AppConfig {@Beanpublic UserService userService(){return new UserService();}
}

不过我们很少这样使用Spring,而是使用Spring MVC 或者 SpringBoot,但是它们都是基于上面这种方式的,都需要在内部去创建一个ApplicationContext的,只不过:

  • Spring MVC创建的是XmlWebApplicationContext,和ClassPathXmlApplicationContext类似,都是基于XML配置的
  • Spring Boot创建的是AnnotationConfigApplicationContext

Spring中是如何创建一个对象

先看下面代码

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService) context.getBean("userService");
userService.test();

当我们调用context.getBean(“userService”)时,就会去创建一个对象,但是getBean方法内部怎么知道"userService"对应的是UserService类呢?

所以,我们就可以分析出来,在调用AnnotationConfigApplicationContext的构造方法时,也就是第一行代码,会去做一些事情:

  1. 解析APPConfig.class,得到包扫描路径
  2. 遍历扫描路径下的所有Java类,如果如果发现带有@Component、@Service等注解时,Spring会把这个类记录下来,存在一个Map中,比如Map<String,Class>。(实际上,Srping源码中确实存在这么类似的Map,叫BeanDefinitionMap)
  3. Spring会根据某个规则生成当前类对应的beanName,作为key存入Map,并把当前作为Value存入

这样,但调用context.getBean(“userService”)时,就可以根据"userService"找到UserService类,从而就可以去创建对象了。

Bean的创建过程

  1. 利用该类的构造方法来实例化得到一个对象
  2. 得到一个对象后,Spring 会判断该对象中是否存在被@Autowire注解了的属性,吧这些属性找出来并由Spring进行赋值(依赖注入)。
  3. 依赖注入后,Spring会判断该对象是否实现了BeanNameAware接口、BeanClassLoaderAware接口、BeanFactoryAware接口,如果实现了,就表示当前对象必须实现该接口中所定义的setBeanName()、setBeanClassLoader()、setBeanFactory()方法,那Spring就会调用这些方法并传入相应的参数(Aware回调)
  4. Aware回调后,Spring会判断该对象中是否存在某个方法被@PostConstruct注解了,如果存在,Spring会调用当前对象的此方法(初始化前)。
  5. 紧接着,Spring会判断该对象是否实现了InitializingBean接口,如果实现了,就表示当前对象必须实现afterPropertiesSet()方法,那Spring就会调用当前对象中的afterPropertiesSet()方法(初始化
  6. 最后Spring会判断当前对象需不需进行AOP,如果不需要,那么Bean就创建完成了,如果需要进行AOP,则会进行动态代理并生成一个代理对象作为Bean(初始化后)。

通过最后一步,我们发现,当Spring根据UserService类来创建一个Bean时:

  1. 如果不用进行AOP,那么Bean就是UserService累的构造方法所得到的对象。
  2. 如果进行AOP,那么Bean就是UserService的代理类所实例化得到的对象,而不是UserService本身所得到的对象。

Bean创建出来后:

  1. 如果当前Bean是单例Bean,那么会把该Bean存入一个Map<String,Object>,Map的key为beanName,value为Bean对象。这样下次getBean时就可以直接从Map中拿到Bean对象了。(实际上,在Spring源码中,这个Map就是单例池)
  2. 如果当前Bean是原型Bean,那么后续没有其他动作,不会存入一个Map,下次getBean时会再次执行上述创建过程,得到一个新的Bean对象。

UserService.class —> 无参构造方法 —>普通对象—>依赖注入(属性赋值、BeanNameAware接口、BeanClassLoaderAware接口、BeanFactoryAware接口)—>初始化前(postconstruct)—>初始化(initializingBean)—>初始化后(aop)—>代理对象—>Bean

推断构造方法

Spring在基于某个类生成Bean的过程中,需要利用该类的构造方法来实例化一个对象,但是如果一个类存在多个构造方法,Spring会使用哪个呢?

Spring的判断逻辑如下:

  1. 如果一个类只存在一个构造方法,不管该构造方法是无参构造方法还是有参构造方法,Spring都会使用这个构造方法。
  2. 如果一个类存在多个构造方法
    1. 这些构造方法中,存在一个无参的构造方法,那么Spring就会用这个无参的构造方法
    2. 这些构造方法中,如果不存在无参的构造方法,那么Spring就会报错

Spring的设计思想是这样的:

  1. 如果一个类只有一个构造方法,那么没得选择,只能用这个构造方法

  2. 如果一个类存在多个构造方法,Spring不知道如何选择,就会看是否有无参的构造方法,因为无参构造方法本身表示了一种默认的意义

  3. 不过如果某个构造方法上加了@Autowired注解,那就表示程序员告诉Spring就用这个加了注解的方法,那Spring就会用这个加了@Autowired注解构造方法了

如果Spring选择了一个有参的构造方法,Spring在调用这个有参构造方法时,需要传入参数,那这个参数是怎么来的呢?

  1. 现根据入参类型找,如果只找到一个,那么久直接用来作为入参
  2. 如果根据类型找到多个,则再根据入参名字来确定唯一一个
  3. 最终如果没有找到,则会报错,无法创建Bean对象

确定用哪个构造方法,确定入参的Bean对象,这个过程就叫做推断构造方法。

AOP大致流程

AOP就是动态代理,在创建一个Bean的过程中,Spring在最后一步会去判断这个Bean是不是需要进行AOP,如果需要则会进行动态代理。

如何判断当前Bean对象是否需要进行AOP:

  1. 找出所有的切面Bean
  2. 遍历切面中的每个方法,看看是否写了@before、@After等注解
  3. 如果写了,则判断所对应的pointcut是否和当前Bean对象的类是否匹配。
  4. 如果匹配则表示当前Bean对象有匹配的pointcut,表示需要进行AOP

利用cglib进行AOP的大致流程:

  1. 生成代理类UserServiceProxy,代理类继承UserService
  2. 代理类中重写了父类的方法,比如UserService的Test()方法
  3. 代理类中还会有一个target属性,该属性的值为被代理的对象
  4. 代理类中的test()方法被执行时逻辑如下:
    1. 执行切面逻辑(@Before)
    2. 调用target.test()

当我们从Spring容器得到UserService的Bean对象时,拿到的就是UserServiceProxy所生成的对象,也就是代理对象。

UserService代理对象.test()—>执行切面逻辑—>target.test(),注意target对象不是代理对象,而是被代理对象。

Spring事务

当我们在某个方法上加了@Transactional注解后

Spring事务的代理对象执行某个方法时的步骤:

  1. 判断当前执行的方法是否存在@Transactional注解
  2. 如果存在,则利用事务管理器(transactionManager)新建一个数据库连接
  3. 修改数据库连接的autocommit为false
  4. 执行target.test(),执行业务逻辑代码,执行SQL
  5. 执行完成如果无异常,则提交,否则回滚。

Spring事务是否会失效的判断标准:某个加了@Transaction注解的方法被调用时,要判断到底是不是直接被代理的对象调用的,如果是则事务会生效,如果不是则失败。

相关文章:

Spring底层核心原理解析

Spring简介 ClassPathXmlApplicationContext context new classPathXmlApplicationContext("spring.xml"); UserService userService (UserService) context.getBean("userService"); userService.test();上面一段代码是我们开始学习spring时看到的&…...

OpenStack手动分布式部署Glance【Queens版】

目录 Glance简介 1、登录数据库配置&#xff08;在controller执行&#xff09; 1.1登录数据库 1.2数据库里创建glance 1.3授权对glance数据库的正确访问 1.4退出数据库 1.5创建glance用户密码为000000 1.6增加admin角色 1.7创建glance服务 1.8创建镜像服务API端点 2、安装gla…...

谈一谈你对View的认识和View的工作流程

都2023年了&#xff0c;不会还有人不知道什么是View吧&#xff0c;不会吧&#xff0c;不会吧。按我以往的面试经验来看&#xff0c;View被问到的概率不比Activity低多少哦&#xff0c;个人感觉View在Android中的重要性也和Activity不相上下&#xff0c;所以这篇文章将介绍下Vie…...

Redis集群的脑裂问题

集群脑裂导致数据丢失怎么办&#xff1f; 什么是脑裂&#xff1f; 先来理解集群的脑裂现象&#xff0c;这就好比一个人有两个大脑&#xff0c;那么到底受谁控制呢&#xff1f; 那么在 Redis 中&#xff0c;集群脑裂产生数据丢失的现象是怎样的呢&#xff1f; 在 Redis 主从架…...

互斥信号+任务临界创建+任务锁

普通信号量 1、信号量概念 2、创建信号量函数 3、互斥信号量 创建互斥信号量函数 等待信号量函数 释放互斥信号量 4、创建任务临界区 5、任务锁 任务上锁函数 ​编辑 任务结束函数 效果 普通信号量 1、信号量概念 信号量像是一种上锁机制&#xff0c;代码必须获…...

Elasticsearch7.8.0版本进阶——文档搜索

目录一、文档搜索的概述二、倒排索引不可变的优点三、倒排索引不可变的优点一、文档搜索的概述 早期的全文检索会为整个文档集合建立一个很大的倒排索引并将其写入到磁盘。 一旦新的索引就绪&#xff0c;旧的就会被其替换&#xff0c;这样最近的变化便可以被检索到。倒排索引被…...

spring security权限问题

org.springframework.boot spring-boot-starter-security 引入jar extends WebSecurityConfigurerAdapter 用来配置登陆和权限 configure(HttpSecurity http) 覆盖这个方法 //配置授权相关的 .authorizeRequests () //任何请求 .anyRequest() //要求授权后可以访问 .authen…...

mysql 8.0.22安装

mysql8.0.22安装1. 配置my.ini2. 添加环境变量3. 安装mysql3.1 mysql初始化3.2 安装mysql服务3.3 启动mysql服务4. 连接数据库修改连接数据库的密码前提&#xff1a;已经从官网下载mysql8.0.22安装包并解压&#xff08;下载地址&#xff1a;https://dev.mysql.com/downloads/in…...

Mysql系列:Mysql5.7编译安装

系统环境&#xff1a;Centos7 1&#xff1a;下载mysql源码包 https://dev.mysql.com/downloads/mysql/5.7.html downloads 选择MySQL Community Server>source_code>Generic Linux (Architecture Independent), Compressed TAR Archive -> 选择需要的mysql版本&…...

设备树(配合LED驱动说明)

目录 一、起源 二、基本组成 三、基本语法 四、特殊节点 4.1 根节点 4.2 /memory 4.3 /chosen 4.4 /cpus 多核CPU支持 五、常用属性 5.1 phandle 5.2 地址 --------------- 重要 5.3 compatible --------------- 重要 5.4 中断 --------------- 重要 5.5 …...

(二十六)大白话如何从底层原理解决生产的Too many connections故障?

今天我们继续讲解昨天的那个案例背景&#xff0c;其实就是经典的Too many connections故障&#xff0c;他的核心就是linux的文件句柄限制&#xff0c;导致了MySQL的最大连接数被限制&#xff0c;那么今天来讲讲怎么解决这个问题。 其实核心就是一行命令&#xff1a; ulimit -H…...

ASEMI高压MOS管60R380参数,60R380特征,60R380应用

编辑-Z ASEMI高压MOS管60R380参数&#xff1a; 型号&#xff1a;60R380 漏极-源极电压&#xff08;VDS&#xff09;&#xff1a;600V 栅源电压&#xff08;VGS&#xff09;&#xff1a;20V 漏极电流&#xff08;ID&#xff09;&#xff1a;11A 功耗&#xff08;PD&#x…...

Python期末试卷

《Python程序设计基础》期末试题 班级 学号 姓名 一&#xff0e;选择题(须知:答案写到下方的表格中,其它一律无效.每题2分&#xff0c;共40分) 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 1.在Python交互…...

Linux | 网络通信 | http协议介绍 | cookie策略讲解

文章目录url统一资源定位符http协议介绍GET vs POSThttp状态码http常见headercookie session上篇博客定制了一个协议&#xff0c;该协议用来进行简单的计算&#xff0c;其包含了数据的序列化和反序列化&#xff0c;编码和解码的定制&#xff0c;并且该协议基于TCP通信&#xf…...

招投标系统简介 招投标系统源码 java招投标系统 招投标系统功能设计

项目说明 随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大&#xff0c;公司对内部招采管理的提升提出了更高的要求。在企业里建立一个公平、公开、公正的采购环境&#xff0c;最大限度控制采购成本至关重要。符合国家电子招投标法律法规及相关规范&#xff0c;以及…...

winapi获取和修改camera raw界面元素数据

camera raw 界面如下&#xff1a; 需求就是根据 windows api 来操作界面右边的色温、色调、曝光等属性&#xff0c;进而对图片进行调色。根据 spy 捕获的窗口信息&#xff0c;理论上是可以拿到并修改值的。 根据 class 可以先拿到窗口句柄&#xff1a; #define CAMERA_RAW_CLA…...

C++问答汇总_2023自用

C是一种通用编程语言&#xff0c;具有高级抽象、强类型和编译性能等特点。C语言具有许多特性&#xff0c;包括面向对象编程、模板、多态、运算符重载等等。它广泛应用于各种领域&#xff0c;如系统软件、嵌入式系统、游戏开发、科学计算等等。 1、C11相对于C98的新特性&#xf…...

IDA 实战--(2)熟悉工具

布局介绍 软件启动后会 有几个选项&#xff0c;一般直接选择Go 即可 之后的工作台布局如下 开始分析 分析的第一个&#xff0c;将PE 文件拖入工作区 刚开始接触&#xff0c;我们先保持默认选项&#xff0c;其它选项后面会详细讲解&#xff0c;点击OK 后&#xff0c;等待分析…...

Deep Unsupervised Learning using Nonequilibrium Thermodynamics论文翻译学习

Deep Unsupervised Learning using Nonequilibrium Thermodynamics Author: Jascha Sohl-Dickstein Link: http://proceedings.mlr.press/v37/sohl-dickstein15.pdf Score: ⭐️⭐️⭐️⭐️⭐️ Status: Done Type: Academic Journal 备注: 首篇扩散模型论文 A central prob…...

使用Autoware标定工具包联合标定相机和激光雷达

前面文章介绍了&#xff0c;安装autoware标定工具包、ros驱动usb相机、robosense-16线激光雷达的使用&#xff0c;本文记录使用Autoware标定工具包联合标定相机和激光雷达的过程。1.ros驱动相机&#xff0c;启动相机&#xff1b;启动激光雷达2.联合录制bag包rosbag record -a 参…...

大话软工笔记—需求分析概述

需求分析&#xff0c;就是要对需求调研收集到的资料信息逐个地进行拆分、研究&#xff0c;从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要&#xff0c;后续设计的依据主要来自于需求分析的成果&#xff0c;包括: 项目的目的…...

Spark 之 入门讲解详细版(1)

1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室&#xff08;Algorithms, Machines, and People Lab&#xff09;开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目&#xff0c;8个月后成为Apache顶级项目&#xff0c;速度之快足见过人之处&…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

Qt Http Server模块功能及架构

Qt Http Server 是 Qt 6.0 中引入的一个新模块&#xff0c;它提供了一个轻量级的 HTTP 服务器实现&#xff0c;主要用于构建基于 HTTP 的应用程序和服务。 功能介绍&#xff1a; 主要功能 HTTP服务器功能&#xff1a; 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

AGain DB和倍数增益的关系

我在设置一款索尼CMOS芯片时&#xff0c;Again增益0db变化为6DB&#xff0c;画面的变化只有2倍DN的增益&#xff0c;比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析&#xff1a; 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

【分享】推荐一些办公小工具

1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由&#xff1a;大部分的转换软件需要收费&#xff0c;要么功能不齐全&#xff0c;而开会员又用不了几次浪费钱&#xff0c;借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...

MinIO Docker 部署:仅开放一个端口

MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...

十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建

【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...

保姆级【快数学会Android端“动画“】+ 实现补间动画和逐帧动画!!!

目录 补间动画 1.创建资源文件夹 2.设置文件夹类型 3.创建.xml文件 4.样式设计 5.动画设置 6.动画的实现 内容拓展 7.在原基础上继续添加.xml文件 8.xml代码编写 (1)rotate_anim (2)scale_anim (3)translate_anim 9.MainActivity.java代码汇总 10.效果展示 逐帧…...