Go-net源码解析

Posted Dav-ove3

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go-net源码解析相关的知识,希望对你有一定的参考价值。

学习一门语言,那么我们必然要涉及到网络通信,而谈到网络通信却又离不开tcp,这里我们利用go标准库net来模拟一个服务端、客户端的流程,从而深入学习其中的代码流程(深入其中解析本质)

func main() 
	server, err := net.Listen("tcp", "127.0.0.1:8080") // 开启服务端
	if err != nil 
		log.Fatal(err)
	
	defer server.Close()

	go func()  // 模拟客户端往服务端发送数据
		coon, err := net.Dial("tcp", "127.0.0.1:8080")
		if err != nil 
			log.Fatal(err)
		
		defer coon.Close()
		coon.Write([]byte("hello world")) // 客户端发送数据
	()

	client, _ := server.Accept() // 接受客户端
	defer client.Close()

	fmt.Println("client addr: ", client.LocalAddr().String()) // 打印服务端地址
	var recv []byte = make([]byte, 100)
	client.Read(recv)
	//recv, _ := io.ReadAll(client)
	fmt.Println("server recv from client: ", string(recv)) // 打印客户端发送的数据

以上代码完成了一个简单的网络通信过程,那么我们就先从服务端入手吧,这里显而易见的是net.Listen("tcp", "127.0.0.1:8080")这个函数,我们可以猜想这个函数的处理流程应该是极其重要的,跟进看看:

func Listen(network, address string) (Listener, error) 
	var lc ListenConfig
	return lc.Listen(context.Background(), network, address) // 返回一个Listener接口

