1. 程式人生 > 實用技巧 >BeanFactory和Factory的區別: FactoryBean的基礎使用

BeanFactory和Factory的區別: FactoryBean的基礎使用

用了這麼久的SpringMVC框架,有一天看到一個問題,BeanFactory和FactoryBean有什麼區別?

我當時的第一想法是BeanFactory不就是生產bean的工廠嗎,FactoryBean不就是工廠裡面生產出來的Bean嗎?

後來發現,我的答案不是很對。去查了Spring的原始碼,看到了FactoryBean的介面,如下

public interface FactoryBean<T> {

	String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
	@Nullable
	T getObject() throws Exception;
	@Nullable
	Class<?> getObjectType();
	default boolean isSingleton() {
		return true;
	}
}

從開始的註釋第一句就是,FactoryBean是BeanFactory裡面使用到的介面。真的是在BeanFactory使用到的bean。同時實現了這個介面的bean不能向常規的bean一樣使用他,如何注入一個FactoryBean後面的例子會提到。

但是FactoryBean實際上還是一個工廠,他有一個泛型T,表示這個工廠建立的例項型別,getObject() 則是返回T,就是建立bean的方法。getObjectType返回的是建立bean的Class物件。而isSingleton則是表示一個FactoryBean創建出來的Bean是不是單例,

這個應該不難理解。

那麼如何在實際開發裡面使用呢?

這裡有兩個物件,一個是要創建出來的泛型T,一個是實現FactoryBean介面的類。

類:ToolFactoryBean

public class ToolFactoryBean implements FactoryBean<Tool> {
	private int factoryId;
	private int toolId;

	public void setFactoryId(int factoryId) {
		this.factoryId = factoryId;
	}

	public int getToolId() {
		return toolId;
	}

	public void setToolId(int toolId) {
		this.toolId = toolId;
	}

	@Override
	public Tool getObject() throws Exception {
		return new Tool(toolId);
	}

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

	public int getFactoryId() {
		return factoryId;
	}
}

需要注意的是如果你用的是xml配置方式,那麼你需要有setter來設定屬性。

被創建出來的例項:

public class Tool {
	private int id;
	public Tool(int i) {
		this.id = i;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
}

這裡只是實現功能不需要定義複雜的屬性。只需要定義一個id即可。

配置類:

@Configuration
public class FactoryBeanAppConfig {
	@Bean(name = "toolFactory")
	public ToolFactoryBean getTooFactoryBean() {
		ToolFactoryBean toolFactoryBean = new ToolFactoryBean();
		toolFactoryBean.setFactoryId(1111);
		toolFactoryBean.setToolId(2333);
		return toolFactoryBean;
	}

//	@Bean
//	public Tool getTool() throws Exception {
//		return getTooFactoryBean().getObject();
//	}
}

xml配置方式多少有點落伍了,這裡直接使用配置類的方式。需要說明的是如果配置了ToolFactoryBean就無需再配置出他創建出來的那個bean了,因為spring會糊塗。

使用方式:

package com.example.springmvcdemo.bean;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.jupiter.api.Assertions.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = FactoryBeanAppConfig.class)
public class ToolFactoryBeanTest1 {
	@Autowired
	private Tool tool;

	@Resource(name = "&toolFactory")
	private ToolFactoryBean toolFactoryBean;

	@Test
	public void test() {
		assertThat(tool.getId(), equalTo(2333));
		assertThat(toolFactoryBean.getFactoryId(), equalTo(1111));
	}

}

由於FactoryBean無法通過正常的AutoWired獲取到,所以使用& + beanName的方式獲取,同樣的,你會發現沒有配置的Toolbean居然可以直接Autowired

以上就是FactoryBean的簡單的使用,可以看出,FactoryBean可以給我們留有一些預設Bean屬性的餘地。