引言
在以往的spring项目中,我们的应用程序需要部署在Tomcat容器内部运行。现在Springboot将Tomcat嵌入到程序中运行,增加了应用程序的灵活性。为以后的微服务分布式打下基础。
现在来看下如何嵌入Tomcat
创建项目
创建一个简单的POM项目
引入Tomcat依赖
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>8.5.16</version>
</dependency>
<!-- tomcat对jsp支持 -->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jasper</artifactId>
<version>8.5.16</version>
</dependency>
编写启动类
public class TomcatTest {
public static void main(String[] args) throws ServletException, LifecycleException {
start();
}
public static void start() throws ServletException, LifecycleException {
//创建Tomcat容器和设置端口
Tomcat tomcatServer = new Tomcat();
tomcatServer.setPort(9001);
tomcatServer.setBaseDir("/");
HttpServlet httpServlet = new HttpServlet() {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().print("success request!!!");
}
};
System.out.println(new File("src/main").getAbsolutePath());
StandardContext ctx = (StandardContext) tomcatServer.addWebapp("/demo", new File("src/main").getAbsolutePath());
ctx.setReloadable(false);
ctx.addLifecycleListener(new AprLifecycleListener(){
@Override
public void lifecycleEvent(LifecycleEvent event) {
super.lifecycleEvent(event);
}
});
tomcatServer.addServlet("/demo","testServlet",httpServlet);
ctx.addServletMappingDecoded("/test.do", "testServlet");
//启动容器
tomcatServer.start();
tomcatServer.getServer().await();
}
}
测试
引入Spring容器
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<!-- <dependency>-->
<!-- <groupId>org.springframework</groupId>-->
<!-- <artifactId>spring-context</artifactId>-->
<!-- <version>5.2.0.RELEASE</version>-->
<!-- </dependency>-->
<!-- <!– https://mvnrepository.com/artifact/org.springframework/spring-web –>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework</groupId>-->
<!-- <artifactId>spring-web</artifactId>-->
<!-- <version>5.2.0.RELEASE</version>-->
<!-- </dependency>-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
编写spring配置
配置类
@ComponentScan("com.tomcat")
@Configuration
public class AppConfig {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
System.out.println(context.getBean(MyService.class));
}
}
自定义个Bean
@Component
public class MyService {
@PostConstruct
public void init(){
System.out.println(MyService.class.getName()+"初始化");
}
}
测试Spring
至此Spring Tomcat 都可以独立启动了,那如何才能同时启动Spring呢,根据spi规范,Tomcat启动时会扫描包下的META-INF下service文件下
javax.servlet.ServletContainerInitializer内部定义的类。
定义回调ServletContainerInitializer
public class MyServletContainerInitializer implements ServletContainerInitializer {
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
System.out.println("我的tomcat 启动了。。。。。。。。。。");
}
}
在这里可以引入加载Spring 容器 SpringMVC等一些相关的内容。
同样的 在Springweb下也是使用的这样的方式用来初始化spring的
SpringServletContainerInitializer 代码
@HandlesTypes({WebApplicationInitializer.class})
public class SpringServletContainerInitializer implements ServletContainerInitializer {
public SpringServletContainerInitializer() {
}
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList();
Iterator var4;
if (webAppInitializerClasses != null) {
var4 = webAppInitializerClasses.iterator();
while(var4.hasNext()) {
Class<?> waiClass = (Class)var4.next();
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
initializers.add((WebApplicationInitializer)ReflectionUtils.accessibleConstructor(waiClass, new Class[0]).newInstance());
} catch (Throwable var7) {
throw new ServletException("Failed to instantiate WebApplicationInitializer class", var7);
}
}
}
}
if (initializers.isEmpty()) {
servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
} else {
servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
AnnotationAwareOrderComparator.sort(initializers);
var4 = initializers.iterator();
while(var4.hasNext()) {
WebApplicationInitializer initializer = (WebApplicationInitializer)var4.next();
initializer.onStartup(servletContext);
}
}
}
}
通过@HandlesTypes({WebApplicationInitializer.class})引入WebApplicationInitializer对象并且调用WebApplicationInitializer->onStartup(方法)
实现AbstractAnnotationConfigDispatcherServletInitializer
回调类
public class SpringServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
System.out.println("-----------------------------");
return new Class[]{};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
配置类
@ComponentScan("com.tomcat.mvc")
@Configuration
public class WebConfig implements WebMvcConfigurer {
}
注册Bean
@RestController
public class MyController {
@GetMapping("/index")
public String getIndex(){
return "this is CustomSpringBoot index";
}
}