Spring MVC源码剖析系列(2) - DispatcherServlet工作原理之HandlerMapping

在本系列的第一篇,我剖析了DispatcherServlet的初始化过程,但还有很多东西没有说清楚,比如HandlerMapping的具体初始化,本篇就来厘清它。 如果你没有显式指定(通过xml配置文件或者Annotation)你要用的HandlerMapping类的话,DispatcherServlet默认会去classpath底下找DispatcherServlet.properties这个文件,然后从这个文件中读取出HandlerMapping类,并实例化对象。 DispatcherServlet.properties文件如下:(这里用的是4.3.9.release版本的Spring-MVC,里面的那个DefaultAnnotationHandlerMapping已经被Deprecated了,更新的版本是用的RequestMappingHandlerMapping,但这并不影响我们的分析): 我们先看一下DefaultAnnotationHandlerMapping类的继承关系: 我们看到这个DefaultAnnotationHandlerMapping最后其实是实现了ApplicationContextAware这个接口,我们要记住这个,因为它在后面会发挥重要的作用。 我们这里关注的是, »

Read More

Jetty源码剖析系列(7) - 底层网络通信的细节

我们先来回顾一下Jetty负责网络连接的类ServerConnector的构造函数: 可以看到在ServerConnector的构造函数里会创建一个SelectorManager,然后加到它的bean里面(这里其实体现了Jetty的一个设计模式,就是设计了一个containner,把相关的模块放到这个containner里面,启动该container(调用doStart方法)就会连带启动里面的模块(调用模块的doStart方法), Jetty里面的Server,Connector都是这样的containner。) 我们再来看newSelectorManager方法: 就是创建一个ServerConnectorManager对象,ServerConnectorManager继承了SelectorManager类: ,我们再看一下SelectorManager的doStart方法: 可以看到在调用父类的doStart方法之前,会创建ManagedSelector,并将该selector加到SelectorManager的bean里面,随后再在调用父类的doStart方法时调用该selector的doStart方法,注意selector的数目是根据CPU的数量计算出来的, newSelector方法其实就是直接构建一个ManagedSelector对象: 我们看一下ManagedSelector的构造函数: 关于ManagedSelector,我在系列(4) »

Read More

Spring MVC源码剖析系列(1) - DispatcherServlet工作原理之初始化

最近接手一个项目,用的是SpringMVC框架。循例想剖析一下它的源码,以求更深刻地理解MVC的实现。 DispatcherServlet是SpringMVC最核心的类,就拿它开刀:) 在web.xml中定义DispatcherServlet和它的Mapping: DispatcherServlet继承于FrameworkServlet,而FrameworkServlet又继承于HttpServletBean, HttpServletBean再继承于HttpServlet: DispatcherServlet有一段静态代码块值得关注: 它会到ClassPath下加载一个叫DispatcherServlet.properties的文件的内容,在SpringMVC的jar包里面有这个文件: 你可以理解为SpringMVC为你预先定义好一些后面有可能会用到的类。 Servlet容器(如Jetty)会调用Servlet的init方法,在这里,HttpServletBean重写了init()方法如下: 上面方法中值得注意的是调用了initServletBean方法,这个方法在FrameworkServlet中被重写了: 我们看到这里将会通过调用initWebApplicationContext方法来初始化一个webApplicationContext,这个非常重要, »

Read More

Jetty源码剖析系列(6) - Connector与ServerSocket

本文主要从源代码的角度来分析Jetty的Connector如何通过ServerSocket来绑定和监听网络地址和端口的过程。 Jetty的Connector实现类是ServerConnector,循例从它的doStart()方法开始(至于是如何到达这个方法,请移步本系列的前几篇): 它的doStart方法先调用父类AbstractNetworkConnector的doStart方法: 在父类的doStart方法里面会调用子类实现的open方法,此处是ServerConnector的open方法: 到这里已经可以看到Jetty的Connector与Java NIO的关系了,将会调用openAcceptChannel方法来构建一个NIO的ServerSocketChannel: 从上图的代码我们可以看到,Jetty默认用Java NIO来实现了它的网络框架,另外一点就是,如果你用java来实现一套网络框架,无非就是BIO和NIO两种,返朴归真。 先常规调用ServerSocketChannel的静态方法open方法来打开一个ServerSocketChannel: 因为Java的NIO是基于Selector来实现的,所以在这里会通过SelectorProvider类的静态方法provider来加载Selector的实现类: 它先尝试从System Property里加载Selector的实现类并实例化: 如果没有的话,就尝试通过SPI的方式来加载Selector的实现类并实例化: »

