spring技术内幕——深入解析spring架构与设计原理

林纳斯·托瓦兹(Linus Torvalds)说:“我从心底认为,优秀的程序员与平庸的程序员之间的区别,是在于认为自己的代码重要还是数据结构更加重要。平庸的程序员眼里只有代码,优秀的程序员则关注数据结构及之前的关系。” 

1、spring的设计理念

  • spring提供了一个轻量级的开发框架,抽象了实际开发中的很多共性问题;在javaee的开发中,支持pojo和使用javabean的开发方式,使应用面向接口开发、充分支持OO;
  • 通过spring的ioc容器,将复杂的对象耦合关系变成了一个文本化、外部化的工作,通过一个或几个xml文件来方便的对应用对象的耦合关系进行维护、修改和浏览,极大地简化了应用开发;
  • 通过ioc容器的依赖反转,将依赖关系从java对象中解放出来,交给了ioc容器完成,对象之间的关系进行了解耦,对象——对象之间的关系转化成了对象——IOC容器——对象的关系;
  • IOC容器和AOP模块是spring最为基础的底层抽象,IOC来管理bean对象,aop以动态和非侵入的方式增强服务功能。

2、spring的整体架构

springioc、spring aop、springmvc、springjdbc/orm、spring事务处理、spring的远端调用、spring应用;其中aop以纵向切面的方式贯穿在整个架构中;

Spring 中两个数据结构最核心:① BeanDefinition,用于表示 Bean 的定义;② BeanFactory,用于表示整个 IoC 容器。

3、spring framework的核心:IOC容器的实现

ioc容器概述

  • 面向对象系统:对象封装了数据和对数据的处理,对象的依赖关系主要体现在对数据和方法的依赖上。这种依赖关系可以通过把对象的依赖注入交给框架或者IOC容器来完成
  • 依赖注入:依赖对象获得被反转了,由自身主动的获取反转到交给ioc容器来注入、获取。新建对象、对象的引用赋值等操作交由容器来统一完成。从而将散落在不同代码中的功能相同的部分集中成了容器的一部分,成了面向对象基础设施的一部分。
  • 对面向对象系统中的对象分2类:数据对象、处理数据的对象。后者不经常变化,很少涉及数据和状态共享的问题,是系统中基础的部分。同时这些对象间依赖关系也很稳定,这些特性非常适合由ioc容器来进行管理

IOC容器的设计与实现:

BeanFactory和ApplicationContext:

我们通常说的ioc容器实际上指的是一些功能各异的容器产品,各有特点

beanfactory:容器的基本功能;applicationcontext:应用上下文,作为容器的高级形态而存在,增加了很多面向框架的特性和适配。

beandefinition:抽象了对bean的定义,管理各种对象,是依赖翻转模式中管理的对象依赖关系的数据抽象,是容器发挥作用的主要数据类型。计算机中,所有的功能都是建立在通过数据对现实进行抽象的基础上的。

IOC容器的接口设计关系:

1、从接口BeanFactory---HierarchicalBeanFactory---ConfigurableBeanFactory,是一条主要的BeanFactory设计路径。

2、第二条接口设计主线是以ApplicationContext应用上下文接口为核心的接口设计,从BeanFactory---ListableBeanFactory---ApplicationContext---WebApplicationContext(ConfigurableApplicationContext)。

3、具体的IoC容器都是在以上的接口体系下实现的,比如DefaultListableBeanFactory,实现了ConfigurableBeanFactory,从而成为一个简单IoC容器的实现。其他的如XmlBeanFactory,都是在DefaultListableBeanFactory的基础上做扩展,ApplicationContext也是如此。

4、BeanFactory是IoC容器最基本的接口,提供的是最基本的IoC容器的功能,比如getBean、containsBean等,其他高级IoC容器接口再在此基础功能上进行扩展。

5、BeanFactory是一个对象工厂,管理Spring中所有的Bean,而FactoryBean是一个特殊的Bean。

IOC容器的创建步骤:

(1)创建IoC配置文件的抽象资源,包含了BeanDefinition的定义信息;

(2)创建一个BeanFactory;

(3)创建一个载入BeanDefinition的读取器;

(4)从定义好的资源位置读入配置信息。

核心属性(Spring 循环依赖):

  1. Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256):Bean 名称到单例 Bean 的映射,用于存放完全初始化好的 Bean。可以理解成,这就是所谓的容器。这是一级缓存。

  2. Map<String, Object> earlySingletonObjects = new HashMap<>(16):Bean 到“未成熟”单例 Bean 的映射。该 Bean 对象只是被创建出来,但是还没有注入依赖。在容器解决循环依赖时,用于存储中间状态。这是二级缓存。

  3. Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16):Bean 名称到 Bean 的 ObjectFactory 对象的映射,存放 Bean 工厂对象。在容器解决循环依赖时,用于存储中间状态。这是三级缓存。

