简体   繁体   中英

Spring controller bean is created in root context AND in servlet context

I'm programming a Tomcat application which serves as a proxy for some internal services.

After struggling with some issues (see ApplicationContext ) , my Tomcat app nearly works as expected.

But the loggings of my app say that the controller bean is initialized twice, and I don't find the reason. I don't use XML configuration, only annotations and Java config.

It seems to me the annotation attribute excludeFilters in the root context is ignored.

See my classes below. web.xml is empty.

spring bootstrap

package com.application.config;

import javax.servlet.*;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.servlet.DispatcherServlet;

public class MyAppSpringBoot implements WebApplicationInitializer
{

    @Override
    public void onStartup(ServletContext container) throws ServletException
    {
        initRootContext(container);

        initDispatcherContext(container);

        addFilters(container);
    }

    private void initDispatcherContext(ServletContext container)
    {
        AnnotationConfigWebApplicationContext servletContext = new AnnotationConfigWebApplicationContext();
        servletContext.register(MyAppDispatcherServletContext.class);
        ServletRegistration.Dynamic dispatcher =
                container.addServlet("myAppDispatcherServlet", new DispatcherServlet(servletContext));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/");
    }

    private void initRootContext(ServletContext container)
    {
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
        rootContext.register(MyAppRootContext.class);
        container.addListener(new ContextLoaderListener(rootContext));
    }

    private void addFilters(ServletContext container)
    {
        FilterRegistration.Dynamic registration =
                container.addFilter("userDbAuthenticationFilter", DelegatingFilterProxy.class);
        registration.addMappingForUrlPatterns(null, false, "/mapgate/*");

        registration = container.addFilter("prepareRequestFilter", DelegatingFilterProxy.class);
        registration.addMappingForUrlPatterns(null, false, "/mapgate/*");

        registration = container.addFilter("responseTextXmlFilter", DelegatingFilterProxy.class);
        registration.addMappingForUrlPatterns(null, false, "/mapgate/*");
    }
}

root context Java config:

package com.application.config;

import java.io.File;
import java.io.IOException;
import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import javax.xml.stream.*;

import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.context.annotation.*;
import org.springframework.jdbc.datasource.lookup.DataSourceLookupFailureException;
import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.stereotype.Controller;

import com.application.controller.MyAppXmlFilterWords;
import com.application.urlmapping.UrlPairing;

@Configuration
@ComponentScan(basePackages = "com.application", excludeFilters = @ComponentScan.Filter(Controller.class))
public class MyAppRootContext
{

    private static Logger logger = LogManager.getLogger(MyAppRootContext.class.getName());

    /*

    These 3 filter beans are annotated with @Component. They are working as expected

    @Bean
    public UserDbAuthenticationFilter userDbAuthenticationFilter()
    {
        return new UserDbAuthenticationFilter();
    }

    @Bean
    public PrepareRequestFilter prepareRequestFilter()
    {
        return new PrepareRequestFilter();
    }

    @Bean
    public ResponseTextXmlFilter responseTextXmlFilter()
    {
        return new ResponseTextXmlFilter();
    }

    */
    @Bean
    public DataSource userDbJpaDataSource() throws DataSourceLookupFailureException
    {

        JndiDataSourceLookup lookup = new JndiDataSourceLookup();
        DataSource dataSource = lookup.getDataSource("jdbc/userDbPostgres");
        logger.info("U3R Datasource: {}", dataSource);
        return dataSource;
    }

    @Bean
    public EntityManagerFactory entityManagerFactory()
    {
        LocalContainerEntityManagerFactoryBean fb = new LocalContainerEntityManagerFactoryBean();
        fb.setDataSource(userDbJpaDataSource());
        fb.afterPropertiesSet();
        return fb.getNativeEntityManagerFactory();
    }

    @Bean
    public DiskFileItemFactory diskFileItemFactory()
    {
        DiskFileItemFactory factory = new DiskFileItemFactory();
        factory.setSizeThreshold(50_000 * 1024);
        factory.setRepository(new File("/WEB-INF/upload"));
        return factory;
    }

