(七)Bean的实例化方式


Spring学习目录

上一篇:(六)Spring之回顾工厂模式

下一篇:(八)Bean的生命周期

环境

spring6里程碑版本的仓库
依赖:spring context依赖、junit依赖、log4j2依赖
log4j2.xml文件放到类路径下。

Bean的实例化方式

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

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

通过构造方法实例化

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

public class SpringBean1 {
    public SpringBean1() {
        System.out.println("Spring Bean1的无参构造方法执行");
    }
}

创建spring.xml配置:

<bean id="springBean1" class="com.bean.instantiation.bean.SpringBean1"/>

测试程序:

    @Test
    public void testInstantiation1(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        SpringBean1 springBean1 = applicationContext.getBean("springBean1", SpringBean1.class);
        System.out.println(springBean1);
    }

请添加图片描述

通过简单工厂模式实例化

简单工厂模式实例化就是,创建一个简单工厂类,提供一个静态方法,手动实例化Bean对象,可见这个Bean是我们自己new出来的。
需要在Spring配置文件中告诉Spring框架,调用哪个类的哪个方法获取Bean。

定义一个Bean:SpringBean2类

public class SpringBean2 {
    public SpringBean2() {
        System.out.println("Spring Bean2的无参构造方法执行");
    }
}

定义工厂类角色:SpringBean2Factory

/**
 * 简单工厂模式中的工厂类角色。
 */
public class SpringBean2Factory {
    //简单工厂模式又叫做静态工厂方法模式,有一个静态方法。
    public static SpringBean2 get(){
        //可见这个对象最终创建的时候还是我们负责new的。
        return new SpringBean2();
    }
}

spring.xml配置:
factory-method属性:配置哪个方法获取Bean。

<bean id="springBean2" class="com.bean.instantiation.bean.SpringBean2Factory" factory-method="get"/>

测试程序:

    @Test
    public void testInstantiation2(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        SpringBean2 springBean2 = applicationContext.getBean("springBean2", SpringBean2.class);
        System.out.println(springBean2);
    }

请添加图片描述

通过工厂方法模式实例化

工厂方法模式实例化就是,创建一个简单工厂类,只是这个方法不再是静态方法,而是实例方法,手动实例化Bean对象,可见这个Bean也是我们自己new出来的。
因为是实例方法,需要在Spring配置文件中配置这个工厂的Bean,并告诉Spring框架,调用哪个类的哪个方法获取Bean。

定义一个Bean:SpringBean3类

/**
 * 具体产品角色
 */
public class SpringBean3 {
    public SpringBean3() {
        System.out.println("Spring Bean3的无参构造方法执行");
    }
}

工厂角色:SpringBean3Factory类

/**
 * 具体工厂角色
 */
public class SpringBean3Factory {
    //工厂方法模式里的方法是实例方法
    public SpringBean3 get(){
        //可见,创建对象还是我们直接创建的
        return new SpringBean3();
    }
}

spring.xml配置:
通过factory-bean + factory-method共同完成
因为是实例方法,需要实例化对象,所以工厂方法也需要Spring管理,需要配置bean

  • factory-method属性:配置哪个方法获取Bean。
  • factory-bean属性:指定哪个对象创建bean
	<bean id="factory" class="com.bean.instantiation.bean.SpringBean3Factory"/>

    <bean id="springBean3" factory-bean="factory" factory-method="get"/>

测试程序:

    @Test
    public void testInstantiation3(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        SpringBean3 springBean3 = applicationContext.getBean("springBean3", SpringBean3.class);
        System.out.println(springBean3);
    }

请添加图片描述

通过FactoryBean接口实例化

前三种方式中,factory-bean是我们自定义的,factory-method也是我们自己定义的。
在Spring中,当你编写的类直接实现FactoryBean接口之后,factory-bean不需要指定了,factory-method也不需要指定了。
factory-bean会自动指向实现FactoryBean接口的类,factory-method会自动指向getObject()方法。
第四种方案实际是第三种方案的简化

定义一个Bean:SpringBean4类

public class SpringBean4 {
    public SpringBean4() {
        System.out.println("Spring Bean4的无参构造方法执行");
    }
}

定义一个工厂:SpringBean4FactoryBean,实现FactoryBean接口
这个工厂也是一个Bean,只不过这个Bean比较特殊,叫做工厂Bean
通过这个工厂Bean可以获取普通的Bean
FactoryBean接口有三个方法,分别是:

  • getObject():抽象方法,在这个方法创建Bean,并返回。
  • getObjectType():抽象方法,在这个方法编写返回Bean的类型,是一个Class类型。
  • isSingleton():默认方法,它会告诉Spring,创建Bean是否是单例的,默认为true是单例的,如果不想Bean为单例,则可以覆盖此方法,并返回false就可以。
public interface FactoryBean<T> {
    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

    @Nullable
    T getObject() throws Exception;

    @Nullable
    Class<?> getObjectType();

    default boolean isSingleton() {
        return true;
    }
}

SpringBean4FactoryBean:

public class SpringBean4FactoryBean implements FactoryBean<SpringBean4> {
    /*
       在这个方法创建Bean
     */
    @Override
    public SpringBean4 getObject() throws Exception {
        //最终也是程序员自己new的
        return new SpringBean4();
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }
    /*
        在源码中有一个默认方法,它会告诉Spring,创建Bean是否是单例的,如果不想单例,覆盖该方法并返回false就可以
        这里就不在操作了,默认调用接口的默认方法
     */
    @Override
    public boolean isSingleton() {
        return FactoryBean.super.isSingleton();
    }
}

spring.xml配置:

<bean id="springBean4" class="com.bean.instantiation.bean.SpringBean4FactoryBean"/>

测试程序:

    @Test
    public void testInstantiation4(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        SpringBean4 springBean4 = applicationContext.getBean("springBean4", SpringBean4.class);
        System.out.println(springBean4);
    }

请添加图片描述

BeanFactory和FactoryBean的区别

BeanFactory

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

FactoryBean

FactoryBean:它是一个Bean,是一个能够辅助Spring实例化其它Bean对象的一个Bean。
在Spring中,Bean可以分为两类:

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

工厂Bean的使用:注入自定义Date

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

所以我们可以使用FactoryBean接口对Bean的创建进行增强操作。

定义一个学生类:Student

public class Student {
    private Date birth;

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

    @Override
    public String toString() {
        return "Student{" +
                "birth=" + birth +
                '}';
    }
}

创建一个工厂Bean:DateFactoryBean类,实现FactoryBean

public class DateFactoryBean implements FactoryBean<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.xml配置:

	<bean id="date" class="com.bean.instantiation.bean.DateFactoryBean">
        <constructor-arg index="0" value="2020-10-11"/>
    </bean>
    <bean id="student" class="com.bean.instantiation.bean.Student">
        <property name="birth" ref="date"/>
    </bean>

测试程序:

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

在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

忆亦何为

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值