【问题标题】:Why doesn't just autowiring a field in a GWT servlet in Spring work?为什么不能在 Spring 中自动装配 GWT servlet 中的字段?
【发布时间】:2012-02-14 13:37:56
【问题描述】:

在 GWT servlet 中仅将字段标记为 @Autowired 不会按预期工作。代码将编译并且 Web 应用程序将启动 - 这意味着 Spring 能够成功地自动装配字段,但是当 servlet 实际被客户端代码命中时,它将产生一个 NullPointerException - 就像有一个不同的未初始化的被命中的 servlet 的副本。

我在网上找到了几种方法来实现这一点,一种是使用一个执行一些 Spring 逻辑的基本 servlet 类,但这样做意味着每个 GWT servlet 都必须扩展这个基类。另一种方法是使用 AspectJ 和 @Configurable Spring 注释。这里涉及的配置非常少,而且效果非常好。

我的问题是,为什么自动装配字段不能按预期工作? GWT 做了什么导致它崩溃。

【问题讨论】:

    标签: spring gwt aspectj autowired configurable


    【解决方案1】:

    代码将编译并且网络应用程序将启动 - 这 意味着 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);
    }
    

    【讨论】:

    • 虽然您在回答的第一部分在技术上是正确的,但默认情况下,Spring 会根据需要处理 Autowired 带注释的字段/方法,因此,它将验证它是否构建了一个可以匹配带注释的 bean物品。如果没有,它会爆炸,并且 Web 容器将无法启动。
    • 另外,在你回答的第二部分,我在网上看到了这个解决方案,但需要注意的是 1)我需要创建一个父 servlet 类来扩展我的所有 GWT servlet 类,我希望避免的事情,以及 2)这种模式与异常处理相混淆,并在它们被抛出时阻止对其进行正确处理。在此处查看作者的 cmets:blog.maxmatveev.com/2011/02/…,以及他的解决方案 - 使用 AspectJ。
    • 不需要创建一个基类,每个servlet都可以自己重写init() :)
    • 是的。然后你会到处都有冗余代码,只是尖叫“基类......” - 我认为这是你的观点。
    【解决方案2】:

    当从客户端调用 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 控制器的集成。

    希望这会有所帮助。

    【讨论】:

    • 确认!对不起。我没有说清楚我们没有使用 Spring MVC,只是使用 Spring Web。鉴于我在网络上找到的信息,即一个控制器统治他们所有的模式对我来说真的是错误的,因为我们会吸收整个框架组件并且只使用一小部分。
    • 对我来说,Spring MVC 的真正强大之处在于能够创建任意数量的控制器,将类似的功能分组在一起,将控制器方法绑定到 URI,并在逐个方法的基础上添加安全性 - 和只需很少的编码,这一切都会自动发生。
    • 我认为您正在将调度程序 servlet 与一个控制器混合在一起。这个 servlet 映射给出了控制器使用的 URL 的一般定义,例如 /rpc/* 。这就是想法。如果你已经包含了像 Spring Security 这样的框架,你仍然有可能在方法级别上获得安全性。
    【解决方案3】:

    事实证明,至少在使用 Spring 时,有一种更简单的方法可以做到这一点,这样您就可以使用 @Autowired 并且它不涉及大量配置或基类。需要注意的是,您还必须使用 AspectJ。以下是您的 GWT servlet 所需的内容:

    @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/>
    

    最后一点。如果您还在 GWT 应用程序(以及 GWT servlet 中)使用 Spring 安全性,则需要确保定义正确的模式以确保正确完成 AspectJ 编织(即,您同时获得 @Secured 注释处理和@Autowired 处理)您将需要:

       <!-- 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"/>
    

    【讨论】:

      猜你喜欢
      • 2012-06-11
      • 2016-01-09
      • 2015-07-28
      • 1970-01-01
      • 1970-01-01
      • 2014-07-26
      • 2021-04-03
      • 1970-01-01
      相关资源
      最近更新 更多