У меня есть класс ApplicationInitializer, который реализует WebApplicationInitializer, и в него я добавляю свой собственный ContextLoaderListener. Когда я запускаю свое приложение в STS, оно работает отлично, но когда я пытаюсь развернуть файл war в моем tomcat, приложение не развертывается и выдает следующую ошибку многоконтекстного прослушивателя:
10-Oct-2019 10:51:58.252 INFO [Catalina-utility-2] org.apache.catalina.core.ApplicationContext.log 3 Spring WebApplicationInitializers detected on classpath
10-Oct-2019 10:52:05.987 INFO [Catalina-utility-2] org.apache.catalina.core.ApplicationContext.log Initializing Spring embedded WebApplicationContext
10-Oct-2019 10:52:11.237 SEVERE [Catalina-utility-2] org.apache.catalina.core.StandardContext.listenerStart Exception sending context initialized event to listener instance of class [org.springframework.web.context.ContextLoaderListener]
java.lang.IllegalStateException: Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your web.xml!
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:262)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:103)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4683)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5146)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:717)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:690)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:705)
at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:978)
at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1849)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:118)
at org.apache.catalina.startup.HostConfig.deployWARs(HostConfig.java:773)
at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:427)
at org.apache.catalina.startup.HostConfig.check(HostConfig.java:1620)
at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:305)
at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:123)
at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1151)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1353)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1357)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1335)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:835)
10-Oct-2019 10:52:11.240 INFO [Catalina-utility-2] org.apache.catalina.core.ApplicationContext.log Closing Spring root WebApplicationContext
Iпрочитайте следующую документацию: https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-create-a-deployable-war-file
Из того, что я понял, я могу полностью удалить свой класс AppInitializer и добавить его содержимое в класс приложения весенней загрузки. Затем я посмотрел, как было запущено onStartup SpringBootServletInitializer, и изменил мой код на:
@SpringBootApplication
@EntityScan("com.example")
@EnableJpaRepositories("com.example")
@ComponentScan("com.example")
@EnableConfigurationProperties(CustomProperties.class)
public class Application extends SpringBootServletInitializer{
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
@Override
public void onStartup(final ServletContext sc) throws ServletException{
AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext();
root.scan("com.example");
sc.addListener(new ContextLoaderListener(root){
@Override
public void contextInitialized(ServletContextEvent event) {
// no-op because the application context is already initialized
}
});
ServletRegistration.Dynamic appServlet = sc.addServlet("mvc", new DispatcherServlet(new GenericWebApplicationContext()));
appServlet.setLoadOnStartup(1);
appServlet.addMapping("/");
sc.addFilter("securityFilter", new DelegatingFilterProxy("springSecurityFilterChain"))
.addMappingForUrlPatterns(null, false, "/*");
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
На этот раз файл войны развертывается нормально, но когда я пытаюсь попасть на домашнюю страницу, я получаю следующую ошибку, хотя и сделалдобавьте springSecurityFilterChain:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'springSecurityFilterChain' available
org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:771)
org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1221)
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:294)
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204)
org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1111)
org.springframework.web.filter.DelegatingFilterProxy.initDelegate(DelegatingFilterProxy.java:337)
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:263)
Это то, что у меня было изначально (два отдельных класса):
public class AppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(final ServletContext sc) throws ServletException{
AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext();
root.scan("com.example");
sc.addListener(new ContextLoaderListener(root));
ServletRegistration.Dynamic appServlet = sc.addServlet("mvc", new DispatcherServlet(new GenericWebApplicationContext()));
appServlet.setLoadOnStartup(1);
appServlet.addMapping("/");
sc.addFilter("securityFilter", new DelegatingFilterProxy("springSecurityFilterChain"))
.addMappingForUrlPatterns(null, false, "/*");
}
}
@SpringBootApplication
@EntityScan("com.example")
@EnableJpaRepositories("com.example")
@ComponentScan("com.example")
@EnableConfigurationProperties(CustomProperties.class)
public class Application extends SpringBootServletInitializer{
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Пожалуйста, помогите мне понять, что я делаю неправильно.