今天看一個新項目的代碼, 對裏面ServiceLocatorFactoryBean的使用不太明白, 便研究了一番。
首先ServiceLocatorFactoryBean的使用場景是這樣的, 如果你有一個對象是從spring的beanfactory拿出來,spring的bean一般分爲singleton和prototype, singleton是整個spring容器中只有一個實例,prototype是每次注入的時候new一個新實例。但注入一般是注入到對象的屬性中,那對於一個對象一般只會注入一次。
假如我每次call一個方法的時候希望都使用的是新的實例, 這時就要靠ServiceLocatorFactoryBean出場了。
官方文檔是這樣寫的
“They will typically be used for prototype beans, i.e. for factory methods that are supposed to return a new instance for each call. ”
具體用法是這樣的
首先定義一個接口用來創建之後要使用的目標對象IPhase
interface IPhaseFactory {
IPhase getPhase(String name);
}
然後設置工廠對象,傳入這個接口
<beans:bean class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean" id="phaseFactory">
<beans:property name="serviceLocatorInterface" value="com.lich.IPhaseFactory"/>
</beans:bean>
在具體要使用IPhase的對象的類裏面設置工廠bean
class PhaseBuilder {
@Inject
private IPhaseFactory phaseFactory;
IPhase build(String name) {
IPhase phase = phaseFactory.getPhase(name);//這裏每次拿到的就是新的對象了
return phase;
}
看代碼時這裏有個困擾我的問題是 IPhaseFactory接口, 項目代碼裏面是沒有實現類的, spring是在運行時動態代理生成了一個實現類, 那麼這裏就奇怪了,它怎麼知道要用什麼樣的邏輯來返回我要的那個對象呢,比如 IPhase 接口下面有很多實現類,它怎麼知道是哪一個呢?
看下ServiceLocatorFactoryBean類的源碼就知道了
private Object invokeServiceLocatorMethod(Method method, Object[] args) throws Exception {
Class serviceLocatorMethodReturnType = getServiceLocatorMethodReturnType(method);
try {
String beanName = tryGetBeanName(args);
if (StringUtils.hasLength(beanName)) {
// Service locator for a specific bean name
return beanFactory.getBean(beanName, serviceLocatorMethodReturnType);
}
else {
// Service locator for a bean type
return beanFactory.getBean(serviceLocatorMethodReturnType);
}
}
}
private String tryGetBeanName(Object[] args) {
String beanName = "";
if (args != null && args.length == 1 && args[0] != null) {
beanName = args[0].toString();
}
// Look for explicit serviceId-to-beanName mappings.
if (serviceMappings != null) {
String mappedName = serviceMappings.getProperty(beanName);
if (mappedName != null) {
beanName = mappedName;
}
}
return beanName;
}
上面的代碼中會測試着使用接口方法中的參數作爲bean的name來去beanfactory裏面找, 如果接口方法沒有參數,
// Service locator for a specific bean name
return beanFactory.getBean(beanName, serviceLocatorMethodReturnType);
就會使用返回對象的類型來找
// Service locator for a bean type
return beanFactory.getBean(serviceLocatorMethodReturnType);
那麼在我們的列子中就是 用參數中的name來找了
IPhase getPhase(String name);
比如下面的實現類
@Component("DataPersistPhase")
@Prototype
class DataPersistPhase implements IPhase