Spring 原理

  • 🎥 个人主页:Dikz12
  • 🔥个人专栏:Spring学习之路
  • 📕格言:吾愚多不敏,而愿加学
  • 欢迎大家👍点赞✍评论⭐收藏

目录

Bean的作用域

代码实现

观察Bean的作用域

Bean的生命周期

Spring Boot自动配置

原理分析 

1. 元注解.

2.  @SpringBootConfiguration.

3. @EnableAutoConfiguration (开启⾃动配置).

4.@ComponentScan (包扫描)

总结 


Bean的作用域

在Spring中⽀持6种作⽤域,后4种在Spring MVC环境才⽣效
  1. singleton:单例作⽤域
  2. prototype:原型作⽤域(多例作⽤域)
  3. request:请求作⽤域
  4. session:会话作⽤域
  5.  Application: 全局作⽤域
  6.  websocket:HTTP WebSocket 作⽤域
     作⽤域
 说明
singleton
每个Spring IoC容器内同名称的bean只有⼀个实例(单例)(默认)
prototype
每次使⽤该bean时会创建新的实例(⾮单例)
request
每个HTTP 请求⽣命周期内, 创建新的实例(web环境中, 了解)
session
每个HTTP Session⽣命周期内, 创建新的实例(web环境中, 了解)
 Application
每个ServletContext⽣命周期内, 创建新的实例(web环境中, 了解)
websocket
每个WebSocket⽣命周期内, 创建新的实例(web环境中, 了解)

官方参考文档:https://docs.spring.io/spring-framework/reference/core/beans/factory-scopes.html

代码实现

定义几个不同作用域Bean.

@Configuration
public class BeanConfig {

    @Scope("singleton")
    @Bean
    public User singleUser() {
        return new User();
    }

    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    @Bean
    public User prototypeUser() {
        return new User();
    }
    //请求作用域
    @RequestScope
    @Bean
    public User requestUser() {
        return new User();
    }
    //会话作用域
    @SessionScope
    @Bean
    public User sessionUser() {
        return new User();
    }
    //全局作用域
    @ApplicationScope
    @Bean
    public User applicationUser() {
        return new User();
    }
}
@RequestScope 等同于 @Scope(value = WebApplicationContext.SCOPE_REQUEST , proxyMode = ScopedProxyMode.TARGET_CLASS )
proxyMode⽤来为spring bean设置代理. proxyMode = ScopedProxyMode. TARGET_CLASS
表⽰这个Bean基于CGLIB实现动态代理. Request, session和application作⽤域的Bean 需要设置
proxyMode
@RestController
@RequestMapping("/scope")
public class BeanScopeController {
    @Autowired
    private ApplicationContext context;
    @Resource(name = "singleUser")
    private User singleUser;

    @Resource(name = "prototypeUser")
    private User prototypeUser;

    @Resource(name = "requestUser")
    private User requestUser;

    //单例作用域
    @RequestMapping("/single")
    public String single(){
        /**
         * 1. 从context获取对象
         * 2. 属性注入获取对象
         */
        User user = (User) context.getBean("singleUser");
        return "context获取的对象:"+user+",属性注入获取的对象:"+singleUser;
    }
    //原型作用域(多例)
    @RequestMapping("/prototype")
    public String prototypeUser(){
        /**
         * 1. 从context获取对象
         * 2. 属性注入获取对象
         */
        User user = (User) context.getBean("prototypeUser");
        // 栈上的引用地址
//        return "context获取的对象:"+user+",属性注入获取的对象:"+prototypeUser;
        //打印内存地址
        return "context获取的对象:"+System.identityHashCode(user)+",属性注入获取的对象:"+System.identityHashCode(prototypeUser);
    }

    //请求作用域
    @RequestMapping("/request")
    public String requestUser() {
        User user = (User) context.getBean("requestUser");
//        return "context获取的对象:"+System.identityHashCode(user)+",属性注入获取的对象:"+System.identityHashCode(requestUser);
        System.out.println(user.toString());
        System.out.println(user.getClass().getName() + "@" + Integer.toHexString(user.hashCode()));
        return "context获取的对象:"+user+",属性注入获取的对象:"+requestUser;
    }
}

观察Bean的作用域

单例作用域 :

多次访问, 得到的都是同⼀个对象, 并且 @Autowired applicationContext.getBean() 也是同⼀个对象.

多例作用域 :

观察ContextDog, 每次获取的对象都不⼀样(注⼊的对象在Spring容器启动时, 就已经注⼊了, 所以多次 请求也不会发⽣变化).

