Spring can't see beans between servlet-context and contextConfigLocation beans
Asked Answered
G

2

7

I have a spring mvc project set up like so:

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

It appears if I make a bean in configuration-context.xml and reference a bean in servlet-context.xml it cannot find it. Are these created as two different contexts? Why does this happen / work like this in general?

Griselgriselda answered 2/3, 2012 at 10:9 Comment(0)
J
6

Yes there are two contexts stacked on each other (parent and child context).

The beans from the DispatcherServlet (servlet-context.xml) can access the beans from the ContextLoaderListener (configuration-context.xml), but not the other way around.

So put the basic stuff in the configuration-context.xml and the web related once into servlet-context.xml.

@See also this Stack Overflow question: ContextLoaderListener or not?

Jarredjarrell answered 2/3, 2012 at 10:12 Comment(1)
could you please tell me why I can't reach, from my web servlet, the txManager defined in applicationContext?Rondelle
T
0

Spring container can definitely see the components decided by component scan base package of context and you can get the bean from the context.

There are two types of context in spring
1. Root context (ApplicationContext)
2. Servlet context (WebApplicationContext)

Visiblity of beans defined in rootContext to servletContext - YES

Beans defined in root context is always visible in all servlet contexts by default. for example dataSource bean defined in root context can be accessed in servlet context as given below.

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

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

    ...
}

Visiblity of beans defined in servletContext to rootContext - yes*

(Why * in Yes)
1. Initialization of context order is rootContext first and servletContext next. In the root context configuration class/xml if you try to get the bean defined in servletContext you will get NULL. (because servletContext is not initialized yet, hence we can say beans not visible while initialization of rootContext)

But you can get beans defined in servletContext after initialization of servletContext(you can get beans through application context)

you can print and confirm it by

applicationContext.getBeanDefinitionNames();


2. If you want to access beans of servlet context in the filter or in the another servlet context, add "org.springframework.web.servlet" base package to your root config class/xml

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

after adding you can get all below beans from application context

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

If you want to get your custom beans from rootContext add base package value to rootContext component scan as given below.

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

Above given configuration will be helpful if you want injected dependency be available in your rootContext and can be accessed in your servlet-filter. For example If you catch exception in filter and want to send error response which is same as response sent by HttpMessageConverter but it is configured in servletContext, then you may want to access that configured converter to send the same response.

Note this, below autowiring will not work in servlet-filters

@Autowired
private ApplicationContext appContext;

this will not work in servlet filter, as filters are initialized before spring container got initialized.(Depends on order of filter and DelegatingProxyFilter)

So, to get applicationContext in filter

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());
    }
}

Hope it gives clear idea of how beans can be accessed between contexts.

Triley answered 29/8, 2019 at 13:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.