Spring 拾枝杂谈—Spring原生容器结构剖析(通俗易懂)

news2025/7/19 15:42:35

目录

一、前言

二、Spring快速入门

        1.简介 : 

        2. 入门实例 : 

三、Spring容器结构分析

        1.bean配置信息的存储 : 

        2.bean对象的存储 : 

        3.bean-id的快捷访问 : 

四、总结


一、前言

  • 开门见山,11.25日开始我们正式进入Java框架—Spring的学习,此前,up已经出过Java基础-->Java进阶-->MySQL-->JDBC-->JavaWeb的系列文章,大佬们可以进入我的主页,选择不同专栏进行阅读🌹🌹。对于这个新的系列,up准备和此前的JDBC系列一样,重点把内容讲清楚,说明白,以达到博文查漏补缺的本意,至于细枝末节,概所不录。
  • 第一节内容,up主要和大家分享一下Spring原生容器结构,以及Spring入门案例
  • 关于注意事项,还是老规矩——代码中的注释也很重要;不要眼高手低,自己跟着过一遍才有收获;点击文章的侧边栏目录或者文章开头的目录可以进行跳转。
  • 良工不示人以朴,所有文章都会适时补充完善。大家如果有问题都可以在评论区进行交流或者私信up。感谢阅读!

二、Spring快速入门

        1.简介 : 

        (1) 我们平时所说的Java框架"Spring"通常指的是"Spring Framework"。Spring本身作为一个框架,又可以整合其他的框架,即可以认为,Spring是管理其他框架的框架

        (2) Spring核心知识点——IOC(Inversion of Control)控制反转,AOP(Aspect Oriented Programming)面向切面编程,JDBCTemplate,声明式事务

        (3) Spring5核心组件如下图所示 : 

        2. 入门实例 : 

                需求 : 使用Spring的方式获取JavaBean对象,并打印出该对象的信息
                首先,需要向Java项目中导入所需要的jar包,除commons-logging.jar外,其余都可在Spring的安装目录下的libs子目录中找到。如下图所示 : 

                接着,在src目录下创建beans.xml配置文件,创建流程如下图所示 : 

                若创建文件后,出现提示“Application context not configured for this file”,根据IDEA给出的提示操作即可。
                接着,up在com.cyan.spring.bean包下新创建一个JavaBean类,以Student类为例,Student类代码如下 : 

package com.cyan.spring.bean;

/**
 * @author : Cyan_RA9
 * @version : 21.0
 */
public class Student {
    private String name;
    private int age;
    private int score;

    public Student() {

    }
    public Student(String name, int age, int score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

    public int getScore() {
        return score;
    }
    public void setScore(int score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}';
    }
}

                beans.xml代码如下 : (注意注释内容)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--
        (1) 在根元素beans中,通过<bean></bean>子元素来配置JavaBean对象。
            每配置一个bean,相当于配置了一个Java对象。
        (2) bean子元素需要配置两个属性———class 和 id。其中,
            class表示所要实例化类的正名(全类名);
            id表示该对象在Spring容器中的标识,通过id可以获取到对象。
        (3) property子元素用于配置该对象的成员变量(对象的属性),其中,
            name表示属性名称,value表示属性的值。
        (4) XML内容回顾———若一个标签没有标签体,以<age></age>为例,可以简写为<age/>。
    -->
    <bean class="com.cyan.spring.bean.Student" id="stu01">
        <property name="name" value="Cyan"></property>
        <property name="age" value="21"></property>
        <property name="score" value="450"></property>
    </bean>
    <bean class="com.cyan.spring.bean.Student" id="stu02">
        <property name="name" value="Rain"></property>
        <property name="age" value="19"></property>
        <property name="score" value="443"></property>
    </bean>
    <!--
        PS : 若配置bean时,未给出id属性,IDEA不会报错,系统会分配默认的id。
             默认id的规则是 : 全类名#0, 全类名#1, 全类名#2......
    -->
