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

走进Spring的世界 —— Spring底层核心原理解析(一)

文章目录

  • 前言
  • 一、Spring中是如何创建一个对象
  • 二、Bean的创建过程
  • 三、推断构造方法
  • 四、AOP大致流程
  • 五、Spring事务


前言

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

这是学习Spring的hello world。可是,这三行代码底层都做了什么,比如:

  • 第一行代码,会构造一个ClassPathXmlApplicationContext对象,ClassPathXmlApplicationContext该如何理解,调用该构造方法除开会实例化得到一个对象,还会做哪些事情?
  • 第二行代码,会调用ClassPathXmlApplicationContext的getBean方法,会得到一个UserService对象,getBean()是如何实现的?返回的UserService对象和我们自己直接new的UserService对象有区别吗?
  • 第三行代码,就是简单的调用UserService的test()方法

光看这三行代码,其实并不能体现出来Spring的强大之处,也不能理解为什么需要ClassPathXmlApplicationContext和getBean()方法
对于这三行代码,你现在可以认为:如果你要用Spring,你就得这么写。就像你要用Mybatis,你就得写各种Mapper接口。

但是用ClassPathXmlApplicationContext其实已经过时了,在新版的Spring MVC和Spring Boot的底层主要用的都是AnnotationConfigApplicationContext,比如:

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

可以看到AnnotationConfigApplicationContext的用法和ClassPathXmlApplicationContext是非常类似的,只不过需要传入的是一个class,而不是一个xml文件。

而AppConfig.class和spring.xml一样,表示Spring的配置,比如可以指定扫描路径,可以直接定义Bean,比如:

spring.xml中的内容为:

<context:component-scan base-package="xxx"/>
<bean id="userService" class="xxxxx"/>

AppConfig中的内容为:

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

所以spring.xml和AppConfig.class本质上是一样的。

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

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

因为AnnotationConfigApplicationContext是比较重要的,并且AnnotationConfigApplicationContext和ClassPathXmlApplicationContext大部分底层都是共同的

一、Spring中是如何创建一个对象

不管是AnnotationConfigApplicationContext还是ClassPathXmlApplicationContext,目前,我们都可以简单的将它们理解为就是用来创建Java对象的,比如调用getBean()就会去创建对象(此处不严谨,getBean可能也不会去创建对象)

在Java语言中,肯定是根据某个类来创建一个对象的。我们在看一下实例代码:

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

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

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

  • 解析Config.class,得到扫描路径
  • 遍历扫描路径下的所有Java类,如果发现某个类上存在@Component、@Service等注解,那么Spring就把这个类记录下来,存在一个Map中,比如Map<String, Class>
  • Spring会根据某个规则生成当前类对应的beanName,作为key存入Map,当前类作为value

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

二、Bean的创建过程

那么Spring到底是如何来创建一个Bean的呢,这个就是Bean创建的生命周期,大致过程如下:

  1. 利用该类的构造方法来实例化得到一个对象(但是如何一个类中有多个构造方法,Spring则会进行选择,这个叫做推断构造方法)
  2. 得到一个对象后,Spring会判断该对象中是否存在被@Autowired注解了的属性,把这些属性找出来并由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对象。

三、推断构造方法

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

Spring的判断逻辑如下:

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

Spring的设计思想是这样的:

  1. 如果一个类只有一个构造方法,那么没得选择,只能用这个构造方法
  2. 如果一个类存在多个构造方法,Spring不知道如何选择,就会看是否有无参的构造方法,因为无参构造方法本身表示了一种默认的意义
  3. 不过如果某个构造方法上加了@Autowired注解,那就表示程序员告诉Spring就用这个加了注解的方法,那Spring就会用这个加了@Autowired注解构造方法了

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

Spring会根据入参的类型和入参的名字去Spring中找Bean对象(以单例Bean为例,Spring会从单例池那个Map中去找):

  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属性,该属性的值为被代理对象(也就是通过UserService类推断构造方法实例化出来的对象,进行了依赖注入、初始化等步骤的对象)
  4. 代理类中的test()方法被执行时的逻辑如下:
    a. 执行切面逻辑(@Before)
    b. 调用target.test()

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

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

其实代理代理就是创建一个类的子类,去基础它,然后在内部创建一个类(类似:UserService target;),然后把target = 传进来普通UserService

五、Spring事务

当我们在某个方法上加了@Transactional注解后,就表示该方法在调用时会开启Spring事务,而这个方法所在的类所对应的Bean对象会是该类的代理对象。

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

  1. 判断当前执行的方法是否存在@Transactional注解
  2. 如果存在,则利用事务管理器(TransactionMananger)新建一个数据库连接
  3. 修改数据库连接的autocommit为false
  4. 执行target.test(),执行程序员所写的业务逻辑代码,也就是执行sql
  5. 执行完了之后如果没有出现异常,则提交,否则回滚

相关文章:

