模拟sringboot启动
模拟sringboot启动
我们在使用spring和springboot之间还是有很多不同的,比如springboot内置tomcat..等容器,我们这里就简单通过模拟简单的springboot启动,来解释mvc
依赖
需要tomcat embed的jar包 ,我是使用的gradle
dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' compile(project(":spring-context")) compile(project(":spring-webmvc")) // https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-core compile group: 'org.apache.tomcat.embed', name: 'tomcat-embed-core', version: '8.5.53' }
简易版
先创建一个启动类
public class Main {
public static void main(String[] args) {
MySpringApplication.run();
}
}
建立MySpringApplication
package debugdir.mvc.main;
import debugdir.mvc.AppConfig;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.startup.Tomcat;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import java.io.File;
public class MySpringApplication {
public static void run(){
// 创建支持注解的web上下文
AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
// 加载配置类
ac.register(AppConfig.class);
ac.refresh();
// 创建tomcat
Tomcat tomcat = new Tomcat();
String webAppDirLocation = "src/main/";
//Set Port #
tomcat.setPort(8080);
// 指定context目录
File base = new File(MySpringApplication.class.getResource("/").getPath());
//StandardContext ctx = (StandardContext) tomcat.addWebapp("/", new File(webAppDirLocation).getAbsolutePath());
Context ctx = tomcat.addContext("/",base.getAbsolutePath());
// Create and register the DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(ac);
// 设置映射,这里其实就是xml里的<servlet-mapping>
Tomcat.addServlet(ctx,"testServlet",servlet);
ctx.addServletMappingDecoded("/","testServlet");
try {
tomcat.start();
} catch (LifecycleException e) {
e.printStackTrace();
}
// tomcat 等待请求
tomcat.getServer().await();
}
}
AppConfig
package debugdir.mvc;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
// 扫描包
@ComponentScan("debugdir.mvc")
public class AppConfig {
}
spring实现思路
ServletContainerInitializer
曾经开发是离不开XML配置的,现在servlet 3.0支持通过实现ServletContainerInitializer方式代替XML.但是需要配置项目
META-INF/services/javax.servlet.ServletContainerInitializer
文件
spring是如何支持的?
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException{
List<WebApplicationInitializer> initializers = new LinkedList<>();
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)
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;
}
servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
AnnotationAwareOrderComparator.sort(initializers);
for (WebApplicationInitializer initializer : initializers) {
initializer.onStartup(servletContext);
}
}
}
- 首先在spring-webmvc项目中,
META-INF/services/javax.servlet.ServletContainerInitializer
中添加org.springframework.web.SpringServletContainerInitializer
,这样web容器启动后就会加载SpringServletContainerInitializer
@HandlesTypes(WebApplicationInitializer.class)
扫描所有接口WebApplicationInitializer的实现类传入参数Set<Class<?>> c
中,在onStartup()中循环调用initializer.onStartup(servletContext);
- 方法直接传入
ServletContext
,因此可以直接注册一些servlet,这样DispatcherServlet
可以在此处注册.
模拟sringboot启动
https://www.blaaair.com/archives/mo-ni-sringboot-qi-dong