Spring 注解驱动(二)Servlet 3.0 注解驱动在 Spring MVC 中的应用

Spring 注解驱动(二)Servlet 3.0 注解驱动在 Spring MVC 中的应用

Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html)

在 Servlet 3.0 时支持注解启动,不再需要 web.xml 配制文件。详见《Servlet 3.0 规范(二)注解规范》:https://www.cnblogs.com/binarylei/p/10204208.html

一、Servlet 3.0 与 Spring MVC 整合

@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
    @Override
    public void onStartup(@Nullable Set> webAppInitializerClasses, ServletContext servletContext)
            throws ServletException {

        List initializers = new LinkedList<>();
        if (webAppInitializerClasses != null) {
            for (Class waiClass : webAppInitializerClasses) {
                // WebApplicationInitializer 的实现类
                if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
                        WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
                    try {
                        initializers.add((WebApplicationInitializer)
                                ReflectionUtils.accessibleConstructor(waiClass).newInstance());
                    } catch (Throwable ex) {
                        throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
                    }
                }
            }
        }

        if (initializers.isEmpty()) {
            servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
            return;
        }

        // 执行 onStartup
        AnnotationAwareOrderComparator.sort(initializers);
        for (WebApplicationInitializer initializer : initializers) {
            initializer.onStartup(servletContext);
        }
    }

}

Spring MVC 启动时会调用 WebApplicationInitializer 实现类的 onStartup 方法启动 WEB 容器。WebApplicationInitializer 的继承关系如下:

WebApplicationInitializer
    |- AbstractContextLoaderInitializer
        |- AbstractDispatcherServletInitializer
            |- AbstractAnnotationConfigDispatcherServletInitializer
  • AbstractContextLoaderInitializer 创建 Root 根容器并注册 ContextLoaderListener,创建根容器由子类实现。核心方法:registerContextLoaderListener

  • AbstractDispatcherServletInitializer 创建 Servlet 容器,并注册 DispatcherServlet 和 Filete,创建根容器由子类实现。核心方法:registerDispatcherServlet

  • AbstractAnnotationConfigDispatcherServletInitializer 创建 Root 和 Servlet 容器。核心方法:createRootApplicationContext、createServletApplicationContext

断点调试,webAppInitializerClasses 有以下类,显然只有一个实现类 MyAbstractAnnotationConfigDispatcherServletInitializer 执行了 onStartup 方法。

0 = {Class@4467} "class org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer"
1 = {Class@4468} "class org.springframework.web.servlet.support.AbstractDispatcherServletInitializer"
2 = {Class@4469} "class org.springframework.web.server.adapter.AbstractReactiveWebInitializer"
3 = {Class@4470} "class org.springframework.web.context.AbstractContextLoaderInitializer"
4 = {Class@4471} "class com.github.binarylei.MyAbstractAnnotationConfigDispatcherServletInitializer"

二、WebMvcConfigurer 接管 xml 配置

(1) @EnableWebMvc

开启 Spring 高级功能,相当于

(2) WebMvcConfigurer

对应以前 XML 配置中的每一项,以 interceptors 为例,其余详见官方文档:Spring 注解配置类 WebMvcConfigurer(https://docs.spring.io/spring/docs/5.1.3.RELEASE/spring-framework-reference/web.html#mvc-config)

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LocaleChangeInterceptor());
        registry.addInterceptor(new ThemeChangeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");
        registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*");
    }
}

以上代码相当于之前 XML 中的


    
    
        
        
        
    
    
        
        
    

三、模拟 Spring Boot 将 WEB 打成 jar 包运行

Spring 官方文档注解配置

使用 tomcat7-maven-plugin 插件模拟 Spring Boot。

Spring 注解驱动(二)Servlet 3.0 注解驱动在 Spring MVC 中的应用_第1张图片

(1) WebApplicationInitializer 实现类

public class MyAbstractAnnotationConfigDispatcherServletInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    // Root 容器配置
    protected Class[] getRootConfigClasses() {
        return new Class[0];
    }

    // Servlet 容器配置
    protected Class[] getServletConfigClasses() {
        return new Class[]{MyServletConfig.class};
    }

    // Servlet Mapping,取代 web.xml 中的 servlet-mapping 配置
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    // Filter 配置,取代 web.xml 中的 filter 配置
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
        encodingFilter.setEncoding("utf-8");
        encodingFilter.setForceRequestEncoding(true);
        encodingFilter.setForceResponseEncoding(true);

        return new Filter[]{encodingFilter};
    }
}

// 取代 spring-mvc.xml 配制
@Configuration
@ComponentScan(basePackages = "com.github.binarylei",
        excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)})
public class MyRootConfig {
}

// 取代 spring-context.xml 配制
@Configuration
@ComponentScan(basePackages = "com.github.binarylei",
        includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)})
public class MyServletConfig {

    @Bean
    public ViewResolver viewResolver(){
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix("/WEB-INF/view/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }
}

(2) tomcat7-maven-plugin 配制

tomcat7-maven-plugin 官网:http://tomcat.apache.org/maven-plugin-2.1/executable-war-jar.html

war

    5.1.0.RELEASE

    utf-8
    1.8
    1.8



    
        org.springframework
        spring-webmvc
        ${spring.version}
    
    
        javax.servlet
        javax.servlet-api
        3.1.0
        provided
    
    
        jstl
        jstl
        1.2
    



    
        
            org.apache.maven.plugins
            maven-war-plugin
            3.2.0
            
                false
            
        
        
            org.apache.tomcat.maven
            tomcat7-maven-plugin
            2.1
            
                
                    tomcat-run
                    
                        exec-war-only
                    
                    package
                    
                        /
                    
                
            
        
    

(3) 运行

执行 mvn package 后生成了两个文件:spring-war-1.0.0.war 和 spring-war-1.0.0-war-exec.jar

# localhost:8080/
java -jar spring-war-1.0.0-war-exec.jar 
# IDEA remote 调试时(suspend=y)
java -jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005 spring-war-1.0.0-war-exec.jar

tomcat 启动远程时报错:https://www.aliyun.com/jiaocheng/1443062.html


每天用心记录一点点。内容也许不重要,但习惯很重要!

你可能感兴趣的:(Spring 注解驱动(二)Servlet 3.0 注解驱动在 Spring MVC 中的应用)