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屬性的餘地。