• 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<Class<?>> webAppInitializerClasses, ServletContext servletContext)
                throws ServletException {
    
            List<WebApplicationInitializer> 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 高级功能,相当于 <mvc:annotation-driven/>

    (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 中的

    <mvc:interceptors>
        <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <mvc:exclude-mapping path="/admin/**"/>
            <bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor"/>
        </mvc:interceptor>
        <mvc:interceptor>
            <mvc:mapping path="/secure/*"/>
            <bean class="org.example.SecurityInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
    

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

    Spring 官方文档注解配置

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

    目录结构

    (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

    <packaging>war</packaging>
    <properties>
        <spring.version>5.1.0.RELEASE</spring.version>
    
        <project.build.sourceEncoding>utf-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
    </dependencies>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.0</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.1</version>
                <executions>
                    <execution>
                        <id>tomcat-run</id>
                        <goals>
                            <goal>exec-war-only</goal>
                        </goals>
                        <phase>package</phase>
                        <configuration>
                            <path>/</path>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    

    (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


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

  • 相关阅读:
    《剑指offer》— JavaScript(29)最小的K个数
    《剑指offer》— JavaScript(28)数组中出现次数超过一半的数字
    《剑指offer》— JavaScript(27)字符串的排列
    《剑指offer》— JavaScript(26)二叉搜索树与双向链表
    《剑指offer》— JavaScript(25)复杂链表的复制
    【备忘】接口
    【备忘】WPF基础
    UWP-动态磁贴
    UWP-磁贴初识
    【备忘】C#语言基础-2
  • 原文地址:https://www.cnblogs.com/binarylei/p/10203391.html
Copyright © 2020-2023  润新知