Java中依赖注入的继承(后期绑定)

时间:2014-06-01 04:36:17

标签: java spring inheritance soa late-binding

我正在使用Spring DI来连接我的组件,我遇到了这个问题。

我有一个BaseService类,它有多个实现。它上面的层有一个构建器,它调用服务来获取数据来填充POJO。我需要调用的服务实现(ServiceA,ServiceB)根据我需要构建的POJO类型进行更改。

在这种情况下,我如何自动装配服务,因为它需要延迟绑定服务。我该如何处理这种情况? (Spring DI中的示例确实会有帮助)

Builder calling Services

我读过类似的问题,却找不到答案。我读到服务主机等SOA模式为确切的用例提供了不同的解决方案。

请帮忙。 感谢

5 个答案:

答案 0 :(得分:7)

如何使用FactoryBean

public class BuilderFactory implements FactoryBean<Builder> {

  @Autowired
  private ApplicationContext appContext;

  ...

  @Override
  public Builder getObject() {
      Builder builder = new Builder();      
      switch(something()) { 
         case "foo":
             builder.service = new ServiceA(); 
             break;
         case "bar":
             builder.service= new ServiceB();
             break;
         ...
         default:
             //handle cases where it's unclear which type to create

         }
     return builder;
  }

}

其中Builder个实例有一个公共/包私有字段BaseService service,可以在getData()buildPojos()以及其他方法中调用。

(如果您希望此字段为私有,您也可以使用静态工厂方法来实例化Builder

答案 1 :(得分:5)

您可以使用ServiceLocatorFactoryBean。在你的情况下,你会做这样的事情:

public interface BaseServiceLocator {

   BaseService lookup(String qualifier); //use whatever qualifier type makes sense here
}

<bean id="serviceLocatorFactoryBean"
    class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean">
    <property name="serviceLocatorInterface"
              value="your.package.BaseServiceLocator" />
</bean>

然后你的建造者看起来像这样:

public class Builder {

  @Autowired
  private BaseServiceLocator baseServiceLocator;

  @Override
  public YourReturnType businessMethod() {
      SomeData data = getData();
      BaseService baseService = baseServiceLocator(data.getType()); //here I am assuming that getType() is a String

      //whatever
  }

答案 2 :(得分:2)

我的一个项目中有相同的要求。我根据pojo要求使用反射来获取服务。这样就没有静态值,即使你将来定义新的pojo和服务,你也不必改变任何实现。

我已经将我的pojos和服务命名为类似。即

POJO名称:Pond5DownloadStrategy和ServiceName:Pond5DownloadStrategyService

我在春天定义了所有服务。我有一个DownloadStrategyFactory有一个方法 getService(Object obj)。它也被实例化为spring bean。 getService方法做了什么。 我使用obj.getClass().getSimpleName()将POJO名称作为字符串,然后在最后添加Service。恩。 如果我通过Pond5DownloadStrategy,那么我执行AppContext.getBean(“Pond5DownloadStrategyService”);

答案 3 :(得分:2)

请查看我的回答here

虽然是在春季批量主题下,但它实际上与您的问题和策略设计模式有关。

策略A策略B是您的ServiceA,ServiceB等 您需要在Builder类中使用StrategyLocator(在原始答案中,它等效于MyTaskelt)。查找将基于您的pojo类型。

strategy = strategyLocator.lookup(POJOs.class);  

在答案中,我建议使用PlugableStrategyMapper,但是如果你预定义所有Servcies,你可以将它们放在application-context.xml中的Map中

答案 4 :(得分:1)

例如,对于手动绑定:

public class Builder {

    @Autowired
    private Map<String, Service> services;
    // Bind pojo classes to bean names.
    private Map<Class<?>, String> binding;

    public Service getService(Object object) {
        return services.get(binding.get(object.getClass()));
    }

    public Map<Class<?>, String> getBinding() {
        return binding;
    }

    public void setBinding(Map<Class<?>, String> binding) {
        this.binding = binding;
    }
}

然而,手动绑定可能是重复的,所以如果你真的不需要他的灵活性,你可以使用命名约定(@AmitChotaliya回答)或通过服务方法强制执行绑定。

public interface Service {

    Class<?> getTargetType();
}


public class Builder {

    @Autowired
    private Set<Service> services;
    // Bind pojo classes to Services.
    private Map<Class<?>, Service> binding = new ConcurrentHashMap<Class<?>, Service>();

    @PostConstruct
    public void init() {
        for (Service service : services) {
            binding.put(service.getTargetType(), service);

        }
    }

    public Service getService(Object object) {
        return binding.get(object.getClass());
    }
}