Spring Java Config with Multiple Dispatchers

后端 未结 3 1371
挽巷
挽巷 2020-12-14 04:50

I\'ve some experience Spring now and also have some pure java config web-apps in use. However, these are usually based on a quiet simple setup:

  • application con
相关标签:
3条回答
  • 2020-12-14 05:15

    I think you can work it out if you use generic WebApplicationInitializer interface rather than using abstract implementation provided by spring - AbstractAnnotationConfigDispatcherServletInitializer.

    That way, you could create two separate initializers, so you would get different ServletContext on startUp() method and register different AppConfig & dispatcher servlets for each of them.

    One of such implementing class may look like this:

    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");
    
        }
    
    }
    
    0 讨论(0)
  • 2020-12-14 05:21

    I faced the same issue. Actually I had a complex configuration with multiple dispatcher servlets, filters and listeners.

    I had a web.xml like below

    <?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>
    

    I replaced above web.xml with below java file

    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;
        }
    
    }
    
    0 讨论(0)
  • 2020-12-14 05:41

    Mahesh C. showed the right path, but his implementation is too limited. He is right on one point : you cannot use directly AbstractAnnotationConfigDispatcherServletInitializer for multiple dispatcher servlet. But the implementation should :

    • create a root application context
    • gives it an initial configuration and say what packages it should scan
    • add a ContextListener for it to the servlet context
    • then for each dispatcher servlet
      • create a child application context
      • gives it the same an initial configuration and packages to scan
      • create a DispatcherServlet using the context
      • add it to the servlet context

    Here is a more complete implementation :

    @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
        ...
    }
    

    That way, you have full control on which beans will end in which context, exactly as you would have with XML configuration.

    0 讨论(0)
提交回复
热议问题