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>

配置一个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 多例的
request WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中
session WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中
global session WEB 项目中,应用在 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实例进行初始化....");
    }
}
<bean class="com.suke.hello.impl.HelloImpl" id="hello" scope="singleton">bean>

测试代码:

 @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));
    }

测试结果:
Spring学习:二、Bean的管理_第1张图片

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

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

Spring学习:二、Bean的管理_第2张图片

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,我要走了...");
    }
}

<bean class="com.suke.hello.impl.HelloImpl" id="hello"  init-method="init" destroy-method="destroy">bean>

测试代码:

@Test
public void testLife(){
    AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    IHello hello = applicationContext.getBean("hello", IHello.class);
    hello.sayHello("spring");
    applicationContext.close();
}

测试效果:
Spring学习:二、Bean的管理_第3张图片

4.4 Spring Bean 的加载流程概述

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

​ springBean的加载过程大致分为两个过程:解析注册,实例化
Spring学习:二、Bean的管理_第4张图片

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

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

Spring学习:二、Bean的管理_第5张图片

Spring通过BeanDefinition来进行bean的实例化, 实例化的bean存在BeanFactory的singletonObjects中
Spring学习:二、Bean的管理_第6张图片

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;
    }
}

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;
    }
}

配置:

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

我们在使用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>

当我们通知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"
    

Spring学习:二、Bean的管理_第7张图片

  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>
    
    
4.5.1.3 构造方法注入

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

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

Spring学习:二、Bean的管理_第8张图片

Spring学习:二、Bean的管理_第9张图片

配置:

<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>

标签属性说明:

  • 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>

你可能感兴趣的:(spring学习,spring,学习,java)