2010-01-26 4 views
0

В моем текущем проекте я имею дело с EJB, реализующими огромные интерфейсы. Реализация осуществляется через бизнес-делегат, который реализует один и тот же интерфейс и содержит реальный бизнес-код.Java + Command Pattern + Spring + remoting: Как добавить зависимости к объекту Command?

Как полагают некоторые статьи, как

Последовательность использования этого 'команда' является

  1. клиент создает команду и параметрирование
  2. клиента посылает команду на сервер
  3. сервер команды получить, журнал, аудит и утверждать команды может быть подан
  4. сервер команды выполнить
  5. результат
  6. сервера возвращение команды для клиента

Проблемы иметь место в Шаг 4 .:

Прямо сейчас я использую контекст spring, чтобы получить bean из контекста внутри команды, , но я хочу, чтобы встраивать зависимости в команду.

Это наивное применение для иллюстрации. Я добавил комментарии, где у меня есть проблемы:

public class SaladCommand implements Command<Salad> {  
    String request; 

    public SaladBarCommand(String request) {this.request = request;} 

    public Salad execute() {  
     //this server side service is hidden from client, and I want to inject it instead of retrieving it 
     SaladBarService saladBarService = SpringServerContext.getBean("saladBarService");  
     Salad salad = saladBarService.prepareSalad(request);  
     return salad; 
    } 
} 

public class SandwichCommand implements Command<Sandwich> {  
    String request; 

    public SandwichCommand(String request) {this.request = request;} 

    public Sandwich execute() { 
     //this server side service is hidden from client, and I want to inject it instead of retrieving it  
     SandwichService sandwichService = SpringServerContext.getBean("sandwichService");  
     Sandwich sandwich = sandwichService.prepareSandwich(request);  
     return sandwich; 
    } 
} 

public class HungryClient { 
    public static void main(String[] args) { 
     RestaurantService restaurantService = SpringClientContext.getBean("restaurantService"); 
     Salad salad = restaurantService.execute(new SaladBarCommand(
      "chicken, tomato, cheese" 
     )); 
     eat(salad); 

     Sandwich sandwich = restaurantService.execute(new SandwichCommand(
      "bacon, lettuce, tomato" 
     )); 
     eat(sandwich); 
    } 
} 

public class RestaurantService { 
    public <T> execute(Command<T> command) { 
     return command.execute(); 
    } 
} 

Я хочу, чтобы избавиться от звонков как SandwichService sandwichService = SpringServerContext.getBean("sandwichService"); и моя служба вводится вместо этого.

Как это сделать проще всего?

+1

Эта проблема не имеет ничего общего с EJB, действительно? Похоже, вы просто спрашиваете, как подключаться к весне. Что такое 'SampleCommand'? Кто его создает? Кто его использует? Что это? – skaffman

+0

Я обновил свой вопрос до разъяснения после комментария skaffman. – Guillaume

+0

Если вы когда-либо реализовали что-то для этой проблемы, я бы с удовольствием это услышал. У меня такая же проблема со службами, которые необходимы для выполнения команд, которым не нужно заботиться клиенту. – Jaapjan

ответ

0

Если SimpleCommand вводится в классы с использованием Spring ApplicationContext (и, действительно, это должно быть), тогда вам просто нужно выразить свои зависимости как конструкторы-аргументы или сеттеры, а также внедрить их.

Это трудно давать какие-либо другие особенности, не понимая, кто использует SimpleCommand, где он приходит, и т.д.

+0

SampleCommand - это всего лишь образец ... это мнимая команда. Команды создаются в «клиенте» и отправляются на «сервер». Поэтому мы не можем использовать Spring DI при создании команды: зависимости - это серверная. – Guillaume

1

Я построил что-то удивительно подобное в прошлом, за исключением того, что мы не использовали шаблон команды, как вы в настоящее время делает. В вашем случае ваши команды, похоже, ничего не делают, кроме фактического поиска и запускают метод службы, поэтому почему бы просто не представить этот метод службы как API, а не использовать шаблон команды вообще. Затем вы можете подключить служебные вызовы к EJB через Spring Remoting, и все особенности Spring могут оставаться в определенных для протокола уровнях (Servlet, EJB, MDB ...), и ваш код остается удивительно незнающим о том, что происходит вокруг него ,

Наша инфраструктура выглядит так. (Для тех, кто собирается жаловаться на существование EJB, это не вся инфраструктура, а по соображениям безопасности и производительности мы используем EJB для вызовов EJB для обслуживания для взаимодействия с сервисом).

Eclipse Rich Client -> (Spring Remoting - HTTP) -> Servlet -> (Локальный интерфейс) -> EJB -> Внедрение Сервис

сервлетов - Использует контекст Spring для просмотра локального EJB интерфейс и вызывает общий метод вызова универсального интерфейса EJB с объектом RemoteInvocation (созданным и отправленным HttpProxyFactoryBean из Spring Remoting) и именем интерфейса службы.

EJB- - Смотрит сервис, основанный на его имени интерфейса (также от имени боба) и использует RemoteInvocationExecutor для вызова метода по реализации услуг с объектом RemoteInvocation.

