likes
comments
collection
share

Spring之Bean实例化的四种方式

作者站长头像
站长
· 阅读数 16

Bean的实例化方式

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

  • 第一种:通过构造方法实例化
  • 第二种:通过简单工厂模式实例化
  • 第三种:通过工程方法模式实例化
  • 第四种:通过FactoryBean接口实例化

1. 通过构造方法实例化

我们之前一直使用的就是这种方式。默认情况下,会调用Bean的无参数构造方法。在spring配置文件中直接配置类全路径,spring会自动调用该类的无参构造方法来实例化Bean。

public class SpringBean {
    private int a;
    public SpringBean() {
        System.out.println("无参构造:"+this);
    ·}
    public int getA() {
        return a;
    }
    public void setA(int a) {
        this.a = a;
    }
}
<?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="springBean" class="com.qiuye.beanInstance.entity.SpringBean">
    <property name="a" value="1"></property>
 </bean>
</beans>
public void test() {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spirng-instance.xml");
    SpringBean springBean = applicationContext.getBean("springBean",SpringBean.class);
    System.out.println(springBean);
    System.out.println(springBean.getA());
}

执行结果:

Spring之Bean实例化的四种方式

注意: spring的Bean的作用域默认是单例(singleton,是bean标签里面scope属性的值之一,不配置是scope属性则其默认为singleton),此时构造函数是在解析xml的时候就进行调用了,所以Bean的创建也是在这个时候进行的,并非是在调用getBean方法时创建。可以在测试类只保留ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spirng-instance.xml");进行验证。

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

简单工厂模式是工厂方法的一种特殊实现,简单工厂模式由三个角色组成:工厂类角色、抽象产品角色、具体产品角色。 ①编写简单工厂模式当中的工厂类,这里面需要注意的是获取Bean的方法必须是静态的

public class SpringBeanSimpleFactory {
    public static SpringBean getSpringbean(){ //必须是静态方法
        return new SpringBean();
    }
}

②在Spring配置文件中指定创建该Bean的方法(使用factory-method属性指定),其实就是告诉Spring框架,调用该方法可以获取到Bean。

<bean id="getSpirngBean1" class="com.qiuye.beanInstance.factory.SpringBeanSimpleFactory" factory-method="getSpringbean"/>

③编写测试程序

public void test() {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spirng-instance.xml");
    SpringBean springBean = applicationContext.getBean("getSpirngBean1",SpringBean.class);
    System.out.println(springBean);
    System.out.println(springBean.getA());
}

执行结果:

Spring之Bean实例化的四种方式

3. 通过工厂方法模式实例化

工厂方法模式有抽象/具体工厂、抽象/具体产品四个角色,这里主要使用具体工厂和具体产品角色。

①定义具体工厂类,工厂类中定义实例方法

public class SpringBeanFactory {
    public SpringBean getSpringBean(){
        return new SpringBean();
    }
}

②在Spring配置文件中指定factory-bean(指定工厂类)以及factory-method(指定工厂类的方法),其实就是告诉spring从哪个工厂Bean的那个方法获取到需要的Bean。

<bean id="springBeanFactory" class="com.qiuye.beanInstance.factory.SpringBeanFactory"></bean>
<bean id="getSpirngBean2" factory-bean="springBeanFactory" factory-method="getSpringBean"/>

③编写测试程序

public void test3() {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-instance.xml");
    SpringBean springBean = applicationContext.getBean("getSpirngBean2",SpringBean.class);
    System.out.println(springBean);
}

执行结果:

Spring之Bean实例化的四种方式

4. 通过FactoryBean接口实例化

通过工厂方法模式进行实例化时,factory-bean是我们自定义的,factory-method也是我们自己定义的。 在Spring中,提供了FactoryBean接口,实现该接口之后factory-bean不需要指定了,factory-method也不需要指定了。factory-bean会自动指向实现FactoryBean接口的类,factory-method会自动指向getObject()方法。以下是FactoryBean的源码:

public interface FactoryBean<T> {
   String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
   @Nullable
   T getObject() throws Exception;
   @Nullable
   Class<?> getObjectType();
   default boolean isSingleton() { //默认方法,判断是否是单例,默认返回true
      return true;
   }

①编写一个类实现FactoryBean接口

public class SpringBeanFactoryImpl implements FactoryBean<SpringBean> {

    @Override
    public SpringBean getObject() throws Exception {
        return new SpringBean();
    }

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

    @Override
    public boolean isSingleton() { //该方法在需要转换作用域时重写。默认调用接口的默认方法
        return FactoryBean.super.isSingleton(); 
    }
}

②在Spring配置文件中配置FactoryBean

<bean id="getSpirngBean3" class="com.qiuye.beanInstance.factory.SpringBeanFactoryImpl"/>

测试程序:

public void test3() {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-instance.xml");
    SpringBean springBean = applicationContext.getBean("getSpirngBean3",SpringBean.class);
    System.out.println(springBean);
}

执行结果

Spring之Bean实例化的四种方式

FactoryBean在Spring中是一个接口。被称为“工厂Bean”。“工厂Bean”是一种特殊的Bean。所有的“工厂Bean”都是用来协助Spring框架来创建其他Bean对象的。 工厂的职责是生产和加工,我们可以用一个例子来体验一下工厂的加工职责。java.util.Date在Spring中被当做简单类型,简单类型在注入的时候可以直接使用value属性或value标签来完成。但我们之前已经测试过了,对于Date类型来说,采用value属性或value标签赋值的时候,对日期字符串的格式要求非常严格,必须是这种格式的:Mon Oct 10 14:30:26 CST 2022。其他格式是不会被识别的。我们习惯的字符串类型是“yyyy-MM-dd”这样的,或者其他的形式。代码如下: ①编写一个Student类

public class Student { //定义Student类,有Date类型的属性
    private String name;
    private Date birth;
    public String getName() {return name}
    public void setName(String name) {this.name = name;}
    public Date getBirth() {return birth;}
    public void setBirth(Date birth) {this.birth = birth;}
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + ''' +
                ", birth=" + birth +
                '}';
    }
}

②创建Date类型的工厂Bean

public class DateFactory implements FactoryBean<Date> { //定义Date的工厂Bean
    private String dataStr;
    public void setDataStr(String dataStr) {
        this.dataStr = dataStr;
    }
    @Override
    public Date getObject() throws Exception { //在这里对Date类型进行处理
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date date = simpleDateFormat.parse(dataStr);
        return date;
    }
    @Override
    public Class<?> getObjectType() {
        return null;
    }
}

③编写XML配置 这里就是使用Date的工厂Bean对Date类型进行处理,然后再注入到Student类型里

<bean id="date" class="com.qiuye.beanInstance.factory.DateFactory">
    <property name="dataStr" value="1998-01-01"/>
</bean>
<bean id="Student" class="com.qiuye.beanInstance.entity.Student">
    <property name="birth" ref="date"/>
    <property name="name" value="qy"/>
</bean>

④测试

public void test4() {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-instance.xml");
    Student student = applicationContext.getBean("Student",Student.class);
    System.out.println(student);
}

Spring之Bean实例化的四种方式

5.BeanFactory和FactoryBean的区别

5.1 BeanFactory

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

5.2 FactoryBean

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

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

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