请求作用域:

在⼀次请求中, @Autowired applicationContext.getBean() 也是同⼀个对象.
但是每次请求, 都会重新创建对象.

Bean的生命周期

⽣命周期指的是⼀个对象从诞⽣到销毁的整个⽣命过程,我们把这个过程就叫做⼀个对象的⽣命周期.

1. 实例化(为Bean分配内存空间)
2. 属性赋值(Bean注⼊和装配,⽐如 @AutoWired )
3. 初始化
       a. 执⾏各种通知,如BeanNameAware ,BeanFactoryAware ,ApplicationContextAware 的接⼝⽅法.
      b. 执⾏初始化⽅法
           ▪ xml定义 init-method
           ▪ 使⽤注解的⽅式 @PostConstruct
           ▪ 执⾏初始化后置⽅法( BeanPostProcessor )
4. 使⽤Bean.

5.销毁Bean.

实例化和属性赋值对应构造⽅法和setter⽅法的注⼊.  初始化和销毁是⽤⼾能⾃定义扩展的两个阶段,可以在实例化之后,类加载完成之前进⾏⾃定义"事件"处理.

⽐如我们现在需要买⼀栋房⼦,那么我们的流程是这样的:

  1. 先买房(实例化,从⽆到有)
  2. 装修(设置属性)
  3. 买家电,如洗⾐机,冰箱,电视,空调等([各种]初始化,可以⼊住);
  4. ⼊住(使⽤ Bean)
  5. 卖房(Bean 销毁)

 执行流程如下:

Spring Boot自动配置

SpringBoot的⾃动配置就是当Spring容器启动后,⼀些配置类,bean对象等就⾃动存⼊到了IoC容器中,不需要我们⼿动去声明,从⽽简化了开发,省去了繁琐的配置操作.
SpringBoot⾃动配置,就是指SpringBoot是如何将依赖jar包中的配置类以及Bean加载到Spring IoC容器中的.

原理分析 

SpringBoot是如何帮助我们做的呢?⼀切的来⾃起源SpringBoot的启动类开始.

@SpringBootApplication 标注的类就是SpringBoot项⽬的启动类.

@SpringBootApplication
public class SpringIocApplication {
    public static void main(String[] args) {
         //获取Spring上下⽂对象
        ApplicationContext context = SpringApplication.run(SpringIocApplication.class, args);
         //从Spring上下⽂中获取对象
        BeanLifeComponent beanLifeComponent = context.getBean(BeanLifeComponent.class);
          beanLifeComponent.use();
   }
}

这个类和普通类唯⼀的区别就是 @SpringBootApplication 注解,这个注解也是SpringBoot实现
⾃动配置的核⼼.

@SpringBootApplication 是⼀个组合注解,注解中包含了:

1. 元注解.

JDK中提供了4个标准的⽤来对注解类型进⾏注解的注解类,我们称之为meta-annotation(元注
解),他们分别是:
• @Target描述注解的使⽤范围(即被修饰的注解可以⽤在什么地⽅)
• @Retention描述注解保留的时间范围
• @Documented描述在使⽤javadoc⼯具为类⽣成帮助⽂档时是否要保留其注解信息
• @Inherited使被它修饰的注解具有继承性(如果某个类使⽤了被@Inherited修饰的注解,则
其⼦类将⾃动具有该注解)

2.  @SpringBootConfiguration.

⾥⾯就是@Configuration,标注当前类为配置类,其实只是做了⼀层封装改了个名字⽽已.
(@Indexed注解,是⽤来加速应⽤启动的,不⽤关⼼)

3. @EnableAutoConfiguration (开启⾃动配置).

  看下@EnableAutoConfiguration 注解的实现:

这个注解包含两部分:
1. @Import({AutoConfigurationImportSelector.class}) 。

    使⽤@Import注解,导⼊了实现ImportSelector接⼝的实现类 .

  •     selectImports() ⽅法底层调⽤ getAutoConfigurationEntry() ⽅法,获取可⾃动配置的
  •     配置类信息集合.
  •    getAutoConfigurationEntry() ⽅法通过调⽤  getCandidateConfigurations(annotationMetadata, attributes) ⽅法获取在配置⽂件中配置的所有⾃动配置类的集合.

2. @AutoConfigurationPackage.

