7

我有一个这样设置的spring mvc项目:

<servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/spring-contexts/servlet-context.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/spring-contexts/configuration-context.xml</param-value>
</context-param>

如果我在 configuration-context.xml 中创建一个 bean 并在 servlet-context.xml 中引用一个 bean,它似乎找不到它。这些是作为两个不同的上下文创建的吗?为什么会发生这种情况/通常会这样工作?

4

2 回答 2

6

是的,有两个相互堆叠的上下文(父上下文和子上下文)。

DispatcherServlet ( servlet-context.xml) 中的 bean 可以访问 ContextLoaderListener ( configuration-context.xml) 中的 bean,但反之则不行。

所以把基本的东西configuration-context.xml和web相关的东西放到servlet-context.xml.

@另见这个堆栈溢出问题:ContextLoaderListener or not?

于 2012-03-02T10:12:35.320 回答
0

Spring容器肯定可以看到组件扫描上下文的基础包决定的组件,你可以从上下文中获取bean。

spring 中有两种上下文
1. 根上下文(ApplicationContext)
2. Servlet上下文(WebApplicationContext)

rootContext 中定义的 bean 对 servletContext 的可见性 - 是

默认情况下,在根上下文中定义的 Bean 在所有 servlet 上下文中始终可见。例如,在根上下文中定义的 dataSource bean 可以在 servlet 上下文中访问,如下所示。

@Configuration
public class RootConfiguration
{
    @Bean
    public DataSource dataSource()
    {
       ...
    }
}

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.pvn.mvctiles")
public class ServletConfiguration implements WebMvcConfigurer
{
    @Autowired
    private DataSource dataSource;

    ...
}

servletContext 中定义的 bean 对 rootContext 的可见性 - 是*

(为什么*在是)
1.初始化上下文顺序是rootContext在前,servletContext在后。在根上下文配置类/xml 中,如果您尝试获取在 servletContext 中定义的 bean,您将获得 NULL。(因为 servletContext 尚未初始化,因此我们可以说 bean 在 rootContext 初始化时不可见)

但是可以在 servletContext 初始化后获取 servletContext 中定义的 bean(可以通过应用上下文获取 bean)

您可以通过以下方式打印并确认

applicationContext.getBeanDefinitionNames();


2. 如果您想在过滤器或另一个 servlet 上下文中访问 servlet 上下文的 bean,请将"org.springframework.web.servlet"基本包添加到您的根配置类/xml

@Configuration
@ComponentScan(basePackages = "org.springframework.web.servlet" )
public class RootConfiguration

添加后,您可以从应用程序上下文中获取所有以下 bean

springSecurityConfig, tilesConfigurer, themeSource, themeResolver, messageSource, localeResolver, requestMappingHandlerMapping, mvcPathMatcher, mvcUrlPathHelper, mvcContentNegotiationManager, viewControllerHandlerMapping, beanNameHandlerMapping, resourceHandlerMapping, mvcResourceUrlProvider, defaultServletHandlerMapping, requestMappingHandlerAdapter, mvcConversionService, mvcValidator, mvcUriComponentsContributor, httpRequestHandlerAdapter, simpleControllerHandlerAdapter, handlerExceptionResolver, mvcViewResolver,mvcHandlerMappingIntrospector

如果您想从 rootContext 获取自定义 bean,请将基本包值添加到 rootContext 组件扫描,如下所示。

@Configuration
@ComponentScan(basePackages = { "com.your.configuration.package", "org.springframework.web.servlet" })
public class RootConfiguration

如果您希望注入的依赖项在您的 rootContext 中可用并且可以在您的 servlet-filter 中访问,那么上面给定的配置将很有帮助。例如,如果您在过滤器中捕获异常并希望发送与发送的响应相同HttpMessageConverter但在 servletContext 中配置的错误响应,那么您可能希望访问该配置的转换器以发送相同的响应。

请注意,下面的自动装配在 servlet-filters 中不起作用

@Autowired
private ApplicationContext appContext;

这在 servlet 过滤器中不起作用,因为过滤器是在 spring 容器初始化之前初始化的。(取决于过滤器和 DelegatingProxyFilter 的顺序)

因此,要在过滤器中获取 applicationContext

public class YourFilter implements Filter
{
    private ApplicationContext appContext;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException
    {
        Filter.super.init(filterConfig);
        appContext = WebApplicationContextUtils.getRequiredWebApplicationContext(filterConfig.getServletContext());
    }
}

希望它能清楚地说明如何在上下文之间访问 bean。

于 2019-08-29T13:39:56.987 回答