Listener接口必然映射这一个底层的结构体,那么我们就找到这个结构体分析一下:(跟入lc.Listen(context.Background(), network, address)函数

func (lc *ListenConfig) Listen(ctx context.Context, network, address string) (Listener, error) 
	addrs, err := DefaultResolver.resolveAddrList(ctx, "listen", network, address, nil)
	if err != nil 
		return nil, &OpErrorOp: "listen", Net: network, Source: nil, Addr: nil, Err: err
	
	sl := &sysListener // 实例化一个sysListener结构体
		ListenConfig: *lc,
		network:      network,
		address:      address,
	
	var l Listener
	la := addrs.first(isIPv4)
	switch la := la.(type)  // 检查监听的协议
	case *TCPAddr:
		l, err = sl.listenTCP(ctx, la) // 监听tcp,并设置l为TCPListener结构体
	case *UnixAddr:
		l, err = sl.listenUnix(ctx, la) // 设置l为UnixListener结构体
	default:
		return nil, &OpErrorOp: "listen", Net: sl.network, Source: nil, Addr: la, Err: &AddrErrorErr: "unexpected address type", Addr: address
	
	if err != nil 
		return nil, &OpErrorOp: "listen", Net: sl.network, Source: nil, Addr: la, Err: err // l is non-nil interface containing nil pointer
	
	return l, nil

而最终返回的结构体则是从sl.listenTCP(ctx, la)或者sl.listenUnix(ctx, la)得到的,那我们就由sl.listenTCP(ctx, la)来分析底层的结构体:

func (sl *sysListener) listenTCP(ctx context.Context, laddr *TCPAddr) (*TCPListener, error) 
	fd, err := internetSocket(ctx, sl.network, laddr, nil, syscall.SOCK_STREAM, 0, "listen", sl.ListenConfig.Control) // 相当于C语言之中的socket函数
	if err != nil 
		return nil, err
	
	return &TCPListenerfd: fd, lc: sl.ListenConfig, nil // 返回的是TCPListener结构体

其实际流程为初始化一个socket套接字,并封装于TCPListener结构体之中

type TCPListener struct 
	fd *netFD       // 套接字
	lc ListenConfig // TCP配置

type ListenConfig struct 
	Control func(network, address string, c syscall.RawConn) error
	KeepAlive time.Duration

那么上层使用的Accpet函数实际为:

func (l *TCPListener) Accept() (Conn, error) 
	if !l.ok() 
		return nil, syscall.EINVAL
	
	c, err := l.accept() // 开始监听,调用内部函数
	if err != nil 
		return nil, &OpErrorOp: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err
	
	return c, nil


func (ln *TCPListener) accept() (*TCPConn, error) 
	fd, err := ln.fd.accept() // 开始监听,对于netFD结构体的一层封装
	if err != nil 
		return nil, err
	
	tc := newTCPConn(fd)      // 返回tcp客户端,设置tc为TCPConn结构体
	if ln.lc.KeepAlive >= 0  // 如果持续存活
		setKeepAlive(fd, true)
		ka := ln.lc.KeepAlive
		if ln.lc.KeepAlive == 0 
			ka = defaultTCPKeepAlive
		
		setKeepAlivePeriod(fd, ka)
	
	return tc, nil

而返回结果则是tcp对于的一个客户端会话:

type TCPConn struct  // 实际上就是一个套接字,经过了层层(二层)封装
	conn

// TCPConn 继承于 conn,而conn是套接字的封装
type conn struct  // 对于套接字的一层封装,具有有读写等功能
	fd *netFD

同理,客户端对于服务端的连接流程大致一样,同样从net.Dial("tcp", "127.0.0.1:8080")开始分析:

func Dial(network, address string) (Conn, error) 
	var d Dialer                    // 拨号器
	return d.Dial(network, address) // connect封装


func (d *Dialer) Dial(network, address string) (Conn, error) 
	return d.DialContext(context.Background(), network, address)

// 关键函数如下
func (d *Dialer) DialContext(ctx context.Context, network, address string) (Conn, error) 
        ...
        c, err := sd.dialParallel(ctx, primaries, fallbacks) // 解析 `整个连接`
        ...

关键函数sd.dialParallel(ctx, primaries, fallbacks),如下:

func (sd *sysDialer) dialParallel(ctx context.Context, primaries, fallbacks addrList) (Conn, error) 
	if len(fallbacks) == 0 
		return sd.dialSerial(ctx, primaries)
	

	returned := make(chan struct)
	defer close(returned)

	type dialResult struct 
		Conn
		error
		primary bool
		done    bool
	
	results := make(chan dialResult) // unbuffered

	startRacer := func(ctx context.Context, primary bool) 
		ras := primaries
		if !primary 
			ras = fallbacks
		
		c, err := sd.dialSerial(ctx, ras) // 开始尝试连接
		select 
		case results <- dialResultConn: c, error: err, primary: primary, done: true: // 传输连接成功返回的结果
		case <-returned: //如果该函数应该返回,则释放资源
			if c != nil 
				c.Close()
			
		
	

	var primary, fallback dialResult

	// Start the main racer.
	primaryCtx, primaryCancel := context.WithCancel(ctx)
	defer primaryCancel()
	go startRacer(primaryCtx, true)

	// Start the timer for the fallback racer.
	fallbackTimer := time.NewTimer(sd.fallbackDelay())
	defer fallbackTimer.Stop()

	for  // 循环等待
		select 
		case <-fallbackTimer.C:
			fallbackCtx, fallbackCancel := context.WithCancel(ctx)
			defer fallbackCancel()
			go startRacer(fallbackCtx, false)

		case res := <-results: // 等待结果返回,实际为dialResult结构体
			if res.error == nil 
				return res.Conn, nil
			
			if res.primary 
				primary = res
			 else 
				fallback = res
			
			if primary.done && fallback.done 
				return nil, primary.error
			
			if res.primary && fallbackTimer.Stop() 
				// If we were able to stop the timer, that means it
				// was running (hadn\'t yet started the fallback), but
				// we just got an error on the primary path, so start
				// the fallback immediately (in 0 nanoseconds).
				fallbackTimer.Reset(0)
			
		
	

好了,现在我们可以看出来,net实际上就是对于socket的层层封装罢了

Spring 源码解析之HandlerAdapter源码解析

Spring 源码解析之HandlerAdapter源码解析(二)

前言

看这篇之前需要有Spring 源码解析之HandlerMapping源码解析(一)这篇的基础,这篇主要是把请求流程中的调用controller流程单独拿出来了

解决上篇文章遗留的问题

  1. getHandler(processedRequest) 这个方法是如何查找到对应处理的HandlerExecutionChain和HandlerMapping的,比如说静态资源的处理和请求的处理肯定是不同的HandlerMapping
  2. getHandlerAdapter(mappedHandler.getHandler());如果取到对应的HandlerAdapter

问题一

先来看DispatcherServlet中HandlerMapping初始化,从下属代码看来,其实HandlerMapping的初始化工作并不在DispatcherServlet,而是在Spring初始化的地方,这里只不过是把所有的HandlerMapping加载到DispatcherServlet中,并且排序生成集合


private void initHandlerMappings(ApplicationContext context) {
        this.handlerMappings = null;

        if (this.detectAllHandlerMappings) {
            // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
            //这里从BeanFactory中获取已经初始化好的HandlerMapping
            Map<String, HandlerMapping> matchingBeans =
                    BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
                // We keep HandlerMappings in sorted order.
                //对handlerMappings进行排序
                AnnotationAwareOrderComparator.sort(this.handlerMappings);
            }
        }
        else {
            try {
                HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
                this.handlerMappings = Collections.singletonList(hm);
            }
            catch (NoSuchBeanDefinitionException ex) {
                // Ignore, we'll add a default HandlerMapping later.
            }
        }

        // Ensure we have at least one HandlerMapping, by registering
        // a default HandlerMapping if no other mappings are found.
        if (this.handlerMappings == null) {
            this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
            if (logger.isDebugEnabled()) {
                logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
            }
        }
    }