这个注解主要是导⼊⼀个配置⽂件 AutoConfigurationPackages.Registrar.class.

   static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
        Registrar() {
        }

        public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            AutoConfigurationPackages.register(registry, (String[])(new PackageImports(metadata)).getPackageNames().toArray(new String[0]));
        }

        public Set<Object> determineImports(AnnotationMetadata metadata) {
            return Collections.singleton(new PackageImports(metadata));
        }
    }

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

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

4.@ComponentScan (包扫描)

可以通过 basePackageClasses  或 basePackages 来定义要扫描的特定包,如果没有定义
特定的包,将从声明该注解的类的包开始扫描,这也是为什么SpringBoot项⽬声明的注解类必须要在启动类的⽬录下.
excludeFilters⾃定义过滤器,通常⽤于排除⼀些类,注解等.

总结 

SpringBoot⾃动配置原理的⼤概流程如下:


 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[单片机课设]十字路口交通灯的设计

题目要求&#xff1a; 模拟交通灯运行情况。南北绿灯亮30秒&#xff0c;南北黄灯亮3秒&#xff0c;东西红灯亮33秒&#xff1b;南北红灯亮33秒&#xff0c;东西绿灯亮30秒&#xff0c;东西黄灯亮3秒&#xff1b;要求数码管同步显示时间的倒计时&#xff0c;用定时器实现延时。…

Java_从入门到JavaEE_07

一、数组的排序&#xff08;冒泡排序&#xff09; 原理&#xff1a; 从下标“0”开始&#xff0c;相邻两个元素依次进行比较&#xff0c;每次找出最大的往后移动。 规律&#xff1a;N个数字来排队&#xff0c;两两相比小靠前&#xff0c;外层循环N-1&#xff0c;内层循环N-1-i…

error LNK2001: 无法解析的外部符号 “__declspec(dllimport) public: __cdecl ......

运行程序时&#xff0c;报如上图所示错误&#xff0c;其中一条是&#xff1a; ReflectionProbe.obj : error LNK2001: 无法解析的外部符号 "__declspec(dllimport) public: __cdecl osg::Object::Object(bool)" (__imp_??0ObjectosgQEAA_NZ) 报这个错误一般是因为…

MongoDB详解

目录 一、MongoDB概述 1.MongoDB定义 2.MongoDB主要特点 2.1文档 2.2集合 2.3数据库 2.4数据模型 二、安装MongoDB 1.Windows安装MongoDB 1.1下载MongoDB 1.2安装MongoDB 1.3配置MongoDB 1.3.1可能遇到的问题 1.4安装一盒可视化工具 2.Linux安装MongoDB 2.1下载…

鸿蒙内核源码分析(用栈方式篇) | 程序运行场地谁提供的

精读内核源码就绕不过汇编语言&#xff0c;鸿蒙内核有6个汇编文件&#xff0c;读不懂它们就真的很难理解以下问题. 1.系统调用是如何实现的? 2.CPU是如何切换任务和进程上下文的? 3.硬件中断是如何处理的? 4.main函数到底是怎么来的? 5.开机最开始发生了什么? 6.关机…

WPF之XmlDataProvider使用

1&#xff0c;WPF XAML支持数据提供&#xff08;DataProvider&#xff09;&#xff0c;但其提供的数据只供查看不可进行修改&#xff0c;删除&#xff0c;添加等。 数据提供者都继承自System.Windows.DataSourceProvider类&#xff0c;目前&#xff0c;WPF只提供两个数据提供者…

Stream流操作

看到Stream流这个概念&#xff0c;我们很容易将其于IO流联系在一起&#xff0c;事实上&#xff0c;两者并没有什么关系&#xff0c;IO流是用于处理数据传输的&#xff0c;而Stream流则是用于操作集合的。 当然&#xff0c;为了方便我们区分&#xff0c;我们依旧在这里复习一下…

深度学习:基于Keras,使用长短期记忆神经网络模型LSTM和RMSProp优化算法进行销售预测分析

前言 系列专栏&#xff1a;【机器学习&#xff1a;项目实战100】【2024】✨︎ 在本专栏中不仅包含一些适合初学者的最新机器学习项目&#xff0c;每个项目都处理一组不同的问题&#xff0c;包括监督和无监督学习、分类、回归和聚类&#xff0c;而且涉及创建深度学习模型、处理非…

今日早报 每日精选15条新闻简报 每天一分钟 知晓天下事 5月5日,星期日

每天一分钟&#xff0c;知晓天下事&#xff01; 2024年5月5日 星期日 农历三月廿七 立夏 1、 近日国际金价大幅震荡&#xff0c;跌至近一个月新低。 2、 2024亚洲少年攀岩锦标赛&#xff1a;中国选手包揽U14和U12速度赛男女组前三名。 3、 马来西亚将进一步优化中国游客入境程…

