03_02_Spring配置Bean对象

一、Spring Bean的配置

由 Spring IoC 容器管理的对象称为 Bean,Bean 根据 Spring 配置文件中的信息被创建。所谓配置Bean就是告诉Spring的IOC容器将要去管理的对象。

1.传统方式

采用XML文件的形式进行配置,applicationContext.xml
Person类:

public class Person{
	private String name;
    private int age;
    private double money;
    
    一系列的构造、get()set()方法等等.......
}

applicationContext.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">
    <!--bean标签:让Spring创建一个对象并放置在IOC容器内,一个bean标签就对应某个类的一个对象
        标签属性:
           id: 该Bean对象的唯一标识符,bean的名称,不可重复,在IOC容器中必须是唯一的,无论后面拆分配置文件还是使用注解,都要求id不能重复;若id没有指定,Spring自动将类的全局限定类名作为bean的名字;
           class: 需要创建对象的类型的全局限定名,Spring通过反射机制创建该类的对象(要求:该类必须拥有无参构造方法)
    -->
    <bean id="person1" class="com.newcapec.bean.Person"/>
    <bean id="person2" class="com.newcapec.bean.Person">
</beans>

BeanTest1测试类

public class BeanTest1 {
    @Test
    public void testBeanXML(){
        //获得 Spring 中定义的 Bean 对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        //通过id名称,获取各自的实例对象
        Person p1 = (Person) ac.getBean("person1"); 
        Person p2 = (Person) ac.getBean("person2"); 
        //测试p1和p2是不是指向同一个地址
        System.out.println(p1 == p2);//false,每个Bean都各自对应一个对象
        Person p3 = (Person) ac.getBean("person1");
        System.out.println(p1 == p3);//true
    }
}

2.Java 注解方式

3.Java 配置类方式

二、Spring Bean的实例化

1.通过构造方法实例化Bean

Spring IoC容器能使用默认的空构造方法,也能使用有参的构造方法,底层通过反射机制来实例化Bean对象。

2.通过工厂实例化Bean

  • 调用静态工厂方法创建bean是将对象创建的过程封装到静态方法中。当客户端需要对象时,只需要简单地调用静态方法,而无需关心创建对象的细节;
  • 要声明通过静态方法创建的bean,需要在bean的class属性里指定拥有该工厂的方法的类,同时在factory-method属性里指定工厂方法的名称。最后,使用元素为该方法传递方法参数;
    Cat类:
public class Cat {
    private String name;
    private int age;
 
    public Cat() {
    }
 
    public Cat(String name, int age) {
        this.name = name;
        this.age = age;
    }
 
    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;
    }
 
    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

CatStaticFactory.java:

/**
 * 一个用于创建cat对象的静态工厂
 */
public class CatStaticFactory {
    /**
     * 提供一个创建对象的静态方法
     */
    public static Cat getInstance(String name, int age){
        return new Cat(name, age);
    }
}

applicationContext.xml:

<!-- 静态工厂-->
<bean id="cat1" class="com.newcapec.factory.CatStaticFactory" factory-method="getInstance">
    <constructor-arg value="汤姆猫"/>
    <constructor-arg value="2"/>
</bean>

3.通过FactoryBean实例化Bean

  • Spring中有两种类型的bean,一种是普通bean,另一种是工厂bean,即FactoryBean;
  • 工厂bean跟普通bean不同,其返回的对象不是指定类的一个实例,其返回的是该工厂bean的getObject方法所返回的对象;

CatFactoryBean.java:

public class CatFactoryBean implements FactoryBean<Cat> {
    private String name;
    private int age;
 
    public void setName(String name) {
        this.name = name;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    /**
     * 获取对象
     */
    @Override
    public Cat getObject() throws Exception {
        return new Cat(name, age);
    }
 
    /**
     * 生成对象的Class类型
     */
    @Override
    public Class<?> getObjectType() {
        return Cat.class;
    }
 
    /**
     * 设置该对象是否为单例模式
     */
    @Override
    public boolean isSingleton() {
        return true;
    }
}

applicationContext.xml:

<!-- FactoryBean配置bean -->
<bean id="cat3" class="com.newcapec.factory.CatFactoryBean">
    <property name="name" value="加菲猫"/>
    <property name="age" value="5"/>
</bean>

4. 元素常用的属性或子元素

在 XML 配置的 元素中可以包含多个属性或子元素,常用的属性或子元素如下表所示:
在这里插入图片描述在这里插入图片描述

三、Spring容器

IoC 思想是基于 IoC 容器实现的,IoC 容器底层其实就是一个 Bean 工厂,Spring 框架为我们提供了两种不同类型的 IoC 容器,它们分别是 BeanFactoryApplicationContext

1.BeanFactory