</beans>

                在test包下另定义一个测试类,用于获取到配置好的Student对象,并打印出该对象的信息。   
                StudentBeanTest类代码如下 : 

package com.cyan.spring.test;

import com.cyan.spring.bean.Student;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author : Cyan_RA9
 * @version : 21.0
 */
public class StudentBeanTest {
    @Test
    public void getStudent() {
        //(1) 创建容器ApplicationContext,该容器与beans.xml配置文件关联
            //接口多态
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");

        //(2) 通过getBean方法,获取到容器中配置好的对象
        //Object stu01 = applicationContext.getBean("stu01");
            //向下转型
        Student stu01 = (Student) applicationContext.getBean("stu01");
            //向下转型后,即可使用子类特有的方法
        String name = stu01.getName();
        int age = stu01.getAge();
        int score = stu01.getScore();

            //亦可通过getBean的重载方法直接返回JavaBean对应的类型。
        Student stu02 = applicationContext.getBean("stu02", Student.class);

        //(3) 打印对象信息
        System.out.println("stu01 = " + stu01);
        System.out.println("stu01's name = " + name);
        System.out.println("stu01's age = " + age);
        System.out.println("stu01's score = " + score);

        System.out.println(String.format("stu02: name = %s,age = %d,score = %d",stu02.getName(),stu02.getAge(),stu02.getScore()));
    }
}

                运行结果 : 


三、Spring容器结构分析

        1.bean配置信息的存储 : 

                注意刚才的案例中有这么一行代码:

//(1) 创建容器ApplicationContext,该容器与beans.xml配置文件关联
            //接口多态
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");

                在Debug界面中,可以看到applicationContext对象的结构,beanFactory是该容器对象的一个非常重要的属性,如下图所示 : 

                在beanFactory属性下,可以找到它维护的beanDefinitionMap,是CurrentHashMap类型。如下所示 : 

                此处的Node是CurrentHashMap的一个静态内部类, 它与我们之前接触过的HashMap$Node类型以及Hashtable$Entry类型一样,都实现了Map接口内部的Entry接口,如下图所示 : 

                我们可以在table数组中,找到beans.xml文件中配置的对象的信息,如下图所示 : 

                可以看到,key就是我们为每一个bean元素配置的id属性;而在val中,首先我们可以看到保存的类的全类名,如下所示 : 

                此处的beanClass即保存了当前bean对应的class属性,即配置的类的正名(全类名)
                此外,我们还能在val中找到一个propertyValues属性,该属性保存了当前bean中的所有property子元素的值,如下所示 : 

                可以看到,居然出现了我们熟悉的ArrayList和elementData[],数组中的每一个元素,都对应一个bean的property属性,即对象的属性,如下图所示 : (eg : name = "Cyan")

        2.bean对象的存储 : 

                 在beanFactory属性下,除了方才的beanDefinitionMap,我们还可以找到一个重要的属性singletonObjects,如下图所示 : 

                可以看到,singletonObjects属性同方才的beanDefinitionMap属性一样,也是ConcurrentHashMap类型,并且它们都维护了一个ConcurrentHashMap$Node类型的数组table,我们仍然可以在table数组中找到配置的两个Student类对象,只不过它们这次是真的以"对象"形式来保存了(单例),如下图所示:

        3.bean-id的快捷访问 : 

                仍然是在beanFactory属性下,除了方才的beanDefinitionMap和singletonObjects属性外,我们还要注意到beanDefinitionNames属性,如下图所示 : 

                这是Spring的设计者为了开发人员能够快捷地访问到Spring容器中保存的对象的id,专门把id保存在了该属性中,可以看到,它直接就用ArrayList来存储了。于是我们可以在elementData数组中,发现之前在beans.xml中配置的两个bean的id,如下图所示 : 

                我们可以通过applicationContext对象的getBeanDefinitionNames()方法来快速获取到当前Spring容器中所有的id
                代码演示如下 : (仍然在StudentBeanTest类中,新定义一个方法,通过引入JUnit框架进行单元测试)

    @Test
    public void testGetStudentsID() {
        //不要忘记传入要关联的beans.xml配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();

        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println("id = " + beanDefinitionName);
        }
    }

                运行结果 : 


