Spring之Bean实例化的四种方式
Bean的实例化方式
Spring为Bean提供了多种实例化方式,通常包括4种方式。(也就是说在Spring中为Bean对象的创建准备了多种方案,目的是:更加灵活)
- 第一种:通过构造方法实例化
- 第二种:通过简单工厂模式实例化
- 第三种:通过工程方法模式实例化
- 第四种:通过FactoryBean接口实例化
1. 通过构造方法实例化
我们之前一直使用的就是这种方式。默认情况下,会调用Bean的无参数构造方法。在spring配置文件中直接配置类全路径,spring会自动调用该类的无参构造方法来实例化Bean。
public class SpringBean {
private int a;
public SpringBean() {
System.out.println("无参构造:"+this);
·}
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
}
<?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="springBean" class="com.qiuye.beanInstance.entity.SpringBean">
<property name="a" value="1"></property>
</bean>
</beans>
public void test() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spirng-instance.xml");
SpringBean springBean = applicationContext.getBean("springBean",SpringBean.class);
System.out.println(springBean);
System.out.println(springBean.getA());
}
执行结果:
注意:
spring的Bean的作用域默认是单例(singleton,是bean标签里面scope属性的值之一,不配置是scope属性则其默认为singleton),此时构造函数是在解析xml的时候就进行调用了,所以Bean的创建也是在这个时候进行的,并非是在调用getBean方法时创建。可以在测试类只保留ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spirng-instance.xml");
进行验证。
2. 通过简单工厂模式实例化
简单工厂模式是工厂方法的一种特殊实现,简单工厂模式由三个角色组成:工厂类角色、抽象产品角色、具体产品角色。 ①编写简单工厂模式当中的工厂类,这里面需要注意的是获取Bean的方法必须是静态的
public class SpringBeanSimpleFactory {
public static SpringBean getSpringbean(){ //必须是静态方法
return new SpringBean();
}
}
②在Spring配置文件中指定创建该Bean的方法(使用factory-method属性指定),其实就是告诉Spring框架,调用该方法可以获取到Bean。
<bean id="getSpirngBean1" class="com.qiuye.beanInstance.factory.SpringBeanSimpleFactory" factory-method="getSpringbean"/>
③编写测试程序
public void test() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spirng-instance.xml");
SpringBean springBean = applicationContext.getBean("getSpirngBean1",SpringBean.class);
System.out.println(springBean);
System.out.println(springBean.getA());
}
执行结果:
3. 通过工厂方法模式实例化
工厂方法模式有抽象/具体工厂、抽象/具体产品四个角色,这里主要使用具体工厂和具体产品角色。
①定义具体工厂类,工厂类中定义实例方法
public class SpringBeanFactory {
public SpringBean getSpringBean(){
return new SpringBean();
}
}
②在Spring配置文件中指定factory-bean(指定工厂类)以及factory-method(指定工厂类的方法),其实就是告诉spring从哪个工厂Bean的那个方法获取到需要的Bean。
<bean id="springBeanFactory" class="com.qiuye.beanInstance.factory.SpringBeanFactory"></bean>
<bean id="getSpirngBean2" factory-bean="springBeanFactory" factory-method="getSpringBean"/>
③编写测试程序
public void test3() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-instance.xml");
SpringBean springBean = applicationContext.getBean("getSpirngBean2",SpringBean.class);
System.out.println(springBean);
}
执行结果:
4. 通过FactoryBean接口实例化
通过工厂方法模式进行实例化时,factory-bean是我们自定义的,factory-method也是我们自己定义的。 在Spring中,提供了FactoryBean接口,实现该接口之后factory-bean不需要指定了,factory-method也不需要指定了。factory-bean会自动指向实现FactoryBean接口的类,factory-method会自动指向getObject()方法。以下是FactoryBean的源码:
public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton() { //默认方法,判断是否是单例,默认返回true
return true;
}
①编写一个类实现FactoryBean接口
public class SpringBeanFactoryImpl implements FactoryBean<SpringBean> {
@Override
public SpringBean getObject() throws Exception {
return new SpringBean();
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() { //该方法在需要转换作用域时重写。默认调用接口的默认方法
return FactoryBean.super.isSingleton();
}
}
②在Spring配置文件中配置FactoryBean
<bean id="getSpirngBean3" class="com.qiuye.beanInstance.factory.SpringBeanFactoryImpl"/>
测试程序:
public void test3() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-instance.xml");
SpringBean springBean = applicationContext.getBean("getSpirngBean3",SpringBean.class);
System.out.println(springBean);
}
执行结果
FactoryBean在Spring中是一个接口。被称为“工厂Bean”。“工厂Bean”是一种特殊的Bean。所有的“工厂Bean”都是用来协助Spring框架来创建其他Bean对象的。 工厂的职责是生产和加工,我们可以用一个例子来体验一下工厂的加工职责。java.util.Date在Spring中被当做简单类型,简单类型在注入的时候可以直接使用value属性或value标签来完成。但我们之前已经测试过了,对于Date类型来说,采用value属性或value标签赋值的时候,对日期字符串的格式要求非常严格,必须是这种格式的:Mon Oct 10 14:30:26 CST 2022。其他格式是不会被识别的。我们习惯的字符串类型是“yyyy-MM-dd”这样的,或者其他的形式。代码如下: ①编写一个Student类
public class Student { //定义Student类,有Date类型的属性
private String name;
private Date birth;
public String getName() {return name}
public void setName(String name) {this.name = name;}
public Date getBirth() {return birth;}
public void setBirth(Date birth) {this.birth = birth;}
@Override
public String toString() {
return "Student{" +
"name='" + name + ''' +
", birth=" + birth +
'}';
}
}
②创建Date类型的工厂Bean
public class DateFactory implements FactoryBean<Date> { //定义Date的工厂Bean
private String dataStr;
public void setDataStr(String dataStr) {
this.dataStr = dataStr;
}
@Override
public Date getObject() throws Exception { //在这里对Date类型进行处理
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date date = simpleDateFormat.parse(dataStr);
return date;
}
@Override
public Class<?> getObjectType() {
return null;
}
}
③编写XML配置 这里就是使用Date的工厂Bean对Date类型进行处理,然后再注入到Student类型里
<bean id="date" class="com.qiuye.beanInstance.factory.DateFactory">
<property name="dataStr" value="1998-01-01"/>
</bean>
<bean id="Student" class="com.qiuye.beanInstance.entity.Student">
<property name="birth" ref="date"/>
<property name="name" value="qy"/>
</bean>
④测试
public void test4() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-instance.xml");
Student student = applicationContext.getBean("Student",Student.class);
System.out.println(student);
}
5.BeanFactory和FactoryBean的区别
5.1 BeanFactory
Spring IoC容器的顶级对象,BeanFactory被翻译为“Bean工厂”,在Spring的IoC容器中,“Bean工厂”负责创建Bean对象。BeanFactory是工厂。
5.2 FactoryBean
FactoryBean:它是一个Bean,是一个能够辅助Spring实例化其它Bean对象的一个Bean。
在Spring中,Bean可以分为两类:
- 第一类:普通Bean
- 第二类:工厂Bean(注意:工厂Bean也是一种Bean,只不过这种Bean比较特殊,它可以辅助Spring实例化其它Bean对象。)
转载自:https://juejin.cn/post/7213665606628655141