Подтвердить что ты не робот

Наследование (позднее связывание) через инъекцию зависимостей в Java

Я использую Spring DI для подключения моих компонентов, и я столкнулся с этой проблемой.

У меня есть класс BaseService, который имеет несколько реализаций. И слой над ним имеет построитель, который вызывает службу, чтобы получить данные для заполнения POJO. Реализация службы Мне нужно вызвать (ServiceA, ServiceB) изменения в соответствии с типом POJO, который мне нужно создать.

В таком случае, как я могу авторизовать службу, так как она требует позднего связывания службы. Как я могу решить такой сценарий? (Пример в Spring DI действительно поможет)

Builder calling Services

Я читал похожие вопросы, но не смог найти ответ. И я читал, что шаблоны SOA, такие как Service Host, предоставляют различные решения для точного использования.

Пожалуйста, помогите. Благодаря

4b9b3361

Ответ 1

Вы можете использовать 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

Как насчет использования 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 unclear which type to create

         }
     return builder;
  }

}

где Builder экземпляры имеют общедоступное/пакетно-приватное поле BaseService service, которое вызывается в своих getData(), buildPojos() и везде, где другие методы.

(вы также можете использовать статические методы factory для создания экземпляра Builder, если вы хотите, чтобы это поле было закрытым)

Ответ 3

У меня было одно и то же требование в одном из моих проектов. Я использовал рефлексию для получения услуг в соответствии с требованием pojo. Таким образом, не будет статических значений, даже если вы определите новое pojo и службу в будущем, вам не придется изменять какую-либо реализацию.

Я назвал свои pojos и Services аналогичным. то есть

POJO Name: Pond5DownloadStrategy и ServiceName: Pond5DownloadStrategyService.

Я определил все службы в spring. У меня был DownloadStrategyFactory, у которого был единственный метод getService(Object obj). который также создается как spring bean. какой метод getService был. Я получаю имя POJO как строку, используя obj.getClass().getSimpleName(), а затем добавляю службу в конце. ех. Если я передаю Pond5DownloadStrategy, тогда я делаю AppContext.getBean( "Pond5DownloadStrategyService" );

Ответ 4

Пожалуйста, посмотрите мой ответ здесь.

Несмотря на то, что в разделе spring пакетной темы он действительно связан с вашим вопросом и шаблоном проектирования стратегии.

StrategyA StrategyB - это ваш ServiceA, ServiceB и т.д.
Вам нужно использовать StrategyLocator в вашем классе Builder (в исходном ответе его эквивалент MyTaskelt). Поиск будет основан на вашем типе pojo.

strategy = strategyLocator.lookup(POJOs.class);  

В ответе я предложил PlugableStrategyMapper, но если вы предопределяете все Servcies, вы можете поместить их в Map в application-context.xml

Ответ 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) или принудительно привязать привязку с помощью метода службы.

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