走进Spring的世界 —— Spring底层核心原理解析(一)

文章目录 前言一、Spring中是如何创建一个对象二、Bean的创建过程三、推断构造方法四、AOP大致流程五、Spring事务 前言 ClassPathXmlApplicationContext context new ClassPathXmlApplicationContext("config.xml"); UserService userService (UserService) cont…...

快看看你的手机有没有:谷歌Android全面封杀此类软件!

谷歌坐不住了&#xff0c;因为Android应用商店中&#xff0c;充斥着大量可窃取用户数据的应用&#xff0c;所以必然要出手整治了。 一款名叫“SonicSpy”软件是整个事情的导火索&#xff0c;而该应用是典型的窃取用户数据的应用&#xff0c;其除了可以从手机中提取个人数据外&…...

spark ui 指南

spark ui 指南 1.sparkUI 基本介绍2.jobs页面3.stages 页面4.storage 页面5.environment 页面6.ececutor 页面7 sql 页面  spark ui 是反应一个spark 作业执行情况的页面,通过查看作业的执行情况,分析作业运行的状态. 1.sparkUI 基本介绍 进入运行主页面如下,主要有6各部…...

【分布式事务】

文章目录 解决分布式事务的思路seata四种模式1. XA模式2. AT模式AT模式与XA模式的区别是什么&#xff1f;脏写问题 3. TCC模式事务悬挂和空回滚 4. SAGA模式 四种模式对比口述AT模式与TCC模式高可用 什么是分布式事务&#xff1f; 分布式事务&#xff0c;就是指不是在单个服务或…...

linux 清除卸载jenkins

1、停服务进程 查看jenkins服务是否在运行&#xff0c;如果在运行&#xff0c;停掉 查看服务 ps -ef|grep jenkins 停掉进程 kill -9 XXX2、查找安装目录 find / -name "jenkins*"3、删掉相关目录 删掉相关安装目录 rm -rf /root/.jenkins/# 删掉war包 rm -rf /…...

番外4:VMware安装

step4: 安装过程中&#xff0c;有些选项不需要点&#xff08;安装地址建议选C盘或默认&#xff0c;装载在其他盘后续会报错&#xff09;&#xff0c;如&#xff1a; may error&#xff08;本人猜测安装虚拟机完整版需要C盘的一些桥插件支持&#xff09;: step5: 安装虚拟机成功…...

Oracle 19.20 patch 注意事项

1. 打patch 用root 打 /u01/app/19.0.0/grid/OPatch/opatchauto apply /u01/app/patch/35319490 2.打patch 之前 所有NODE上OPatch 版本要一样 3. OPatch 目录不要是root权限 4.打一台&#xff0c;一台自动重启。 有几个node 在几个node 打。patch 都要传到不同的node上 …...

ElementUI之增删改及表单验证

⭐⭐本文章收录与ElementUI原创专栏&#xff1a;ElementUI专栏 ⭐⭐ ElementUI的官网&#xff1a;ElementUI官网 目录 一.前言 二.使用ElementUI完成增删改 2.1 后台代码 2.2 前端代码 三.使用ElementUI完成表单验证 一.前言 本章是继上一篇的基础之上在做完善&#xff0…...

【Java 进阶篇】深入理解 JDBC:Java 数据库连接详解

数据库是现代应用程序的核心组成部分之一。无论是 Web 应用、移动应用还是桌面应用&#xff0c;几乎都需要与数据库交互以存储和检索数据。Java 提供了一种强大的方式来实现与数据库的交互&#xff0c;即 JDBC&#xff08;Java 数据库连接&#xff09;。本文将深入探讨 JDBC 的…...

Web开发-session介绍

目录 session介绍session使用场景session具体使用需要注意的是 session介绍 session 可以被看作是一种缓冲区&#xff0c;用于在多个请求之间存储和传递用户数据。在 Web 应用程序中&#xff0c;session 通常用于存储用户登录信息、购物车数据、用户偏好设置等。当用户在应用程…...

基于Qt Creator开发的坦克大战小游戏

目录 介绍开发环境技术介绍安装说明项目目录设计思想项目介绍运行演示知识点记录Gitee源码链接 介绍 &#xff01;&#xff01;&#xff01;资源图片是从网上免费下载&#xff0c;源码都是原创&#xff0c;供个人学习使用&#xff0c;非盈利&#xff01;&#xff01;&#xff…...

小说推文和短剧推广以及电影达人带货电影票

小说推文、短剧推广、电影达人&#xff08;带或电影票&#xff09;都可以通过“巨量推文“进行申请授权 小说推文和短剧推广是什么&#xff1f; 小说推文和短剧推广的逻辑其实一样&#xff0c;分为cpa拉新和cps分成的推广形式 cpa拉新是你推广的用户必须为新用户&#xff0c…...

朴素贝叶斯分类(下):数据挖掘十大算法之一