接下来是查找适合的HandlerExecutionChain,从代码来看,上面的排序代码AnnotationAwareOrderComparator.sort(this.handlerMappings);是有很大用处的,从这段代码逻辑来看,其实是通过for循环优先找到排在最前面并且适合的HandlerExecutionChain,从上一篇《Spring 源码解析之HandlerMapping源码解析(一)》文章可知,我这里大概初始化了十种处理请求的handlerMappings,普通的页面请求和json请求都是通过RequestMappingHandlerMapping进行处理的

//DispatcherServlet中的getHandler
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        for (HandlerMapping hm : this.handlerMappings) {
            if (logger.isTraceEnabled()) {
                logger.trace(
                        "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
            }
            HandlerExecutionChain handler = hm.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
        return null;
    }

//RequestMappingHandlerMapping的父类AbstractHandlerMapping中实现了getHandler方法
@Override
    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        //调用子类AbstractHandlerMethodMapping getHandlerInternal()
        Object handler = getHandlerInternal(request);
        //如果没有获取到,就使用默认的
        if (handler == null) {
            handler = getDefaultHandler();
        }
        //如果默认的没有定义就返回null
        if (handler == null) {
            return null;
        }
        //说实话当时我看到源码里面的注释,当时我内心是崩溃的,Spring开发人员自己都不知道这个代码是做什么的,你难道是问我 - -
        //你tm一定是在逗我
        // Bean name or resolved handler?(这个英文注释是开发人员自己写的,不是我写上去的)
        //反正大概意思就是handler如果定义了一个字符串,那么根据这个name去查找Handler
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = getApplicationContext().getBean(handlerName);
        }
        //根据handlermethod获取相应的拦截器处理调用链
        HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
        if (CorsUtils.isCorsRequest(request)) {
            CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
            CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
            CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
            executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
        }
        return executionChain;
    }
 //AbstractHandlerMethodMapping 中实现AbstractHandlerMapping getHandlerInternal方法,去获取HandlerMethod
    protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
        //获取访问路径比如定义了路径/admin/login
        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
        if (logger.isDebugEnabled()) {
            logger.debug("Looking up handler method for path " + lookupPath);
        }
        //获取可读锁,暂时不知道用意在哪里
        this.mappingRegistry.acquireReadLock();
        try {
            HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
            if (logger.isDebugEnabled()) {
                if (handlerMethod != null) {
                    logger.debug("Returning handler method [" + handlerMethod + "]");
                }
                else {
                    logger.debug("Did not find handler method for [" + lookupPath + "]");
                }
            }
            return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
        }
        finally {
            //解锁
            this.mappingRegistry.releaseReadLock();
        }
    }