四、总结

                🆗,以上就是Spring系列第一小节的全部内容了。
                最后,我们可以用一张图总结一下Spring原生容器结构,如下图所示 : 

        System.out.println("END----------------------------------------------");

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

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

相关文章

midjourney过时了?如何使用基于LCM的绘图技术画出你心中的画卷。

生成 AI 艺术在近年来迅速发展&#xff0c;吸引了数百万用户。然而&#xff0c;传统的生成 AI 艺术需要等待几秒钟或几分钟才能生成&#xff0c;这对于快节奏的现代社会来说并不理想。 近日&#xff0c;中国清华大学和 AI 代码共享平台 HuggingFace 联合开发了一项新的机器学习…

群晖NAS基础设置

群晖NAS基础设置 最近一直在玩群晖NAS系统&#xff0c;有一些基础的配置跟大家分享一下 开启ssh登录 1.开启方法 控制面板—>终端和SNMP—>终端机 2.使用ssh软件登录 这里我用SecureCRT登录 进入ssh 3.进入root用户 starstar-nas:~$ sudo su -l root Password: ro…

Python----函数的数据 拆包(元组和字典)

Python拆包&#xff1a; 就是把元组或字典中的数据单独的拆分出来&#xff0c;然后赋予给其他的变量。 拆包: 对于函数中的多个返回数据, 去掉 元组, 列表 或者字典 直接获取里面数据的过程。 元组的拆包过程 def func():# 经过一系列操作返回一个元组return 100, 200 …

【Qt绘制仪表盘】

目的 使用Qt的绘制事件绘制一个仪表盘 思路 需要创建一个带绘制事件的控件重写绘制事件显示 实现 以下是实现代码&#xff0c;可复制到程序到&#xff0c;直接运行。 .h // GaugeWidget.h #ifndef GAUGEWIDGET_H #define GAUGEWIDGET_H#include <QWidget>class Ga…

redis事务及管道

目录 redis事务 1、redis事务命令 2、示例 redis管道 1、管道命令 2、示例 redis事务 在Redis中&#xff0c;事务是一组命令的有序队列&#xff0c;可以一次执行多个命令&#xff0c;本质是一组命令的集合。一个事务中的所有命令都会序列化&#xff0c;按顺序地串行化执…

【JavaEE】多线程 (1)

目录 1. 认识线程&#xff08;Thread&#xff09; 1) 线程是什么 2) 为啥要有线程 3) 进程和线程的区别 2.第⼀个多线程程序 3.多线程的其他创建方式 方法二:实现 Runnable 接⼝ 方法三:匿名内部类 方法四:实现Runable, 重写run, 匿名内部类 方法五:使用lambda表达式…

Leetcode—35.搜索插入位置【简单】

2023每日刷题&#xff08;四十&#xff09; Leetcode—35.搜索插入位置 实现代码 int lower_bound(int* arr, int numsSize, int tar) {int left 0, right numsSize;int mid;// 左闭右开[left, right)while(left < right) {mid left (right - left) / 2;if(arr[mid] &…

4G执法记录仪在大型安保集团,保安集团、蓝天救援队中的 应用,行为规范化,人员定位,考勤打卡,应急指挥调度

【智能化升级】揭秘4G/5G执法记录仪在安保与救援领域如何重塑行业标准与效率 在快速发展的社会当中&#xff0c;大型安保集团、保安集团和蓝天救援队所肩负的任务日益繁重与复杂。无论是在平时的治安巡查、安保执勤&#xff0c;还是在突发公共事件的应急响应中&#xff0c;如何…

C++ STL-----容器

STL容器就是将运用最广泛的一些数据结构实现出来 常用的数据结构&#xff1a;数组, 链表,树, 栈, 队列, 集合, 映射表 等 这些容器分为序列式容器和关联式容器两种: 序列式容器:强调值的排序&#xff0c;序列式容器中的每个元素均有固定的位置。 关联式容器:二叉树结构&…

