基于Spring代码的配置 - IllegalArgumentException:需要ServletContext [英] Spring code-based configuration - IllegalArgumentException: A ServletContext is required
问题描述
我在这里找到了一个基于100%代码的弹簧配置的例子:
I have found an example of 100% code-based spring configuration here:
http://docs.spring.io/spring/docs/3.1.x/javadoc-api/org/springframework/web/WebApplicationInitializer.html
内容:
public class MyWebAppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext container) {
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext =
new AnnotationConfigWebApplicationContext();
rootContext.register(AppConfig.class);
// Manage the lifecycle of the root application context
container.addListener(new ContextLoaderListener(rootContext));
// Create the dispatcher servlet's Spring application context
AnnotationConfigWebApplicationContext dispatcherContext =
new AnnotationConfigWebApplicationContext();
dispatcherContext.register(DispatcherConfig.class);
// Register and map the dispatcher servlet
ServletRegistration.Dynamic dispatcher =
container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}
refresh()注册配置类后。
但是API说 - 必须调用refresh()才能使上下文完全处理新类。
所以我添加refresh()每个寄存器语句
In the example above they never called refresh() after registering a configuration class. But API says - that refresh() must be called in order for the context to fully process the new class. So I added refresh() afrer each register statement
rootContext.register(AppConfig.class);
rootContext.refresh();
dispatcherContext.register(DispatcherConfig.class);
dispatcherContext.refresh();
结果:
SEVERE: ContainerBase.addChild: start:
org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[]]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:726)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:702)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:699)
at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1647)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:300)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:465)
at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:415)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:300)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1487)
at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:97)
at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1328)
at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1420)
at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:848)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:322)
at sun.rmi.transport.Transport$1.run(Transport.java:177)
at sun.rmi.transport.Transport$1.run(Transport.java:174)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:173)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:556)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:811)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:670)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:724)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'defaultServletHandlerMapping' defined in class path resource [org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.class]: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.springframework.web.servlet.HandlerMapping org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.defaultServletHandlerMapping()] threw exception; nested exception is java.lang.IllegalArgumentException: A ServletContext is required to configure default servlet handling
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:592)
推荐答案
在这种情况下,这只对于 ApplicationContext
传递给 DispatcherServlet
。 DispatcherServlet
构造函数状态
In your case, this is only important for the ApplicationContext
passed to the DispatcherServlet
. That DispatcherServlet
constructor states
给定的Web应用程序上下文可能尚未刷新。如果
尚未刷新(建议的方法),那么将会出现
:
The given web application context may or may not yet be refreshed. If it has not already been refreshed (the recommended approach), then the following will occur:
- 如果给定的上下文没有父级,则根应用上下文将被设置为父级。
- 如果给定的上下文尚未分配ID,则会为其分配一个
-
ServletContext
和ServletConfig
对象将被委派给应用程序上下文 -
postProcessWebApplicationContext
将被调用 - 任何
ApplicationContextInitializers
通过
指定contextInitializerClasses param或通过
的setContextInitializers属性将被应用。如果上下文实现ConfigurableApplicationContext
,将调用 -
refresh li>
- If the given context does not already have a parent, the root application context will be set as the parent.
- If the given context has not already been assigned an id, one will be assigned to it
ServletContext
andServletConfig
objects will be delegated to the application contextpostProcessWebApplicationContext
will be called- Any
ApplicationContextInitializers
specified through the "contextInitializerClasses" init-param or through the setContextInitializers property will be applied. refresh()
will be called if the context implementsConfigurableApplicationContext
如果上下文已经刷新,上面将不会出现
,假设用户有
因此,对于 DispatcherServlet
,您必须执行以下操作:
So for the DispatcherServlet
, you have to do the following
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
dispatcherContext.register(DispatcherConfig.class);
// will take care of calling refresh() on the ApplicationContext
ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
这是 DispatcherServlet
配置所必需的,因为由于 @EnableWebMvc
(或等效的< mvc:annotation-driven>
)生成的一些bean需要 ServletContext
和/或 ServletConfig
由Servlet容器提供的对象。
This is necessary for the DispatcherServlet
configuration because some of the beans generated because of @EnableWebMvc
(or the equivalent <mvc:annotation-driven>
) require the ServletContext
and/or ServletConfig
objects which are provided by the Servlet container.
根上下文不应该有这样的依赖,所以它是安全的做
The root context should not have such dependencies so it is safe to do
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(AppConfig.class);
rootContext.refresh();
<通过将 @Configuration
类作为参数传递给它的构造函数。
Note that you could just create the AnnotationConfigWebApplicationContext
object by passing the @Configuration
classes as arguments to its constructor.
这篇关于基于Spring代码的配置 - IllegalArgumentException:需要ServletContext的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!