  • BeanFactory 是 IoC 容器的基本实现,也是 Spring 提供的最简单的 IoC 容器。
  • 它提供了 IoC 容器最基本的功能,由 org.springframework.beans.factory.BeanFactory 接口定义。
  • BeanFactory 采用懒加载(lazy-load)机制,容器在加载配置文件时并不会立即创建对象,只有在获取(使用)这个对象时才会创建。

2.ApplicationContext

  • ApplicationContext 是 BeanFactory 接口的子接口,是对 BeanFactory 的扩展。
  • ApplicationContext 在 BeanFactory 的基础上增加了许多企业级的功能,例如 AOP(面向切面编程)、国际化、事务支持等。

3.ApplicationContext的主要实现类

  • ClassPathXmlApplicationContext:从类路径上加载配置文件;
  • FileSystemXmlApplicationContext:从文件系统中加载配置文件;
  • WebApplicationContext:专门为Web应用而准备的,它允许从相对于Web根目录的路径中完成初始化工作;

4.从容器中获取Bean

  • getBean(String name)方法,通过Bean的id名称从容器中获取Bean对象;
  • getBean(Class requiredType)方法,通过Bean的Class类型从容器中获取Bean对象;
  • getBean(String name, Class requiredType)方法,通过Bean的id和Class类型从容器中获取Bean对象;
注意:当IOC容器中存放着多个同类型对象时,不能通过Class类型来获取Bean对象。

BeanTest2测试类

public class BeanTest2 {
    @Test
    public void testGetBean() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        //1.参数为字符串类型
        Person p1 = (Person) ac.getBean("person1");
      
        //2.参数为Class类型,缺点:当IOC容器中存在多个此类型对象时,抛出异常
        Person person = ac.getBean(Person.class);
       
        //3.参数为字符串类型+Class类型
        Person p2 = ac.getBean("person2", Person.class);
    }
}

四、依赖注入

1.基于属性注入

  • 在 Spring 实例化 Bean 的过程中,IoC 容器首先会调用默认的构造方法(无参构造方法)实例化 Bean(Java 对象),然后通过 Java 的反射机制调用这个 Bean 的 setXxx() 方法,将属性值注入到 Bean 中。
  • 使用 Setter 注入的方式进行属性注入,大致步骤如下:
    (1)在 Bean 中提供一个默认的无参构造函数(如果没有带参构造函数),并为所有需要注入的属性提供一个 setXxx() 方法;
    (2)在 Spring 的 XML 配置文件中,使用 及其子元素 对 Bean 进行定义;
    (3)在 元素内使用 元素对各个属性进行赋值,使用name属性指定Bean的属性名称,value属性或子标签指定属性值。属性注入是实际应用中最常用的注入方式。

applicationContext.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">
 
    <!-- 通过setter方法注入属性值 -->
    <bean id="person" class="com.newcapec.bean.Person">
        <!--property标签:表示通过属性的set方法为属性赋值,也叫做依赖注入
                    属性:
        	          name: 对象中的属性名称
        	          value: 属性值                               -->
      <property name="name" value="张三"/>
      <property name="age" value="20"/>
      <property name="money"><value>3600.5</value></property>
    </bean>
</beans>

2.基于构造方法注入

  • 使用构造函数实现属性注入大致步骤如下:
    (1)在 Bean 中添加一个有参构造函数,构造函数内的每一个参数代表一个需要注入的属性;
    (2)在Spring 的 XML 配置文件中,通过 及其子元素 对 Bean 进行定义;
    (3)在 元素内使用 元素,对构造函数内的属性进行赋值,Bean 的构造函数内有多少个参数,就需要使用多少个 元素。
  • Car类:
public class Car {
    private String name;
    private String type;
    private double price;
    private int doors;
 
    public Car(String name, String type, double price, int doors) {
        this.name = name;
        this.type = type;
        this.price = price;
        this.doors = doors;
    }
 
    public Car(String name, String type, int doors) {
        this.name = name;
        this.type = type;
        this.doors = doors;
    }
 
