目录标题
前言
FactoryBean 接口对于 Spring 框架来说占有重要的地位,Spring 自身就提供了 70 多个FactoryBean 的实现。它们隐藏了实例化一些复杂 bean 的细节,给上层应用带来了便利。
一、FactoryBean介绍
1、Spring为什么使用FactoryBean
一般情况下,Spring 通过反射机制利用 bean 的 class 属性指定实现类来实例化 bean。
在某些情况下,实例化 bean 过程比较复杂,如果按照传统的方式,则需要在中提供大量的配置信息,配置方式的灵活性是受限的,这时采用编码的方式
可能会得到一个简单的方案。
Spring 为此提供了一个 org.Springframework.bean.factory.FactoryBean 的工厂类接口,用户可以通过实现该接口定制实例化 bean 的逻辑
。
2、FactoryBean接口
2.1 接口定义
从Spring3.0开始,FactoryBean 开始支持泛型,即接口声明改为 FactoryBean< T> 的形式:
package org.springframework.beans.factory;
import org.springframework.lang.Nullable;
public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
}
2.2 方法说明
- T getObject():返回由 FactoryBean 创建的 bean 实例,如果 isSingleton()返回 true,则该实例会放到 Spring 容器中单实例缓存池中。
- boolean isSingleton():返回由 FactoryBean 创建的 bean 实例的作用域是 singleton 还是prototype。
- Class getObjectType():返回 FactoryBean 创建的 bean 类型。
3、FactoryBean在Spring中的作用
当配置文件中< bean>的 class 属性配置的实现类是 FactoryBean 时,通过 getBean()方法返回的不是 FactoryBean 本身,而是 FactoryBean#getObject() 方法所返回的对象
。相当于FactoryBean#getObject()代理了 getBean()方法。
二、FactoryBean使用
现在,让我们通过demo的形式演示FactoryBean如何使用吧。
目录结构如下:
1、定义POJO
package com.cms.factorybean;
import lombok.Data;
/**
* @author: coffee
* @date: 2023/3/5 7:04 PM
* @description: ...
*/
@Data
public class Car {
private String color;
private String maxSpeed;
private String price;
@Override
public String toString() {
return "Car{" +
"color='" + color + '\'' +
", maxSpeed='" + maxSpeed + '\'' +
", price='" + price + '\'' +
'}';
}
}
2、实现FactoryBean
package com.cms.factorybean;
import org.springframework.beans.factory.FactoryBean;
/**
* @author: coffee
* @date: 2023/3/5 7:07 PM
* @description: 通过逗号分隔符的方式一次性为Car的所有属性指定配置值。
*/
public class CarFactoryBean implements FactoryBean<Car> {
private String carInfo;
@Override
public Car getObject() throws Exception {
Car car = new Car();
String[] infoArr = carInfo.split(",");
car.setColor(infoArr[0]);
car.setPrice(infoArr[1]);
car.setMaxSpeed(infoArr[2]);
return car;
}
@Override
public Class<Car> getObjectType() {
return Car.class;
}
@Override
public boolean isSingleton() {
return false;
}
/**
* 功能描述:给carInfo属性注入指定值。(xml方式注入值)
*
* @param carInfo 值
*/
public void setCarInfo(String carInfo) {
this.carInfo = carInfo;
}
}
3、配置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 = "car" class="com.cms.factorybean.CarFactoryBean" >
<property name="carInfo" value="红色,100,200"/>
</bean>
</beans>
4、测试类
package com.cms.factorybean;
import org.junit.jupiter.api.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author: cms
* @date: 2023/3/3 3:19 PM
* @description: xxx
*/
public class FactoryBeanTest {
@Test
public void test () {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("com/cms/factorybean/car.xml");
// 1.当调用 getBean("car")时,Spring 通过反射机制发现 CarFactoryBean 实现了 FactoryBean的接口,这时 Spring 容器就调用接口方法 CarFactoryBean#getObject()方法返回。
Car car = (Car) context.getBean("car");
// 输出:Car{color='红色', maxSpeed='200', price='100'}
System.out.println(car);
//2.如果希望获取CarFactoryBean 的实例,则需要在使用 getBean(beanName)方法时在 beanName 前显示的加上"&”前缀,例如 getBean("&car")。
CarFactoryBean carFactoryBean = (CarFactoryBean)context.getBean("&car");
// 输出:com.cms.factorybean.CarFactoryBean@7748410a
System.out.println(carFactoryBean.toString());
}
}
结果:
08:00:41.209 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@2b6856dd
08:00:41.322 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 1 bean definitions from class path resource [com/cms/factorybean/car.xml]
08:00:41.346 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'car'
Car{color='红色', maxSpeed='200', price='100'}
com.cms.factorybean.CarFactoryBean@7748410a
Process finished with exit code 0
三、getBean(“&car”)与getBean(“car”)
单例池存储内容
getBean(“car”)
源码debug:
getBean(“&car”)
getBean(“&car”)返回的是factorybean对象:
源码debug:
四、源码位置
总结
待补充。