//AbstractHandlerMethodMapping 中根据路径查询到相应的Controller方法
    protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
        List<Match> matches = new ArrayList<Match>();
        //从注册的mappingRegistry中获取直接符合的
        List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
        //如果不等于null,添加符合的进去
        if (directPathMatches != null) {
            addMatchingMappings(directPathMatches, matches, request);
        }
        if (matches.isEmpty()) {
            // No choice but to go through all mappings...
            addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
        }

        if (!matches.isEmpty()) {
            Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
            Collections.sort(matches, comparator);
            if (logger.isTraceEnabled()) {
                logger.trace("Found " + matches.size() + " matching mapping(s) for [" +
                        lookupPath + "] : " + matches);
            }
            //排序后取第一个符合的
            Match bestMatch = matches.get(0);
          //如果符合处理请求HandlerMethod的数量大于1
            if (matches.size() > 1) {
                if (CorsUtils.isPreFlightRequest(request)) {
                    return PREFLIGHT_AMBIGUOUS_MATCH;
                }
                //判断第一个和第二个符合的,如果都一样 那么就抛出异常
                Match secondBestMatch = matches.get(1);
                if (comparator.compare(bestMatch, secondBestMatch) == 0) {
                    Method m1 = bestMatch.handlerMethod.getMethod();
                    Method m2 = secondBestMatch.handlerMethod.getMethod();
                    throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
                            request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
                }
            }
            // 存入request的attribute中,具体有什么用不太了解request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, lookupPath);
            handleMatch(bestMatch.mapping, lookupPath, request);
            //获取handlerMethod
            return bestMatch.handlerMethod;
        }
        else {
            return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
        }
    }

 //AbstractHandlerMapping中获取HandlerExecutionChain调用链
    protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
        HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
                (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

        String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
        for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
            if (interceptor instanceof MappedInterceptor) {
                MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
                if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                    chain.addInterceptor(mappedInterceptor.getInterceptor());
                }
            }
            else {
                chain.addInterceptor(interceptor);
            }
        }
        return chain;
    }

大致流程如上面代码,所示其实核心无非就是把url和controller里面的method关联起来,通过查找去找到合适的

问题二

如何根据合适的找到合适的HandlerAdapter,看看下面代码

//初始化就不继续讲拉,跟handpermapping一模一样,也是经过排序后的
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    //遍历所有的handlerAdapters
        for (HandlerAdapter ha : this.handlerAdapters) {
            if (logger.isTraceEnabled()) {
                logger.trace("Testing handler adapter [" + ha + "]");
            }
            //调用相应实现的support方法,排在最前面的优先调用
            if (ha.supports(handler)) {
                return ha;
            }
        }
        throw new ServletException("No adapter for handler [" + handler +
                "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    }
    //比如说`RequestMappingHandlerAdapter`的实现如下 ,用instanceof 来判断是否是HandlerMethod即可
    @Override
    public final boolean supports(Object handler) {
        return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
    }
    @Override
    protected boolean supportsInternal(HandlerMethod handlerMethod) {
        return true;
    }

从上面看来,其实想定义自己的HandlerAdapter也是可以的,只要把排序的Order设置大一些,优先找到自定义的HandlerAdapter即可

HandlerAdapter功能介绍

这里再次详细介绍一下HandlerAdapter,HandlerAdapter实现大概分为以下几种

1.RequestMappingHandlerAdapter(3.1之前是AnnotationMethodHandlerAdapter)

Renderings

这里我就直接先分析RequestMappingHandlerAdapter,大致类图如上所示,RequestMappingHandlerAdapter主要作用是调用相应的HandlerMethod,并把参数封装成具体method需要的格式,初始化的时候RequestMappingHandlerAdapter默认加载了如下的参数解析方式

private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
        List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
        // Annotation-based argument resolution
    //添加RequestParam 普通的参数解析@RequestParam 注解参数,但不处理参数类型为Map,且不包含value值
        resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
    //Resolves {@link Map} method arguments annotated with an @{@link RequestParam}
    //上述英文描述,大致就是说把参数解析成map的Resolver,解决了RequestParamMethodArgumentResolver不能解析成map的缺点
        resolvers.add(new RequestParamMapMethodArgumentResolver());
    //PathVariableMethod这个经常用spring的都知道,其实就是路径里面的参数,restful风格的参数
        resolvers.add(new PathVariableMethodArgumentResolver());
    //处理是参数类型是map的情况
    /**  @RequestMapping(value = "/index/article/{id:\\\\d+}",  produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String getArticleDetail(@PathVariable Map map) {
        int id=0;
    */
    //比如上面的id 转换到map中,就是key为 id value为具体值
        resolvers.add(new PathVariableMapMethodArgumentResolver());
    //spring 3.2后增加的注解@MatrixVariable的解析,是 @PathVariable的一种辅助注解,具体可以百度下看看使用方式
        resolvers.add(new MatrixVariableMethodArgumentResolver());
        resolvers.add(new MatrixVariableMapMethodArgumentResolver());
    //Also adds a fall-back strategy to instantiate the model attribute from a URI template variable or from a request parameter if the name matches the model attribute name and there is an appropriate type conversion strategy.
    //上述英文是Spring文档里面对这个类的描述,大概意思就是request的attribute name名跟model的属性名相同的时候
        resolvers.add(new ServletModelAttributeMethodProcessor(false));
    //@RequestBody和@ResponseBody 注解的解析
        resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
    //Supported method argument types include MultipartFile
    //这个主要是文件上传的解析,文件上传的时候可以指定名字,支持@RequestPart
        resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
    //支持@RequestHeader
        resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
    //支持@RequestHeader map参数类型
        resolvers.add(new RequestHeaderMapMethodArgumentResolver());
    //支持Cookie参数
        resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
    //支持注解@Value
        resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));

    //上面都是基于注解的解析,下面都是基于参数名称的解析
        // Type-based argument resolution
    /**
    Resolves request-related method argument values of the following types:
    WebRequest
    ServletRequest
    MultipartRequest
    HttpSession
    Principal
    Locale
    TimeZone (as of Spring 4.0)
    ZoneId (as of Spring 4.0 and Java 8)
    InputStream
    Reader
    HttpMethod (as of Spring 4.0)
    **/
    //这个主要是解析上面的参数
        resolvers.add(new ServletRequestMethodArgumentResolver());
    //处理返回类型
    /**
    * ServletResponse
    * OutputStream
    * Writer
    **/
        resolvers.add(new ServletResponseMethodArgumentResolver());
    //解析 HttpEntity RequestEntity
        resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
    //Resolves  RedirectAttributes
        resolvers.add(new RedirectAttributesMethodArgumentResolver());
    //Resolves  Model arguments and handles  Model return values
    //解析Model参数
        resolvers.add(new ModelMethodProcessor());
    //Resolves  Map method arguments and handles  Map return values.
        resolvers.add(new MapMethodProcessor());
    // Resolves Errors method arguments
        resolvers.add(new ErrorsMethodArgumentResolver());
    //Resolves a SessionStatus argument
        resolvers.add(new SessionStatusMethodArgumentResolver());
    // Resolvers argument values of type  UriComponentsBuilder
        resolvers.add(new UriComponentsBuilderMethodArgumentResolver());

        // Custom arguments
    //这里可以自己实现getCustomArgumentResolvers() 去定义自己的参数实现
        if (getCustomArgumentResolvers() != null) {
            resolvers.addAll(getCustomArgumentResolvers());
        }

        // Catch-all
    //Resolves method arguments annotated with  @RequestParam
        resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
    //Resolves 参数包含注解ModelAttribute
        resolvers.add(new ServletModelAttributeMethodProcessor(true));

        return resolvers;
    }

