基于注释的ServiceLocatorFactoryBean
今天看一个新项目的代码, 对里面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
接口Parser.class
public interface Parser { 
    void parse(String str); 
} 
实现上面的接口。
JsonParser.java
public class JsonParser implements Parser { 
    @Override 
    public void parse(String str) { 
    System.out.println("JsonParser.parse::" + str); 
    } 
} 
XMLParser.java
public class XMLParser implements Parser{ 
    @Override 
    public void parse(String str) { 
    System.out.println("XMLParser.parse :: " + str); 
    } 
} 
ParserFactory.java实际工厂接口。
public interface ParserFactory { 
    public Parser getParser(ParserType parserType); 
} 
ParseType.java枚举指定解析类型(避免错别字和安全)
public enum ParserType { 
JSON("jsonParser"), XML("xmlParser"); 
private final String value; 
    ParserType(String input) { 
    this.value = input; 
    } 
    public String getValue() { 
    return this.value; 
    } 
    @Override 
    public String toString() { 
    return this.value; 
    } 
} 
ParseService.java,其中商业逻辑Implemeted一个。
@Service 
public class ParserService { 
@Autowired 
private ParserFactory parserFactory; 
public void doParse(String parseString, ParserType parseType) { 
    Parser parser = parserFactory.getParser(parseType); 
    System.out.println("ParserService.doParse.." + parser); 
    parser.parse(parseString); 
} 
} 
最后AppConfig.java的Spring Java配置类,所有我的豆注册为容器管理豆。
@Configuration 
@ComponentScan(basePackages = {"<Your Package Name>"}) 
public class AppConfig { 
@Bean 
public FactoryBean serviceLocatorFactoryBean() { 
    ServiceLocatorFactoryBean factoryBean = new ServiceLocatorFactoryBean(); 
    factoryBean.setServiceLocatorInterface(ParserFactory.class); 
    return factoryBean; 
} 
@Bean(name = "jsonParser") 
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE) 
public JsonParser jsonParser() { 
    return new JsonParser(); 
} 
@Bean(name = "xmlParser") 
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE) 
public XMLParser xmlParser() { 
    return new XMLParser(); 
} 
} 
现在,在任一控制器或测试类里面自动装配ParserService豆,并调用parese(String, ParseType)方法来测试。
这是我的测试。
@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(classes = AppConfig.class) 
public class ServiceLocatorFactoryExample { 
@Autowired 
private ParserService parserService; 
@Test 
public void testParserFactory() { 
    parserService.doParse("Srilekha", ParserType.JSON); 
    parserService.doParse("Srilekha", ParserType.XML); 
} 
} posted on 2022-07-05 19:12 1450811640 阅读(385) 评论(0) 收藏 举报
 
                     
                    
                 
                    
                 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号