07 Bean的实例化方式
Spring 为 Bean 提供了多种实例化方式,通常包括 4 种方式。(也就是说在 Spring 中为 Bean 对象的创建准备了多种方案,目的是:更加灵活) - 第一种:通过构造方法实例化 - 第二种:通过简单工厂模式实例化 - 第三种:通过 factory-bean 实例化 - 第四种:通过 FactoryBean 接口实例化
7.1 通过构造方法实例化¶
我们之前一直使用的就是这种方式。默认情况下,会调用 Bean 的无参数构造方法。
```java title:User package com.powernode.spring6.bean;
/** * @author 动力节点 * @version 1.0 * @className User * @since 1.0 */ public class User { public User() { System.out.println("User类的无参数构造方法执行。"); } }
```xml title:spring.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 id="userBean" class="com.powernode.spring6.bean.User"/>
</beans>
```java title:SpringInstantiationTest package com.powernode.spring6.test;
import com.powernode.spring6.bean.User; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;
/** * @author 动力节点 * @version 1.0 * @className SpringInstantiationTest * @since 1.0 */ public class SpringInstantiationTest {
@Test
public void testConstructor(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
User user = applicationContext.getBean("userBean", User.class);
System.out.println(user);
}
} ``` 执行结果: ![[07.01-1.png]]
7.2 通过简单工厂模式实例化¶
第一步:定义一个 Bean
java title:Vip
package com.powernode.spring6.bean;
/**
* @author 动力节点
* @version 1.0
* @className Vip
* @since 1.0
*/
public class Vip {
}
第二步:编写简单工厂模式当中的工厂类 ```java title:VipFactory package com.powernode.spring6.bean;
/** * @author 动力节点 * @version 1.0 * @className VipFactory * @since 1.0 */ public class VipFactory { public static Vip get(){ return new Vip(); } }
第四步:编写测试程序 ```java title:testSimpleFactory @Test public void testSimpleFactory(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml"); Vip vip = applicationContext.getBean("vipBean", Vip.class); System.out.println(vip); }
执行结果:
![[07.02-1.png]]
---
## 7.3 通过 factory-bean 实例化
这种方式本质上是:通过工厂方法模式进行实例化。
第一步:定义一个 Bean
```java title:Order
package com.powernode.spring6.bean;
/**
* @author 动力节点
* @version 1.0
* @className Order
* @since 1.0
*/
public class Order {
}
第二步:定义具体工厂类,工厂类中定义实例方法 ```java title:OrderFactory package com.powernode.spring6.bean;
/** * @author 动力节点 * @version 1.0 * @className OrderFactory * @since 1.0 */ public class OrderFactory { public Order get(){ return new Order(); } }
第三步:在 Spring 配置文件中指定 `factory-bean` 以及 `factory-method`
```xml title:spring.xml
<bean id="orderFactory" class="com.powernode.spring6.bean.OrderFactory"/>
<bean id="orderBean" factory-bean="orderFactory" factory-method="get"/>
第四步:编写测试程序 ```java title:testSelfFactoryBean @Test public void testSelfFactoryBean(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml"); Order orderBean = applicationContext.getBean("orderBean", Order.class); System.out.println(orderBean); }
执行结果:
![[07.03-1.png]]
---
## 7.4 通过 FactoryBean 接口实例化
以上的第三种方式中,factory-bean 是我们自定义的,factory-method 也是我们自己定义的。
在 Spring 中,当你编写的类直接实现 FactoryBean 接口之后,factory-bean 不需要指定了,factory-method 也不需要指定了。
**factory-bean 会自动指向实现 FactoryBean 接口的类,factory-method 会自动指向 `getObject ()` 方法。**
第一步:定义一个 Bean
```java title:Person
package com.powernode.spring6.bean;
/**
* @author 动力节点
* @version 1.0
* @className Person
* @since 1.0
*/
public class Person {
}
第二步:编写一个类实现 FactoryBean 接口 ```java title:PersonFactoryBean package com.powernode.spring6.bean;
import org.springframework.beans.factory.FactoryBean;
/** * @author 动力节点 * @version 1.0 * @className PersonFactoryBean * @since 1.0 */ public class PersonFactoryBean implements FactoryBean {
@Override
public Person getObject() throws Exception {
return new Person();
}
@Override
public Class getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
// true表示单例
// false表示原型
return true;
}
}
第三步:在 Spring 配置文件中配置 FactoryBeanxml title:spring.xml
测试程序: ```java title:testFactoryBean @Test public void testFactoryBean(){ ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml"); Person personBean = applicationContext.getBean("personBean", Person.class); System.out.println(personBean);
Person personBean2 = applicationContext.getBean("personBean", Person.class);
System.out.println(personBean2);
} ``` 执行结果: ![[07.04-1.webp]] FactoryBean 在 Spring 中是一个接口。被称为“工厂 Bean”。“工厂 Bean”是一种特殊的 Bean。所有的“工厂 Bean”都是用来协助 Spring 框架来创建其他 Bean 对象的。
7.5 BeanFactory 和 FactoryBean 的区别¶
7.5.1 BeanFactory¶
Spring IoC 容器的顶级对象,BeanFactory 被翻译为“Bean 工厂”,在 Spring 的 IoC 容器中,“Bean 工厂”负责创建 Bean 对象。 BeanFactory 是工厂。
7.5.2 FactoryBean¶
FactoryBean:它是一个 Bean,是一个能够辅助 Spring 实例化其它 Bean 对象的一个 Bean。 在 Spring 中,Bean 可以分为两类: - 第一类:普通 Bean - 第二类:工厂 Bean(记住:工厂 Bean 也是一种 Bean,只不过这种 Bean 比较特殊,它可以辅助 Spring 实例化其它 Bean 对象。)
7.6 注入自定义 Date¶
我们前面说过,java. util. Date 在 Spring 中被当做简单类型,简单类型在注入的时候可以直接使用 value 属性或 value 标签来完成。但我们之前已经测试过了,对于 Date 类型来说,采用 value 属性或 value 标签赋值的时候,对日期字符串的格式要求非常严格,必须是这种格式的:Mon Oct 10 14:30:26 CST 2022。其他格式是不会被识别的。如以下代码:
java title:Student
package com.powernode.spring6.bean;
import java.util.Date;
/**
* @author 动力节点
* @version 1.0
* @className Student
* @since 1.0
*/
public class Student {
private Date birth;
public void setBirth(Date birth) {
this.birth = birth;
}
@Override
public String toString() {
return "Student{" +
"birth=" + birth +
'}';
}
}
```xml title:spring.xml
```java title:testDate
@Test
public void testDate(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Student studentBean = applicationContext.getBean("studentBean", Student.class);
System.out.println(studentBean);
}
执行结果: ![[07.06-1.webp]] 如果把日期格式修改一下:
```xml title:spring.xml
执行结果:
![[07.06-2.png]]
这种情况下,我们就可以使用 FactoryBean 来完成这个骚操作。
编写 DateFactoryBean 实现 FactoryBean 接口:
```java title:DateFactoryBean
package com.powernode.spring6.bean;
import org.springframework.beans.factory.FactoryBean;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author 动力节点
* @version 1.0
* @className DateFactoryBean
* @since 1.0
*/
public class DateFactoryBean implements FactoryBean {
// 定义属性接收日期字符串
private String date;
// 通过构造方法给日期字符串属性赋值
public DateFactoryBean(String date) {
this.date = date;
}
@Override
public Date getObject() throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.parse(this.date);
}
@Override
public Class getObjectType() {
return null;
}
}
编写 spring 配置文件:
```xml title:spring.xml
执行测试程序: ![[07.06-3.png]]