首先先下载spring的源码,在项目中新建项目。
这里是用了官网推荐的启动方式:https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html
这种启动方式是依赖了servlet3.0的知识,就是启动tomcat完成的时候会调用实现WebApplicationInitializer的接口,我的代码为:
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletCxt) {
// Load Spring web application configuration
AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
//ac.register(AppConfig.class);
//ac.refresh();
ac.scan("com.test");
//ac.register(com.test.controller.TestController.class);
ac.refresh();
// Create and register the DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(ac);
ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/app/*");
}
}
这里主要是加载dispatherServlet,那为什么tomcat启动时会调用这个接口实现类,应为在spring-web这个项目里面有配置:
这里文件的内容是:
org.springframework.web.SpringServletContainerInitializer
打开这个类看,内容是:
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
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);
}
}
}
其实是tomcat会找到META-INF下的services的文件对应的类,在这里类去调用实现WebApplicationInitializer的类。
然后在要启动tomcat,这里直接像springboot那样,引用tomcat的类来启动,首先要添加tomcat的引用
dependencies {
compile 'org.apache.tomcat.embed:tomcat-embed-core:8.5.5'
compile 'org.apache.tomcat.embed:tomcat-embed-el:8.5.5'
compile 'org.apache.tomcat.embed:tomcat-embed-jasper:8.5.5'
compile project(':spring-context')
compile project(':spring-context-support')
compile project(':spring-beans')
compile project(':spring-webmvc')
testCompile group: 'junit', name: 'junit', version: '4.12'
}
然后代码执行是
public class SpringRun {
public void run(){
Tomcat tom = new Tomcat();
tom.setPort(8888);
try{
//获取项目编译后的claess 路径
String path = SpringRun.class.getResource("/").getPath();
//获取webapp 文件
//String filePath = new File("src/main/webapp").getAbsolutePath();
//然后将webapp下的项目添加至tomcat的context容器(context对应一个运行的项目)
Context context =tom.addWebapp("/test","D:\\html"); //参数1:一般是项目名 对应请求url中的项目名
//webResourceRoot 用于加载 项目的class文件
WebResourceRoot webResource = new StandardRoot(context);
webResource.addPreResources(new DirResourceSet(webResource,"/WEB-INF/classes",path,"/"));
tom.start();
}catch (Exception e)
{
e.printStackTrace();
}
//阻塞 ,等待前端连接 tom.getServer().await();
}
}
public static void main(String[] args) {
new SpringRun().run();
try {
Thread.sleep(1000000);
}catch (Exception e){
e.printStackTrace();
}
}
好了,这里配置好环境了,现在要写controller,有3种方式分别是:
@Controller
@RequestMapping("/cong")
public class TestController {
@RequestMapping("/test")
@ResponseBody
public String test(){
return "123";
}
}
@Component("/test2")
public class Test2Controller implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
return null;
}
}
@Component("/test3")
public class Test3Controller implements HttpRequestHandler {
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
好了,可以调了,下一节开始断点分析