【第四十讲】Tomcat内嵌容器
内嵌容器基本使用
内嵌容器加载 DispatherServlet 的时机
Tomcat 基本结构
Server
└───Service
├───Connector (协议, 端口)
└───Engine
└───Host(虚拟主机 localhost)
├───Context1 (应用1, 可以设置虚拟路径, / 即 url 起始路径; 项目磁盘路径, 即 docBase )
│ │ index.html
│ └───WEB-INF
│ │ web.xml (servlet, filter, listener) 3.0
│ ├───classes (servlet, controller, service ...)
│ ├───jsp
│ └───lib (第三方 jar 包)
└───Context2 (应用2)
│ index.html
└───WEB-INF
web.xml
关键代码
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.startup.Tomcat;
import org.apache.coyote.http11.Http11Nio2Protocol;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Collections;
import java.util.Set;
public class TestTomcat {
public static void main(String[] args) throws LifecycleException, IOException {
// 1.创建 Tomcat 对象
Tomcat tomcat = new Tomcat();
tomcat.setBaseDir("tomcat");
// 2.创建项目文件夹, 即 docBase 文件夹
File docBase = Files.createTempDirectory("boot.").toFile();
docBase.deleteOnExit();
// 3.创建 Tomcat 项目, 在 Tomcat 中称为 Context
Context context = tomcat.addContext("", docBase.getAbsolutePath());
// 4.编程添加 Servlet
context.addServletContainerInitializer(new ServletContainerInitializer() {
@Override
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
HelloServlet helloServlet = new HelloServlet();
ctx.addServlet("aaa", helloServlet).addMapping("/hello");
}
}, Collections.emptySet());
// 5.启动 Tomcat
tomcat.start();
// 6.创建连接器, 设置监听端口
Connector connector = new Connector(new Http11Nio2Protocol());
connector.setPort(8080);
tomcat.setConnector(connector);
}
}
HelloServlet.java
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().print( "<h3>hello</h3>");
}
}
集成 Spring 容器
增加一个配置类 Config 和 WebApplicationContext
public static WebApplicationContext getApplicationContext() {
//AnnotationConfigServletWebServerApplicationContext
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(Config.class);
context.refresh();
return context;
}
@Configuration
static class Config {
@Bean
public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
}
@Bean
// 这个例子中必须为 DispatcherServlet 提供 AnnotationConfigWebApplicationContext, 否则会选择 XmlWebApplicationContext 实现
public DispatcherServlet dispatcherServlet(WebApplicationContext applicationContext) {
return new DispatcherServlet(applicationContext);
}
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
RequestMappingHandlerAdapter handlerAdapter = new RequestMappingHandlerAdapter();
handlerAdapter.setMessageConverters(Arrays.asList(new MappingJackson2HttpMessageConverter()));
return handlerAdapter;
}
@RestController
static class MyController {
@GetMapping("hello2")
public Map<String,Object> hello() {
Map<String,Object> resMap = new HashMap<>();
resMap.put("hello2", "hello2, spring!");
return resMap;
}
}
}
在浏览器中输入地址,映射结果
更加通用的注册方法