    public Car(String name, String type, double price) {
        this.name = name;
        this.type = type;
        this.price = price;
    }
 
    public Car(String n, String t) {
        this.name = n;
        this.type = t;
    }
 
    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                ", type='" + type + '\'' +
                ", price=" + price +
                ", doors=" + doors +
                '}';
    }
}
  • applicationContext.xml:
    注意:如果该类中有多个构造方法,可以通过index、type或name对构造方法进行精确选取。
<?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">
 
    <!-- 通过构造方法注入属性值 -->
    <bean id="car1" class="com.newcapec.bean.Car">
        <!-- constructor-arg : 表示创建该类型的对象时,使用的构造方法的参数
                         属性:
                             value : 构造方法的参数值
                             index : 构造方法参数的索引
                             type : 构造方法参数的类型
                              name : 构造方法参数的名称            -->
          <constructor-arg value="宝马"/>
          <constructor-arg value="轿车"/>
          <constructor-arg value="360000"/>
          <constructor-arg value="4"/>
    </bean>
   <!-- 按索引匹配构造方法参数 -->
   <bean id="car2" class="com.newcapec.bean.Car">
          <constructor-arg value="越野" index="1"/>
          <constructor-arg value="奔驰" index="0"/>
          <constructor-arg value="4" index="3"/>
          <constructor-arg value="560000" index="2"/>
   </bean>
   <!-- 按类型匹配构造方法参数 -->
  <bean id="car3" class="com.newcapec.bean.Car">
         <constructor-arg value="大众" type="java.lang.String"/>
         <constructor-arg value="商务车" type="java.lang.String"/>
         <constructor-arg value="290000" type="double"/>
  </bean>
   <!-- 按参数名称匹配构造方法参数-->
  <bean id="car4" class="com.newcapec.bean.Car">
        <constructor-arg value="电动车" name="t"/>
        <constructor-arg value="特斯拉" name="n"/>
  </bean>  
</beans>

3.Autowire自动装配

  • 我们把 Spring 在 Bean 与 Bean 之间建立依赖关系的行为称为“装配”。 Spring 的 IOC 容器虽然功能强大,但它本身不过只是一个空壳而已,它自己并不能独立完成装配工作。还需要我们主动将 Bean 放进去,并告诉它 Bean 和 Bean 之间的依赖关系,它才能按照我们的要求完成装配工作。
  • Spring 的自动装配功能可以让 Spring 容器依据某种规则(自动装配的规则,有五种),为指定的 Bean 从应用的上下文(AppplicationContext 容器)中查找它所依赖的 Bean,并自动建立 Bean 之间的依赖关系。
  • Spring 的自动装配功能能够有效地简化 Spring 应用的 XML 配置,因此在配置数量相当多时采用自动装配降低工作量。
  • Spring 框架式默认不支持自动装配,要想使用自动装配,则需要对 Spring XML 配置文件中 元素的 autowire 属性进行设置。
  • Spring 共提供了 五种自动装配规则,它们分别与 autowire 属性的 5 个取值对应,具体说明如下表:
    自动装配规则

五、Bean的作用域

  • 默认情况下,所有的 Spring Bean 都是单例的,也就是说在整个 Spring 应用中,Bean 的实例只有一个。
  • 我们可以在 元素中添加 scope 属性来配置 Spring Bean 的作用范围。例如,如果每次获取 Bean 时,都需要一个新的 Bean 实例,那么应该将 Bean 的 scope 属性定义为 prototype,如果 Spring 需要每次都返回一个相同的 Bean 实例,则应将 Bean 的 scope 属性定义为 singleton。
  • Spring 5 共提供了 6 种 scope 作用域,如下表:
    在这里插入图片描述

1.Singleton

  • singleton 是 Spring 容器默认的作用域。当 Bean 的作用域为 singleton 时,Spring IoC 容器中只会存在一个共享的 Bean 实例。这个 Bean 实例将存储在高速缓存中,所有对于这个 Bean 的请求和引用,只要 id 与这个 Bean 定义相匹配,都会返回这个缓存中的对象实例。
  • 如果一个 Bean 定义的作用域为 singleton ,那么这个 Bean 就被称为 singleton bean。在 Spring IoC 容器中,singleton bean 是 Bean 的默认创建方式,可以更好地重用对象,节省重复创建对象的开销。
  • 在 Spring 配置文件中,可以使用 元素的 scope 属性,将 Bean 的作用域定义成 singleton,其配置方式如下所示:
