• Spring学习:二、Bean的管理


    4. Bean的管理

    ​ Spring的基本Bean管理包括Bean配置,Bean实例化和Bean的依赖注入。这些管理可以通过手工编码的方式把每个Bean注册到容器中,也可以通过properties文件和xml文件配置Bean和Bean之间的依赖关系。通常我们的配置方式是XML作为配置文件。

    4.1 Bean的配置

    ​ 我们可以看一看前面例子的配置文件:

    <bean id="dog" class="org.suke.Dog" >bean>
    <bean id="cat" class="org.suke.Cat" >bean>
    <bean id="boy" class="org.suke.Boy" >
       <property name="pet" ref="dog">property>
    bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    配置一个Bean,id为Bean的标识,在配置Bean时,可以使用name属性为Bean指定标识。id 和name 属性都是用来指定bean的标识符。id具有唯一性,并且是XML中真正的id属性,XML解析器可以验证其的合法性,在使用中必须和Java中命名变量一样去命名id的值,比如不能以数字开始等约束。name属性值则没有要求,甚至在name中可以使用特殊字符(如等)。

    ​ 如果在配置文件中既没有配置id,也没有配置name,Spring会默认使用类的全名来标识,如果需要配置多个类名相同的对象,则spirng会使用 类名+#+数字的形式来标识。即如果配置了三个,那么标识分别是 “org.suke.Dog”” org.suke.Dog #1”,和” org.suke.Dog #2”

    ​ name属性其实就是为该Bean指定的别名,多个别名之间使用”,”进行分隔。还可以使用< alias >来指定别名,比如上面的dog使用alias来配置别名可以做如下配置:

    ​ 这样dog对象就被被标识为 dog,dog1,dog2,dog3,dog4这4个标识名,标记中的name可以是id的值,也可以是name的值(也就是说使用别名还可以再次重新命名),那么在程序中我们通过ApplicationContext对象或者BeanFactory的get方法获取bean对象的时候,就可以使用dog,dog1,dog2,dog3,dog4这4中标识中的任意一个来获取bean对象,获取到的bean对象都是同一个对象。

    class是Bean的全限定名。

    配置Bean的属性,name表示属性名,这个属性实际上是javaBean的setter方法,所以配置的类必须符合javaBean的规范。

    节点可以通过ref属性引用其他已经配置的Bean,ref的值是其他已经配置Bean的标识。如果这个属性的值是基本数据类型或者是String类型,只要该属性具有setter访问器,就可以使用value直接设置值。

    4.2 Bean的作用域(scope)

    ​ 配置文件中的Bean实例化后,该如何保存,就是Bean的作用域问题。比如:默认的作用域是singleton,表示对应Bean在容器中是单例的,整个系统只保存一份实例,实例化后即保存起来,直到系统结束才销毁,期间所有线程共享一份实例。Bean的作用域使用节点的scope属性来表示。

    ​ scope:指对象的作用范围,取值如下:

    取值范围说明
    singleton默认值,单例的
    prototype多例的
    requestWEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中
    sessionWEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中
    global sessionWEB 项目中,应用在 Portlet 环境,没有 Portlet 环境globalSession 相当于session

    重点是singleton与prototype两个作用域:

    1)当scope的取值为singleton时

    Bean的实例化个数:1个

    Bean的实例化时机:当Spring核心文件被加载时,实例化配置的Bean实例

    Bean的生命周期:

    • 对象创建:当应用加载,创建容器时,对象就被创建了

    • 对象运行:只要容器在,对象一直活着

    • 对象销毁:当应用卸载,销毁容器时,对象就被销毁了

    2)当scope的取值为prototype时

    Bean的实例化个数:多个

    Bean的实例化时机:当调用getBean()方法时实例化Bean

    • 对象创建:当使用对象时,创建新的对象实例

    • 对象运行:只要对象在使用中,就一直活着

    • 对象销毁:当对象长时间不用时,被 Java 的垃圾回收器回收了

    public class HelloImpl implements IHello {
        public String sayHello(String word) {
            return "hello:"+word;
        }
    
        public HelloImpl() {
            System.out.println("HelloImpl实例进行初始化....");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    <bean class="com.suke.hello.impl.HelloImpl" id="hello" scope="singleton">bean>
    
    • 1

    测试代码:

     @Test
        public void testScope(){
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
            IHello hello = applicationContext.getBean("hello", IHello.class);
    
            IHello hello2 = applicationContext.getBean("hello", IHello.class);
            System.out.println("是否是同一个对象:"+(hello == hello2));
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    测试结果:
    在这里插入图片描述

    现在我们把HelloImpl的bean设置为prototype,再来测试,看控制台的效果:

    <bean class="com.suke.hello.impl.HelloImpl" id="hello" scope="prototype">bean>
    
    • 1

    在这里插入图片描述

    4.3 Bean的生命周期的配置

    我们可以在Bean标签中使用init-method属性和destroy-method属性对bean的生命周期进行相关配置:

    • init-method:指定类中的初始化方法名称

    init-method用于指定bean的初始化方法。 我们知道spring会帮我们实例化对象,实例化对象之后,spring就会查找我们是否配置了init-method如果配置了,spring就会调用我们配置的initmethod方法,进行bean的初始化。

    • destroy-method:指定类中销毁方法名称

    destroy-methodinit-method一样,只是它是用来配置释放资源的方法,spring会在销毁当前bean对象之前调用destroy-method制定的方法。

    package com.suke.hello.impl;
    
    import com.suke.hello.IHello;
    
    public class HelloImpl implements IHello {
        public String sayHello(String word) {
            return "hello:"+word;
        }
    
        public HelloImpl() {
            System.out.println("HelloImpl实例进行初始化....");
        }
    
        public void init(){
            System.out.println("哈哈,我出生了...");
        }
    
        public void destroy(){
            System.out.println("555,我要走了...");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    <bean class="com.suke.hello.impl.HelloImpl" id="hello"  init-method="init" destroy-method="destroy">bean>
    
    • 1

    测试代码:

    @Test
    public void testLife(){
        AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        IHello hello = applicationContext.getBean("hello", IHello.class);
        hello.sayHello("spring");
        applicationContext.close();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    测试效果:
    在这里插入图片描述

    4.4 Spring Bean 的加载流程概述

    ​ Spring 作为 Ioc 框架,实现了依赖注入,由一个中心化的 Bean 工厂来负责各个 Bean 的实例化和依赖管理。各个 Bean 可以不需要关心各自的复杂的创建过程,达到了很好的解耦效果。

    ​ springBean的加载过程大致分为两个过程:解析注册,实例化
    在这里插入图片描述

    ​ spring先解析xml文件或者注解配置,读取所有要加载类信息。根据类信息创建对应的BeanDefinition对象,再根据Beandefination对象创建实例对象。

    ​ BeanDefinition是SpringBean的描述对象,主要封装了如下信息:

    在这里插入图片描述

    Spring通过BeanDefinition来进行bean的实例化, 实例化的bean存在BeanFactory的singletonObjects中
    在这里插入图片描述

    4.5 依赖注入属性配置

    4.5.1 依赖注入二种方式

    ​ 在DI的案例中,我们在UserService中是怎么把UserDao注入进来的呢?其实在Spring中提供了两种注入方式:

    • Set方法的注入
    • 构造方法的注入
    4.5.1.1 属性setter方法注入

    通过 元素,实现属性setter方法注入

    package com.suke.injection;
    
    public class Dog {
        private String name;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    package com.suke.injection;
    
    public class Person {
        private String name;
        private Dog dog;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Dog getDog() {
            return dog;
        }
    
        public void setDog(Dog dog) {
            this.dog = dog;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    配置:

     <bean id="d1" class="com.suke.injection.Dog">
         <property name="name" value="旺财"/>
     bean>
    
    • 1
    • 2
    • 3

    我们在使用property和constructor-arg为bean注入属性时,如果属性是简单类型,我们可以通过value直接注入。

    这里简单类型主要是指java的基本类型和String型

    <bean id="p1" class="com.suke.injection.Person">
        <property name="name" value="张三"/>
        <property name="dog" ref="d1"/>
    bean>
    
    • 1
    • 2
    • 3
    • 4

    当我们通知spring帮我们注入某个引用对象时,我们可以使用ref通知spring注入bean的beanName

    4.5.1.2 P命名空间使用

    ​ Spring2.5 版本之后,为了简化属性setter依赖注入,提供虚拟名称空间 p ,使用步骤:

    1. 在spring的配置文件中标签引入p命令空间

       xmlns:p="http://www.springframework.org/schema/p"
      
      • 1

    在这里插入图片描述

    1. 使用p命令空间

      <bean id="d2" class="com.suke.injection.Dog">
              <property name="name" value="来福"/>
      bean>
      <bean id="p2" class="com.suke.injection.Person" p:name="李四" p:dog-ref="d2">bean>
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
    4.5.1.3 构造方法注入

    ​ 通过 进行构造器参数注入

    ​ 我们分别在Dog类和Person类提供了无参和有参的构造方法

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Noixp5l-1669895043785)(assets/image-20220731173131884.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aKRWGN31-1669895043787)(assets/image-20220731173159237.png)]

    配置:

    <bean id="d3" class="com.suke.injection.Dog">
        <constructor-arg name="name" value="大黄"/>
    bean>
    
    <bean id="p3" class="com.suke.injection.Person">
        <constructor-arg name="name" value="王五"/>
        <constructor-arg name="dog" type="com.suke.injection.Dog" index="1" ref="d3"/>
    bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    标签属性说明:

    • name: 属性名
    • type: 属性类型
    • index: 参数索引(从0开始)
    4.5.2 集合属性的注入

    ​ 某些类的属性是可能是集合,包括:数组LISTMAPSETPROPERTIES等集合,在Spring中同样可以使用XML配置文件的方式对属性进行注入。

    主要用于 参数配置 !

    • 数组或者List ----- 或者 注入

    • Set ---- 注入

    • Map — 注入

    • Properties — 注入

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZQslqlYO-1669895043787)(assets/image-20220731181126728.png)]

    配置:

      <bean id="p4" class="com.suke.injection.Person">
            <property name="list">
                <list>
                    <value>aaavalue>
                    <value>bbbvalue>
                    <value>aaavalue>
                    <value>cccvalue>
                list>
            property>
            <property name="set">
                <set>
                    <value>aaavalue>
                    <value>bbbvalue>
                    <value>aaavalue>
                    <value>cccvalue>
                set>
            property>
            <property name="map">
                <map>
                    <entry key="abc" value="123">entry>
                    <entry key="bcd" value="456">entry>
                    <entry key="efg" value="567">entry>
                map>
            property>
            <property name="props">
                <props>
                    <prop key="zhangsan">张三prop>
                    <prop key="lisi">李四prop>
                    <prop key="wangwu">王五prop>
                props>
            property>
        bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
  • 相关阅读:
    2022 CCF BDCI 返乡发展人群预测 [0.9117+]
    关于软考高级要不要报班学习
    一文带你弄懂 CDN 技术的原理
    centos7中mysql5.7.32服务离线升级到5.7.39教程
    什么是AWG?
    Java实验报告(三)
    yolo增加Inner-IoU,一文搞定(Inner-SIoU,Inner-WIoU,Inner-EIoU,Inner-MPDIoU)
    【Python基础入门4】关于变量
    十分钟了解MES系统的发展历程和标准体系
    Vue学习(十九)插槽
  • 原文地址:https://blog.csdn.net/H215919719/article/details/128137571