【问题标题】:Inheritance (Late Binding) via Dependency Injection in Java通过 Java 中的依赖注入进行继承(后期绑定)
【发布时间】:2014-07-21 12:34:33
【问题描述】:

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

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

在这种情况下,我该如何自动装配服务,因为它需要后期绑定服务。我该如何应对这种情况? (Spring DI 中的示例真的很有帮助)

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

请帮忙。 谢谢

【问题讨论】:

  • 在春季,它是在启动时绑定一次。您是否希望根据您传递的 pojo 类型调用不同的服务 impl?
  • 这正是我想要的。
  • 您可以使用 Spring AOP(带有 Around 建议)拦截对 Builder.buildPOJO(MyPojo.class) 方法的调用,并在建议内部,根据作为参数传递的类,建议将致电ServiceA.buildPOJO()ServiceB.buildPOJO() 等。

标签: java spring inheritance soa late-binding


【解决方案1】:

如何使用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

【讨论】:

  • 我忘记了 FactoryBeans。
  • 这种模式的优势是什么?我的意思是,我们在这里使用了一个额外的开关盒,类似于我的构建器类实现中的开关盒。在这种情况下也不能让 Builder 成为单身人士,对吗?那么这是一种有效的设计策略吗?
【解决方案2】:

您可以使用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
  }

【讨论】:

  • 这个实现真的很棒。感谢您的全面回答。
  • @ChinthakaDharmasiri 很高兴你喜欢它:)!
【解决方案3】:

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

我已经为我的 pojos 和 Services 命名了类似的名称。即

POJO 名称:Pond5DownloadStrategy 和服务名称:Pond5DownloadStrategyService

我在 spring 中定义了所有服务。我有一个 DownloadStrategyFactory 有一个方法 getService(Object obj)。它也被实例化为spring bean。 getService 方法所做的是。 我使用obj.getClass().getSimpleName() 将 POJO 名称作为字符串获取,然后在末尾附加 Service。前任。 如果我通过 Pond5DownloadStrategy 然后我做 AppContext.getBean("Pond5DownloadStrategyService");

【讨论】:

    【解决方案4】:

    请看我的回答here

    虽然属于春季批处理主题,但它实际上与您的问题和策略设计模式有关。

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

    strategy = strategyLocator.lookup(POJOs.class);  
    

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

    【讨论】:

      【解决方案5】:

      例如手动装订:

      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 回答)或通过 Service 方法强制绑定。

      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());
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2011-12-24
        • 2023-03-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多