Content Table

FactoryBean

FactoryBean 是用来创建 Bean 的工厂,实现 FactoryBean 接口 的类就可以用来创建其他 Bean 了,在 Bean Configuration File 里的 <bean> 里定义要生成的 Bean。

FactoryBean 命名规范:Bean 的类名 后跟着 FactoryBean,例如创建 User 的 FactoryBean 的类名应该为 UserFactoryBean。

如果 Bean 的创建不只是简单的 setter, constructor 注入,而是有其他的逻辑,这个时候就可以用 FactoryBean 来创建 Bean(有点像同时用了 Factory Pattern 和 Builder Pattern)。

FactoryBean 是很常见的,例如 Spring 集成 MyBatis 时用 SqlSessionFactoryBean 来创建 SqlSession。

下面的示例展示怎么实现 UserFactoryBean,用来创建 User 的对象。

spring-beans.xml

1
2
3
4
5
6
7
8
9
10
11
12
<?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="user" class="com.xtuer.beans.factory.UserFactoryBean">
<property name="username" value="Alice"/>
<property name="password" value="Passw0rd"/>
</bean>
</beans>
  1. <bean> 和普通 Bean 的定义完全一样
  2. 虽然最后是要生成 User 的对象,但是 class 不是 com.xtuer.beans.User,而是创建它的工厂 com.xtuer.beans.factory.UserFactoryBean
  3. username, password 等都是注入到 UserFactoryBean
  4. 当 Spring 看到 UserFactoryBean 实现了 FactoryBean 接口,就会调用 UserFactoryBean.getObject() 来创建 User 的对象

User

1
2
3
4
5
6
7
8
9
10
package com.xtuer.beans;

public class User {
private int id;
private String username;
private String password;
private Address address;

// 省略 setter and getter
}

UserFactoryBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.xtuer.beans.factory;

import com.xtuer.beans.User;
import org.springframework.beans.factory.FactoryBean;

public class UserFactoryBean implements FactoryBean {
private String username;
private String password;

@Override
public Object getObject() throws Exception {
User user = new User();

// 可以有很复杂的逻辑
user.setUsername(username.toUpperCase());
user.setPassword(password);

return user;
}

@Override
public Class<?> getObjectType() {
return User.class;
}

@Override
public boolean isSingleton() {
return true;
}

public void setUsername(String username) {
this.username = username;
}

public void setPassword(String password) {
this.password = password;
}
}

FactoryBeanTest

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import com.xtuer.beans.User;
import com.xtuer.util.CommonUtils;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class FactoryBeanTest {
private static ApplicationContext context;

@BeforeClass
public static void setup() {
context = new ClassPathXmlApplicationContext("spring-beans.xml");
}

@Test
public void test() {
// 这里得到的不是 UserFactoryBean,而是它的 getObject() 方法返回的 User
User user = context.getBean("user", User.class);
CommonUtils.output(user);
CommonUtils.output(user.getClass());
}
}

输出

1
2
3
4
5
6
7
{
"id" : 0,
"username" : "ALICE",
"password" : "Passw0rd",
"address" : null
}
"com.xtuer.beans.User"