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

Spring 原理

目录

Bean 的作用域

概念

Bean 的作用域

Bean 的生命周期

源码阅读

Spring Boot 自动装配

Spring 加载 Bean

SpringBoot 源码

@EnableAutoConfiguration

1. @Import{Auto ConfigurationImportSelector.class}

2. @AutoConfigurationPackage

Spring 三级缓存

Spring 解决循环依赖

Spring MVC 流程

完!


Bean 的作用域

概念

在 Spring IoC&DI 中,研究了 Spring 帮我们管理对象的方法

        1. 通过 @Controller,@Service,@Respository,@Component,@Configuration,@Bean 注解来声明一个 Bean 对象

        2. 通过 @ApplicationContext 和 @BeanFactory 注解来获取对象

        3. 通过 @Autowired / @Resource / @Qualifire / Setter 方法 / 构造方法为应用程序注入所依赖的 Bean 对象

发现输出的 Bean 对象的地址值是一致的,说明每次从 Spring 容器中取出来的 Bean 对象是同一个,即单例模式。默认情况下,Spring 容器中的 bean 中都是单例的,这种行为模式,我们称之为 Bean 的作用域。

Bean 的作用域指 Bean 在 Spring 框架中的某种行为模式

比如单例作用域:表示该 Bean 对象,在整个 Spring 中就只有一份,是全局共享的, 当卡他人修改了这个值之后,另一个人收到的就是修改的值。

dog1 和 dog2 是同一个对象,dog2 拿到了 dog1 设置的值。

Bean 的作用域

在 Spring 中支持 6 中作用域,后 4 种在 Spring MVC 种才起作用

单例作用域中,多次访问的时候,得到的都是同一个对象,并且 @Autowired 和 applicationContext.getBean() 也是一个对象

多例作用域中,每次获取的对象都不一样。(@Autowired 注入的对象在 Spring

容器启动的时候,就已经注入了,所以多次请求的时候也不会发生变化)

请求作用域中,@Autowired 和 applicationContext.getBean() 也是同一个对象,但是每次请求的时候,都会重新创建对象

会话作用域中,在一个 session 中,多次请求,获得的对象都是同一个对象。

但是,当我们换另一个浏览器斤西瓜访问的时候,就会重现创建一个对象(换了浏览器就换了一个 Session)

Application 作用域中,在一个应用中,多次访问都是同一个对象。

在一个容器中 ApplicationContext 可以有多个。

Application scope 是针对于整个 web 容器来说的,bean 的作用域是 ServletContext 级别的,Application scope 和 singleten 有点类似,区别在于,Application scope 是 ServlectContext,singleton 是一个 ApplicationContext 的单例。

Bean 的生命周期

生命周期指的就是一个对象从创建到销毁的全过程。

Bean 的生命周期可以分为五个部分:

        1. 实例化(为 Bean 分配内存空间)

        2. 属性赋值(Bean 注入和赋值,例如 @Autowired)

        3. 初始化:

                3.1:执行各种通知(Aware 接口)(没有方法,仅用于标记 Bean 需要感知容器资源),常见的有 BeanNameAware:让 Bean 知道自己在容器中的名字,BeanFactoryAware:让 Bean 拿到容器的 BeanFactory,ApplicationContextAware:让 Bean 拿到容器的 ApplicationContext(即容器主动给 Bean 发消息,把容器的资源告诉 Bean)

                3.2:执行初始化方法,Bean 完成基础的 实例化 + 属性赋值后,Spring 就会调用开发者自定义的方法,让 Bean 完成额外的初始化工作

        4. 使用 Bean

        5. 销毁 Bean

源码阅读

创建 Bean 的代码入口在 AbstractAutowireCapableBeanFactory#createBean

doCreateBean 方法:

initializeBean:

调用三个Bean开头的Aware方法

invokeInitMethod:

通过反射调用开发者自定义的初始化方法

Spring Boot 自动装配

SpringBoot 的自动装配,指的是当 Spring 容器启动后,一些配置类,Bean 对象,就自动存储在了 IoC 容器中,不需要我们手动声明。

即,SpringBoot 是如何将依赖 jar 包中的配置类以及 Bean 加载到 Spring IoC 容器中。

Spring 加载 Bean

我们之前在使用第三方的 jar 包的时候,都是直接导包引入即可使用,但如果我们在自己的项目下创建不同的目录来模拟第三方的代码引入,就会发生报错。

原因:Spring  通过五大注解和 @Bean 注解可以帮助我们把 Bean 加载到 SpringIoC 容器中,但有个前提是,这些注解类必须和 SpringBoot 的启动类在同一个目录下。

但第三方的 jar 包也并不在启动类的目录系,为什么 Spring 能够帮我们管理呢?


解决办法:

        1. ComponentScan 组件扫描

        2. Import 导入(使用 @Import 导入的类会被 Spring 加载到 IoC 容器中)


使用 @ComponentScan 注解,可以指定 Spring 的扫描路径

但试想,如果我们大量引入第三方依赖,就需要大量的扫描注解,极其繁琐。

@Import

        1. 导入类

        2. 导入 ImportSelector 接口实现类

这种导入类的方式和扫描一样,也很繁琐。

这种方法先将一些第三方方法在 MyImportSelector 中进行导入,然后一个 Import 导入项目启动类即可。

但还是有一个缺点:使用者需要知道第三方以来中有那些 bean 对象或配置类,容易忽略。

但是,可以让第三方依赖的开发者完成这件事。

Spring 采用的就是这种方式

SpringBoot 源码

SpringBoot 底层是如何实现,一切来源与 SpringBoot 的启动类开始