⭐️⭐️⭐️⭐️⭐️欢迎来到我的博客⭐️⭐️⭐️⭐️⭐️ 🐴作者:秋无之地 🐴简介:CSDN爬虫、后端、大数据领域创作者。目前从事python爬虫、后端和大数据等相关工作,主要擅长领域有:爬虫、后端、大数据开发、数据分析等。 🐴欢迎小伙伴们点赞👍🏻、收藏⭐️、…...

9.30作业

C语言基础考题&#xff08;40&#xff09; 选择题 20分每题2分 1、已知字母A的ASCII码为十进制数值65&#xff0c;且S为字符型&#xff0c;则执行语句SA6-3&#xff1b;后S中的值为 ( ) A.D B.68 C.不确定的值 D.C 2、若有定义语句&#xff1a;int a12;&#xff0c;则执…...

[GWCTF 2019]枯燥的抽奖

参考 https://www.cnblogs.com/AikN/p/15764428.html [GWCTF 2019]枯燥的抽奖-CSDN博客 打开环境 笑死我了&#xff0c;怎么那么像我高中校长 查看源代码 看到check.php&#xff0c;去访问一下 ok看到源代码了 因为上次做过&#xff0c;看到这个我就想到用php_mt_seed逆推…...

vue3中sync修饰符的使用

props是子组件与父组件进行通信的常用方式&#xff0c;使用步骤主要有以下几个&#xff1a; 1. 在子组件中定义props要从父组件接收的变量&#xff08;变量的类型必须写明&#xff0c;默认值可选&#xff09; // 这里以 document.vue 子组件为例 // 通过 defineProps 宏的方…...

Qt全屏显示与退出

仿照 按Escape键退出程序中的实现&#xff0c;我们在程序开始的时候全屏显示&#xff0c;按esc键的时候退出全屏。 showFullScreen 全屏显示只需要调用QWidget类&#xff08;QMainWindow也是一个QWidget类&#xff09;的 showFullScreen() 成员函数即可。 退出全屏&#x…...

OpenCV之直线曲线拟合

直线拟合fitLine void fitLine( InputArray points, OutputArray line, int distType,double param, double reps, double aeps ); points:二维点的数组或vector line:输出直线,Vec4f (2d)或Vec6f (3d)的vector distType:距离类型 param:距离参数 reps:径向的精度参数 a…...

2023年哪款PDF虚拟打印机好用?

PDF文档想必大家都不陌生&#xff0c;在工作中经常会用到该格式的文档&#xff0c;那么有哪些方法能制作PDF文档呢&#xff1f;一般都是借助PDF虚拟打印机的&#xff0c;那么有哪些好用的软件呢&#xff1f; pdfFactory不仅为用户提供了丰富的PDF文档生成、打印功能&#xff0…...

Redis各数据类型特定的命令和用法 1.0版本

目录 一、Sring数据类型1.1 概述1.2 set/get/append/strlen命令1.3 incr/decr/incrby/decrby 命令1.4 getset命令1.5 setex命令1.6 setnx命令1.7 mset/mget/msetnx命令 二、List数据类型2.1 概述2.2 lpush/lpushx/lrange命令2.3 lpop/llen命令2.4 lrem/lset/lindex/ltrim命令2.…...

uniapp 对接腾讯云IM群组成员管理(增删改查)

UniApp 实战&#xff1a;腾讯云IM群组成员管理&#xff08;增删改查&#xff09; 一、前言 在社交类App开发中&#xff0c;群组成员管理是核心功能之一。本文将基于UniApp框架&#xff0c;结合腾讯云IM SDK&#xff0c;详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

19c补丁后oracle属主变化,导致不能识别磁盘组

补丁后服务器重启&#xff0c;数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后&#xff0c;存在与用户组权限相关的问题。具体表现为&#xff0c;Oracle 实例的运行用户&#xff08;oracle&#xff09;和集…...

地震勘探——干扰波识别、井中地震时距曲线特点

目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波&#xff1a;可以用来解决所提出的地质任务的波&#xff1b;干扰波&#xff1a;所有妨碍辨认、追踪有效波的其他波。 地震勘探中&#xff0c;有效波和干扰波是相对的。例如&#xff0c;在反射波…...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

代码随想录刷题day30

1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额&#xff0c;返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机

这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机&#xff0c;因为在使用过程中发现 Airsim 对外部监控相机的描述模糊&#xff0c;而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置&#xff0c;最后在源码示例中找到了&#xff0c;所以感…...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)

引言 在人工智能飞速发展的今天&#xff0c;大语言模型&#xff08;Large Language Models, LLMs&#xff09;已成为技术领域的焦点。从智能写作到代码生成&#xff0c;LLM 的应用场景不断扩展&#xff0c;深刻改变了我们的工作和生活方式。然而&#xff0c;理解这些模型的内部…...

SQL Server 触发器调用存储过程实现发送 HTTP 请求

文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...