L
L
LearnJava
Search…
FactoryBean理解

一、简介

Spring中有两种Bean,一种是普通的Bean,另外一种就是FactoryBean。FactoryBean与普通的Bean不同,其返回的对象不是指定类的一个实例,而是该FactoryBean的getObject方法所返回的对象。创建出来的对象的类型由getObjectType方法决定,是否是单例由isSingleton方法决定。上面提到的这个三个方法就组成了FactoryBean接口。
package org.springframework.beans.factory;
import org.springframework.lang.Nullable;
public interface FactoryBean<T> {
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
}

二、什么时候用?

一般情况下,Spring利用反射实例化<bean>的class属性执行的实现类来初始化bean,在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在<bean>中提供大量的配置信息,配置方式的灵活性是受限的。Spring为此提供了一个FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。FactoryBean接口对于Spring框架来说占用重要的地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂Bean的细节,给上层应用带来了便利。
FactoryBean 通常是用来创建比较复杂的bean,一般的bean 直接用xml配置即可,但如果一个bean的创建过程中涉及到很多其他的bean 和复杂的逻辑,用xml配置比较困难,这时可以考虑用FactoryBean。

三、实践出真知

3.1 新建一个maven项目

引入Spring的依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>LearnFactoryBean</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.4.RELEASE</version>
</dependency>
</dependencies>
</project>
成品的目录结构如下,下面依次实现每个类和接口。
.
├── pom.xml
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── wangjun
│ │ │ └── test
│ │ │ ├── Main.java
│ │ │ ├── TestFactoryBean.java
│ │ │ ├── TestInterface.java
│ │ │ ├── TestInterfaceImplA.java
│ │ │ └── TestInterfaceImplB.java
│ │ └── resources
│ │ └── spring.xml

3.2 接口和实现类

public interface TestInterface {
void name();
}
public class TestInterfaceImplA implements TestInterface {
public void name() {
System.out.println("impl:a");
}
}
public class TestInterfaceImplB implements TestInterface {
public void name() {
System.out.println("impl:b");
}
}

3.3 工厂Bean

public class TestFactoryBean implements FactoryBean<TestInterface> {
private Class<?> testInterface;
/**
* 随机返回TestInterface接口的实现类A或实现类B
* @return
* @throws Exception
*/
public TestInterface getObject() throws Exception {
return new Random().nextInt(2) == 0? new TestInterfaceImplA(): new TestInterfaceImplB();
}
/**
* 返回bean的类型
* @return
*/
public Class<?> getObjectType() {
return testInterface;
}
public void setTestInterface(Class<?> testInterface) {
this.testInterface = testInterface;
}
public void test() {
System.out.println("test1111");
}
}

3.4 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 name="testFactoryBean" class="com.wangjun.test.TestFactoryBean">
<property name="testInterface" value="com.wangjun.test.TestInterface"/>
</bean>
</beans>

3.5 测试类

public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring.xml");
TestInterface testInterface = context.getBean(TestInterface.class);
// 也可以这样获取bean
// TestInterface testInterface = (TestInterface) context.getBean("testFactoryBean");
testInterface.name();
// 如果需要获取实现了FactoryBean的实例FirstFactoryBean,而不是getObject返回的实例,则需要在beanName前加&
// 参考:https://stackoverflow.com/questions/49199901/what-does-the-mean-in-in-a-bean-name
FirstFactoryBean f = (FirstFactoryBean) context.getBean("&shareInterface");
f.test();
}
}

3.6 测试运行

impl:a 和 impl:b 随机打印
Copy link
On this page
一、简介
二、什么时候用?
三、实践出真知
3.1 新建一个maven项目
3.2 接口和实现类
3.3 工厂Bean
3.4 xml
3.5 测试类
3.6 测试运行