@SpringBootApplication 标注的类,就是 SpringBoot 项目的启动类

SpringBootApplication 是一个组合注解

        1. 元注解:JDK 中提供了 4 个标准的用来对注解类型再进行注解的注解类,我们称为元注解。

                @Target 描述注解的使用范围

                @Retention:描述注解保留的时间范围

                @Documented:描述再使用 javadoc 工具为类生成帮助文档时是否保留注解信息

                @Inherited 使被它修饰的注解具有继承性

        2. @SpringBootConfiguration:里面就是 @Configuration,标注当前类为配置类

        3. @EnableAutoConfiguration:开启自动装配,后面我们详细了解

        4. @ComponentScan:包扫描。如果没有定义特定的包,就从声明该注解类的包开始扫描,这也是为什么 SpringBoot 项目声明的注解类必须要在启动类目录下的原因(excludeFilters:自定义过滤器,用于排除一些类)

@EnableAutoConfiguration

这个注解包含两部分:

1. @Import{Auto ConfigurationImportSelector.class}

即是我们上面将的方法,使用 @Import,导入实现了 ImportSelector 接口的实现类

ImportSelector 方法调用了 getAutoConfigurationEntry 方法

getAutoConfigurationEntry 方法调用了 getCandidateConfigrations 方法


getCandidateConfigurations 方法中,获取所有基于

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.impots文件

META-INF/spring.factories 文件中配置类的集合

在引入的起步依赖中,通常都包含这两个文件

在这里面,就包含了很多第三方依赖的配置文件

2. @AutoConfigurationPackage

这个注解主要是导入一个配置文件 AutoConfigurationPackages.Registrar.class

Registrar实现了 ImportBeanDefinitionRegistrar 类,就可以被注解@Import导⼊到spring 容器里.

(String[])(new PackageImports(metadata)).getPackageNames().toArray(new String[0]) :当前启动类所在的包名.

即 @AutoConfigurationPackage 的作用就是将启动类所在的包下面的所有的组件都扫描注册到 Spring 容器中

SpringBoot 自动装配原理流程图如下:

当 SpringBoot 程序启动的时候,会加载配置文件中所定义的配置类,通过 @Import 注解将这些注解全部加载到 Spring 的 IoC 容器中管理。

Spring 三级缓存

Spring 是如何解决循环依赖问题的 ==》 三级缓存

什么是循环依赖?

举个栗子:A 对象依赖了 B 对象,但是 B 对象同时也依赖了 A 对象

回顾 Bean 的生命周期:

上面前四步执行完毕后,才算一个初始化完毕的 Bean,也就是 Spring 容器中完整的 Bean 对象

Spring 容器中保存 Bean,使用缓存的方式:使用 Map<String,Object> 结构,key 为 Bean 的名称,value 为 Bean 的对象。需要的时候直接从缓存中获取。

如果出现 A,B 互相依赖的情况:

容器中没有 A,会实例化 A 对象

在实例化 A 的时候,需要装配 B 对象,发现 B 在容器中没有,则先实例化 B

实例化 B 对象

在实例化 B 的时候,需要装配 A 对象,发现 A 在容器中没有,则对 A 进行实例化

重复了~~~ 开始套娃~~

注意:由于 Spring 支持构造方法注入,属性注入,Setter 注入,所以,不能简单的先把所有的对象都实例化放到缓存中,然后执行初始化。

原因:虽然可以先全都实例化,获取所有对象的引诱,但对象中的属性都是 null,当我们执行初始化的时候可能会出现空指针异常。

即,Spring 其实只能解决部分循环依赖问题。

Spring 解决循环依赖

Spring 使用三级缓存的机制来解决循环依赖的问题。

单例模式中 A B 循环依赖执行流程如下:

Spring MVC 流程

完!

http://www.dtcms.com/a/467500.html

相关文章:

  • openharmony之预置应用配置与安装命令
  • Python生产环境构建
  • 北京网站建设w亿玛酷1专注关于加强公司网站建设的通知
  • 珠海网站制作渠道电商推广和网络推广的策略
  • 旅游网站建设案例分析镇江公交优化
  • 用everything实现从主机下载资源
  • 网站开发与维护好找工作吗wordpress分类目录添加图片
  • 深入了解 IDS/IPS/IDP:概念、问题与应对策略
  • 珠海企业建站西宁软件网站建设
  • 什么网站可以做动画报名系统网站开发
  • 杭州富阳建设局网站女孩子做室内设计累吗
  • flash做网站步骤最近中文字幕2018免费版2019
  • 个人网站可以做推广不dedecms做的网站手机上看图片变形
  • 江苏住房建设厅网站温州建设集团招聘信息网站
  • 【iOS】KVC总结
  • 湖北省建设厅投标报名官方网站企业产品做哪个网站推广好
  • stable-diffusion试验1-静态人物
  • 信息网站建设费使用年限望野王
  • C++ 中 std::numeric_limits使用详解
  • 爱网站无法登录怎么回事seo网络优化公司
  • 思睿鸿途北京网站建设网页设计模板素材网站
  • Google 智能体设计模式:反思
  • 网页设计与网站建设实训目的装修平台app
  • dede无法更新网站主页到asp.net网站开发典型模块与实例精讲
  • [嵌入式系统-90]:GPU是一个以极致并行计算为目标的专用加速器芯片,其特点是拥有海量轻量级处理单元和高带宽内存系统,用于执行高度规则的数据并行任务。
  • 类和对象的创建
  • 网站建设管理风险点站外推广渠道
  • 永兴做网站聚美优品网站建设分析
  • 实现支持链式调用但构造函数不可链式调用的 JavaScript 类
  • Python 函数与Lambda表达式完整指南