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

简介: Spring 第一节 拾枝杂谈 分析Spring底层容器。

目录

一、前言

二、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核心组件如下图所示 :

    image.gif 编辑

           2. 入门实例 :

                   需求 :使用Spring的方式获取JavaBean对象,并打印出该对象的信息

                   首先,需要向Java项目中导入所需要的jar包,除commons-logging.jar外,其余都可在Spring的安装目录下的libs子目录中找到。如下图所示 :

    image.gif编辑

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

    image.gif编辑

                   若创建文件后,出现提示“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 +
                    '}';
        }
    }

    image.gif

                   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>

    image.gif

                   在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()));
        }
    }

    image.gif

                   运行结果 :

    image.gif编辑


    三、Spring容器结构分析

           1.bean配置信息的存储 :

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

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

    image.gif

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

    image.gif编辑

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

    image.gif编辑

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

    image.gif编辑

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

    image.gif编辑

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

    image.gif编辑

                   此处的beanClass即保存了当前bean对应的class属性,即配置的类的正名(全类名)

                   此外,我们还能在val中找到一个propertyValues属性,该属性保存了当前bean中的所有property子元素的值,如下所示 :

    image.gif编辑

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

    image.gif编辑

           2.bean对象的存储 :

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

    image.gif编辑

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

    image.gif编辑

          3.bean-id的快捷访问 :

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

    image.gif编辑

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

    image.gif编辑

                   我们可以通过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);
            }
        }

    image.gif

                  运行结果 :

    image.gif编辑


    四、总结

                   🆗,以上就是Spring系列第一小节的全部内容了。

                   最后,我们可以用一张图总结一下Spring原生容器结构,如下图所示 :

    image.gif编辑

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

    目录
    相关文章
    |
    3月前
    |
    XML Java 数据格式
    Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
    这篇文章是Spring5框架的实战教程,主要介绍了如何在Spring的IOC容器中通过XML配置方式使用外部属性文件来管理Bean,特别是数据库连接池的配置。文章详细讲解了创建属性文件、引入属性文件到Spring配置、以及如何使用属性占位符来引用属性文件中的值。
    Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
    |
    29天前
    |
    Java 测试技术 Windows
    咦!Spring容器里为什么没有我需要的Bean?
    【10月更文挑战第11天】项目经理给小菜分配了一个紧急需求,小菜迅速搭建了一个SpringBoot项目并完成了开发。然而,启动测试时发现接口404,原因是控制器包不在默认扫描路径下。通过配置`@ComponentScan`的`basePackages`字段,解决了问题。总结:`@SpringBootApplication`默认只扫描当前包下的组件,需要扫描其他包时需配置`@ComponentScan`。
    |
    16天前
    |
    人工智能 Anolis 开发者
    |
    1月前
    |
    XML Java 数据格式
    Spring IOC容器的深度解析及实战应用
    【10月更文挑战第14天】在软件工程中,随着系统规模的扩大,对象间的依赖关系变得越来越复杂,这导致了系统的高耦合度,增加了开发和维护的难度。为解决这一问题,Michael Mattson在1996年提出了IOC(Inversion of Control,控制反转)理论,旨在降低对象间的耦合度,提高系统的灵活性和可维护性。Spring框架正是基于这一理论,通过IOC容器实现了对象间的依赖注入和生命周期管理。
    65 0
    |
    2月前
    |
    XML Java 开发者
    经典面试---spring IOC容器的核心实现原理
    作为一名拥有十年研发经验的工程师,对Spring框架尤其是其IOC(Inversion of Control,控制反转)容器的核心实现原理有着深入的理解。
    120 3
    |
    3月前
    |
    XML Java 数据格式
    Spring5入门到实战------5、IOC容器-Bean管理(三)
    这篇文章深入探讨了Spring5框架中IOC容器的高级Bean管理,包括FactoryBean的使用、Bean作用域的设置、Bean生命周期的详细解释以及Bean后置处理器的实现和应用。
    Spring5入门到实战------5、IOC容器-Bean管理(三)
    |
    3月前
    |
    XML Java 数据格式
    Spring5入门到实战------6、IOC容器-Bean管理XML方式(自动装配)
    这篇文章是Spring5框架的入门教程,详细讲解了IOC容器中Bean的自动装配机制,包括手动装配、`byName`和`byType`两种自动装配方式,并通过XML配置文件和Java代码示例展示了如何在Spring中实现自动装配。
    Spring5入门到实战------6、IOC容器-Bean管理XML方式(自动装配)
    |
    3月前
    |
    XML Java 数据格式
    Spring5入门到实战------2、IOC容器底层原理
    这篇文章深入探讨了Spring5框架中的IOC容器,包括IOC的概念、底层原理、以及BeanFactory接口和ApplicationContext接口的介绍。文章通过图解和实例代码,解释了IOC如何通过工厂模式和反射机制实现对象的创建和管理,以及如何降低代码耦合度,提高开发效率。
    Spring5入门到实战------2、IOC容器底层原理
    |
    3月前
    |
    XML Java 数据格式
    Spring5入门到实战------8、IOC容器-Bean管理注解方式
    这篇文章详细介绍了Spring5框架中使用注解进行Bean管理的方法,包括创建Bean的注解、自动装配和属性注入的注解,以及如何用配置类替代XML配置文件实现完全注解开发。
    Spring5入门到实战------8、IOC容器-Bean管理注解方式
    |
    6天前
    |
    Kubernetes Cloud Native Docker
    云原生时代的容器化实践:Docker和Kubernetes入门
    【10月更文挑战第37天】在数字化转型的浪潮中,云原生技术成为企业提升敏捷性和效率的关键。本篇文章将引导读者了解如何利用Docker进行容器化打包及部署,以及Kubernetes集群管理的基础操作,帮助初学者快速入门云原生的世界。通过实际案例分析,我们将深入探讨这些技术在现代IT架构中的应用与影响。
    28 2