Шаблон сервлетов и команд, компиляция и время выполнения? - PullRequest
1 голос
/ 06 февраля 2012

Я пишу сервлет Java, который действует как Front Controller.Для выполнения функций я использую шаблон Команды Домена.В настоящее время я инициализирую все свои команды и сохраняю их на карте с именем (строкой) команды в качестве ключа и объектом в качестве значения.Всякий раз, когда сервлет получает запрос, я получаю команду с карты, передавая командный запрос из URL как:

// at init
Hashmap<String, DomainCommand> commands = new Hashmap<String, DomainCommand>();
commands.put("someCommand", new SomeCommand());

// at request
String command = request.getParameter("command");
DomainCommand c = commands.get(command);
c.execute();

Это работает хорошо и делает то, что я хочу, так как у моих DomainCommands нет атрибутов класса, которые будут разделенымежду нитями.Альтернативой этому является использование отражения для создания объекта следующим образом:

String command = request.getParameter("command");
DomainCommand c = Class.forName(command).newInstance(); // assuming in same (default) package
c.execute();

Обе эти работы.Что лучше с точки зрения производительности / экономии памяти?

Ответы [ 5 ]

3 голосов
/ 06 февраля 2012

Производительность

При использовании Map единственной стоимостью является доступ к HashMap (незначительный). Отражение, с другой стороны, может занять гораздо больше времени и быть менее безопасным - помните, что вы должны убедиться, что пользователь не передает фальшивый command, что позволяет ему запускать произвольный код.

Память

При создании DomainCommand при запуске они через некоторое время окажутся в старом поколении, поэтому большую часть времени не будут подвергаться сборке мусора. С другой стороны, когда они создаются для каждого запроса, они, скорее всего, будут сразу же собирать мусор. Таким образом, в целом, объем памяти будет сопоставим, за исключением того, что второй подход требует более запусков GC.

В целом, карта команд - намного лучший подход. Кстати, если вы используете DI-фреймворки, такие как Spring или Guice (если это не слишком для вас), или веб-фреймворки, такие как Struts / Spring MVC, они будут выполнять точно такую ​​же работу для вас.

1 голос
/ 06 февраля 2012

Вы запросили ответ конкретно с точки зрения производительности / экономии памяти, а другие ответы на него отвечают. Я согласен, что в этом отношении подход с использованием карт, вероятно, лучше.

Однако вы должны быть уверены, что это даже проблема, прежде чем беспокоиться об этом в данный момент; Я предполагаю, что сетевые издержки на один вызов вашего сервлета намного перевешивают один поиск HashMap короткой строки.

Большей проблемой должны быть ясность и ремонтопригодность. И в этом отношении я бы сказал, что подход «Карта» намного лучше, так как он:

  • Не привязывает API (допустимые значения параметра команды) к реализации (имена классов)
  • Дает понять, какие классы предназначены для использования в качестве команд, а какие нет (очень важно, если вы позже захотите внести изменения)
  • Позволяет API быть более гибким (например, вы можете разрешить ввод параметра команды без учета регистра или иметь более одной карты команд для одного и того же класса)

Цитируя Zen of Python : «Явное лучше, чем неявное».

1 голос
/ 06 февраля 2012

С точки зрения производительности 1-й подход, который вы упомянули, определенно быстрее.

Как насчет следующих опций?

  1. с использованием Visitor шаблон для команды
  2. хранение командных компонентов и поиск командного компонента по его имени (из запроса) в JNDI (есть служба, которая извлекает команду из JNDI)
  3. с использованием инфраструктуры IoC (Spring), в которой все командные компоненты инициализируются при запуске контейнера, а поиск команды выполняется в контексте приложения

По производительности я бы предпочел третий вариант.

1 голос
/ 06 февраля 2012

Первый подход хранения команд в HashMap лучше. Проблема второго подхода заключается в том, что вам нужно загружать класс команд каждый раз, когда вы выполняете эту команду.

Фактически фреймворки, такие как Struts, которые точно соответствуют шаблону команд с сервлетом контроллера в качестве фронт-контроллера с отдельными классами действий в качестве команд.

0 голосов
/ 06 февраля 2012

Как насчет объединения двух вариантов вместе?

Struts делает то же самое. Он содержит Map, который кэширует все ваши команды, запрошенные сервлетом. Если команда не существует, она создает newInstance() команды (так же, как созданный вами вариант 2).

Преимуществом этого является более быстрое выполнение вашего процесса: извлеките команду из кеша, или создайте новую, и сохраните созданную новую команду в кеше. Это определенно быстрее, чем вариант 2.

...