硬啃世界--------Springboot请求处理流程
欢迎来到硬啃世界
你好,希望你每天给⾃⼰⼀点信⼼和耐⼼,不做被公司、⾯试者、社会淘汰的程序员,在这⾥硬啃汉带你去硬啃源码重新捡回信⼼。Springboot请求处理流程
今天来讲⼀下springboot接收到⼀个请求再到controller都经历了什么,作为⼀个java程序员现在⼏乎是离不开spring了,然后⼤多数java 程序员都是做web开发,那就肯定离不开controller了,⼯作上闭着眼每天都会写controller然后再返回给前端,但是⼤家有没有想过为什么spring能知道⼀个请求进来就能到这个⽅法调⽤呢,为什么我们写的出参是个对象能帮我们转成json串返回呢,都经历了什么,今天我们就来看看!
硬啃之前的⼀些准备
1. 这次使⽤的springboot版本是
2.4.5。
2. 创建好这个版本的demo项⽬,就很普通的⼀个项⽬就⾏。
3. 分别创建⼀个controller和,都没什么逻辑,主要是想看处理流程⽽不是看业务处理。
4. 别忘记创建⼀个配置类,将我们⾃⼰创建的添加进去。
5. ⼯具我这⾥⽤的eclipse(其实⼯具⽤啥⽆所谓都⼀样这么看)
具体结构:
controller的代码
@RestController
@RequestMapping
public class TestController {
//啥时不⼲,就打印然后返回
@GetMapping("/test")
public String test(){
String s ="哇哈哈";
System.out.println(s);
return s;
}
}
的代码
@Component
public class MyInterceptor implements HandlerInterceptor {
//进⼊controller前调⽤
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("进来了");
return true;
}
springboot是啥}
配置类的代码
public class WebMvcConfig implements WebMvcConfigurer{
@Autowired
private MyInterceptor myInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(myInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("");
}
}
开始硬啃
开启debug模式启动项⽬,因为我们创建了⼀个get请求接⼝,所以可以直接在浏览器或者⽤⼯具来模拟,⼀般我是使⽤postman来模拟请求,⼀开始我们应该是并不知道代码会经过哪⼀些类的处理才到controller的(⼤神除外,也可能是因为我⽐较弱鸡┭┮﹏┭┮),那怎么办呢,我们直接把断点打到controller⾥⾯,然后查看调⽤链:
然后我们通过调⽤链看到我们以前⼤伙都刚学甚⾄⼯作的时候java web的时候都会⽤到的⼀个类HttpServlet.class(当然这些年很多新⼊坑的⼩伙伴应该是不⽤再学这玩意了),我们看到他是调⽤了这个service⽅法
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try{
request =(HttpServletRequest) req;
response =(HttpServletResponse) res;
}catch(ClassCastException e){
throw new String("_http"));
}
//我们把断点打到这⼀句,然后按跳过断点之后重新发起请求让其停在这⾥
service(request, response);
}
重新进来断点直接,我们看到了这⾥只做了⼀件事情,就是帮我们把ServletRequest和ServletResponse 强转为HttpServletRequest和HttpServletResponse,主要是在原来的基础上新增了很多接⼝⽅法,⽅便⽤于扩展。
我们进⼊这⼀句代码service(request, response),发现新进⼊了⼀个类FrameworkServlet.class的service⽅法:
@SuppressWarnings("serial")
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
//为了⽅便显⽰,我们省略其余的⽅法代码,只看有关联的代码
//通过HttpServlet.service⽅法调⽤进来
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpMethod httpMethod = Method());
if(httpMethod == HttpMethod.PATCH || httpMethod == null){
processRequest(request, response);
}
else{
super.service(request, response);
}
}
}
@SuppressWarnings("serial")
public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {
//为了⽅便显⽰,我们省略其余的⽅法代码,只看有关联的代码
从类上看到继承HttpServletBean,然后我们再点进去看HttpServletBean发现是继承HttpServlet,验证了Spring就是基于Servlet来处理请求,我们继续往下⾛,因为HttpServletBean是没有重写service⽅法的所以这⾥调⽤的是HttpServlet的service⽅法:
简单看⼀下就好,这⾥其实也是没什么逻辑,
就是通过request获取到请求类型,然后调⽤对应的⽅法,
⽐如get请求就调⽤doGet,post请求就调⽤doPost
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String method = Method();
if(method.equals(METHOD_GET)){
//该⽅法固定返回-1
long lastModified =getLastModified(req);
if(lastModified ==-1){
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
}else{
long ifModifiedSince;
try{
ifModifiedSince = DateHeader(HEADER_IFMODSINCE);
}catch(IllegalArgumentException iae){
// Invalid date header - proceed as if none was set
ifModifiedSince =-1;
}
if(ifModifiedSince <(lastModified /1000*1000)){
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
}else{
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
}else if(method.equals(METHOD_HEAD)){
long lastModified =getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
}else if(method.equals(METHOD_POST)){
doPost(req, resp);
}else if(method.equals(METHOD_PUT)){
doPut(req, resp);
}else if(method.equals(METHOD_DELETE)){
doDelete(req, resp);
}else if(method.equals(METHOD_OPTIONS)){
doOptions(req,resp);
}else if(method.equals(METHOD_TRACE)){
doTrace(req,resp);
}else{
//
// Note that this means NO servlet supports whatever
// method was requested, anywhere on this server.
//
/
/到对应的请求类型就返回错误出去
String errMsg = String("hod_not_implemented");
Object[] errArgs =new Object[1];
errArgs[0]= method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}
进⼊具体⽅法,这⾥我们是进⼊doGet,这⾥只有⼀句代码
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
然后我好奇的看了⼀下其他请求类型是怎么样的,结果就是我们常⽤的4种类型GET、POST、PUT、DELETE的调⽤都是⼀样的
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected final void doPut(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected final void doDelete(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
我们接着⾛进⼊到processRequest⽅法⾥⾯去看,在这⾥我们将代码⾛到doService⽅法调⽤
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论