通过上述的代码表明,RequestMappingHandlerAdapter封装了所有的参数解析,继续看核心内容,handlerAdapter对方法的调用逻辑如下

@Override
    protected ModelAndView handleInternal(HttpServletRequest request,
            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

        ModelAndView mav = null;
    //校验该请求的method是否支持, 也就是这上面支持的方法@RequestMapping(value = "edit/save", method = RequestMethod.POST)
        checkRequest(request);

        // Execute invokeHandlerMethod in synchronized block if required.
    //是否采用session 锁,这块暂时没有找到在哪用,倒是可以通过配置bean的方式来实现,下面是 英文的解释
    /**
    Set if controller execution should be synchronized on the session, to serialize parallel invocations from the same client.
    More specifically, the execution of the handleRequestInternal method will get synchronized if this flag is "true". The best available session mutex will be used for the synchronization; ideally, this will be a mutex exposed by HttpSessionMutexListener.

    The session mutex is guaranteed to be the same object during the entire lifetime of the session, available under the key defined by the SESSION_MUTEX_ATTRIBUTE constant. It serves as a safe reference to synchronize on for locking on the current session.

    In many cases, the HttpSession reference itself is a safe mutex as well, since it will always be the same object reference for the same active logical session. However, this is not guaranteed across different servlet containers; the only 100% safe way is a session mutex.
    */
        if (this.synchronizeOnSession) {
            HttpSession session = request.getSession(false);
            if (session != null) {
                Object mutex = WebUtils.getSessionMutex(session);
                synchronized (mutex) {
          //具体的方法调用处
                    mav = invokeHandlerMethod(request, response, handlerMethod);
                }
            }
        }
    //这块感觉跟上面的逻辑有点重复,如果加了锁并且锁住了上面执行一遍invokeHandlerMethod 这里还会执行一遍invokeHandlerMethod,无论做了什么操作,性能上会有一些下降吧,个人看法
        mav = invokeHandlerMethod(request, response, handlerMethod);

        if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
            applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
        }
        else {
            prepareResponse(response);
        }

        return mav;
    }

