目的
有时候需要一个小web项目,而懒得单独下载tomcat运行,想直接像springboot一样打包成一个可运行jar执行,方便快捷
原理
具体原理可百度嵌入式tomcat,这里就简单介绍一下
在Tomcat8以上版本支持一个配置启动的东西,意思就是tomcat启动时会自动去扫描所有 jar 中目录为「 META-INF/services/ 」中是否有个名字是「javax.servlet.ServletContainerInitializer」的配置文件,然后根据里面内容反编译启动等等一系列操作,具体如下图配置:
如上图配置后tomcat启动时就会自动生成HelloServlet了,大概原理就这样,不过SpringMVC已经把上图中的基本配置已经搞定直接使用即可,具体往下看
普通Maven项目的依赖
<properties>
<spring.version>5.2.3.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.2</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>9.0.30</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<version>9.0.30</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
主要SpringMVC配置
Spring官网:https://docs.spring.io/spring/docs/5.0.14.RELEASE/spring-framework-reference/web.html#spring-web
代码中的 app.xml 是普通Spring项目的配置,关于SpringMVC配置就代码中已加入的注解式配置
public class MyWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
// 返回Spring应用根容器中定义的beans,对应ContextLoaderListener,是Spring根容器
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{RootConfig.class};
}
//protected Class<?>[] getRootConfigClasses() {
// return new Class[0];
//}
// 返回Spring MVC应用容器中定义的beans,对应DispatcherServlet中加载的bean
// Spring MVC容器是根容器的子容器,子容器可以看到根容器中定义的beans,反之不行
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{ServletConfig.class};
}
// 指定映射拦截URL
protected String[] getServletMappings() {
return new String[]{"/"};
}
// 修改 通过重写此方法修改DispatcherServlet的名称,对应<servlet-name></servlet-name>标签
@Override
protected String getServletName() {
return super.getServletName();
}
@Override
protected Filter[] getServletFilters() {
return new Filter[]{new SimpleFilter()};
}
}
@Configuration
@ImportResource(locations = "classpath:config/app.xml")
public class RootConfig {
private final Logger logger = LoggerFactory.getLogger(RootConfig.class);
@Bean
public ApplicationContextAware applicationContextAware(ApplicationContext ctx) {
return args -> {
/**
System.err.println("beans:");
String[] beanNames = ctx.getBeanDefinitionNames();
//Arrays.sort(beanNames);
for (String beanName : beanNames) {
System.err.println("---> " + beanName);
}
*/
System.out.println("Beans: " + ctx.getBeanDefinitionCount());
logger.info("==========- 启动完成 -==========");
};
}
}
@Configuration
@EnableWebMvc //@EnableWebMvc 同等 WebMvcConfigurationSupport
@ComponentScan("com.*.*.web.controller")
public class ServletConfig {
@Bean
public ViewResolver viewResolver() { // 配置 视图解析器
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF");
viewResolver.setSuffix(".jsp");
viewResolver.setExposeContextBeansAsAttributes(true);
//viewResolver.setOrder(0);
//viewResolver.setViewClass(org.springframework.web.servlet.view.JstlView.class);
return viewResolver;
}
}
Tomcat启动代码
package com.fourlambs.proxyip;
import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.startup.Tomcat;
import org.apache.tomcat.util.descriptor.web.ErrorPage;
import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
/**
* @Author yuwan [2020-02-07]
* @Date February, 07, Friday
* @Comment ...
*/
public class AppMain {
static void testPort(int port) throws IOException {
// 检测端口是否被占用
ServerSocket socket = null;
try {
socket = new ServerSocket(port);
} catch (IOException e) {
System.err.println(port + " 端口已被占用");
System.exit(0);
return;
} finally {
socket.close();
}
}
public static void main(String[] args) {
int port = 8080;
try {
if (args.length > 0) {
port = Integer.parseInt(args[0]);
}
testPort(port);
// Windows系统上运行必须要有webapps文件夹,不然启动不了,辣鸡!
String osName = System.getProperties().getProperty("os.name");
if (osName.toLowerCase().contains("windows")) {
String path = AppMain.class.getResource("/").getPath() + "/webapps";
File file = new File(path);
if (!file.exists()) {
file.mkdir();
}
}
Tomcat tomcat = new Tomcat();
//System.setProperty("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE", "true");
String baseDir = Thread.currentThread().getContextClassLoader().getResource("").getPath();
tomcat.setBaseDir(baseDir);
tomcat.setPort(port);
Context ctx = tomcat.addWebapp("", baseDir);
ctx.setParentClassLoader(Thread.currentThread().getContextClassLoader());
//ctx.setLoader(new WebappLoader(Thread.currentThread().getContextClassLoader()));
ctx.setRequestCharacterEncoding("UTF-8");
ErrorPage ep = new ErrorPage();
//ep.setErrorCode(404);
ep.setLocation("/error");
ctx.addErrorPage(ep);
// 特殊资源
//StandardRoot resources = new StandardRoot(ctx);
//WebResourceSet resourceSet = new EmptyResourceSet(resources);
//WebResourceSet resourceSet = new DirResourceSet(resources, "/", "/", "/");
//resources.addPreResources(resourceSet);
//ctx.setResources(resources);
Connector connector = tomcat.getConnector();
connector.setAttribute("maxThreads", 500);
//connector.setAttribute("minSpareThreads", 2);
//tomcat.enableNaming();
tomcat.start();
tomcat.getServer().await();
} catch (Exception e) {
System.err.println("启动错误 Error:" + e.getMessage());
System.err.println("命令启动时第一个参数为端口号(默认端口" + port + ")");
e.printStackTrace();
}
}
}
Tomcat简单嵌入重中之重就是上面的tomcat启动代码。。。。难点是官网没有文档,憋来没办法去研究源码。。。阿帕奇是个大坑比!!
重点代码已列出来了,仅供学习参考!高级的tomcat配置及使用建议最好还是老老实实下载tomcat来运行和配置
来源:oschina
链接:https://my.oschina.net/medvin/blog/3191010