文章目录
- 环境
- Bean的实例化方式
- 通过构造方法实例化
- 通过简单工厂模式实例化
- 通过工厂方法模式实例化
- 通过FactoryBean接口实例化
- BeanFactory和FactoryBean的区别
- BeanFactory
- FactoryBean
- 工厂Bean的使用:注入自定义Date
上一篇:(六)Spring之回顾工厂模式
环境
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);
}