Read More

Jetty源码剖析系列(4)-Connector如何接收处理网络请求

书接上文,上文分析到ServerConnector的doStart方法会根据CPU的数量协调出一定数量的Acceptor,然后再把Acceptor交给线程池去执行: AbstractConnector.doStart(): Acceptor实现了Runnable接口,进去看它的run方法: 我们注意到它在while循环里面调用了accept方法,这个方法就是接收网络请求的入口了: 从上图的accept方法我们可以看到,它实际上就是调用了ServerSocketChannel的accept方法,我们终于回归到了NIO的基本,注意ServerSocketChannel的accept方法是阻塞的,直到接收到一个建立连接的请求,它就会返回一个SocketChannel,然后调用accepted方法,继续进入accepted方法看看: 先把SocketChannel设置为nonBlocking的,然后从SocketChannel里拿出Socket设置一些TCP属性: 比如会把该socket设置为TCP_NODELAY,这个是要disable Nagle's algorithm。设置完Socket后,就会调用SelectorManager的accept方法: »

Read More

Jetty源码剖析系列(3)-Connector如何接收处理网络请求

在本系列的第一篇提到,Jetty由Connector组件负责接收网络请求,如下图: ServerConnector是Jetty Connector的实现类,我们直接看它的doStart方法: 它先是调用了父类AbstractNetworkConnector的doStart方法: 这个父类的doStart方法先是调用了open方法,注意这里实际调用的是ServerConnector实现的open方法: 它先是调用openAcceptChannel方法来创建一个NIO的ServerSocketChannel: 上面的就是一个经典的NIO ServerSocketChannel创建过程:先是ServerSocketChannel.open(),然后再把ServerSocketChannel的ServerSocket绑定到相应的InetSocketAddress,熟悉的配方,熟悉的味道:) 再回到ServerConnector的open方法,它拿到这个ServerSocketChannel后,会调用它的configureBlocking方法,把它设置为阻塞的,这里其实是为了设置它的ServerSocket在调用accept方法的时是阻塞模式(即调用accept方法就会进入线程阻塞直到有网络连接进来)。 我们再回到AbstractNetworkConnector的doStart方法,当它执行完open方法打开ServerSocketChannel后,接着会调用它的父类AbstractConnector的doStart方法: »

Read More

Scalable IO in Java解读

大神Doug Lea的Scalable IO in Java,篇幅虽短,但大家之作,高屋建瓴,有如内功心法。每当我在对NIO的一些东西不甚了解的时候,翻出它来仔细研读,总能找到我想要的答案。 当今基于TCPIP的网络应用服务(分布式?),大多数都有着类似的结构(流程): 从底层IO读取网络字节请求 把读取的网络字节请求进行解码,封装成为业务请求对象 对解码封装后的业务请求对象进行业务处理 将业务逻辑处理完后的响应进行编码为底层IO可传输的字节响应 利用底层IO发送已编码的字节响应 整体流程如上图所示,但具体每一步所用到的技术手段有可能都不一样,比如解码协议是自定义的还是业界流行的?(比如是用XML还是JSON, »

Read More

旧文一篇-我的2015之跳槽

2015年年底我从HSBC跳槽出来后,在我原来的博客写下了这篇文章,当时被黑客派收录,但后来我的VPS被黑了后,博客也挂了,也没有存档,所以 我也早就忘了我还写过这篇文章。 后来我进爱立信广研的时候,这篇文章不知道被哪位同事在黑客派看到然后发到广研的微信大群里面,结果让我好生尴尬。 时光荏苒,岁月如梭,光阴似箭,白驹过隙,斗转星移,潜龙勿用,亢龙有悔,How time flies..... 又逢岁末,自然不能免俗地想来做个年终总结,今天又恰好是我在爱立信广州研发中心工作了整整一个月,就应景总结一下这次的跳槽历程。 其实我想离开 »

Read More