JavaScript解构数组

还记得之前我们是如何读取到数组里面的元素的么&#xff1f; const arr [2, 3, 4]; const a arr[0]; const b arr[1]; const c arr[2];然后通过这个方式去读取数组中的数据&#xff1b; 现在我们可以使用解构赋值的方法去实现 const [x, y, z] arr; console.log(x, y, …

网络运维与网络安全 学习笔记2023.11.25

网络运维与网络安全 学习笔记 第二十六天 今日目标 ACL原理与类型、基本ACL配置、高级ACL配置 高级ACL之ICMP、高级ACL之telnet ACL原理与类型 项目背景 为了企业的业务安全&#xff0c;要求不同部门对服务器有不同的权限 PC1不能访问Server PC2允许访问Server 允许其他所…

Linux基本指令(前篇)

目录 1.ls指令 2.pwd指令 3.cd 指令 4.touch指令 5.mkdir指令&#xff08;重要&#xff09; 6.rmdir指令 && rm 指令&#xff08;重要&#xff09; 7.man指令&#xff08;重要&#xff09; 1.ls指令 ls 选项 目录或文件 对于目录&#xff0c;该命令列出该目录下的所…

MYSQL基础知识之【添加数据,查询数据】

文章目录 前言MySQL 插入数据通过命令提示窗口插入数据使用PHP脚本插入数据 MySQL 查询数据通过命令提示符获取数据使用PHP脚本来获取数据内存释放 后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;Mysql &#x1f431;‍&#x1f453;博…

STM32 配置中断常用库函数

单片机学习 目录 一、配置AFIO相关库函数 1.1函数GPIO_AFIODeInit 1.2函数GPIO_EventOutputConfig 1.3函数GPIO_EventOutputCmd 1.4函数GPIO_EXTILineConfig 二、配置EXTI相关库函数 2.1函数EXTI_DeInit 2.2函数EXTI_Init 2.3函数EXTI_StructInit 2.4函数 EXTI_Gener…

html实现我的故乡,城市介绍网站(附源码)

文章目录 1. 我生活的城市北京&#xff08;网站&#xff09;1.1 首页1.2 关于北京1.3 北京文化1.4 加入北京1.5 北京景点1.6 北京美食1.7 联系我们 2.效果和源码2.1 动态效果2.2 源代码 源码下载 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43…

spring本地事务与单/多线程

请直接看原文 原文链接:多线程与数据库事务以及数据库连接之间的关系 - 知乎 (zhihu.com) -------------------------------------------------------------------------------------------------------------------------------- 今天我们来梳理一下&#xff0c; 多线程、数…

033.Python面向对象_类补充_生命周期

我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448; 入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448; 虚 拟 环 境 搭 建 &#xff1a;&#x1f449;&…

Java基准测试工具JMH的简介与使用

JMH是一套Java基准测试工具&#xff0c;用于对Java执行进行基准测试以及生成测试报告。平时应用于Java一些基础Api或者一些工具类这种离开网络因素的纯系统测试。 使用方式 maven引入&#xff1a; <dependency><groupId>org.openjdk.jmh</groupId><art…

linux账户管理实例二

要求&#xff1a;我的 用户pro1&#xff0c;pro2&#xff0c;pro3是同一个项目开发人员&#xff0c;想让这三个人用户在同一个目录下工作&#xff0c;但这三个人拥有自己的主文件夹和基本的私有用户组&#xff0c;工作目录为/srv/projecta&#xff0c;如何实现&#xff1f; 分…

03_MySQL基本SQL语句讲解

#课程目标 能够创建、删除数据表能够对表里的数据记录进行增加、删除、修改、查询操作能够创建、删除用户能够给用户授权并回收权限了解delete和truncate语句的区别 #一、数据库基本操作 ##1、查看数据库相关信息 mysql> show databases; 查看所有数据库 mysql>…