Почему не работает просто автоматическое подключение поля в сервлете GWT в Spring?

Просто пометить поле как @Autowired в сервлете GWT не работает как задумано. Код скомпилируется, и веб-приложение запустится - это означает, что Spring успешно смог автоматически связать поле, но когда сервлет на самом деле поражен клиентским кодом, он выдаст NullPointerException - как будто есть другая, неинициализированная копия сервлета, на которую наносят удар.

В Интернете я нашел несколько способов заставить это работать, один из них - использовать базовый класс сервлета, который выполняет некоторую логику Spring, но это означает, что каждый сервлет GWT должен расширять этот базовый класс. Другой способ был с помощью AspectJ и @Configurable Весенняя аннотация. Здесь было очень мало настроек, и это просто волшебно сработало.

Мой вопрос: почему просто не выполняется автоматическое подключение поля? То, что делает GWT, заставляет это ломаться.

3 ответа

Решение

Оказывается, что при использовании Spring, по крайней мере, существует НАМНОГО более простой способ сделать это, так что вы можете использовать @Autowired, и он не требует массивной конфигурации или базовых классов. Предостережение заключается в том, что вы также должны использовать AspectJ. Вот что вам нужно для вашего сервлета GWT:

@Configurable
public class MyGwtServiceImpl extends RemoteServiceServlet implements MyGwtService
{
  @Autowired
  private MyService service;

  // ...
}

И в вашей конфигурации Spring убедитесь, что у вас также есть:

   <!-- enable autowiring and configuration of non-spring managed classes, requires AspectJ -->
   <context:spring-configured/>

Последнее замечание Если вы также используете Spring Security с вашим приложением GWT (и в ваших сервлетах GWT), вам необходимо убедиться, что вы определили правильный режим, чтобы убедиться, что переплетение AspectJ выполняется правильно (т. Е. Вы получаете как обработку аннотации @Secured, так и @ Автоматическая обработка) вам понадобится:

   <!-- turn on spring security for method annotations with @Secured(...) -->
   <!-- the aspectj mode is required because we autowire spring services into GWT servlets and this
        is also done via aspectj. a server 500 error will occur if this is changed or removed. -->
   <security:global-method-security secured-annotations="enabled" mode="aspectj"/>

Код скомпилируется и веб-приложение запустится - это означает, что Spring успешно смог автоматически подключить поле

Не обязательно. Веб-контейнер может создать экземпляр сервлета без помощи Spring. Что вы могли испытывать:

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

попробуйте переопределить init сервлета ():

@Override
public void init(ServletConfig config) throws ServletException {
    super.init(config);

    WebApplicationContextUtils.getWebApplicationContext(config.getServletContext())
        .getAutowireCapableBeanFactory().autowireBean(this);
}

Когда служба RPC вызывается из клиента, "серверная сторона", просматривающая вызываемый URL и отображение сервлетов, найдет класс, создаст экземпляр и будет обслуживать запрос. Смысл, если у вас есть @Autowired аннотации, или у вас уже есть экземпляр класса RPC в контексте Spring, это не имеет значения. Новый экземпляр будет создан, и он не будет "знать" о Spring.

Я решаю это путем реализации класса, который расширяет RemoteServiceServlet и реализует Controller (из Spring MVC) и ServletContextAware, Таким образом, вы можете отобразить каждую службу RPC по URL, используя подход Spring MVC, например:

<bean id="publicUrlMapping"
        class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
          <props>
            <prop key="/myFirstRpc">firstRpcServiceBeanRef</prop>
            <prop key="/mySecondRpc">secondRpcServiceRef</prop>
          </props>
        </property>
    </bean>

Вы также избегаете объявлений для каждого отдельного сервлета RPC в web.xml, отображения чистые, и у вас есть инъекция Spring. Вы объявляете только одно отображение в web.xml за org.springframework.web.servlet.DispatcherServlet который будет обслуживать все вызовы RPC.

В сети есть несколько примеров с объяснением об интеграции GWT RPC и Spring MVC.

Надеюсь, это поможет.

Другие вопросы по тегам