Spring 系列目錄(http://www.javashuo.com/article/p-kqecupyl-bm.html)html
在 Servlet 3.0 時支持註解啓動,再也不須要 web.xml 配製文件。詳見《Servlet 3.0 規範(二)註解規範》:http://www.javashuo.com/article/p-kktlszqi-dv.htmljava
@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 的繼承關係以下:git
WebApplicationInitializer |- AbstractContextLoaderInitializer |- AbstractDispatcherServletInitializer |- AbstractAnnotationConfigDispatcherServletInitializer
AbstractContextLoaderInitializer
建立 Root 根容器並註冊 ContextLoaderListener,建立根容器由子類實現。核心方法:registerContextLoaderListenergithub
AbstractDispatcherServletInitializer
建立 Servlet 容器,並註冊 DispatcherServlet 和 Filete,建立根容器由子類實現。核心方法:registerDispatcherServletweb
AbstractAnnotationConfigDispatcherServletInitializer
建立 Root 和 Servlet 容器。核心方法:createRootApplicationContext、createServletApplicationContextspring
斷點調試,webAppInitializerClasses 有如下類,顯然只有一個實現類 MyAbstractAnnotationConfigDispatcherServletInitializer 執行了 onStartup 方法。apache
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"
(1) @EnableWebMvcapi
開啓 Spring 高級功能,至關於 <mvc:annotation-driven/>
spring-mvc
(2) WebMvcConfigurertomcat
對應之前 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>
使用 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
天天用心記錄一點點。內容也許不重要,但習慣很重要!