Servlet与SpringBoot的前世今生

本文详细阐述了Servlet从Web1.0到SpringBoot Web4.0的发展历程,包括从原始Servlet手动管理到Spring的IOC容器,再到SpringMVC的出现以及SpringBoot的自动配置和内嵌式Servlet容器。SpringBoot通过自动配置简化了项目搭建,并通过内嵌Tomcat实现了快速启动。此外,还介绍了SpringBoot如何通过条件注解实现自动配置。
摘要由CSDN通过智能技术生成

Servlet与SpringBoot的前世今生个人分为了4个阶段

  • Web1.0

原始的servlet,servlet中维护service(手动new),service中维护dao(QueryRunner等DbUtils),此时在web.xml中配置好url映射与servlet的关系,在tomcat接收到请求时,根据匹配的servlet,通过反射创建servlet对象,执行doGet或doPost方法。一般需要手动设置一些响应头信息。

  • Web 2.0

此时有了spring框架,通过spring的ioc容器,可方便的创建出service层以及dao层的bean。但是servlet是需要被tomcat创建的,此时还无法让spring创建servlet,但是servlet中的service是可以从spring容器中获取的(不用再手动new了),service层也可以自动注入mapper。

  • Web 3.0

虽然spring的ioc容器能够很方便管理项目中的service和mapper层的组件,但是没有办法解决servlet这个痛点,于是springmvc出现了。随之而来的DispatcherServlet代替了之前手动在web.xml中写的一大堆servlet,此时多出了controller层。只需要编写类以及方法,在方法上使用@RequestMapping注解指定url就可以处理请求了。如此方便的springmvc是一个怎样的流程?首先DispathcerServlet还是有tomcat创建,而tomcat在创建servlet后会调用其init方法,在这个方法中DispathcerServlet做了一系列初始化工作,最重要的就是创建一个子容器(一般springmvc只扫描controller), 并设置父容器(spring管理的service和mapper容器)。此时controller层就可以自动装配service,因为都被spring管理了,初始化好容器以后,继续初始化处理器适配器,参数解析器,视图解析器等九大组件,这些都初始化好以后,dispathcerservlet就可以接收并 处理请求了。请求来到dispathcerservlet,根据请求信息找到处理器(handlermethod),此时返回的是一个处理器执行链,包括拦截器,controller对象(如果被代理了,则会是代理对象)。再根据处理器找到处理器适配器,让适配器来执行目标方法。得到ModelAndView对象,交给视图解析器处理。此时我们不需要手动往response输出流中写内容,springmvc会帮我们处理。

  • Web 4.0

4.0就是个人理解的springboot时代,springboot主要提供了两个强大功能,一个是自动配置,另一个就是内嵌式的servlet容器。
当引入 spring-boot-starter-web这个依赖的时候,发现启动项目时,自动开启了tcp链接,也就是启动了tomcat服务器,而其他地方并没有改变任何一行代码,这是怎么实现的?通过查看源码得知,在springboot启动时,会通过

    static WebApplicationType deduceFromClasspath() {
        if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {
            return REACTIVE;
        } else {
            String[] var0 = SERVLET_INDICATOR_CLASSES;
            int var1 = var0.length;

            for(int var2 = 0; var2 < var1; ++var2) {
                String className = var0[var2];
                if (!ClassUtils.isPresent(className, (ClassLoader)null)) {
                    return NONE;
                }
            }

            return SERVLET;
        }
    }

如果类路径下有特定的类,则会创建一个 AnnotationConfigServletWebServerApplicationContext容器,而这个容器重写了父类的onRefresh方法

    protected void onRefresh() {
        super.onRefresh();

        try {
            this.createWebServer();
        } catch (Throwable var2) {
            throw new ApplicationContextException("Unable to start web server", var2);
        }
    }
    private void createWebServer() {
        WebServer webServer = this.webServer;
        ServletContext servletContext = this.getServletContext();
        if (webServer == null && servletContext == null) {
            StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
            ServletWebServerFactory factory = this.getWebServerFactory();
            createWebServer.tag("factory", factory.getClass().toString());
            this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
            createWebServer.end();
            this.getBeanFactory().registerSingleton("webServerGracefulShutdown", new WebServerGracefulShutdownLifecycle(this.webServer));
            this.getBeanFactory().registerSingleton("webServerStartStop", new WebServerStartStopLifecycle(this, this.webServer));
        } else if (servletContext != null) {
            try {
                this.getSelfInitializer().onStartup(servletContext);
            } catch (ServletException var5) {
                throw new ApplicationContextException("Cannot initialize servlet context", var5);
            }
        }

        this.initPropertySources();
    }

正是在这个方法里面启动了服务器。

除此之外,springboot的自动配置也是极其方便的,以spring-boot-starter-data-redis为例,如果是之前的ssm工程,则需要引入各种依赖,同时也需要自己维护好这些依赖的版本,引入好依赖后,在spring.xml中配置好和redis相关的bean以及连接工厂等,或者再写一个配置类,@Bean一下。这样在其他地方就能使用了。但是在springboot这些统统不需要做,只需要在properties配置文件中配置好相关属性即可。当引入redis-start之后,此时spring就会加载该jar包下spring.factories文件,这个文件指定了spring需要加载的自动配置类,一般这种自动配置类都会结合一个xxxProperties类,比如redis的RedisProperties,此时spring就会继续创建这个Properties类,而这个Properties类的属性就是和application.properties文件配置的属性值绑定的。此时在创建RedisTemplate等Bean时就会用到这个Properties类中的属性 ,进而创建好Bean,这样在其他类中就可以使用了。

spring的autoconfiure包中维护了大量的xxxAutoConfguirtion,但是这些配置类不是都生效的,通常又会结合@Condition注解来使用,最典型的就是当类路径下有某个类时才会生效,在springboot的源码中,经常看到一些爆红的类,就是当前我们的项目没有引入这个类,但是发现运行springboot项目时并不会报错?这是因为我们在引入springboot或者其他第三方jar包时,引入的都是已经打包好的class文件,这种是已经被编译好的文件,即便当前类路径下并没有某个class也不会报错,对于class文件来说,里面的内容就是一些普通字符串,只有在真正用到某个类时,说不定才会报错,正常运行已经编译好的class文件不会报错。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值