Spring 为 Bean 提供了多种实例化方式,通常包括4种方式
也就是说在 Spring 中为 Bean 对象的创建准备了多种方案,目的是:更加灵活
-
第一种:通过构造方法实例化
-
第二种:通过简单工厂模式实例化
-
第三种:通过 factory-bean 实例化
-
第四种:通过 FactoryBean 接口实例化
一、通过构造方法实例化
public class SpringBean {
public SpringBean(){
System.out.println("SpringBean 的无参数构造方法执行.......");
}
}
<!--
Spring 提供的实例化方式
第一种:在Spring配置文件中直接配置类全路径,Spring会自动调用该类的无参数构造方法来实例化Bean
-->
<bean id="springBean" class="org.qiu.spring.bean.SpringBean"/>
@Test
public void testInstantiationOne(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
SpringBean springBean = applicationContext.getBean("springBean", SpringBean.class);
System.out.println(springBean);
}
运行结果:
二、通过简单工厂模式实例化
public class Star {
public Star(){
System.out.println("Star 的无参数构造方法执行......");
}
}
public class StarFactory {
public static Star get(){
// 这个 Star 实际上创建的时候还是我们自己 new 的对象
return new Star();
}
}
<!--
Spring 提供的实例化方式
第二种:简单工厂模式。需要在Spring配置文件中告诉Spring框架,调用哪个类的哪个方法获取Bean
factory-method : 指定工厂类中的静态方法,告诉Spring框架,调用这个方法可以获取Bean
-->
<bean id="starBean" class="org.qiu.spring.bean.StarFactory" factory-method="get"/>
@Test
public void testtestInstantiationTwo(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Star star = applicationContext.getBean("starBean", Star.class);
System.out.println(star);
}
运行结果:
三、通过 factory-bean 实例化
这种方式本质上是:通过工厂方法模式进行实例化
public class Gun{
public Gun() {
System.out.println("Gun 的无参数构造方法执行......");
}
}
public class GunFactory{
public Gun get(){
return new Gun();
}
}
<!--
Spring 提供的实例化方式
第三种:通过工厂方法模式
-->
<bean id="gunFactory" class="org.qiu.spring.bean.GunFactory"/>
<bean id="gun" factory-bean="gunFactory" factory-method="get"/>
@Test
public void testtestInstantiationThree(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Gun gun = applicationContext.getBean("gun", Gun.class);
System.out.println(gun);
}
运行结果:
四、通过 FactoryBean 接口实例化
以上的第三种方式中,factory-bean 是我们自定义的,factory-method 也是我们自己定义的
在 Spring 中,当你编写的类直接实现 FactoryBean 接口之后,factory-bean 不需要指定了,factory-method 也不需要指定了
factory-bean 会自动指向实现 FactoryBean 接口的类,factory-method 会自动指向 getObject() 方法
package org.qiu.spring.bean;
/**
* @author 秋玄
* @version 1.0
* @email qiu_2022@aliyun.com
* @project Spring
* @package org.qiu.spring.bean
* @date 2022-11-10-22:15
* @since 1.0
*/
public class Person {
public Person() {
System.out.println("Person 的无参数构造方法执行......");
}
}
package org.qiu.spring.bean;
import org.springframework.beans.factory.FactoryBean;
/**
* @author 秋玄
* @version 1.0
* @email qiu_2022@aliyun.com
* @project Spring
* @package org.qiu.spring.bean
* @date 2022-11-10-22:16
* @since 1.0
*/
public class PersonFactoryBean implements FactoryBean<Person> {
@Override
public Person getObject() throws Exception {
// 最终这个 Bean 的创建还是程序员自己 new 的
return new Person();
}
@Override
public Class<?> getObjectType() {
return null;
}
/**
* 这个方法 FactoryBean 接口有默认实现
* default boolean isSingleton() {
* return true;
* }
* 即获取的 Bean 默认情况下是单例的
* 若需要修改为多例,修改为 return false 即可
*/
@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}
<!--
Spring 提供的实例化方式
第四种:通过 FactoryBean 接口来实现,实际上简化了第三种方式
通过 factoryBean 这个工厂 Bean 主要是想对普通 Bean 进行加工处理
-->
<bean id="personBean" class="org.qiu.spring.bean.PersonFactoryBean"/>
@Test
public void testInstantiationFour(){
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);
}
运行结果:
FactoryBean 在 Spring 中是一个接口,被称为 “工厂Bean”。“工厂Bean”是一种特殊的 Bean。所有的“工厂Bean”都是用来协助Spring 框架来创建其他 Bean 对象的
五、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 对象)
六、注入自定义 Date
前面说过,java.util.Date 在 Spring 中被当做简单类型,简单类型在注入的时候可以直接使用 value 属性或 value 标签来完成。但我们之前已经测试过了,对于 Date 类型来说,采用 value 属性或 value 标签赋值的时候,对日期字符串的格式要求非常严格,必须是这种格式的:Mon Oct 10 14:30:26 CST 2022,其他格式是不会被识别的。如以下代码:
package org.qiu.spring.bean;
import java.util.Date;
/**
* @author 秋玄
* @version 1.0
* @email qiu_2022@aliyun.com
* @project Spring
* @package org.qiu.spring.bean
* @date 2022-11-10-22:34
* @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 +
'}';
}
}
package org.qiu.spring.bean;
import org.springframework.beans.factory.FactoryBean;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author 秋玄
* @version 1.0
* @email qiu_2022@aliyun.com
* @project Spring
* @package org.qiu.spring.bean
* @date 2022-11-10-22:41
* @since 1.0
*/
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;
}
}
<!--
1、将 value 的值通过 DateFactoryBean 的构造方法 DateFactoryBean(String strDate) 赋值给 DateFactoryBean 的 date 属性
2、DateFactoryBean 实现了 FactoryBean 接口,Spring 会自动调用 getObject 方法
3、getObject 中对第一步注入的字符串(date字符串)进行格式化并返回一个自定义格式的 Date 对象
4、将上一步的 Date 对象注入给 Student 这个 Bean 的 birth 属性
-->
<bean id="date" class="org.qiu.spring.bean.DateFactoryBean">
<constructor-arg index="0" value="2000-01-01"/>
</bean>
<bean id="student" class="org.qiu.spring.bean.Student">
<property name="birth" ref="date"/>
</bean>
@Test
public void testDate(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Student student = applicationContext.getBean("student", Student.class);
System.out.println(student);
}
运行结果:
一 叶 知 秋,奥 妙 玄 心