    @Bean
    public XMLOutputFactory xmlOutputFactory()
    {
        return XMLOutputFactory.newInstance();
    }

    @Bean
    public XMLInputFactory xmlInputFactory()
    {
        return XMLInputFactory.newInstance();
    }

    @Bean
    public XMLEventFactory xmlEventFactory()
    {
        return XMLEventFactory.newInstance();
    }

    @Bean
    public UrlPairing urlPairing() throws IOException
    {
        return new UrlPairing(myAppProperties().getProperty("myApp.UrlPairingFile"));
    }

    @Bean
    public Properties myAppProperties() throws IOException
    {
        Properties p = new Properties();
        p.load(MyAppRootContext.class.getResourceAsStream("/myAppConfig.properties"));
        return p;
    }

    @Bean
    public MyAppXmlFilterWords xmlFilterWords() throws IOException
    {
        MyAppXmlFilterWords words = MyAppXmlFilterWords.createFilterWords(myAppProperties().getProperty("myApp.xmlFilterWordFile"));
        return words;
    }

}

servlet context configuration (no beans here, all in root context)

package com.application.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

/** myApplication Spring dispatcher servlet context
 *
 * Created by ulrich.knaack on 11.08.2015.
 */
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.application.controller", useDefaultFilters = false, includeFilters = @ComponentScan
        .Filter(Controller.class))
public class MyAppDispatcherServletContext
{
// no servlet specific beans required, all in root context
}

controller class

package com.application.controller;

import java.io.*;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;
import javax.annotation.PostConstruct;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.http.*;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.*;
import org.apache.http.entity.*;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.application.filter.MyAppRequestHelper;
import com.application.misc.MyAppHttpTools;

import static com.application.misc.MyAppConstants.*;

@Controller
@RequestMapping(value = "mapgate/**")
public class MyAppProxyController implements ApplicationContextAware
{
    private static final Logger logger = LogManager.getLogger(MyAppProxyController.class.getName());

    @Autowired
    Properties myAppProperties;

    @Autowired
    private DiskFileItemFactory diskFileItemFactory;

    private ApplicationContext appContext;

    @PostConstruct
    public void init() throws ServletException
    {
        requestLogIntervall = (Integer.parseInt(myAppProperties.getProperty("myApp.requestLogIntervall")));
        logger.debug("Controller {} initialisiert. App-Context: {} {}", this.getClass().getName(),
                appContext.hashCode(), appContext);

        logger.debug("Beans im Zugriff von Controller:");
        for (String beanName : appContext.getBeanDefinitionNames())
        {
            logger.debug("          {}", beanName);
        }

        MyAppProxyController controller = (MyAppProxyController) appContext.getBean("myAppProxyController");
        logger.debug("controller-hash im Controller={}", controller.hashCode());
    }

    @SuppressWarnings("TryFinallyCanBeTryWithResources")
    @RequestMapping(method = RequestMethod.POST)
    protected void doPost(HttpServletRequest customerRequest,
                          HttpServletResponse response) throws ServletException,
            IOException
    {
    // some code
    }

