- Bean的实例化方式
- 通过构造方法实例化
- 通过简单工厂模式实例化
- 通过factory-bean实例化(工厂方法模式实例化)
- 通过FactoryBean接口实例化
七、Bean的实例化方式
- Spring 为
Bean
提供了多种实例化方式,包括如下 4 种方式:- 第一种:通过构造方法实例化。
- 第二种:通过简单工厂模式实例化。
- 第三种:通过
factory-bean
实例化(工厂方法模式实例化)。 - 第四种:通过
FactoryBean
接口实例化。
- Spring 中为
Bean
对象的创建准备了多种方案,目的是为了能够更加灵活。
7.1 通过构造方法实例化
我们之前一直使用的就是这种方式。
默认情况下,会调用
Bean
的无参数构造方法。在 Spring 配置文件中直接配置类的全路径,即在 Spring 配置文件中配置
bean
,Spring 会自动调用该类的无参数构造方法来实例化Bean
。1
2
3
4
5
6
7
8package com.f.spring6.bean;
/**
* @author fzy
* @date 2024/1/20 16:40
*/
public class SpringBean {
}1
2
3
4
5
6
7
8
9
10
<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">
<!--
Spring提供的实例化方式第一种:通过构造方法实例化
在Spring配置文件中直接配置类的全路径,Spring会自动调用该类的无参数构选方法米实例化Bean
-->
<bean id="springBean" class="com.f.spring6.bean.SpringBean"/>
</beans>1
2
3
4
5
6
public void testInstantiation1() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
SpringBean springBean = applicationContext.getBean("springBean", SpringBean.class);
System.out.println(springBean);
}
7.2 通过简单工厂模式实例化
1 | package com.f.spring6.bean; |
1 | package com.f.spring6.bean; |
1 |
|
1 |
|
7.3 通过factory-bean实例化(工厂方法模式实例化)
1 | package com.f.spring6.bean; |
1 | package com.f.spring6.bean; |
1 | package com.f.spring6.bean; |
1 | package com.f.spring6.bean; |
1 |
|
1 |
|
7.4 通过FactoryBean接口实例化
以上的第三种方式中,
factory-bean
(生产bean
的工厂bean
)是我们自定义的,factory-method
(生产bean
的工厂方法)也是我们自己定义的。在 Spring 中,当我们编写的类直接实现
FactoryBean
接口之后,用于创建bean
的factory-bean
就不需要我们指定了,工厂bean
的factory-method
也不需要我们指定了。factory-bean
会自动指向实现FactoryBean
接口的类,factory-method
会自动指向该类中的getObject()
方法。- 因为我们在配置文件中指定的用于创建
bean
的类在实现FactoryBean
接口之后,Spring 就知道这是一个工厂类,并且知道用于创建bean
的工厂方法是哪个。
第四种方式实际上就是第三种方式的简化。
- 因为我们在配置文件中指定的用于创建
FactoryBean
在 Spring 中是一个接口,被称为 “工厂Bean”。- “工厂Bean” 是一种特殊的
Bean
,所有的 “工厂Bean” 都是用来协助 Spring 框架来创建其他Bean
对象的。
- “工厂Bean” 是一种特殊的
1 | package com.f.spring6.bean; |
1 | package com.f.spring6.bean; |
1 |
|
1 |
|
- 相比于通过构造方法进行
bean
的实例化(第一种方式),采用工厂方法进行bean
的实例化(第二、三、四种方式),可以使我们在bean
对象创建出来到将创建出来的对象交给 Spring 容器进行管理这一段时间内,对bean
对象进行加工处理。
7.5 BeanFactory和FactoryBean的区别
BeanFactory
BeanFactory
:Spring 容器的顶级父接口。- Spring IoC 容器的顶级对象,
BeanFactory
被翻译为 “Bean工厂”,在 Spring 的 IoC 容器中,“Bean工厂” 负责创建Bean
对象,即BeanFactory
是一个创建bean
对象的工厂。 BeanFactory
是工厂。
FactoryBean
FactoryBean
:它是一个Bean
,是一个能够辅助Spring实例化其它Bean
对象的一个Bean
。- 在 Spring 中,
Bean
可以分为两类:- 第一类:普通Bean。
- 第二类:工厂Bean,工厂 Bean 也是一种
Bean
,只不过这种Bean
比较特殊,它可以辅助 Spring 实例化其它Bean
对象,即工厂 Bean 是一种用于创建Bean
对象的Bean
。 - 我们自己写的,用于实例化
Bean
对象的工厂 Bean 就是FactoryBean
。 - 工厂 Bean 是一种特殊的
Bean
,是用于获取其他Bean
的一种特殊Bean
。FactoryBean
是Bean
。
7.6 FactoryBean实战练习 - 注入自定义Date
java.util.Date
在 Spring 中被当做简单类型,简单类型在注入的时候可以直接使用value
属性或value
标签来完成。- 但是对于
Date
类型来说,采用value
属性或value
标签赋值的时候,对日期字符串的格式要求非常严格,必须是这种格式的:Mon Oct 10 14:30:26 CST 2022
。其他格式是不会被识别的。
- 但是对于
采用工厂方法模式可以让我们以非简单类型的方式,通过
FactoryBean
接口实例化Date
对象,同时还可以对Date
对象进行加工,从而不需要严格按照日期字符串的格式要求,也能创建出日期对象。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22package com.f.spring6.bean;
import java.util.Date;
/**
* @author fzy
* @date 2024/1/20 21:44
*/
public class Student {
private Date birth;
public void setBirth(Date birth) {
this.birth = birth;
}
public String toString() {
return "Student{" +
"birth=" + birth +
'}';
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31package com.f.spring6.bean;
import org.springframework.beans.factory.FactoryBean;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author fzy
* @date 2024/1/20 21:47
*/
public class DateFactoryBean implements FactoryBean<Date> {
// DateFactoryBean这个工厂Bean协助Spring创建普通的Bean:Date
private String strDate;
public DateFactoryBean(String strDate) {
this.strDate = strDate;
}
public Date getObject() throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse(strDate);
return date;
}
public Class<?> getObjectType() {
return Date.class;
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
<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="student" class="com.f.spring6.bean.Student">
<property name="birth" ref="date"/>
</bean>
<!--通过DateFactoryBean这个工厂Bean来帮助我们创建Date Bean-->
<bean id="date" class="com.f.spring6.bean.DateFactoryBean">
<!--只要按yyyy-MM-dd格式输入,就能创建Date对象,因为我们已经在DateFactoryBean中定义了-->
<constructor-arg name="strDate" value="2000-10-10"/>
</bean>
</beans>1
2
3
4
5
6
public void testInstantiation5() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Student student = applicationContext.getBean("student", Student.class);
System.out.println(student);
}从
DateFactoryBean
到Date
的过程为:通过构造方法创建
DateFactoryBean
这个工厂Bean
,并且根据传入的参数<constructor-arg name="strDate" value="2000-10-10"/>
给
DateFactoryBean
的strDate
赋值。Spring 容器会调用工厂 Bean 的
getObject()
方法,在这个方法中,我们根据strDate
创建Date
对象。DateFactoryBean
所创建的Date
对象即为赋给Student
对象的Date
Bean。