简体   繁体   English

在根上下文和servlet上下文中创建Spring控制器bean

[英]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. 我正在编程一个Tomcat应用程序,该应用程序充当某些内部服务的代理。

After struggling with some issues (see ApplicationContext ) , my Tomcat app nearly works as expected. 在遇到一些问题(请参阅ApplicationContext )后,我的Tomcat应用程序几乎可以按预期运行。

But the loggings of my app say that the controller bean is initialized twice, and I don't find the reason. 但是我的应用程序的日志记录说控制器bean初始化了两次,我没有找到原因。 I don't use XML configuration, only annotations and Java config. 我不使用XML配置,仅使用注释和Java配置。

It seems to me the annotation attribute excludeFilters in the root context is ignored. 在我看来,根上下文中的注释属性excludeFilters被忽略了。

See my classes below. 请参阅下面的课程。 web.xml is empty. web.xml为空。

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: 根上下文Java配置:

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) servlet上下文配置(此处没有bean,全部在根上下文中)

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 . @Configuration@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 您的MyAppDispatcherServletContext类位于

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. 然后,它将在servlet上下文中执行相同的操作。

Separate your package more explicitly. 更明确地分离软件包。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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