2013-03-06 4 views
3

Ставшие очень комфортно с инъекцией зависимостей, как стиль, я обнаружил, что написание HTTP-сервлет что-то вроде этого:инъекционные зависимостей в простой старый HTTP Tomcat сервлет

public class FooServlet extends HttpServlet { 

private Dependency dependency; 

public void setDependency(Dependency dependency) { 
    this.dependency = dependency; 
} 

@Override 
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 

     ... 
     Result r = dependency.doSomething(...); 
     ... 
} 

Это красиво легко модульного тестирования , и я очень хочу сохранить модель, но теперь, когда я прихожу к ее развертыванию в Tomcat, я пришел к пониманию, что не знаю, где я могу вызвать setDependency().

Некоторые неопределенные возможности, которые приходят на ум:

  • параметры Get сервлетов в Init(). Это просто String, поэтому мне нужно будет сделать Reflection для создания. Это было бы неверно. просто настроенное создание зависимостей.
  • Что-то с JNDI
  • Как-то из Java-программы, в которую встроен Tomcat, получите Tomcat, чтобы дать мне ссылку на объект Servlet, позвольте мне вызвать его сеттер.
  • Используйте весну. Если я использую Spring, я буду искать способы уменьшить его. Это приложение недостаточно сложно, чтобы гарантировать Spring MVC.

ответ

0

Благодаря Аарону и Филипе я нашел то, что кажется самым легким использованием Весны.

Конфигурирование диспетчерское сервлет в WEB-INF/web.xml:

<servlet> 
      <servlet-name> 
        myDispatcher 
      </servlet-name> 
      <servlet-class> 
        org.springframework.web.servlet.DispatcherServlet 
      </servlet-class> 
      <init-param> 
        <param-name>contextConfigLocation</param-name> 
        <param-value>/WEB-INF/spring/myDispatcher-context.xml</param-value> 
      </init-param> 
    </servlet> 

В WEB-INF/весна/myDispatcher-context.xml, настроить контекст приложения в явном виде, так что BeanNameUrlHandlerMapping отображает запросы на ваш класс обработки, и ваша зависимость вводится.

<bean id="/*" class="org.me.MyHandler"> 
     <property name="dependency" ref="dependency"/> 
    </bean> 
    <bean id="dependency" class="org.me.myDependency"/> 

Написать MyHandler как реализация HttpRequestHandler - это очень аналогично сервлета.

Это дает вам инъекцию зависимости.Он избегает сканирования классов и не загружает десятки классов, но если вы хотите использовать более продвинутые функции Spring MVC, то есть возможность.

2

Я бы использовал Spring, поскольку он обеспечивает большую экосистему функций и функциональных возможностей, которые могут быть использованы вашим проектом для его улучшения. Но только если вы действительно их используете. Нет смысла загружать такую ​​огромную фреймворк только для использования одной маленькой функции в одном месте.

При этом вы также должны заботиться о том, как метод doPost() будет вызываться разными потоками, а ваш объект dependency является переменной-членом. Это сделало бы ваш код небезопасным, поскольку один и тот же экземпляр dependency мог одновременно использоваться разными потоками, если бы он был одним синглом.

+0

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

+0

Ты абсолютно прав. –

2

Это на самом деле только две строки кода, чтобы сделать @Autowire работу в сервлет:

ApplicationContext appContext = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext()); 
appContext.getAutowireCapableBeanFactory().autowireBean(this); 

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

По этой причине я обычно создаю обработчики (см. HttpRequestHandler) и создаю их в doPost() вместо того, чтобы автосервис сам сервлет.

Смежные вопросы