Почему не работает просто автоматическое подключение поля в сервлете 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.
Надеюсь, это поможет.