为什么在 Spring 中自动装配 GWT servlet 中的字段不起作用?

发布于 2024-12-28 02:39:43 字数 416 浏览 2 评论 0原文

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

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

我的问题是为什么自动连接字段不能按预期工作? GWT 正在做什么导致这个问题发生。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

此刻的回忆 2025-01-04 02:39:43

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

不一定。 Web 容器可以实例化 servlet,无需 Spring 的任何帮助。您可能正在经历:

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

尝试重写 Servlet 的 init():

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

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

The code will compile and the web application will start up - which
means Spring was successfully able to autowire the field

Not necessarily. The web container can instantiate a servlet without any help from Spring. Which you could be experiencing:

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.

try overriding Servlet's init():

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

    WebApplicationContextUtils.getWebApplicationContext(config.getServletContext())
        .getAutowireCapableBeanFactory().autowireBean(this);
}
夏尔 2025-01-04 02:39:43

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

希望这会有所帮助。

When the RPC service is called from the client, the "server-side" looking at the called URL and the servlets mapping will find the class, will make the instance and it will serve the request. Meaning if you have @Autowired annotation, or you already have an instance of the RPC class in the spring context, it does not matter. The new instance will be created and it won't "know" about Spring.

I resolve this by implementing a class which extends RemoteServiceServlet and implements Controller (from Spring MVC) and ServletContextAware.
This way you can map every RPC service by URL using the Spring MVC approach, for ex:

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

You also avoid the declarations for every single RPC servlet in web.xml, the mappings are clean and you have the Spring injection.
You declare only a single mapping in web.xml for org.springframework.web.servlet.DispatcherServlet which will serve all RPC calls.

There are couple of examples on the web with explanation about GWT RPC and Spring MVC controller integration.

Hope this will help.

居里长安 2025-01-04 02:39:43

事实证明,至少在使用 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"/>

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"/>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文