<!-- singleton -->
<bean id="book" class="com.newcapec.bean.Book" p:id="101" p:name="西游记" p:price="98.5" p:author="吴承恩" scope="singleton"/>

2.Prototype

  • 如果一个 Bean 定义的作用域为 prototype,那么这个 Bean 就被称为 prototype bean。对于 prototype bean 来说,Spring 容器会在每次请求该 Bean 时,都创建一个新的 Bean 实例。
  • 从某种意义上说,Spring IoC 容器对于 prototype bean 的作用就相当于 Java 的 new 操作符。它只负责 Bean 的创建,至于后续的生命周期管理则都是由客户端代码完成的。
  • 在 Spring 配置文件中,可以使用 元素的 scope 属性将 Bean 的作用域定义成 prototype,其配置方式如下所示:
<!-- prototype -->
<bean id="book" class="com.newcapec.bean.Book" p:id="101" p:name="西游记" p:price="98.5" p:author="吴承恩" scope="prototype"/>

六、Bean的生命周期

  • 在传统的 Java 应用中,Bean 的生命周期很简单,使用 Java 关键字 new 进行 Bean 的实例化后,这个 Bean 就可以使用了。一旦这个 Bean 长期不被使用,Java 自动进行垃圾回收。
  • Spring 中 Bean 的生命周期较复杂,SpringIOC容器可以管理Bean的生命周期,Spring允许在Bean生命周期的特定点执行定制的任务,
    大致可以分为以下 5 个阶段:
    Bean 的实例化——> Bean 属性赋值——> Bean 的初始化——> Bean 的使用 ——> Bean 的销毁
  • Spring 根据 Bean 的作用域来选择 Bean 的管理方式,
    (1) 对于 singleton 作用域的 Bean 来说,Spring IoC 容器能够精确地控制 Bean 何时被创建、何时初始化完成以及何时被销毁;
    (2) 对于 prototype 作用域的 Bean 来说,Spring IoC 容器只负责创建,然后就将 Bean 的实例交给客户端代码管理,Spring IoC 容器将不再跟踪其生命周期。

1. Spring的生命周期流程

Spring Bean 的完整生命周期从创建 Spring IoC 容器开始,直到最终 Spring IoC 容器销毁 Bean 为止,其具体流程如下图所示。

2.Bean 生命周期的整个执行过程

  • Spring 启动,查找并加载需要被 Spring 管理的 Bean,对 Bean 进行实例化。
  • 对 Bean 进行属性注入。
  • 如果 Bean 实现了 BeanNameAware 接口,则 Spring 调用 Bean 的 setBeanName() 方法传入当前 Bean 的 id 值。
  • 如果 Bean 实现了 BeanFactoryAware 接口,则 Spring 调用 setBeanFactory() 方法传入当前工厂实例的引用。
  • 如果 Bean 实现了 ApplicationContextAware 接口,则 Spring 调用 setApplicationContext() 方法传入当前 ApplicationContext 实例的引用。
  • 如果 Bean 实现了 BeanPostProcessor 接口,则 Spring 调用该接口的预初始化方法 postProcessBeforeInitialzation() 对 Bean 进行加工操作,此处非常重要,Spring 的 AOP 就是利用它实现的。
  • 如果 Bean 实现了 InitializingBean 接口,则 Spring 将调用 afterPropertiesSet() 方法。
  • 如果在配置文件中通过 init-method 属性指定了初始化方法,则调用该初始化方法。
  • 如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的初始化方法 postProcessAfterInitialization()。此时,Bean 已经可以被应用系统使用了。
  • 如果在 中指定了该 Bean 的作用域为 singleton,则将该 Bean 放入 Spring IoC 的缓存池中,触发 Spring 对该 Bean 的生命周期管理;如果在 中指定了该 Bean 的作用域为 prototype,则将该 Bean 交给调用者,调用者管理该 Bean 的生命周期,Spring 不再管理该 Bean。
  • 如果 Bean 实现了 DisposableBean 接口,则 Spring 会调用 destory() 方法销毁 Bean;如果在配置文件中通过 destory-method 属性指定了 Bean 的销毁方法,则 Spring 将调用该方法对 Bean 进行销毁。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值