Наследование (позднее связывание) через инъекцию зависимостей в Java
Я использую Spring DI для подключения моих компонентов, и я столкнулся с этой проблемой.
У меня есть класс BaseService, который имеет несколько реализаций. И слой над ним имеет построитель, который вызывает службу, чтобы получить данные для заполнения POJO. Реализация службы Мне нужно вызвать (ServiceA, ServiceB) изменения в соответствии с типом POJO, который мне нужно создать.
В таком случае, как я могу авторизовать службу, так как она требует позднего связывания службы. Как я могу решить такой сценарий? (Пример в Spring DI действительно поможет)
![Builder calling Services]()
Я читал похожие вопросы, но не смог найти ответ. И я читал, что шаблоны SOA, такие как Service Host, предоставляют различные решения для точного использования.
Пожалуйста, помогите.
Благодаря
Ответы
Ответ 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());
}
}