Bean 的获取过程就类似计算机缓存的作用过程:先从一级获取,失败再从二级、三级里面获取。org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean) 方法

实际中最长使用的是ApplicationContext这个高级形态的IOC容器。他除了具备基本的beanfactory的功能,还集成了很多附加功能:

  • 支持信息源,可以实现国际化。(实现MessageSource接口)
  • 访问资源。(实现ResourcePatternResolver接口,这个后面要讲)
  • 支持应用事件。(实现ApplicationEventPublisher接口)
  • 在ApplicationContext中提供的附加服务

IOC容器初始化:

refresh()方法标志着ioc容器的正式启动。具体包括beandefinition的resources定位、载入和注册三个过程

IOC容器的初始化分为三个过程实现:

  • 第一个过程是Resource资源定位。这个Resouce指的是BeanDefinition的资源定位。这个过程就是容器找数据的过程,就像水桶装水需要先找到水一样。
  • 第二个过程是BeanDefinition的载入过程。这个载入过程是把用户定义好的Bean表示成Ioc容器内部的数据结构,而这个容器内部的数据结构就是BeanDefition。
  • 第三个过程是向IOC容器注册这些BeanDefinition的过程,这个过程就是将前面的BeanDefition保存到HashMap中的过程。

Spring容器创建之后,会调用它的refresh方法,refresh的时候会做很多事情:比如完成配置类的解析、各种BeanFactoryPostProcessor和BeanPostProcessor的注册、国际化配置的初始化、web内置容器的构造等等。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/419165.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

部署和调优 3.4 腾讯企业邮箱免费版 未完

浏览器输入腾讯的企业邮箱官网 exmail.qq.com 点右上角的 申请开通 最下面有个 免费版 填好基本信息 根据提示验证密保邮箱 转载于:https://www.cnblogs.com/wangshaojun/p/5079304.html

前端学习(1715):前端系列javascript之页面配置

