突然奇想不用SpringBoot,并且不配置xml文件来启动Web应用程序!
先贴出程序所需的Java代码以及Pom,如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>vip.wulanggroupId>
<artifactId>web-testartifactId>
<version>0.0.1-SNAPSHOTversion>
<packaging>warpackaging>
<properties>
<mysql.version>5.1.34mysql.version>
<spring.version>4.3.0.RELEASEspring.version>
<hibernate.version>5.1.0.Finalhibernate.version>
<druid.version>1.1.10druid.version>
<jpa.version>1.10.4.RELEASEjpa.version>
<test.version>4.12test.version>
<common.version>3.3.2common.version>
<servlet.version>3.1.0servlet.version>
<fastjson.version>1.2.47fastjson.version>
<slf4j.version>1.7.25slf4j.version>
<aspectj.version>1.8.10aspectj.version>
<validation.version>1.1.0.Finalvalidation.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-beansartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-context-supportartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-ormartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-txartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>${druid.version}version>
dependency>
<dependency>
<groupId>org.springframework.datagroupId>
<artifactId>spring-data-jpaartifactId>
<version>${jpa.version}version>
<exclusions>
<exclusion>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
exclusion>
<exclusion>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aopartifactId>
exclusion>
<exclusion>
<groupId>org.springframeworkgroupId>
<artifactId>spring-beansartifactId>
exclusion>
<exclusion>
<groupId>org.springframeworkgroupId>
<artifactId>spring-txartifactId>
exclusion>
<exclusion>
<groupId>org.springframeworkgroupId>
<artifactId>spring-ormartifactId>
exclusion>
<exclusion>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
exclusion>
<exclusion>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-coreartifactId>
<version>${hibernate.version}version>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-entitymanagerartifactId>
<version>${hibernate.version}version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>${mysql.version}version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>${test.version}version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-lang3artifactId>
<version>${common.version}version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>${servlet.version}version>
<scope>providedscope>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>${fastjson.version}version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>${slf4j.version}version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-simpleartifactId>
<version>${slf4j.version}version>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>${aspectj.version}version>
dependency>
<dependency>
<groupId>javax.validationgroupId>
<artifactId>validation-apiartifactId>
<version>${validation.version}version>
dependency>
dependencies>
project>
package vip.wulang.start;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import vip.wulang.config.RootConfig;
import vip.wulang.config.WebMVCConfig;
/**
* @author CoolerWu on 2018/11/12.
* @version 1.0
*/
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{RootConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{WebMVCConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String [] {"/"};
}
}
package vip.wulang.config;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import java.util.ArrayList;
import java.util.List;
/**
* @author CoolerWu on 2018/11/12.
* @version 1.0
*/
@Configuration
@EnableWebMvc // 启动 Spring MVC
@ComponentScan("vip.wulang.controller") // 启用组件扫描
public class WebMVCConfig extends WebMvcConfigurerAdapter {
// 配置 JSP 视图解析器
@Bean
public ViewResolver viewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/view/");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);
return resolver;
}
// 配置静态资源的处理
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer){
configurer.enable();
}
// 使用 alibaba 的 fastjson 来解析 Http 消息转换
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteMapNullValue);
List<MediaType> fastMediaTypes = new ArrayList<>();
fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
fastJsonHttpMessageConverter.setSupportedMediaTypes(fastMediaTypes);
fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);
converters.add(fastJsonHttpMessageConverter);
}
}
package vip.wulang.config;
import org.springframework.context.annotation.*;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
/**
* @author CoolerWu on 2018/11/14.
* @version 1.0
*/
@Configuration
@ComponentScan(
basePackages = {"vip.wulang"},
excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {EnableWebMvc.class})
}
)
public class RootConfig {
}
把项目配置到 Tomcat 服务器中,就能够启动了。就这么几行就可以启动了呢。为什么?在Servlet 3.0环境中,容器会在类路径中查找实现 javax.servlet.ServletContainerInitializer 接口的类,如果发现的话,就会用它来配置Servlet容器。ServletContainerInitializer.java Spring源码如下:
public interface ServletContainerInitializer {
public void onStartup(Set<Class<?>> c, ServletContext ctx)
throws ServletException;
}
Spring提供了这个接口的实现,名为 org.springframework.web.SpringServletContainerInitializer ,这个类反过来又会查找实现 org.springframework.web.WebApplicationInitializer 的类并将配置的任务交给它们来完成。SpringServletContainerInitializer.java Spring源码如下:
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>();
if (webAppInitializerClasses != null) {
for (Class<?> waiClass : webAppInitializerClasses) {
// Be defensive: Some servlet containers provide us with invalid classes,
// no matter what @HandlesTypes says...
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
initializers.add((WebApplicationInitializer) 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;
}
servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
AnnotationAwareOrderComparator.sort(initializers);
for (WebApplicationInitializer initializer : initializers) {
initializer.onStartup(servletContext);
}
}
}
其中@HandlesTypes注解表示 SpringServletContainerInitializer.java 可以处理的类,本文中就是 WebApplicationInitializer.java,在 onStartup(Set
Spring 3.2 引入了一个便利的 WebApplicationInitializer 基础实现,也就是 org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer 。因为我们的 WebAppInitializer 扩展了 AbstractAnnotationConfigDispatcherServletInitializer (同时也就实现了 WebApplicationInitializer ),因此当部署到 Servlet 3.0 容器中的时候,容器会自动发现它,并用它来配置Servlet上下文。
在我们的实现类 WebAppInitializer 中,getServletMappings() ,它会将一个或者多个路径映射到 org.springframework.web.servlet.DispatcherServlet 上。即在本文中,它映射的是"/",这表示它会是应用的默认Servlet。它会处理进入应用的所有请求。getServletConfigClasses(),将会用来配置 DispatcherServlet 来加载 SpringMVC 子容器,即在本文中,将会加载 WebMVCConfig.class 。一般在web.xml中,我们还会在配置一个 org.springframework.web.context.ContextLoaderListener 监听器,用来启动 Spring 父容器。实际上,org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer 会同时创建 DispatcherServlet 和 ContextLoaderListener。所以 getRootConfigClasses() 将会用来配置 ContextLoaderListener 通过来创建应用上下文,即在本文中,将会加载 RootConfig.class 。
需要注意的是,如果按照这种方式配置,而不使用web.xml的话,那唯一问题在于它只能部署到支持 Servlet 3.0 的服务器中才能正常工作,如 Tomcat 7 或 更高版本。现在我们来看看 WebMVCConfig.java 和 RootConfig.java。
这样就知道了为什么这样可以启动该项目了。