1. Spring为Bean提供了多种实例化方式 43

通常包括4种方式。(也就是说在Spring中为Bean对象的创建准备了多种方案,目的是:更加灵活)

● 第一种:通过构造方法实例化

● 第二种:通过简单工厂模式实例化

● 第三种:通过factory-bean实例化

● 第四种:通过FactoryBean接口实例化

2. 通过构造方法实例化   43

我们之前一直使用的就是这种方式。默认情况下,会调用Bean的无参数构造方法。

package com.powernode.spring6.bean;

/**
 * 通过构造方法实例化   43
 **/
public class SpringBean {

    public SpringBean() {
        System.out.println("Spring Bean的无参数构造方法执行。");
    }
}
  <!--Spring提供的实例化方式,第一种:在spring配置文件中直接配置   43
    类全路径,Spring会自动调用该类的无参数构造方法来实例化Bean-->
    <bean id="sb" class="com.powernode.spring6.bean.SpringBean"/>
// 通过构造方法实例化   43
    @Test
    public void testInstantiation1(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        SpringBean sb = applicationContext.getBean("sb", SpringBean.class);
        System.out.println(sb);
    }

Bean的实例化_实例化

3. 通过简单工厂模式实例化 44

第一步:定义一个Bean

package com.powernode.spring6.bean;

/**
 *  通过简单工厂模式实例化 44
 * 明星类(Bean)
 **/
public class Star {

    public Star() {
        System.out.println("Star的无参数构造方法执行。");
    }

}

第二步:编写简单工厂模式当中的工厂类

package com.powernode.spring6.bean;

/**
 * 通过简单工厂模式实例化 44
 * 简单工厂模式中的工厂类角色。星工厂。
 **/
public class StarFactory {
    // 工厂类中有一个静态方法。
    // 简单工厂模式又叫做:静态工厂方法模式。
    public static Star get(){
        // 这个Star对象最终实际上创建的时候还是我们负责new的对象。
        return new Star();
    }
}

第三步:在Spring配置文件中指定创建该Bean的方法(使用factory-method属性指定)

<!--Spring提供的实例化方式,第二种:通过简单工厂模式。你需要在Spring配置文件中告诉Spring框架
    ,调用哪个类的哪个方法获取Bean-->
    <!--factory-method 属性指定的是工厂类当中的静态方法。也就是告诉Spring框架
    ,调用这个方法可以获取Bean。-->
    <bean id="star" class="com.powernode.spring6.bean.StarFactory" factory-method="get"/>

第四步:编写测试程序

//通过简单工厂模式实例化 44
    @Test
    public void testInstantiation2(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        Star star = applicationContext.getBean("star", Star.class);
        System.out.println(star);
    }

Bean的实例化_System_02

4. 通过factory-bean实例化   45

这种方式本质上是:通过工厂方法模式进行实例化。

第一步:定义一个Bean

package com.powernode.spring6.bean;

/**
 * 通过factory-bean实例化   45
 * 工厂方法模式当中的:具体产品角色。
 **/
public class Gun {
    public Gun() {
        System.out.println("Gun的无参数构造方法执行。");
    }
}

第二步:定义具体工厂类,工厂类中定义实例方法

package com.powernode.spring6.bean;

/**
 * 通过factory-bean实例化   45
 * 工厂方法模式当中的:具体工厂角色。
 **/
public class GunFactory {

    // 工厂方法模式中的具体工厂角色中的方法是:实例方法。
    public Gun get(){
        // 实际上new这个对象还是我们程序员自己new的。
        return new Gun();
    }
}

第三步:在Spring配置文件中指定factory-bean以及factory-method

<!--Spring提供的实例化方式,第三种:通过工厂方法模式。  45
    通过 factory-bean属性 + factory-method属性来共同完成。-->
    <!--告诉Spring框架,调用哪个对象的哪个方法来获取Bean。-->
    <bean id="gunFactory" class="com.powernode.spring6.bean.GunFactory"/><!--GunFactory实际上就是一个FactoryBean-->
    <!--以下的配置很关键,factory-bean属性告诉Spring调用哪个对象。factory-method告诉Spring调用该对象的哪个方法。-->
    <bean id="gun" factory-bean="gunFactory" factory-method="get"/>

第四步:编写测试程序

//通过factory-bean实例化   45
    @Test
    public void testInstantiation3(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        Gun gun = applicationContext.getBean("gun", Gun.class);
        System.out.println(gun);
    }

Bean的实例化_实例化_03

5. 通过FactoryBean接口实例化  46

以上的第三种方式中,factory-bean是我们自定义的,factory-method也是我们自己定义的。

在Spring中,当你编写的类直接实现FactoryBean接口之后,factory-bean不需要指定了,factory-method也不需要指定了。

factory-bean会自动指向实现FactoryBean接口的类,factory-method会自动指向getObject()方法。

第一步:定义一个Bean

package com.powernode.spring6.bean;

/**
 * 通过FactoryBean接口实例化  46
 * Bean
 **/
public class Person { // 普通的Bean

    public Person() {
        System.out.println("Person的无参数构造方法执行。");
    }
}

第二步:编写一个类实现FactoryBean接口

package com.powernode.spring6.bean;

import org.springframework.beans.factory.FactoryBean;

/**
 * 通过FactoryBean接口实例化  46
 **/
