Spring 根应用程序上下文和 servlet 上下文混淆 [英] Spring root application context and servlet context confusion

查看:46
本文介绍了Spring 根应用程序上下文和 servlet 上下文混淆的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道我需要在我的 servlet 上下文中注册用 @Controller 注释的类,以使我的 web 应用程序可访问.通常,我会这样做:

I know that I need to register classes annotated with @Controller in my servlet context to make my webapp accesible. Usually, I will do it the following way:

@Configuration
@EnableWebMvc
@ComponentScan({"foo.bar.controller"})
public class WebConfig extends WebMvcConfigurerAdapter {
    //other stuff like ViewResolvers, MessageResolvers, MessageConverters, etc.
}

我添加到我的根应用程序上下文中的所有其他配置类.这是我的调度程序初始化程序通常的样子:

All other configuration classes I added to my root application context. Here is how my dispatcher initializer usually look like:

public class DispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] { RootConfig.class, ServiceConfig.class };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { WebConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
}

但是当我开始使用 WebSockets 时,事情变得更有趣了.为了让 websockets 工作,你必须把 WebSoketConfig.class 放到 servlet 上下文中.这是我的 WebSocketConfig 示例:

But things are getting more interesting when I started to use WebSockets. To get websockets working, you have to put WebSoketConfig.class to servlet context. Here is my example of WebSocketConfig:

@Configuration
@EnableScheduling
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/chat").withSockJS();
    }

    @Override
    public void configureClientInboundChannel(ChannelRegistration channelRegistration) {
        channelRegistration.taskExecutor().corePoolSize(4).maxPoolSize(8);
    }

    @Override
    public void configureClientOutboundChannel(ChannelRegistration channelRegistration) {
        channelRegistration.taskExecutor().corePoolSize(4).maxPoolSize(8);
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/queue", "/topic");
        registry.setApplicationDestinationPrefixes("/app");
    }

}

此外,我创建了一个服务来向主题发送消息:

Also, I've created a service to send a message to the topic:

@Service
public class TimeServiceWsImpl implements TimeServiceWs {

    @Autowired
    private SimpMessagingTemplate messagingTemplate;

    @Override
    public void sentCurrentTime() {
        long currentTime = System.currentTimeMillis();
        String destination = "/topic/chatty";
        logger.info("sending current time to websocket /topic/time : " + currentTime);
        this.messagingTemplate.convertAndSend(destination, currentTime);
    }
}

我需要在其他一些服务中使用这个服务(Autowire it).现在我陷入了僵局:

I need to use this service in some other services (Autowire it). And now I'm in a deadlock:

  1. 如果我试图在根应用程序上下文中创建 TimeServiceWs bean,正如预期的那样,它不会看到 SimpMessagingTemplate bean 并抛出 NoSuchBeanDefinitionException
  2. 如果我试图在 servlet 上下文中创建 TimeServiceWs bean,那么我无法将它自动​​连接到任何其他服务,因为根上下文无法看到 servlet 上下文 bean(就我知道)
  3. 如果我将所有配置移至 servlet 上下文,则所有 bean 均已成功创建,但出现以下异常:java.lang.IllegalStateException: No WebApplicationContext found 并且无法访问我的 webapp
  1. If I'm trying to create TimeServiceWs bean inside root application context, as expected it doesn't see SimpMessagingTemplate bean and throws NoSuchBeanDefinitionException
  2. If I'm trying to create TimeServiceWs bean inside servlet context, then I'm unable to autowire it to any another service, because root context can't see servlet context beans(as far as I know)
  3. If I move all my configurations to servlet context, all beans are successfully created, but I get the following exception: java.lang.IllegalStateException: No WebApplicationContext found and can't access my webapp

我该怎么办?根上下文中应该包含什么?servlet 上下文中应该包含什么?能否请您再澄清一次这些上下文之间的区别?

What am I supposed to do? What should be inside root context? What should be inside servlet context? And could you please clarify the difference between these context one more time please?

如果您需要任何其他信息,请告诉我.

If you will need any additional information, just let me know.

推荐答案

大多数 Spring MVC 应用程序都有一个包含所有服务层/DAO 层 bean 的根上下文,以及应用程序的每个 Spring 调度程序 servlet 一个 servlet 上下文,其中包含(在至少)每个 servlet 的控制器.

Most Spring MVC applications have one root context containing all service layer / DAO layer beans, and one servlet context per spring dispatcher servlet of the application, which contains (at least) the controllers of each servlet.

这个想法是一个应用程序可能有多个 servlet 调度程序,例如一个用于 URL /shopping/*,另一个用于 URL /reporting/*,每个都有自己的一组控制器.

The idea being that is that one application might have several servlet dispatchers, for example one for URL /shopping/* and the other for URL /reporting/*, each with it's own set of controllers.

一个servlet dispatcher的controllers是相互隔离的,也就是说虽然也是Spring bean,但是不能相互注入.

The controllers of one servlet dispatcher are isolated from each other, meaning although they are also Spring beans, they cannot be injected in each other.

根上下文中的服务层和 DAO bean 在所有 servlet 上下文中都是可见的,因此服务层 bean 可以注入任何控制器,但不能反过来.

Service layer and DAO beans in the root context are visible in all servlet contexts, so Service layer beans can be injected in any controller, but not the other way around.

根上下文被认为是控制器 servlet 上下文/上下文的父级.

The root context is said to be the parent of the controller servlet context/contexts.

这一切都是为了将​​ bean 组彼此隔离,以确保不会产生无意义的依赖关系.

It's all meant to be a mechanism of isolating groups of beans from each other to ensure no unmeant dependencies are possible.

鉴于此并通过问题:

  • 如果我试图在根应用程序上下文中创建 TimeServiceWs bean,正如预期的那样,它不会看到 SimpMessagingTemplate bean 并抛出 NoSuchBeanDefinitionException: 移动 SimpleMessagingTemplate对于根上下文,它是一个类似于 DAO 的 bean,可以在应用程序的任何地方使用,因此它应该位于共享的根上下文中.

  • If I'm trying to create TimeServiceWs bean inside root application context, as expected it doesn't see SimpMessagingTemplate bean and throws NoSuchBeanDefinitionException: Move the SimpleMessagingTemplate to the root context, it's a bean like a DAO that can be useful anywhere in the application so it should be in the shared root context.

如果我试图在 servlet 上下文中创建 TimeServiceWs bean,那么我无法将它自动​​装配到任何其他服务:如果它打算自动装配到其他服务,请离开然后在根上下文中.

If I'm trying to create TimeServiceWs bean inside servlet context, then I'm unable to autowire it to any another service: If it's meant to be autowired to other services, leave it in the root context then.

- 如果我将所有配置移动到 servlet 上下文,则所有 bean 都已成功创建,但我得到 java.lang.IllegalStateException: No WebApplicationContext found: 执行相反的操作, 将基本上所有的 bean 移到根上下文,并在 servlet 上下文中只保留应用程序该部分特定的 bean,很多时候只保留控制器.

- If I move all my configurations to servlet context, all beans are successfully created, but I get java.lang.IllegalStateException: No WebApplicationContext found: Do the opposite, move basically all beans to the root context, and leave on the servlet context only the beans that are specific of that part of the application, many times only the controllers.

这篇关于Spring 根应用程序上下文和 servlet 上下文混淆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