为什么在Spring中,对GWT Servlet中的字段进行自动装配不起作用?

IT小君   2023-10-24T23:41:45

在GWT servlet中,仅仅将一个字段标记为@Autowired并不能按预期工作。代码会被编译,web应用程序会启动 - 这意味着Spring成功地完成了字段的自动装配,但当servlet被客户端代码实际调用时,会出现NullPointerException - 就像有一个不同的、未初始化的servlet被调用了。

我在网上找到了几种解决方法,其中一种是使用一个基本servlet类来进行一些Spring逻辑,但这意味着每个GWT servlet都必须扩展这个基类。另一种方法是使用AspectJ和@Configurable Spring注解。这里几乎没有涉及到配置,它就神奇地工作了。

我的问题是为什么只是简单地自动装配字段不能按预期工作?GWT做了什么导致这个问题出现。

评论(3)
IT小君

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

不一定。Web容器可以在没有Spring的帮助下实例化一个servlet。这可能是你遇到的情况:

但当servlet被客户端代码实际触发时,它将产生一个空指针异常 - 就好像被触发的是一个不同的、未初始化的servlet副本。

试试重写Servlet的init()方法:

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

    WebApplicationContextUtils.getWebApplicationContext(config.getServletContext())
        .getAutowireCapableBeanFactory().autowireBean(this);
}
2023-10-24T23:42:11   回复
IT小君

当客户端调用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>

你还可以避免在web.xml中为每个单独的RPC servlet声明,映射是干净的,并且你可以进行Spring注入。你只需要在web.xml中声明一个映射,用于org.springframework.web.servlet.DispatcherServlet来处理所有RPC调用。

网络上有一些关于GWT RPC和Spring MVC控制器集成的例子。

希望这能帮到你。

2023-10-24T23:43:08   回复
IT小君

事实证明,至少在使用Spring时,有一种更简单的方法可以实现这一点,你可以使用@Autowired,而不需要大量的配置或基类。唯一的限制是你必须同时使用AspectJ。以下是你需要的GWT Servlet的代码:

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

  // ...
}

在你的Spring配置文件中,请确保你还有以下内容:

   <!-- 启用非Spring管理类的自动注入和配置,需要使用AspectJ -->
   <context:spring-configured/>

最后一点,如果你在GWT应用程序(以及GWT Servlets)中同时使用了Spring Security,你需要确保定义了正确的模式,以确保AspectJ的织入正确进行(即,你同时获得了@Secured注解的处理和@Autowired的处理)。你需要以下配置:

   <!-- 开启Spring Security的方法注解的@Secured(...)功能 -->
   <!-- 必须使用aspectj模式,因为我们将Spring服务自动注入到GWT Servlet中,这也是通过aspectj来完成的。如果更改或删除,将导致服务器报500错误。-->
   <security:global-method-security secured-annotations="enabled" mode="aspectj"/>
2023-10-24T23:43:35   回复