【详细教程】手把手教你开通YouTube官方API接口(youtube data api v3)

文章目录 一、背景调查1.1 youtube介绍1.2 分析价值与意义1.3 API接口介绍 二、申请接口权限2.1、注册Google账号2.2、创建项目2.3、启用youtube data api v3服务2.4、创建凭据 三、后续发布 一、背景调查 1.1 youtube介绍 众所周知&#xff0c;youtube是目前全球最大的视频社…

MyCat安装配置,及数据分片

&#x1f353; 简介&#xff1a;java系列技术分享(&#x1f449;持续更新中…&#x1f525;) &#x1f353; 初衷:一起学习、一起进步、坚持不懈 &#x1f353; 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正&#x1f64f; &#x1f353; 希望这篇文章对你有所帮助,欢…

Python深度学习基于Tensorflow(1)Numpy基础

numpy的重要性不言而喻&#xff0c;一般不涉及到GPU/TPU计算&#xff0c;都是用numpy&#xff0c;常见的np就是这个玩意。其特点就是快&#xff01;其实如果不涉及到深度学习&#xff0c;还有一个库是很重要的&#xff0c;scipy&#xff0c;集成了很多的东西。 安装和导入如下…

002-ChatGLM4接入Langchain

智谱AI GLM-4 新一代基座大模型GLM-4,整体性能相比GLM3全面提升60%,逼近GPT-4;支持更长上下文;更强的多模态;支持更快推理速度,更多并发,大大降低推理成本;同时GLM-4增强了智能体能力。 基础能力(英文):GLM-4 在 MMLU、GSM8K、MATH、BBH、HellaSwag、HumanEval等…

[云原生]Docker-compose:一站式多容器应用部署神器

目录 引言 一、Docker Compose 简介 &#xff08;一&#xff09;基本信息 &#xff08;二&#xff09;核心特性 &#xff08;三&#xff09;文件格式 二、Docker Compose 环境安装 &#xff08;一&#xff09;准备安装包 &#xff08;二&#xff09;添加执行权限 三、…

[Meachines][Hard]Napper

Main $ nmap -p- -sC -sV 10.10.11.240 --min-rate 1000 $ curl http://10.10.11.240 $ gobuster dir -u "https://app.napper.htb" -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-small-words-lowercase.txt -k 博客 $ ffuf -c -w /usr/share/se…

深入学习和理解Django模板层:构建动态页面

title: 深入学习和理解Django模板层&#xff1a;构建动态页面 date: 2024/5/5 20:53:51 updated: 2024/5/5 20:53:51 categories: 后端开发 tags: Django模板表单处理静态文件国际化性能优化安全防护部署实践 第一章&#xff1a;模板语法基础 Django模板语法介绍 Django模…

Windows如何安装hadoop

Hadoop是一个开源的分布式计算平台&#xff0c;旨在处理大规模数据的存储和处理。它提供了分布式文件系统&#xff08;HDFS&#xff09;和分布式计算框架&#xff08;MapReduce&#xff09;&#xff0c;使得用户能够在大规模集群上存储和处理数据。Hadoop最初由Apache软件基金会…

【Java基础】15.脚本、编译、注解

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 文章目录 系列文章目录15.脚本、编译、注解15.1 Java的脚本机制15.1.1 获取脚本引擎15.1.2 脚本计算与绑定15.1.3 重定向输入和输出15.1.4 调用脚本的函数和方法15.1.5 编…

iOS - Undefined symbols: 解决方法

Undefined symbols: 是让人苦恼的报错&#xff0c;如何知道是 哪个 symbols 不对呢&#xff1f; 今天探索到下面的方法&#xff1a; 1、点击导航上方 最右侧的按钮&#xff0c;查看历史报错 2、选中报错信息&#xff0c;右键选择 Expand All Transcripts 在出现的详细信息面…

【ARM Cortex-M3指南】4:存储器系统

文章目录 四、存储器系统4.1 存储器系统特性概述4.2 存储器映射4.3 存储器访问属性4.4 默认的存储器访问权限4.5 位段操作4.5.1 位段操作的优势4.5.2 不同数据宽度的位段操作4.5.3 C程序实现位段操作 4.6 非对称传输4.7 排他访问4.8 端模式 四、存储器系统 4.1 存储器系统特性…
最新文章