invokeHandlerMethod(request, response, handlerMethod) 是具体调用Controller的部分


protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
      ///包装一下request, response 提供一些操作方法
        ServletWebRequest webRequest = new ServletWebRequest(request, response);
    //获取到DataBinderFactory(这里创建的是ServletRequestDataBinderFactory) 也就是经常使用的@InitBinder,这里以后会单独留一个模块出来进行讲解
        WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
    //Provides methods to initialize the  Model before controller method invocation and to update it afterwards
        ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

        ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
        invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
        invocableMethod.setDataBinderFactory(binderFactory);
        invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

        ModelAndViewContainer mavContainer = new ModelAndViewContainer();
        mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
        modelFactory.initModel(webRequest, mavContainer, invocableMethod);
        mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

        //这里是异步请求的管理,这里暂时不做介绍,对正常的同步请求没有影响
        AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
        asyncWebRequest.setTimeout(this.asyncRequestTimeout);

        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        asyncManager.setTaskExecutor(this.taskExecutor);
        asyncManager.setAsyncWebRequest(asyncWebRequest);
        asyncManager.registerCallableInterceptors(this.callableInterceptors);
        asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

        if (asyncManager.hasConcurrentResult()) {
            Object result = asyncManager.getConcurrentResult();
            mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
            asyncManager.clearConcurrentResult();
            if (logger.isDebugEnabled()) {
                logger.debug("Found concurrent result value [" + result + "]");
            }
            invocableMethod = invocableMethod.wrapConcurrentResult(result);
        }

        //这里调用具体的方法
        invocableMethod.invokeAndHandle(webRequest, mavContainer);
        if (asyncManager.isConcurrentHandlingStarted()) {
            return null;
        }
        //返回响应的ModelAndView对象
        return getModelAndView(mavContainer, modelFactory, webRequest);
    }

上面调用了invocableMethod.invokeAndHandle(webRequest, mavContainer),这个方法在ServletInvocableHandlerMethod中具体实现如下


public void invokeAndHandle(ServletWebRequest webRequest,
            ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
        //调用invokeForRequest实现去具体调用controller方法
        Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
        //设置response状态
        setResponseStatus(webRequest);

        if (returnValue == null) {
            if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
                mavContainer.setRequestHandled(true);
                return;
            }
        }
        else if (StringUtils.hasText(this.responseReason)) {
            mavContainer.setRequestHandled(true);
            return;
        }

        mavContainer.setRequestHandled(false);
        try {
            this.returnValueHandlers.handleReturnValue(
                    returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
        }
        catch (Exception ex) {
            if (logger.isTraceEnabled()) {
                logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
            }
            throw ex;
        }
    }
    //主要解析方法参数,然后调用真正的反射方法
    public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
                Object... providedArgs) throws Exception {
            //通过之前的参数解析器把参数解析成相应的各个对象
            Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
            if (logger.isTraceEnabled()) {
                StringBuilder sb = new StringBuilder("Invoking [");
                sb.append(getBeanType().getSimpleName()).append(".");
                sb.append(getMethod().getName()).append("] method with arguments ");
                sb.append(Arrays.asList(args));
                logger.trace(sb.toString());
            }
            //进行方法的调用
            Object returnValue = doInvoke(args);
            if (logger.isTraceEnabled()) {
                logger.trace("Method [" + getMethod().getName() + "] returned [" + returnValue + "]");
            }
            return returnValue;
        }
        //doInvoke才是真正调用方法的地方
        protected Object doInvoke(Object... args) throws Exception {
            //先通过设置方法的访问权限,用过反射的都知道先setAccessible为true
                ReflectionUtils.makeAccessible(getBridgedMethod());
                try {
                    //执行调用
                    return getBridgedMethod().invoke(getBean(), args);
                }
                catch (IllegalArgumentException ex) {
                    assertTargetBean(getBridgedMethod(), getBean(), args);
                    String message = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
                    throw new IllegalStateException(getInvocationErrorMessage(message, args), ex);
                }
                catch (InvocationTargetException ex) {
                    // Unwrap for HandlerExceptionResolvers ...
                    Throwable targetException = ex.getTargetException();
                    if (targetException instanceof RuntimeException) {
                        throw (RuntimeException) targetException;
                    }
                    else if (targetException instanceof Error) {
                        throw (Error) targetException;
                    }
                    else if (targetException instanceof Exception) {
                        throw (Exception) targetException;
                    }
                    else {
                        String msg = getInvocationErrorMessage("Failed to invoke controller method", args);
                        throw new IllegalStateException(msg, targetException);
                    }
                }
            }

