4

Simply marking a field as @Autowired in a GWT servlet does not work as intended. The code will compile and the web application will start up - which means Spring was successfully able to autowire the field, but when the servlet is actually hit by client-side code, it will yield a NullPointerException - like there's a different, uninitialized copy of the servlet being hit.

I've found several ways on the web to get this working, one is by using a base servlet class that does some Spring logic but doing this means every GWT servlet must extend this base class. The other way was by using AspectJ and the @Configurable Spring annotation. There was very little configuration involved here and it just magically worked.

My question is why doesn't just autowiring the field just work as intended? What is GWT doing that causes this to break.

4

3 回答 3

4

代码将编译并且 Web 应用程序将启动 - 这意味着 Spring 能够成功地自动装配字段

不必要。Web 容器可以在没有任何 Spring 帮助的情况下实例化一个 servlet。您可能会遇到的情况:

但是当 servlet 实际被客户端代码命中时,它将产生 NullPointerException - 就像被命中的 servlet 有一个不同的、未初始化的副本。

尝试覆盖 Servlet 的 init():

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

    WebApplicationContextUtils.getWebApplicationContext(config.getServletContext())
        .getAutowireCapableBeanFactory().autowireBean(this);
}
于 2012-01-19T22:20:32.787 回答
1

当从客户端调用 RPC 服务时,“服务器端”查看被调用的 URL 和 servlet 映射将找到类,创建实例并为请求提供服务。这意味着如果您有@Autowired 注释,或者您已经在 spring 上下文中拥有 RPC 类的实例,那没关系。新实例将被创建,它不会“知道”Spring。

我通过实现一个类来解决这个问题,该类扩展RemoteServiceServlet和实现Controller(来自 Spring MVC)和ServletContextAware. 这样,您可以使用 Spring MVC 方法通过 URL 映射每个 RPC 服务,例如:

<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 servlet 的声明web.xml,映射是干净的,并且您有 Spring 注入。您只声明一个映射web.xmlorg.springframework.web.servlet.DispatcherServlet它将所有 RPC 调用提供服务。

网上有几个例子解释了 GWT RPC 和 Spring MVC 控制器的集成。

希望这会有所帮助。

于 2012-01-20T12:56:38.103 回答
0

It turns out that when using Spring at least, there's a MUCH simpler way to do this such that you can use @Autowired and it doesn't involve massive configuration or base classes. The caveat is that you must also use AspectJ. Here's what you need for your GWT servlet:

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

  // ...
}

And in your Spring config make sure you also have:

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

One final note. If you are also using Spring security with your GWT application (and in your GWT servlets), you will need to make sure you define the correct mode to ensure the AspectJ weaving is done correctly (i.e., you get both @Secured annotation processing AND the @Autowired processing) you will need:

   <!-- 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"/>
于 2013-08-14T16:49:26.037 回答