Java 使用Spring Mvc WebApplicationInitializer、ApplicationContextInitializer和ContextLoaderListener
我使用基于java的SpringMVC配置 我在WebApplicationInitializer实现中注册了Spring dispatcher servlet。 加载Spring应用程序上下文配置文件。Spring概要文件管理的逻辑在ApplicationContextInitializer实现中实现。而且效果很好 以下是原始文件的完整示例: WebApplicationInitializerJava 使用Spring Mvc WebApplicationInitializer、ApplicationContextInitializer和ContextLoaderListener,java,spring,spring-mvc,configuration,Java,Spring,Spring Mvc,Configuration,我使用基于java的SpringMVC配置 我在WebApplicationInitializer实现中注册了Spring dispatcher servlet。 加载Spring应用程序上下文配置文件。Spring概要文件管理的逻辑在ApplicationContextInitializer实现中实现。而且效果很好 以下是原始文件的完整示例: WebApplicationInitializer public class SpringMvcExampleWebApplicationInitial
public class SpringMvcExampleWebApplicationInitializer implements WebApplicationInitializer {
private static final String DISPATCHER_SERVLET_NAME = "dispatcher";
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
registerDispatcherServlet(servletContext);
registerHiddenHttpMethodFilter(servletContext);
}
private void registerDispatcherServlet(final ServletContext servletContext) {
WebApplicationContext dispatcherContext = createContext(WebMvcContextConfiguration.class, InfrastructureContextConfiguration.class);
DispatcherServlet dispatcherServlet = new DispatcherServlet(dispatcherContext);
dispatcherServlet.setContextInitializers(new SpringMvcExampleProfilesInitializer());
ServletRegistration.Dynamic dispatcher = servletContext.addServlet(DISPATCHER_SERVLET_NAME, dispatcherServlet);
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
private WebApplicationContext createContext(final Class<?>... annotatedClasses) {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(annotatedClasses);
return context;
}
private void registerHiddenHttpMethodFilter(ServletContext servletContext) {
FilterRegistration.Dynamic registration = servletContext.addFilter("hiddenHttpMethodFilter", HiddenHttpMethodFilter.class);
registration.addMappingForServletNames(EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD),
false, DISPATCHER_SERVLET_NAME);
}
}
public class SpringMvcExampleProfilesInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext ctx) {
ConfigurableEnvironment environment = ctx.getEnvironment();
List<String> profiles = new ArrayList<String>(getProfiles());
if( profiles == null || profiles.isEmpty() )
{
throw new IllegalArgumentException("Profiles have not been configured");
}
environment.setActiveProfiles(profiles.toArray( new String[0]));
}
//TODO add logic
private Collection<String> getProfiles() {
return Lists.newArrayList("file_based", "test_data");
}
}
然后,我将Spring安全上下文配置添加到应用程序中。要使用它,必须加载DelegatingFilterProxy
。我\n已更新配置:
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
configureServletContext( servletContext );
registerListener(servletContext);
registerDispatcherServlet(servletContext);
...
}
private void configureServletContext(ServletContext servletContext) {
String initializerClasses = servletContext.getInitParameter(ContextLoader.CONTEXT_INITIALIZER_CLASSES_PARAM);
String profilesInitClassName = SpringMvcExampleProfilesInitializer.class.getName();
if (StringUtils.hasText(initializerClasses)) {
initializerClasses += " " + profilesInitClassName;
}
else {
initializerClasses = profilesInitClassName;
}
servletContext.setInitParameter(ContextLoader.CONTEXT_INITIALIZER_CLASSES_PARAM, initializerClasses);
}
添加了新方法并在启动时调用它:
private void registerSpringSecurityFilterChain(ServletContext servletContext) {
FilterRegistration.Dynamic springSecurityFilterChain = servletContext.addFilter(
BeanIds.SPRING_SECURITY_FILTER_CHAIN,
new DelegatingFilterProxy());
springSecurityFilterChain.addMappingForUrlPatterns(null, false, "/*");
}
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
...
registerDispatcherServlet(servletContext);
...
registerSpringSecurityFilterChain(servletContext);
}
现在,当我尝试请求任何url时,我得到了错误:
message No WebApplicationContext found: no ContextLoaderListener registered?
description The server encountered an internal error that prevented it from fulfilling this request.
exception
java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:251)
好的,我添加了以下内容:
private static final Class<?>[] configurationClasses = new Class<?>[]{
WebMvcContextConfiguration.class, InfrastructureContextConfiguration.class};
...
private void registerListener(ServletContext servletContext) {
WebApplicationContext rootContext = createContext(configurationClasses);
servletContext.addListener(new ContextLoaderListener(rootContext));
}
错误已经消失了
但是现在没有加载所有依赖于Spring概要文件的bean。添加ContextLoaderListener
已破坏SpringMvcExampleProfilesInitializer
逻辑
No qualifying bean of type [javax.sql.DataSource] found for dependency
我能做些什么来解决它?有什么想法吗
以下是完整更新的web初始值设定项类:
public class SpringMvcExampleWebApplicationInitializer implements WebApplicationInitializer {
private static final String DISPATCHER_SERVLET_NAME = "dispatcher";
private static final Class<?>[] configurationClasses = new Class<?>[]{
WebMvcContextConfiguration.class, InfrastructureContextConfiguration.class};
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
registerListener(servletContext);
registerDispatcherServlet(servletContext);
registerHiddenHttpMethodFilter(servletContext);
registerSpringSecurityFilterChain(servletContext);
}
private void registerSpringSecurityFilterChain(ServletContext servletContext) {
FilterRegistration.Dynamic springSecurityFilterChain = servletContext.addFilter(
BeanIds.SPRING_SECURITY_FILTER_CHAIN,
new DelegatingFilterProxy());
springSecurityFilterChain.addMappingForUrlPatterns(null, false, "/*");
}
private void registerDispatcherServlet(final ServletContext servletContext) {
WebApplicationContext dispatcherContext = createContext(WebMvcContextConfiguration.class, InfrastructureContextConfiguration.class);
DispatcherServlet dispatcherServlet = new DispatcherServlet(dispatcherContext);
dispatcherServlet.setContextInitializers(new SpringMvcExampleProfilesInitializer());
ServletRegistration.Dynamic dispatcher = servletContext.addServlet(DISPATCHER_SERVLET_NAME, dispatcherServlet);
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
private WebApplicationContext createContext(final Class<?>... annotatedClasses) {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(annotatedClasses);
// context.refresh();
return context;
}
private void registerListener(ServletContext servletContext) {
WebApplicationContext rootContext = createContext(configurationClasses);
servletContext.addListener(new ContextLoaderListener(rootContext));
// servletContext.addListener(new RequestContextListener());
}
private void registerHiddenHttpMethodFilter(ServletContext servletContext) {
FilterRegistration.Dynamic registration = servletContext.addFilter("hiddenHttpMethodFilter", HiddenHttpMethodFilter.class);
registration.addMappingForServletNames(EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD),
false, DISPATCHER_SERVLET_NAME);
}
}
公共类SpringMvcExampleWebApplicationInitializer实现WebApplicationInitializer{
私有静态最终字符串DISPATCHER\u SERVLET\u NAME=“DISPATCHER”;
私有静态最终类[]配置类=新类[]{
WebMvcContextConfiguration.class,InfrastructureContextConfiguration.class};
@凌驾
启动时公共void(ServletContext ServletContext)引发ServletException{
registerListener(servletContext);
registerDispatcherServlet(servletContext);
registerHiddenHttpMethodFilter(servletContext);
registerSpringSecurityFilterChain(servletContext);
}
私有无效注册表SpringSecurityFilterChain(ServletContext ServletContext){
FilterRegistration.Dynamic springSecurityFilterChain=servletContext.addFilter(
BeanIds.SPRING\u SECURITY\u FILTER\u CHAIN,
新的DelegatingFilterProxy());
springSecurityFilterChain.addMappingForUrlPatterns(null,false,“/*”);
}
私有无效注册表DispatcherServlet(最终ServletContext ServletContext){
WebApplicationContext dispatcherContext=createContext(WebMvcContextConfiguration.class,InfrastructureContextConfiguration.class);
DispatcherServlet DispatcherServlet=新DispatcherServlet(dispatcherContext);
setContextInitializers(新的SpringMvcExampleProfilesInitializer());
ServletRegistration.Dynamic dispatcher=servletContext.addServlet(dispatcher\u SERVLET\u名称,dispatcherServlet);
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping(“/”);
}
私有WebApplicationContext createContext(最终类…AnnotatedClass){
AnnotationConfigWebApplicationContext上下文=新的AnnotationConfigWebApplicationContext();
上下文。寄存器(带注释的类);
//context.refresh();
返回上下文;
}
私有无效注册表列表器(ServletContext ServletContext){
WebApplicationContext rootContext=createContext(配置类);
addListener(新的ContextLoaderListener(rootContext));
//addListener(新的RequestContextListener());
}
私有无效注册表HiddenHttpMethodFilter(ServletContext ServletContext){
FilterRegistration.Dynamic registration=servletContext.addFilter(“hiddenHttpMethodFilter”,hiddenHttpMethodFilter.class);
registration.addMappingForServletNames(EnumSet.of(DispatcherType.REQUEST,DispatcherType.FORWARD),
false,DISPATCHER_SERVLET_NAME);
}
}
根据M.Deinum的建议,我将配置文件初始值设置为ServletContext
,而不是将其设置为DispatcherServlet
。以下是更新的配置:
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
configureServletContext( servletContext );
registerListener(servletContext);
registerDispatcherServlet(servletContext);
...
}
private void configureServletContext(ServletContext servletContext) {
String initializerClasses = servletContext.getInitParameter(ContextLoader.CONTEXT_INITIALIZER_CLASSES_PARAM);
String profilesInitClassName = SpringMvcExampleProfilesInitializer.class.getName();
if (StringUtils.hasText(initializerClasses)) {
initializerClasses += " " + profilesInitClassName;
}
else {
initializerClasses = profilesInitClassName;
}
servletContext.setInitParameter(ContextLoader.CONTEXT_INITIALIZER_CLASSES_PARAM, initializerClasses);
}
请发布完整的
springmvcexampleprofilesinializer
,并指定哪个@Configuration
类包含配置文件,哪个@Configuration
类具有ApplicationContextInitializer
。您的问题是,所有内容都要加载两次,并且只在上指定初始值设定项DispatcherServlet
,而不在ContextLoaderListener
上。您应该在ContextLoaderListener
加载常规内容(服务、DAO、基础设施等)和DispatcherServlet
仅加载与web相关的内容(控制器、查看者等)的位置拆分配置。@SotiriosDelimanolis,我已经更新了question@M.Deinum,我尝试仅在DispatcherServlet中加载web配置,而InfrastructureContextConfiguration仅通过ContextLoaderListener加载。但问题是InfrastructureContextConfiguration使用配置文件。它们仅通过SpringMvcExampleProfilesInitializer for web dispatcher servlet激活。结果,我得到了相同的错误:(数据源bean没有加载。正如前面提到的,您只在ContextLoaderListener
上指定了SpringMvcExampleProfilesInitializer
。您通过上下文参数为ContextLoaderListener
指定它(您可以直接在ServletContext
上设置)。实际上您需要两者。ServletContext
中的一个由ContextLoaderListener
使用,而另一个由DispatcherSevlet
使用。
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
configureServletContext( servletContext );
registerListener(servletContext);
registerDispatcherServlet(servletContext);
...
}
private void configureServletContext(ServletContext servletContext) {
String initializerClasses = servletContext.getInitParameter(ContextLoader.CONTEXT_INITIALIZER_CLASSES_PARAM);
String profilesInitClassName = SpringMvcExampleProfilesInitializer.class.getName();
if (StringUtils.hasText(initializerClasses)) {
initializerClasses += " " + profilesInitClassName;
}
else {
initializerClasses = profilesInitClassName;
}
servletContext.setInitParameter(ContextLoader.CONTEXT_INITIALIZER_CLASSES_PARAM, initializerClasses);
}