springboot单体项目的执行流程
首先就是启动springboot项目,即执行主函数,这个主函数的类通常带有SpingBootApplication注解,类中的main方法就是程序的入口。
启动主函数后,SpringBoot会按特定顺序加载配置文件,如application.properties或application.yml,这两种格式的文件都行,还能根据不同的环境加载不同的加载文件,如生产环境,测试环境等。配置文件里一般包含数据库连接的信息,服务端接口,日志级别等。
接着main函数中的run方法会创建一个Spring容器负责管理项目中的Bean,具体过程就是在调用SpingApplication.run方法时,会先创建一个SpringApplication实例,该实例会进行如下工作:
1.推断应用类型,判断时Web应用还是非Web应用。
2.查找并加载初始化器(ApplicationContextInitializer),这些初始化器可以在 ApplicationContext(应用上下文,是一个管理Spring应用中各种组件如Bean,配置信息,时间等的高级容器)刷新之前进行自定义配置。
3.查找并加载监听器,监听器会监听应用启动过程中的各种时间,如应用启动,上下文刷新等。
4.推断主应用类,即包含main方法的类
然后SpringApplition实例会根据应用类型创建相应的ApplicationContext实例。
接下来就是加载Bean定义,ApplicationContext会加载所有的Bean定义,这些Bean定义可以来自多个地方:
1.通过@ComponentScan扫描指定路径下的带有@Component,@Service,@Repository, @Controller等注解的类
2.@Configuration注解的配置类中使用@Bean注解定义的类
接着就是在Applicationtext刷新的过程中,会根据Bean定义创建Bean实例,并进行依赖注入和生命周期管理。Spring容器会确保Bean的单例性(默认情况下,也可以指定为多例),并处理Bean的初始化和销毁方法。
在Sping容器和Bean加载完成后,还会启动服务器,执行命令运行器和应用启动运行器(对实现了CommandLineRunner或ApplicationRunner接口的Bean在应用启动后执行一些初始化操作),最后发布应用启动完成事件。
讲完了springboot的启动后下面就是交互过程了。
客户端发起请求,这个请求是HTTP请求,它包括如下方法:
1.请求方法:常见的有GET(用于获取资源),POST(用于提交数据),PUT(用于更新资源),DELETE(用于更新资源),DELETE(用于删除资源)等
2.请求URL:指明要访问的资源地址
3.请求头:携带关于请求的额外信息,包含很多信息,如客户端类型,请求体的数据格式,请求发送的日期时间,身份验证(例如把token放到请求头中)等等
4.请求体:POST,PUT等方法可能会携带请求体,用于传递数据,数据格式可以是JSON,XML等
接着请求到达了SpringBoot应用所监听的端口,在请求到达之前,服务器一直在监听该端口,端口一般是8080。
嵌入式服务器接收到请求后,会进行如下操作:
1.将原始的HTTP请求封装成HttpServletRequest对象,该对象提供了一系列方法用于获取请求的各种信息,如请求方法,请求URL,请求头,请求体等。
2.同时创建一个HttpServletResponse响应对象,用于后续后端向前端返回消息
请求在到达DispatcherServlet之前,会经过一系列过滤器,过滤器可以实现编码转换,请求日志,权限验证等功能,通过实现Filter接口来定义过滤器。
DispatcherServlet作为SpringMVC的核心调度器,继承自HttpServlet,在SpringBoot启动时自动配置和初始化,接受经过过滤器链处理后的请求。
在查找处理器(三层架构中的controller)之前,DispatcherServlet会进行一些预处理操作:
1.检查请求是否为文件上传请求,若为文件上传请求,则将请求包装成MultipartHttpServletRequest。
2.根据请求的Accept头确定合适的消息转换器,用于后续处理响应数据的格式转换
(这里的Accept头是HTTP请求头中的一个字段,他用于告知服务器客户端能够接受的响应内容类型)
HandlerMapping根据请求的URL和请求方法,从被@Controller或@RestController注解标记的类中查找对应的处理器方法。常见的HandlerMapping实现是RequestMappingHandlerMapping,它依据@RequestMapping,@GetMappingdeng等注解来匹配处理器方法。
在确定请求对应的处理器之后,调用处理器方法之前,会执行拦截器的preHandle方法。拦截器是SpringMVC提供的功能,可用于对处理器方法进行增强,如权限验证,日志记录,性能监控等。
示例:
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class MyInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 权限验证if (request.getSession().getAttribute("user") == null) {response.sendRedirect("/login");return false;}// 记录请求开始时间request.setAttribute("startTime", System.currentTimeMillis());return true;}
}
若拦截器的preHandle方法返回true,HandlerAdapter会将请求中的参数(如URL参数,请求体参数等)绑定到处理器方法的参数上,并调用处理器方法。在这个过程中,控制器可能会调用服务层的方法来处理业务逻辑。
服务层主要负责处理业务规则,数据访问和事务管理等操作。控制器调用服务层的方法,服务层再调用数据访问层(DAO)来与数据库或其他数据源进行交互。
数据访问层负责与底层数据源进行交互,执行数据的增删改查,通常用mybatis或者mybatisplus进行实现。
处理器方法执行完成后,在视图渲染之前,会执行拦截器的postHandle方法。此方法可用于对处理器方法的执行结果进行修改或补充。
处理器方法处理完业务逻辑后,返回一个结果。结果可以是视图名称(用于视图渲染),也可以是数据对象(如JSON,XML等)。如果使用@RequestController注解,默认会将返回的对象转换为JSON格式返回给客户端。
若处理器方法返回的是视图名称,DispatcherServlet会使用ViewResolver解析视图,将模型数据传递给视图模版进行渲染。
视图模板将模型数据和视图模版合并,生成最终的HTML页面。(如果有)
在整个请求处理完成后,包括视图渲染完成,会执行拦截器的afterComletion方法。此方法主要用于进行资源清理操作,如关闭数据库连接,记录请求处理的总时长等。
处理器方法返回的结果(视图或数据)被封装到HttpServletResponse对象中,DispatcherServlet设置响应的状态码,响应头和响应体。
响应在返回客户端之前,再次经过过滤器,过滤器可对响应进行后置处理,如添加响应头,压缩响应数据等。
嵌入式服务器将HttpServletResponse对象中的响应数据返回给客户端,客户端根据响应内容进行相应处理。