복붙노트

[SPRING] 다중 Dispatcher가있는 Spring Java 구성

SPRING

다중 Dispatcher가있는 Spring Java 구성

나는 지금 약간의 경험을 봄과 또한 사용중인 일부 자바 구성 웹 응용 프로그램을 가지고있다. 그러나 이들은 일반적으로 조용한 간단한 설정에 기반합니다.

현재 프로젝트에서 다른 구성을 가진 별도의 디스패처 컨텍스트가 필요합니다. Dispatcher 구성과 독립적 인 전용 ContextLoaderListener가 있으므로 XML 기반 구성에는 문제가 없습니다. 하지만 자바 설정으로 내가 지금하고있는 일이 지금까지 괜찮은 것인지 잘 모르겠다;)

다음은 일반적인 DispatcherConfig입니다.

public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

  @Override
  protected Class<?>[] getRootConfigClasses() {
    return new class[]{MyAppConfig.class};
  }

  @Override
  protected Class<?>[] getServletConfigClasses() {
    return new Class[]{MyDispatcherConfig.class};
  }

  @Override
  protected String[] getServletMappings() {
    return new String[]{"/mymapping/*"};
  }

  @Override
  protected String getServletName() {
    return "myservlet";
  }
}

말했듯이 다른 매핑 (및 확인자 확인)을 사용하여 두 번째 (세 번째, ...) 디스패처가 필요합니다. 그래서 config를 복사하고 getServletName ()을 추가했습니다 (그렇지 않으면 둘 다 오류를 발생시키는 '디스패처'로 이름 지정됩니다). 두 번째 구성은 다음과 같이 보입니다.

public class AnotherWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

  @Override
  protected Class<?>[] getRootConfigClasses() {
    return new class[]{MyAppConfig.class};
  }

  @Override
  protected Class<?>[] getServletConfigClasses() {
    return new Class[]{AnotherDispatcherConfig.class};
  }

  @Override
  protected String[] getServletMappings() {
    return new String[]{"/another_mapping/*"};
  }

  @Override
  protected String getServletName() {
    return "anotherservlet";
  }
}

이런 식으로 사용하면 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:277)
...

그래서 두 번째 MyAppConfig.class 반환을 제거했습니다. AbstractAnnotationConfigDispatcherServletInitializer 및 그것은 잘 작동합니다. 그러나, 그것은 옳은 길로 느껴지지 않습니다;)

내 이해를 위해 : 하나의 AbstractAnnotationConfigDispatcherServletInitializer 내에서 모든 DispatcherConfig를 처리해야합니까? 그렇지 않으면 분리해야합니까? 한 클래스에서 그들을 구성하려고했지만 내 구성이 완전히 섞여서 (그래서 원하는 방식이 아닌 것 같습니다).

그러한 사례를 어떻게 구현합니까? AbstractAnnotationConfigDispatcherServletInitializer 외부의 java config에서 ContextLoaderListener를 설정할 수 있습니까? 또는 루트 구성 만있는 DefaultServlet을 만들어야합니까? 해당 구성 WebApplicationInitializer의 기본 인터페이스를 구현하는 것은 어떻습니까?