Теперь EJB способен привязываться к нескольким сервисам (хотя мы используем одну-единственную модель развертывания). Вы можете использовать Spring Remoting для Http, EJB или JMS-вызовов для службы из разных приложений. Тестирование без развертывания сервера тривиально, поскольку вы просто подключаете тесты непосредственно к реализациям.

Примечание. Я попытаюсь добавить некоторые фрагменты кода, если у меня появится такая возможность.

+0

Команда Well может выполнять больше, чем вызов метода обслуживания: некоторые из них могут быть более сложными, и я могу их связать. Я хочу заменить растущий список методов (иногда очень похожих) в нашем EHB с помощью команд. Команды можно рассматривать как «удаленный обратный вызов». Я не уверен, что имею хорошее представление о том, как «представить этот метод обслуживания как API», но для меня это звучит как гигантский интерфейс службы, который я пытаюсь избавиться от ... – Guillaume

+1

Я не думаю, что это допустимая модель для распределенных действий. Вы хотите создать объект Command на клиенте с помощью только данных, но иметь зависимости этой команды, введенной при ее восстановлении на стороне сервера. Для этого вы, вероятно, должны создать конструктор команд на стороне сервера с созданной клиентом командой как зависимость, а также любые другие зависимости, которые у вас есть. Затем ваш общий EJB получит декоратор через Spring (с уже введенными услугами) и добавит объект Command также до вызова метода execute. – Robin

+1

По-прежнему звучит так, что было бы проще (и чище) упростить ваш «большой интерфейс», разбить его, сделать услуги, которые являются композициями других, такого рода вещи. Затем просто используйте эти новые интерфейсы, чтобы либо скрыть, либо заменить старый. Это прекрасно отделяет ваши бизнес-данные от ваших бизнес-сервисов, что вы хотите для удаленных служб. Объединение данных и действий в одном и том же объекте не очень хорошо поддается обслуживанию сетевых вызовов. – Robin

0
public class SampleCommand implements Command {  
    private final String parameter; 
    private final ServiceBean service; 

    //the client build the command using a parameter 
    public SampleCommand(ServiceBean service, String parameter) { 
     this.parameter = parameter; 
     this.service = service; 
    } 

    //this code will be executed by the server 
    public Object execute() { 
     //do something using the parameter and return the result 
     return service.doSomethingWith(parameter);    
    } 
} 

Вы можете вводить услугу или без весны:

<bean id="sampleCommand" class="package.SampleCommand"> 
    <constructor-arg ref="serviceBean" /> 
    <constructor-arg value="Param" /> 
</bean> 

Некоторые вызова приложения:

ServiceBean service = ServiceProxy.getService(SampleCommand.class); 
Command command = new SampleCommand(service, "Param"); 

Dependency Injection является не зависит от структуры.

+0

Не проблема понимания того, как DI работает с Spring или PicoContainer или без него, или что-то еще, речь идет о том, как предоставить DI, когда компонент создается где-то в сети. – Guillaume

+0

Я думаю, что вы можете быть слишком сложными. Возможно, посмотрите на шаблон стратегии. Служба должна потреблять команду, а не наоборот. – Droo

+0

Что делать, если команде требуется DAO для выполнения своей работы? или внешнюю службу? – Guillaume

2

Это не проблема понимания как DI работает

Я согласен с Гийомом, потому что я встречаю этот же случай.

Основная проблема заключается в инициализации и объекте жизненного цикла.

  1. Команда может быть создана много раз - это тот же метод, например. И программно.

  2. Весна, как и контейнер, предполагает, что вы хотите создать объект один раз с областью (сессия, прототип = нить охват), область действия приложения ...

Таким образом, команда не создавать на весной, и он должен использовать сервис, созданный весной. Но служба не вводится в команду.

Спасибо

3

Вы можете использовать Spring @Configurable аннотацию, чтобы AspectJ придать пружину бобы в объекты, которые не созданы весной.Посмотрите here

2

На стороне сервера, в RestaurantService, выполните следующие действия:

  1. Реализовать интерфейс ApplicationContextAware - это заставит Spring придать ссылку на контекст приложения в RestaurantService.

  2. В методе RestaurantService.execute (команда), сделайте следующее:

    AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory(); 
    beanFactory.autowireBeanProperties(command, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true); 
    command.execute(); 
    
  3. Наконец, в контексте приложения, объявить экземпляр каждого из объектов Command с инжектированных зависимостей.

Это должно иметь эффект, позволяющий создавать объекты на клиенте, сериализовать их, отправить их на сервер, и иметь зависимости инъекционные, прежде чем использовать их. Может быть более чистым делать инъекцию, когда вы получаете объекты, а не только перед их использованием.

Есть и другие варианты использования AutowireCapableBeanFactory - этот пример находит определение компонента в соответствующем классе и задает свойства, определенные в контексте приложения. Если вы можете связать каждую реализацию Command с именем в контексте приложения, вместо этого вы можете использовать configureBean (Object, String), который будет поддерживать обратные вызовы.

+0

Это решения, которые я использую. и мне это очень нравится. –