    @RequestMapping(method = RequestMethod.GET)
    protected void doGet(HttpServletRequest customerRequest, HttpServletResponse customerResponse)
    {
    // some code
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
    {
        appContext = applicationContext;
    }

}

Logging

20150814-165337 INFO  [RMI TCP Connection(5)-127.0.0.1] Root WebApplicationContext: initialization started
20150814-165337 INFO  [RMI TCP Connection(5)-127.0.0.1] Refreshing Root WebApplicationContext: startup date [Fri Aug 14 16:53:37 CEST 2015]; root of context hierarchy
20150814-165337 INFO  [RMI TCP Connection(5)-127.0.0.1] Registering annotated classes: [class com.application.config.MyAppRootContext]
20150814-165337 INFO  [RMI TCP Connection(5)-127.0.0.1] URL-Paring Konstruktor, Datei D:/doorman-ent/doorman-conf/urlpairing.txt
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1] URL-Paare aus Datei <D:/doorman-ent/doorman-conf/urlpairing.txt> lesen...
20150814-165337 INFO  [RMI TCP Connection(5)-127.0.0.1] URL-Pairing: es existieren 17 Service-Paar(e) und 2 File-Paar(e)
20150814-165337 INFO  [RMI TCP Connection(5)-127.0.0.1] Filter com.application.filter.PrepareRequestFilter initialisiert. App-Context: 615649080 Root WebApplicationContext: startup date [Fri Aug 14 16:53:37 CEST 2015]; root of context hierarchy
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1] Konstruktor com.application.filter.ResponseTextXmlFilter
20150814-165337 INFO  [RMI TCP Connection(5)-127.0.0.1] Filter com.application.filter.ResponseTextXmlFilter initialisiert. App-Context: 615649080 Root WebApplicationContext: startup date [Fri Aug 14 16:53:37 CEST 2015]; root of context hierarchy
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1] Beans im Zugriff von XMLFilter:
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           org.springframework.context.annotation.internalConfigurationAnnotationProcessor
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           org.springframework.context.annotation.internalAutowiredAnnotationProcessor
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           org.springframework.context.annotation.internalRequiredAnnotationProcessor
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           org.springframework.context.annotation.internalCommonAnnotationProcessor
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           org.springframework.context.annotation.internalPersistenceAnnotationProcessor
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           org.springframework.context.event.internalEventListenerProcessor
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           org.springframework.context.event.internalEventListenerFactory
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           myAppRootContext
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           myAppDispatcherServletContext
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           prepareRequestFilter
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           responseTextXmlFilter
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           userDbAuthenticationFilter
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           myAppProxyController
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           requestMappingHandlerMapping
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           mvcContentNegotiationManager
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           viewControllerHandlerMapping
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           beanNameHandlerMapping
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           resourceHandlerMapping
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           mvcResourceUrlProvider
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           defaultServletHandlerMapping
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           requestMappingHandlerAdapter
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           mvcConversionService
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           mvcValidator
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           mvcPathMatcher
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           mvcUrlPathHelper
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           mvcUriComponentsContributor
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           httpRequestHandlerAdapter
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           simpleControllerHandlerAdapter
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           handlerExceptionResolver
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           mvcViewResolver
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           diskFileItemFactory
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           entityManagerFactory
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           urlPairing
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           myAppProperties
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           xmlInputFactory
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           userDbJpaDataSource
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           xmlFilterWords
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           xmlOutputFactory
20150814-165337 DEBUG [RMI TCP Connection(5)-127.0.0.1]           xmlEventFactory
20150814-165338 DEBUG [RMI TCP Connection(5)-127.0.0.1] Controller com.application.controller.MyAppProxyController initialisiert. App-Context: 615649080 Root WebApplicationContext: startup date [Fri Aug 14 16:53:37 CEST 2015]; root of context hierarchy
20150814-165338 DEBUG [RMI TCP Connection(5)-127.0.0.1] controller-hash im Controller=1369268001
20150814-165338 DEBUG [RMI TCP Connection(5)-127.0.0.1] controller-hash im XMLFilter=1369268001
20150814-165338 INFO  [RMI TCP Connection(5)-127.0.0.1] U3R Datasource: org.apache.tomcat.dbcp.dbcp2.BasicDataSource@7c912e88
20150814-165338 INFO  [RMI TCP Connection(5)-127.0.0.1] Building JPA container EntityManagerFactory for persistence unit 'userDbPersistence'
20150814-165339 INFO  [RMI TCP Connection(5)-127.0.0.1] Filter com.application.filter.UserDbAuthenticationFilter initialisiert. App-Context: 615649080 Root WebApplicationContext: startup date [Fri Aug 14 16:53:37 CEST 2015]; root of context hierarchy
20150814-165339 DEBUG [RMI TCP Connection(5)-127.0.0.1] EntityManagerFactory: org.hibernate.jpa.internal.EntityManagerFactoryImpl@6567e35f
20150814-165340 INFO  [RMI TCP Connection(5)-127.0.0.1] Mapped "{[/mapgate/**],methods=[GET]}" onto protected void com.application.controller.MyAppProxyController.doGet(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
20150814-165340 INFO  [RMI TCP Connection(5)-127.0.0.1] Mapped "{[/mapgate/**],methods=[POST]}" onto protected void com.application.controller.MyAppProxyController.doPost(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws javax.servlet.ServletException,java.io.IOException
20150814-165340 INFO  [RMI TCP Connection(5)-127.0.0.1] Looking for @ControllerAdvice: Root WebApplicationContext: startup date [Fri Aug 14 16:53:37 CEST 2015]; root of context hierarchy
20150814-165340 INFO  [RMI TCP Connection(5)-127.0.0.1] Root WebApplicationContext: initialization completed in 2831 ms
20150814-165340 INFO  [RMI TCP Connection(5)-127.0.0.1] FrameworkServlet 'myAppDispatcherServlet': initialization started
20150814-165340 INFO  [RMI TCP Connection(5)-127.0.0.1] Refreshing WebApplicationContext for namespace 'myAppDispatcherServlet-servlet': startup date [Fri Aug 14 16:53:40 CEST 2015]; parent: Root WebApplicationContext
20150814-165340 INFO  [RMI TCP Connection(5)-127.0.0.1] Registering annotated classes: [class com.application.config.MyAppDispatcherServletContext]
20150814-165340 DEBUG [RMI TCP Connection(5)-127.0.0.1] Controller com.application.controller.MyAppProxyController initialisiert. App-Context: 332892020 WebApplicationContext for namespace 'myAppDispatcherServlet-servlet': startup date [Fri Aug 14 16:53:40 CEST 2015]; parent: Root WebApplicationContext
20150814-165340 DEBUG [RMI TCP Connection(5)-127.0.0.1] controller-hash im Controller=1145466717
20150814-165340 INFO  [RMI TCP Connection(5)-127.0.0.1] Mapped "{[/mapgate/**],methods=[GET]}" onto protected void com.application.controller.MyAppProxyController.doGet(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
20150814-165340 INFO  [RMI TCP Connection(5)-127.0.0.1] Mapped "{[/mapgate/**],methods=[POST]}" onto protected void com.application.controller.MyAppProxyController.doPost(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws javax.servlet.ServletException,java.io.IOException
20150814-165340 INFO  [RMI TCP Connection(5)-127.0.0.1] Looking for @ControllerAdvice: WebApplicationContext for namespace 'myAppDispatcherServlet-servlet': startup date [Fri Aug 14 16:53:40 CEST 2015]; parent: Root WebApplicationContext
20150814-165340 INFO  [RMI TCP Connection(5)-127.0.0.1] FrameworkServlet 'myAppDispatcherServlet': initialization completed in 86 ms
20150814-165340 WARN  [http-apr-8080-exec-4] No mapping found for HTTP request with URI [/doorman/] in DispatcherServlet with name 'myAppDispatcherServlet'
20150814-165341 WARN  [http-apr-8080-exec-10] No mapping found for HTTP request with URI [/doorman/] in DispatcherServlet with name 'myAppDispatcherServlet'

@Configuration is a meta-annotation of @Component . In other words, it also marks a class as being a candidate for component scanning.

In your root config, you declare your component scan as

@ComponentScan(basePackages = "com.application", excludeFilters = @ComponentScan.Filter(Controller.class))

Your MyAppDispatcherServletContext class is in

package com.application.config;
// [imports]
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.application.controller", useDefaultFilters = false, includeFilters = @ComponentScan
        .Filter(Controller.class))
public class MyAppDispatcherServletContext

It'll therefore get picked up, get loaded, and perform its own configuration within the root context (with its own component scan).

It'll then do the same in the servlet context.

Separate your package more explicitly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM