问题
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?
回答1:
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?
回答2:
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.
来源:https://stackoverflow.com/questions/9531428/spring-cant-see-beans-between-servlet-context-and-contextconfiglocation-beans