基于注释的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  阅读(261)  评论(0编辑  收藏  举报