public class PersonFactoryBean implements FactoryBean {

    // PersonFactoryBean也是一个Bean。只不过这个Bean比较特殊。叫做工厂Bean。
    // 通过工厂Bean这个特殊的Bean可以获取一个普通的Bean。

    @Override
    public Person getObject() throws Exception {
        // 最终这个Bean的创建还是程序员自己new的。
        return new Person();
    }

    @Override
    public Class getObjectType() {
        return null;
    }

    // 这个方法在接口中有默认实现。
    // 默认返回true,表示单例的。
    // 如果想多例,直接将这个方法修改为return false;即可。
    @Override
    public boolean isSingleton() {
        return true;
    }
}

第三步:在Spring配置文件中配置FactoryBean

 <!--Spring提供的实例化方式,第四种:通过FactoryBean接口来实现。  46-->
    <!--这种方式实际上就是第三种方式的简化。-->
    <!--由于你编写的类实现了FactoryBean接口,所以这个类是一个特殊的类,不需要你再手动指定:factory-bean、factory-method-->
    <!--通过一个特殊的Bean:工厂Bean。来返回一个普通的Bean Person对象。-->
    <!--通过FactoryBean这个工厂Bean主要是想对普通Bean进行加工处理。-->
    <bean id="person" class="com.powernode.spring6.bean.PersonFactoryBean"/>

测试程序:

//通过FactoryBean接口实例化  46
    @Test
    public void testInstantiation4(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        //BeanFactory applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        Person person = applicationContext.getBean("person", Person.class);
        System.out.println(person);
    }

Bean的实例化_spring_04

FactoryBean在Spring中是一个接口。被称为“工厂Bean”。“工厂Bean”是一种特殊的Bean。所有的“工厂Bean”都是用来协助Spring框架来创建其他Bean对象的。

6. BeanFactory和FactoryBean的区别  47

6.1 BeanFactory  47

Spring IoC容器的顶级对象,BeanFactory被翻译为“Bean工厂”,在Spring的IoC容器中,“Bean工厂”负责创建Bean对象。

BeanFactory是工厂。

6.2 FactoryBean  47

FactoryBean:它是一个Bean,是一个能够辅助Spring实例化其它Bean对象的一个Bean。

在Spring中,Bean可以分为两类:

● 第一类:普通Bean

● 第二类:工厂Bean(记住:工厂Bean也是一种Bean,只不过这种Bean比较特殊,它可以辅助Spring实例化其它Bean对象。)

7. 注入自定义Date  48

我们前面说过,java.util.Date在Spring中被当做简单类型,简单类型在注入的时候可以直接使用value属性或value标签来完成。但我们之前已经测试过了,对于Date类型来说,采用value属性或value标签赋值的时候,对日期字符串的格式要求非常严格,必须是这种格式的:Mon Oct 10 14:30:26 CST 2022。其他格式是不会被识别的。如以下代码:

package com.powernode.spring6.bean;

import java.util.Date;

/**
 * 一个学生bean  48
 **/
public class Student {

    // java.util.Date 在Spring当中被当做简单类型。 但是简单类型的话,注入的日期字符串格式有要求。
    // java.util.Date 在Spring当中也可以被当做非简单类型。
    private Date birth;

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    @Override
    public String toString() {
        return "Student{" +
                "birth=" + birth +
                '}';
    }
}
<bean id="student" class="com.powernode.spring6.bean.Student">
        <!--把日期类型当做简单类型。-->
        <property name="birth" value="Mon Oct 10 14:30:26 CST 2022"/>
            </bean>
@Test
    public void testDate(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        Student student = applicationContext.getBean("student", Student.class);
        System.out.println(student);
    }

Bean的实例化_spring_05

如果把日期格式修改一下:

<bean id="studentBean" class="com.powernode.spring6.bean.Student">
  <property name="birth" value="2002-10-10"/>
</bean>

Bean的实例化_Bean的实例化_06

这种情况下,我们就可以使用FactoryBean来完成这个骚操作。

编写DateFactoryBean实现FactoryBean接口:

package com.powernode.spring6.bean;

import org.springframework.beans.factory.FactoryBean;

import java.text.SimpleDateFormat;
import java.util.Date;

//注入自定义Date  48
public class DateFactoryBean implements FactoryBean {
    // DateFactoryBean这个工厂Bean协助我们Spring创建这个普通的Bean:Date。

    private String strDate;

    public DateFactoryBean(String strDate) {
        this.strDate = strDate;
    }

    @Override
    public Date getObject() throws Exception {
        //自定义日期格式类型
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = sdf.parse(strDate);
        return date;
    }

    @Override
    public Class getObjectType() {
        return null;
    }
}

编写spring配置文件:

 <!--    注入自定义Date  48-->
    <!--通过工厂Bean:DateFactoryBean 来返回普通Bean:java.util.Date -->
    <bean id="date" class="com.powernode.spring6.bean.DateFactoryBean">
        <constructor-arg index="0" value="1980-10-11"/>
    </bean>
    <bean id="studentBean" class="com.powernode.spring6.bean.Student">
        <property name="birth" ref="date"/>
    </bean>
//注入自定义Date  48
    @Test
    public void testDate(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        Student student = applicationContext.getBean("studentBean", Student.class);
        System.out.println(student);
    }

Bean的实例化_System_07