2.SimpleServletHandlerAdapter

看名字就能够大致猜到这个类的作用,SimpleServletHandlerAdapter 从翻译上来说叫做简单的Servlet处理适配器,源码如下所示,看起来确实没有几句代码,大致英文解释(Adapter to use the Servlet interface with the generic DispatcherServlet.Calls the Servlet’s {@code service} method to handle a request)。大概就是说可以用Spring去管理Servlet,这样就可以在Spring中使用Servlet,这就是说Servlet可以使用ioc和aop的一些功能了,但是感觉这样的使用场景并不多,所以也很少使用,其次还有另外一种使用Spring管理Servlet的方式,就是采用全注解配置DispatcherServlet的方式,所以感觉这个adapter没有太大用处


public class SimpleServletHandlerAdapter implements HandlerAdapter {

    @Override
    public boolean supports(Object handler) {
        return (handler instanceof Servlet);
    }

    @Override
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        ((Servlet) handler).service(request, response);
        return null;
    }

    @Override
    public long getLastModified(HttpServletRequest request, Object handler) {
        return -1;
    }

}

参照网上的实习代码如下所示,servlet的bean name代表了请求路径:


<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    
    xmlns:context="http://www.springframework.org/schema/context"  
    xmlns:ehcache="http://www.springmodules.org/schema/ehcache"  
    xsi:schemaLocation="  
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd  
            http://www.springmodules.org/schema/ehcache http://www.springmodules.org/schema/cache/springmodules-ehcache.xsd"  
            default-lazy-init="true">  


    <!--启用注解   定义组件查找规则 -->  
    <context:component-scan base-package="com.demo">  
        <context:include-filter type="annotation"  
            expression="org.springframework.stereotype.Service" />  
    </context:component-scan>  

    <!-- servlet适配器,这里必须明确声明,因为spring默认没有初始化该适配器 -->  
    <bean id="servletHandlerAdapter" class="org.springframework.web.servlet.handler.SimpleServletHandlerAdapter"/>  


    <!-- demo servlet -->  
    <bean name="/demo.do" class="com.demo.DemoServlet"/>  

</beans>

3.SimpleControllerHandlerAdapter

The Controller interface is explicitly designed to operate on HttpServletRequest and HttpServletResponse objects, just like an HttpServlet. It does not aim to decouple itself from the Servlet API
上面英文大概意思就是,让Controller的用法像使用servlet一样,需要Controller实现Controller接口,实现代码如下,无非就是直接调用Controller方法

public class SimpleControllerHandlerAdapter implements HandlerAdapter {

    @Override
    public boolean supports(Object handler) {
        return (handler instanceof Controller);
    }

    @Override
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        return ((Controller) handler).handleRequest(request, response);
    }

    @Override
    public long getLastModified(HttpServletRequest request, Object handler) {
        if (handler instanceof LastModified) {
            return ((LastModified) handler).getLastModified(request);
        }
        return -1L;
    }

}

总结

本文在这次介绍中总共留下几个流程没有讲述,在接下来的里面会更详细的介绍
1. WebDataBinderFactory 也就是@InitBinder实现的流程?
2. WebAsyncManager 和AsyncWebRequest 这些都是异步请求的管理?
3. Spring是如何知道请求对应Controller的方法的?
4. Spring模板的渲染机制?

其他地方如果读者有问题可以随时联系,你的问题也许是我没有考虑到的地方。

欢迎查看下篇文章Spring 源码解析之HandlerAdapter源码解析(三)

以上是关于Go-net源码解析的主要内容,如果未能解决你的问题,请参考以下文章

Spring 源码解析之HandlerAdapter源码解析

spring系统架构源码解析AutowireCandidateResolver

Netty 源码解析 ——— ChannelConfig 和 Attribute

源码解析:Spring源码解析笔记

Spring 源码解析之ViewResolver源码解析

Spring 源码解析之ViewResolver源码解析