해결법

  1. ==============================

    1.Mahesh C.는 올바른 길을 보여 주었지만 구현이 너무 제한적입니다. 그는 한 순간에 맞습니다. 여러 Dispatcher 서블릿에 대해 AbstractAnnotationConfigDispatcherServletInitializer를 직접 사용할 수 없습니다. 그러나 구현은 다음을 수행해야합니다.

    Mahesh C.는 올바른 길을 보여 주었지만 구현이 너무 제한적입니다. 그는 한 순간에 맞습니다. 여러 Dispatcher 서블릿에 대해 AbstractAnnotationConfigDispatcherServletInitializer를 직접 사용할 수 없습니다. 그러나 구현은 다음을 수행해야합니다.

    다음은보다 완벽한 구현입니다.

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        // root context
        AnnotationConfigWebApplicationContext rootContext =
                new AnnotationConfigWebApplicationContext();
        rootContext.register(RootConfig.class); // configuration class for root context
        rootContext.scan("...service", "...dao"); // scan only some packages
        servletContext.addListener(new ContextLoaderListener(rootContext));
    
        // dispatcher servlet 1
        AnnotationConfigWebApplicationContext webContext1 = 
                new AnnotationConfigWebApplicationContext();
        webContext1.setParent(rootContext);
        webContext1.register(WebConfig1.class); // configuration class for servlet 1
        webContext1.scan("...web1");            // scan some other packages
        ServletRegistration.Dynamic dispatcher1 =
        servletContext.addServlet("dispatcher1", new DispatcherServlet(webContext1));
        dispatcher1.setLoadOnStartup(1);
        dispatcher1.addMapping("/subcontext1");
    
        // dispatcher servlet 2
        ...
    }
    

    그렇게하면 bean이 XML 컨텍스트에서와 마 y 가지로 컨텍스트에서 끝나는지를 완전히 제어 할 수 있습니다.

  2. ==============================

    2.스프링 - AbstractAnnotationConfigDispatcherServletInitializer에서 제공하는 추상 구현을 사용하는 대신 일반 WebApplicationInitializer 인터페이스를 사용하면 해결할 수 있다고 생각합니다.

    스프링 - AbstractAnnotationConfigDispatcherServletInitializer에서 제공하는 추상 구현을 사용하는 대신 일반 WebApplicationInitializer 인터페이스를 사용하면 해결할 수 있다고 생각합니다.

    그렇게하면 두 개의 별도 초기화 프로그램을 만들 수 있으므로 startUp () 메서드에서 서로 다른 ServletContext를 얻고 각 AppConfig 및 dispatcher 서블릿을 각각 등록해야합니다.

    그러한 구현 클래스 중 하나는 다음과 같이 보일 수 있습니다.

    public class FirstAppInitializer implements WebApplicationInitializer {
    
        public void onStartup(ServletContext container) throws ServletException {
    
            AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
            ctx.register(AppConfig.class);
            ctx.setServletContext(container);
    
            ServletRegistration.Dynamic servlet = container.addServlet(
                    "dispatcher", new DispatcherServlet(ctx));
    
            servlet.setLoadOnStartup(1);
            servlet.addMapping("/control");
    
        }
    
    }
    
  3. ==============================

    3.나는 똑같은 문제에 직면했다. 사실 여러 디스패처 서블릿, 필터 및 리스너가있는 복잡한 구성이 있습니다.

    나는 똑같은 문제에 직면했다. 사실 여러 디스패처 서블릿, 필터 및 리스너가있는 복잡한 구성이 있습니다.

    나는 아래처럼 web.xml을 가지고 있었다.

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://xmlns.jcp.org/xml/ns/javaee"
        xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
        version="3.1">
        <listener>
            <listener-class>MyAppContextLoaderListener</listener-class>
        </listener>
        <context-param>
            <param-name>spring.profiles.active</param-name>
            <param-value>${config.environment}</param-value>
        </context-param>
        <context-param>
            <param-name>contextClass</param-name>
            <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
        </context-param>
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>MyAppConfig</param-value>
        </context-param>
        <servlet>
            <servlet-name>restEntryPoint</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextClass</param-name>
                <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
            </init-param>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>MyRestConfig</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>restEntryPoint</servlet-name>
            <url-pattern>/api/*</url-pattern>
        </servlet-mapping>
        <servlet>
            <servlet-name>webSocketEntryPoint</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextClass</param-name>
                <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
            </init-param>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>MyWebSocketWebConfig</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>webSocketEntryPoint</servlet-name>
            <url-pattern>/ws/*</url-pattern>
        </servlet-mapping>
        <servlet>
            <servlet-name>webEntryPoint</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextClass</param-name>
                <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
            </init-param>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>MyWebConfig</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>webEntryPoint</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
        <filter>
            <filter-name>exceptionHandlerFilter</filter-name>
            <filter-class>com.san.common.filter.ExceptionHandlerFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>exceptionHandlerFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
        <filter>
            <filter-name>validationFilter</filter-name>
            <filter-class>MyValidationFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>validationFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
        <filter>
            <filter-name>lastFilter</filter-name>
            <filter-class>MyLastFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>lastFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    </web-app>
    

    위의 web.xml을 java 파일로 대체했습니다.

    import java.util.EnumSet;
    
    import javax.servlet.DispatcherType;
    import javax.servlet.FilterRegistration;
    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRegistration;
    
    import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
    import org.springframework.web.filter.DelegatingFilterProxy;
    import org.springframework.web.servlet.DispatcherServlet;
    import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
    
    
    public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    
        @Override
        public void onStartup(ServletContext servletContext) throws ServletException {
    
            servletContext.addListener(MyAppContextLoaderListener.class);
    
            servletContext.setInitParameter("spring.profiles.active", "dev");
            servletContext.setInitParameter("contextClass", "org.springframework.web.context.support.AnnotationConfigWebApplicationContext");
            servletContext.setInitParameter("contextConfigLocation", "MyAppConfig");
    
            // dispatcher servlet for restEntryPoint
            AnnotationConfigWebApplicationContext restContext = new AnnotationConfigWebApplicationContext();
            restContext.register(MyRestConfig.class);
            ServletRegistration.Dynamic restEntryPoint = servletContext.addServlet("restEntryPoint", new DispatcherServlet(restContext));
            restEntryPoint.setLoadOnStartup(1);
            restEntryPoint.addMapping("/api/*");
    
            // dispatcher servlet for webSocketEntryPoint
            AnnotationConfigWebApplicationContext webSocketContext = new AnnotationConfigWebApplicationContext();
            webSocketContext.register(MyWebSocketWebConfig.class);
            ServletRegistration.Dynamic webSocketEntryPoint = servletContext.addServlet("webSocketEntryPoint", new DispatcherServlet(webSocketContext));
            webSocketEntryPoint.setLoadOnStartup(1);
            webSocketEntryPoint.addMapping("/ws/*");
    
            // dispatcher servlet for webEntryPoint
            AnnotationConfigWebApplicationContext webContext = new AnnotationConfigWebApplicationContext();
            webContext.register(MyWebConfig.class);
            ServletRegistration.Dynamic webEntryPoint = servletContext.addServlet("webEntryPoint", new DispatcherServlet(webContext));
            webEntryPoint.setLoadOnStartup(1);
            webEntryPoint.addMapping("/");
    
            FilterRegistration.Dynamic validationFilter = servletContext.addFilter("validationFilter", new MyValidationFilter());
            validationFilter.addMappingForUrlPatterns(null, false, "/*");
    
            FilterRegistration.Dynamic lastFilter = servletContext.addFilter("lastFilter", new MyLastFilter());
            lastFilter.addMappingForUrlPatterns(null, false, "/*");
    
        }
    
        @Override
        protected Class<?>[] getRootConfigClasses() {
            // return new Class<?>[] { AppConfig.class };
            return null;
        }
    
        @Override
        protected Class<?>[] getServletConfigClasses() {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        protected String[] getServletMappings() {
            // TODO Auto-generated method stub
            return null;
        }
    
    }
    
  4. from https://stackoverflow.com/questions/28877982/spring-java-config-with-multiple-dispatchers by cc-by-sa and MIT license