【问题标题】:Spring ServiceLocator or pure factory pattern?Spring ServiceLocator 还是纯工厂模式?
【发布时间】:2013-09-10 08:53:35
【问题描述】:

我 99% 的依赖是通过 @Autowired Spring 注解使用 DI 模式管理的。

尽管如此,在特定场景中,直到运行时我才能确定要使用哪个实现。

最广为人知的情况,是解析器的多重实现。

第一种解决方案是使用多个@Autowired(丑陋模式)

Interface Parser {
    <T> T parse();
}

@Component("JsonParser")
class JsonParser implements Parser {
    ...
}

@Component("XmlParser")
class XmlParser implements Parser {
    ...
}

class MyService {
    @Autowired
    @Qualifier("XmlParser")
    Parser xmlParser;

    @Autowired
    @Qualifier("JsonParser")
    Parser jsonParser;

    ...     
}

但是如果我有大量的实现是不能接受的。

第二种解决方案是使用 Spring 中的 ServiceLocator

interface ParserServiceLocatorFactory {
    public Parser getParser(String parserName);
}

interface Parser {
    <T> T parse();
}

@Component("JsonParser")
class JsonParser implements Parser {
    ...
}

@Component("XmlParser")
class XmlParser implements Parser {
    ...
}

class MyService {
    @Autowired 
    ServiceFactory parserServiceLocatorFactory;

    void exampleMethod() {
        Parser xmlParser = parserServiceLocatorFactory.getParser("XmlParser");
    }
}

这种方式对我来说似乎是正确的,但与第三种解决方案相比?

第三种方案是使用纯工厂模式并注入。

@Component
public ParserFactory {
    Parser getParser(String parserName) {
        ...
    }
}

interface Parser {
    <T> T parse();
}

@Component("JsonParser")
class JsonParser implements Parser {
    ...
}

@Component("XmlParser")
class XmlParser implements Parser {
    ...
}

class MyService {
    @Autowired 
    ParserFactory parserFactory

    void exampleMethod() {
        Parser xmlParser = parserFactory.getParser("XmlParser");
    }
}

如果您对以前的解决方案有赞成/反对意见,或者对我的问题有更好的解决方案?

PS:这是伪代码,我可能会遗漏一些小东西:)

【问题讨论】:

  • 所提供的答案都没有回答原始问题:服务定位器的附加值是什么

标签: java spring dependency-injection service-locator


【解决方案1】:

作为一个选项,您可以使用列表注入:

public class SomeService {

    @Autowired 
    private List<Parser> parsers;

    public doSomethingWithParser(...) {
        ...
        Parser parser = getParser(JsonParser.class);
        parser.parse(...);
        ...
    }

    private Parser getParser(Class<Parser> targetClass) {
        Parser result = null;
        for(Parser parser : parsers) {
            if(parser.getClass().equals(targetClass)){
                result = parser;
            }
        }
        return transformer;
    }

}

更好的是,你可以添加Parser.isCompatibleWith(SomeInput input)方法来简化paser检测代码。

【讨论】:

  • 嗯,可以@Autowired 一个列表吗?我知道使用 XML 是可能的,但我从未听说过注释。你有一些文档链接吗?
  • 是的,有可能。我实际上在我当前的项目中使用这种方法。 Go down to the typed collections example.
  • 对上面建议的方法稍作修改将使用解析器类型的 MAP 集合。这样,您可以使用作为类型名称的映射键在恒定时间内进行查找。每次要查找解析器服务时,它将避免 FOR 循环。
  • @Kingz 我现在无法测试,但我认为不可能自动装配带有注释的地图。你的地图必须写XML定义吗?还是我错了?
  • @Kakawait,您可以使用注释自动装配 Map。 Map 值将包含预期类型的​​所有 bean,而键将包含相应的 bean 名称。 Go down to map example in the official documentation
【解决方案2】:

以下是服务定位器类的示例。这会从服务注册表返回给定 ID 的服务。注册表是一个 MAP,它是自动装配的,如图所示。这是来自生产系统的工作示例:

@Service
public class MyServiceLocator {

    @Autowired
    private Map<String, MyService> myServiceRegistry;

    /**
     * Service locator to find the right Domain service to interact with the      requested  data store
     *   
     * @param serviceID
     * @return   
     */
    public MyService locateServiceFor(String serviceID) {
        //Using the Given string 'serviceID' as key, lookup the service from the Registry
        return myServiceRegistry.get(serviceID);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-11
    • 1970-01-01
    相关资源
    最近更新 更多