test-page.vue <template><view>test-page</view> </template><script>export default {data() {return {}},methods: {}} </script><style></style>page.json {"pages": [ //pages数组中第一项表示应用启动页&a…

03|复杂度分析(上):如何分析、统计算法的执行效率和资源消耗?

目录 为什么需要复杂度分析&#xff1f; 大 O 复杂度表示法 时间复杂度分析 几种常见时间复杂度 空间复杂度分析 为什么需要复杂度分析&#xff1f; 事后统计法&#xff1a;代码跑一遍&#xff0c;通过统计、监控&#xff0c;就能得到算法执行的时间和占用的内存大小。这种…

前端学习(1716):前端系列javascript之页面配置下

page.vue {"pages": [ //pages数组中第一项表示应用启动页&#xff0c;参考&#xff1a;https://uniapp.dcloud.io/collocation/pages{"path" : "pages/test-page/test-page","style" : {"navigationBarTitleText":"t…

git clone 速度过慢

由于公司内网限制&#xff0c;通过git clone mybatis的源码时速度贼慢 原来的方式&#xff1a;git clone ​​​​​​​https://github.com/mybatis/mybatis-3.git 超级慢——失败 改进方式&#xff1a;git clone https://github.com.cnpmjs.org/mybatis/mybatis-3.git 贼快…

前端学习(1718):前端系列javascript之生命周期上

<script>export default {onLaunch: function() {console.log(App Launch)//登录//用户信息//存储},onShow: function() {console.log(App Show)//时间戳//计算用胡得使用时间},onHide: function() {console.log(App Hide)//应用进入后台所作得得事情},onError(e){consol…

前端学习(1720):前端系列javascript之生命周期下

page2.vue <template><view>这是page2<button type"primary" click"open">点击跳转</button></view> </template><script>export default {data() {return {}},onLoad() {console.log(page onload2)},//页面渲…

06 | 链表(上):如何实现LRU缓存淘汰算法?

缓存 作用 缓存是一种提高数据读取性能的技术&#xff0c;在硬件设计、软件开发中都有着非常广泛的应用&#xff0c;比如常见的 CPU 缓存、数据库缓存、浏览器缓存等等。 淘汰策略 常见的策略有三种&#xff1a;先进先出策略 FIFO&#xff08;First In&#xff0c;First Ou…

C++处理一个动态规划的问题

嗯哼&#xff0c;别人问的问题&#xff0c;看的我也头晕&#xff0c;百度了一下动态规划&#xff0c;看了看才想起来该怎么做&#xff0c;今天写了写代码&#xff0c;实现了~ 要求是递归&#xff0c;动态规划&#xff0c;想了想这种方法也是最简单的~ 所谓动态规划&#xff1a;…

07 | 链表(下):如何轻松写出正确的链表代码?

目录 技巧一&#xff1a;理解指针或者引用的含义 技巧二&#xff1a;警惕指针丢失和内存泄漏 技巧三&#xff1a;利用哨兵简化实现难度 技巧四&#xff1a;重点留意边界条件处理 技巧五&#xff1a;举例画图&#xff0c;辅助思考 技巧六&#xff1a;多写多练&#xff0c;…

【转】成为Java顶尖程序员 ,看这10本书就够了

“学习的最好途径就是看书“&#xff0c;这是我自己学习并且小有了一定的积累之后的第一体会。个人认为看书有两点好处&#xff1a; 1.能出版出来的书一定是经过反复的思考、雕琢和审核的&#xff0c;因此从专业性的角度来说&#xff0c;一本好书的价值远超其他资料2.对着书上的…

08 | 栈:如何实现浏览器的前进和后退功能?

栈 后进者先出&#xff0c;先进者后出&#xff0c;这就是典型的“栈”结构。栈是一种“操作受限”的线性表&#xff0c;只允许在一端插入和删除数据。 为什么要使用到“栈”这种操作受限的数据结构&#xff1f; 事实上&#xff0c;从功能上来说&#xff0c;数组或链表确实可…

09 | 队列:队列在线程池等有限资源池中的应用

队列定义 先进者先出&#xff0c;这就是典型的“队列”。队列跟栈一样&#xff0c;也是一种操作受限的线性表数据结构。 顺序队列和链式队列 顺序队列&#xff1a;用数组实现的队列// 用数组实现的队列 public class ArrayQueue {// 数组&#xff1a;items&#xff0c;数组大…

PICT实现组合测试用例

成功安装后&#xff0c;在命令行中输入命令pict&#xff1a; 可以看到pict命令的一些选项&#xff1a;/o:N 组合数&#xff0c;默认值为2&#xff0c;即pict生成的测试用例集中每条测试数据会有两个值与其他测试集是不同的&#xff1b;/d:C 值与值之间的分隔符&#xff0c;…

10 | 递归:如何用三行代码找到“最终推荐人”?

什么是递归&#xff1f; 递归是一种应用非常广泛的算法&#xff08;或者编程技巧&#xff09;。很多数据结构和算法的编码实现都要用到递归&#xff0c;比如 DFS 深度优先搜索、前中后序二叉树遍历等等。 去的过程叫“递”&#xff0c;回来的过程叫“归” 场景 周末你带着女…

前端学习(1723):前端系列javascript之uniapp语法下

<template><view><view v-if"show">uniapp</view><view>geyao</view><view v-for"item in items">{{item}}</view><view v-on:click"onClick(uni-app)">点击</view></view> …

瑞星杀毒软件、奇虎360杀毒软件、360卫士、百度卫士联手,搞不定弹出广告 amp; 恶意广告图标...

一位网友说他的电脑近期出了问题&#xff1a;开机后桌面和任务栏上的高速启动栏会出现恶意图标。删除了下次开机又会出现&#xff1b;使用电脑过程中每分钟都会弹出广告。他为电脑安装了瑞星杀毒软件、奇虎360杀毒软件、360卫士、百度卫士。以及广告神盾&#xff0c;都不能解决…

11 | 排序(上):为什么插入排序比冒泡排序更受欢迎?

划重点&#xff1a;特定算法是依赖特定的数据结构的&#xff0c;带着问题去学习&#xff0c;是最有效的学习方法 本节分析冒泡排序、插入排序、选择排序三种排序算法 如何分析一个排序算法&#xff1f; 分析一个排序算法&#xff0c;要从以下几个方面入手&#xff1a; 排序算…

12 | 排序(下):如何用快排思想在O(n)内查找第K大元素?

算法对比&#xff1a; 算法时间复杂度适合场景冒泡排序、插入排序、选择排序O(n2)小规模数据归并排序、快速排序O(nlogn&#xff09;大规模数据 归并排序和快速排序都用到了分治思想&#xff0c;非常巧妙。我们可以借鉴这个思想&#xff0c;来解决非排序的问题&#xff0c;比如…