spring源码深度解析
‘壹’ 大家能给推荐几本学习java的书籍吧
如果不是初学者 进阶阶段 Java Cook Book》- 非常推荐* (包含了Java编程的Tips,适合当做手册来查阅) 《O’reilly-Java IO》- 推荐* (包含Java IO编程的各个方面) 《O’reilly-Database Programming with JDBC》- 推荐* (JDBC编程) 《O’reilly-Java Programming with Oracle JDBC》- 参考* 进一步深造可供选择Java Web编程 《O’reilly-Java Server Pages》- 强烈推荐* 《O’reilly-Java Servlet Programming》- 非常推荐* 《O’reilly-Jakarta Struts》- 推荐* (Java Web编程的一个MVC实现框架Struts的书) EJB编程 《J2EE应用与BEA Weblogic Server》- 强烈推荐 《Mastering EJB 2.0》- 非常推荐* 《Enterprise Java Bean》- 推荐* Java XML编程 《O’reilly-Java and XML》- 推荐* 《O’reilly-Java and SOAP》- 参考* (Java的SOAP编程) 设计模式 《Core J2EE Patterns》- 强烈推荐* (J2EE设计模式,设计企业应用软件必备参考书) 《EJB Design Patterns》- 推荐* 其它 《O’reilly Ant - The Definitive Guide》- 推荐* (Ant是一种功能非常强大的Java工具)
‘贰’ spring源码怎么读
在我们的生活之中,有形形色色的万物(Object),有飞机,有汽车,有轮船,还有我这个沧海一粟的java讲师。
试问:了解飞机底层架构的人,就一定能把飞机开好吗?精通汽车的构造和底层原理的人,就保证开车不出事故吗?或者反过来问,一个多年的开出租车的老司机,技术非常娴熟,但是你问他汽车的架构和底层原理,你觉得有多少老司机能准确的答出来?
那就对了,了解了,读懂了spring底层源码的程序员,我们并不能保证他就是一个好程序员,我心中的一个好的程序员是要能够提出解决方案的程序员,就好比清华北大确实只是个过程,最后的目的,是为国家为人民做出奉献才是我们活着的价值。所以说我并不看好去阅读spring源码这个行为。闻道有先后,术业有专攻,我们不是提供底层技术的人!绝大多数的程序员,我以为正确的做法是站在巨人的肩膀上,把前辈留下来的精髓发扬光大才是正道,简而言之,把怎么用,和为什么要这么用学好才是大多数程序员学习技术的关键。就好比去学驾照的时候,教练只需要关心你是否会开车,是否遵守交通规则,并不关心你是否了解汽车是如何在路上跑起来的。
一个人的精力和时间都是有限的,分细了来说,开发者就是技术的使用者,重点在于如何正确熟练的使用,而不是一昧地去关心底层原理,如果要完全读懂spring源码,首先,英语就得很厉害吧,其次,得花多少时间?就算读懂了,那收获和付出也不成正比,大把大把的时间为何不花在java更多,更高级,更有意义的技术上呢?笔者此话并不是说spring源码读了没用,只是让我们的时间更有价值,例如分布式微服务,区块链技术,大数据,python,作为新时代的IT佼佼者,我们是否应该随着时代的脚步,迎接崭新的未来?我奉劝大多数人,不必去看spring源码,除非你确实感兴趣作为技术研究,这样是可以的。一个正常的工作者,是不建议花宝贵的时间去看的,那学生就更不应该去看了。此话怎讲?我以为,学生应以学业为重,士不可不弘毅,任重而道远,首先应该扩展其知识的广度,和技术的娴熟使用,再培养学生独立解决问题的能力,沟通协作的能力,最后才考虑技术的深度。
笔者在多年前也被面试过很多很多问题,但是从来没有一个面试官会问spring底层源码,曾经阿里巴巴的架构师也面试过我,直到后来,我成为了面试官,当我去面试别人的时候,我也不会去问spring源码这些东西,因为99.9%企业招人进来,是要做事实的,不是让你去研究一个技术,绝大多数更在乎的是利用现有的技术,去完成一些项目功能。除了世界上极少数着名的企业他们需要技术研究员,才对这些有所要求,那要招这类人才,估计至少也是名校研究生以上吧,所以普通程序开发者,我觉得学好技术的正确与熟练使用,才是重中之重!
不宜本末倒置,不宜好高骛远。笔者从事Java行业以来,真要说全阶段全程全栈都精通的人,应属风毛菱角,故此,更应让所学知识运筹帷幄,举一反三,千里炉火,万里纯青。以上篇幅在说我对阅读spring源码的一些强烈建议,最终结论,是不看、不读就此作罢。
那有的感兴趣的人非要阅读呢?
Ok,其实阅读spring源码并不算很难。
首先,应该去官网spring.io阅读写spring框架的理念,就好比读一本书,要阅读这本书的纲要,要明白为什么要设计spring架构。
然后,应该分模块阅读,先从核心模块开始阅读:如:
IoC Container, Events, Resources, i18n, Validation, Data Binding, Type Conversion, SpEL, AOP.
那么在阅读的时候,英文能力差的话,可以使用翻译软件翻译成中文阅读,毕竟不是每个程序员英语都很棒,毕竟中国人看中国字更容易去理解。当然,有些翻译过来的并不准确,这个时候可以利用网络,去查看那段不理解的地方。
然后,把spring的jar包下载下来,利用IDEA打开,可以使用download资源,会发现,每个方法上面都会有详细的英文注释。一边看官方的说明,一边查看代码的编写,不难发现,非常多的代码写得很精辟,所以十分考验一个程序员的java基本功,特别是反射,JDK\CGLIB代理,和java常用的设计模式等。
‘叁’ 详解Spring mvc工作原理及源码分析
Model 模型层 (javaBean组件 = 领域模型(javaBean) + 业务层 + 持久层)
View 视图层( html、jsp…)
Controller 控制层(委托模型层进行数据处理)
springmvc是一个web层mvc框架,类似struts2。
springmvc是spring的部分,其实就是spring在原有基础上,又提供了web应用的mvc模块。
实现机制:
struts2是基于过滤器实现的。
springmvc是基于servlet实现的。
运行速度:
因为过滤器底层是servlet,所以springmvc的运行速度会稍微比structs2快。
struts2是多例的
springmvc单例的
参数封装:
struts2参数封装是基于属性进行封装。
springmvc是基于方法封装。颗粒度更细。
⑴ 用户发送请求至DispatcherServlet。
⑵ DispatcherServlet收到请求调用HandlerMapping查询具体的Handler。
⑶ HandlerMapping找到具体的处理器(具体配置的是哪个处理器的实现类),生成处理器对象及处理器拦截器(HandlerExcutorChain包含了Handler以及拦截器集合)返回给DispatcherServlet。
⑷ DispatcherServlet接收到HandlerMapping返回的HandlerExcutorChain后,调用HandlerAdapter请求执行具体的Handler(Controller)。
⑸ HandlerAdapter经过适配调用具体的Handler(Controller即后端控制器)。
⑹ Controller执行完成返回ModelAndView(其中包含逻辑视图和数据)给HandlerAdaptor。
⑺ HandlerAdaptor再将ModelAndView返回给DispatcherServlet。
⑻ DispatcherServlet请求视图解析器ViewReslover解析ModelAndView。
⑼ ViewReslover解析后返回具体View(物理视图)到DispatcherServlet。
⑽ DispatcherServlet请求渲染视图(即将模型数据填充至视图中) 根据View进行渲染视图。
⑾ 将渲染后的视图返回给DispatcherServlet。
⑿ DispatcherServlet将响应结果返回给用户。
(1)前端控制器DispatcherServlet(配置即可)
功能:中央处理器,接收请求,自己不做任何处理,而是将请求发送给其他组件进行处理。DispatcherServlet 是整个流程的控制中心。
(2)处理器映射器HandlerMapping(配置即可)
功能:根据DispatcherServlet发送的url请求路径查找Handler
常见的处理器映射器:BeanNameUrlHandlerMapping,SimpleUrlHandlerMapping,
,(不建议使用)
(3)处理器适配器HandlerAdapter(配置即可)
功能:按照特定规则(HandlerAdapter要求的规则)去执行Handler。
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展多个适配器对更多类型的处理器进行执行。
常见的处理器适配器:HttpRequestHandlerAdapter,,
(4)处理器Handler即Controller(程序猿编写)
功能:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler。
(5)视图解析器ViewReslover(配置即可)
功能:进行视图解析,根据逻辑视图名解析成真正的视图。
ViewResolver负责将处理结果生成View视图,ViewResolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。
springmvc框架提供了多种View视图类型,如:jstlView、freemarkerView、pdfView...
(6)视图View(程序猿编写)
View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf...)
引入相关依赖:spring的基本包、springmvc需要的spring-webmvc,日志相关的slf4j-log4j12,jsp相关的jstl、servlet-api、jsp-api。
因为DispatcherServlet本身就是一个Servlet,所以需要在web.xml配置。
一、使用默认加载springmvc配置文件的方式,必须按照以下规范:
①命名规则:-servlet.xml ====> springmvc-servlet.xml
②路径规则:-servlet.xml必须放在WEB-INF下边
二、如果要不按照默认加载位置,则需要在web.xml中通过标签来指定springmvc配置文件的加载路径,如上图所示。
将自定义的 Controller 处理器配置到 spring 容器中交由 spring 容器来管理,因为这里的 springmvc.xml 配置文件中处理器映射器配置的是 BeanNameUrlHandlerMapping ,根据名字可知这个处理器映射器是根据 bean (自定义Controller) 的 name 属性值url去寻找执行类 Handler(Controller) , 所以bean的name属性值即是要和用户发送的请求路径匹配的 url 。
根据视图解析路径:WEB-INF/jsps/index.jsp
功能:根据bean(自定义Controller)的name属性的url去寻找执行类Controller。
功能:自定义的处理器(Controller)实现了Controller接口时,适配器就会执行Controller的具体方法。
会自动判断自定义的处理器(Controller)是否实现了Controller接口,如果是,它将会自动调用处理器的handleRequest方法。
Controller接口中有一个方法叫handleRequest,也就是处理器方法。
因此,自定义的Controller要想被调用就必须实现Controller接口,重写Controller接口中的处理器方法。
‘肆’ Spring源码解析(一)- 容器的基本实现
Spring使用 基本的JavaBean 来完成以前只可能由EJB完成的事情,是个分层架构。Spring创建bean都需要通过 读取 、 解析 、 校验配置文件, 然后注册创建成Bean。 Spring是一个Bean容器 , 主要作用是替我们管理bean对象 (简单的Java类对象的生命周期)。不管框架如何强大,还是需要我们程序员来告诉其一些必要信息的(比如要 管理的bean对象的类相关信息、是否开启组件扫档纳描 等),这些我们称之为对 Spring框架的配置 ,目前主流的配置方式是 通过使用配置文件或注解。
Spring中最核心的两个源雀类: DefaultListableBeanFactory、XmlBeanDifinitionReader。DefaultListableBeanFactory 是整个bean加载的核心部分,是Spring注册及加载bean的默认实现 。XmlBeanDefinitionReader 主要使用reader属性对资源文件进行读取和注册。
XML配置文件读取是Spring中重要的功能,大部分Spring大部分功能都是 以配置作为切入点 。 XmlBeanFactory 继承自 DefaultListableBeanFactory ,而对于 DefaultListableBeanFactory 不同的地方其实是在 XmlBeanFactory 中使用了自定义的XML读取器 XmlBeanDefinitionReader ,主要用于从XML文档中读取 BeanDefinition, 实现了个性化的 BeanDefinitionReader 读取, DefaultListableBeanFactory 继承了 并实现了 以及 BeanDefinitionRegistry 接口。
Spring的配置文件读取是通过ClasaPathResource进行封装的 ,如:new ClassPathResource("bean.xml")。在java中, 将不同来源的资源的读取逻辑抽象成URL ,通过注册不同的 handler来处理。 一般handler的类型使用不同的前缀,URL没有默认定义相对的path路径,也 没有提供相关方法对资源进行检查 ,顾Spring对其内部需要使用到的资源做了属于自己的抽象结构, 用Resource接口来封装底层资源。
Resource 接口继承 InputStreamSource(封装了任何能返回InputStream的类)。
Resource接口抽象了所有Spring内部使用到的底层资源 ,首先它定义了3个能判断当前资源状态的方法: 存在性(exists)、可读性(isReadable)、是否处于打开状态(isOpen) 。有了Resource接口便可以对所有资源进行统一处理。 ClassPathResource 中的实现是通过class或 classLoader 提供的底层方法进行调用。以此完成对配置文件资源的封装。
当通过Resource相关类完成了对配置文件进行封装,接下来由 XmlBeanDefinitionReader 完成对配置文件的读取工作。雹蠢早
XML文件的验证模式有两种:DTD、XSD(XML Schema).
DTD即文档类型定义, 是一种XML约束模式语言,是XML文件的验证机制 。是一种保证XML文档格式正确的有效方法, 可以通过比较XML文档和DTD文件来查看文档是否符合规范,元素和标签的使用是否正确 。一个DTD文档包含:元素的定义规则、元素间关系的定义规则、元素可使用的属性、可使用的实体或符号规则。 要使用DTD验证模式需要在XML文件的头部声明。
XML Schema语言就是XSD。 XML Schema描述了XML文档的结构。可以用一个指定的XML Schema来验证某个XML文档,以检查该XML文档是否符合其要求。也可以 通过XML Schema指定一个XML文档所允许的结构和内容 。XML Schema本身也是一个XML文档,符合XML语法结构,可以用通用的XML解析器解析它。
使用XML Schema文档对XML实例进行校验,要声明名称空间和指定该名称空间所对应的XML Schema文档存储位置 。通过schemaLocation属性来指定名称空间所对应的XML Schema文档的存储地址(1、名称空间URL;2、该名称空间所标识的XML Schema文件地址或URL地址)。
另外验证模式通过 XmlBeanDefinitionReader 中的setValidationMode方法进行设定。而 Spring 用来检测验证模式的方法实际上就是判断是否包含 DOCTYPE ,如果包含就是 DTD ,否则就是 XSD 。
XML文件经过验证模式,交由DocumentLoader进行解析成对应的 Document。 而解析的过程中存在这么一环节:(EntityResolver) 根据声明去寻找对应的DTD定义,以便对文档进行验证认证 。也可以通过setEntityResolver设置DTD定义。EntityResolver它用来接收两个参数publicId和systemId,xsd格式文件通常publicId为null。而对于不同的验证模式采用不同的解析器进行解析,并把文件转换成Document文件,用于提取及注册bean。
Document 文件通过 BeanDefinitionDocumentReader 进行内部逻辑处理,并提取root用于作为参数继续完成BeanDefinition的注册。
‘伍’ 有没有关于java深入一点的书推荐
学习的最好途径就是看书“,这是我自己学习并且小有了一定的积累之后的第一体会。个人认为看书有两点好处:
1.能出版出来的书一定是经过反复的思考、雕琢和审核的,因此从专业性的角度来说,一本好书的价值远超其他资料。
2.对着书上的代码自己敲的时候方便。
“看完书之后再次提升自我的最好途径是看一些相关的好博文“,我个人认为这是学习的第二步,因为一本书往往有好几百页,好的博文是自己看书学习之后的一些总结和提炼,对于梳理学习的游蠢扮内容很有好处,当然这里不是说自己的学习方法,就不再扯下去了。
很多程序员们往往有看书的冲动,但不知道看哪些书,下面我就给各位Java程序猿们推荐一些好书(每本书的作者会加粗标红),其中绝大多数都是我自己平时在看的书,也算是我对于平时读的书做一个小总结和读后感吧。
首先推荐的不是一本书,而是一个博客,也是我们博客园另外一位博友java_my_life。
目前市面上讲解设计模式的书很多,虽然我前面讲了看书是最好的,但是对设计模式感兴趣的朋友们,我推荐的是这个博客。这位博友的设计模式讲得非常非常好,我认为90%的内容都是没有问题且很值得学习的,其讲解设计模式的大体路线是:
随便开篇点明该设计模式的定义
图文并茂讲解该设计模式中的结构
以详细的代码形式写一下该种设计模式的实现
补充内容
讲解该设计模式的优缺点
对于一个设计模式我们关注、学习的知识点,不就是上面这些吗?
不过我要重点提醒一下网友们,同一种设计档衫模式的写法有多种,并不是说只有按某种写法来写才是这种设计模式。比方说适配器模式,我们关注适配器模式一定要关注的是什么是适配器模式不是怎么写适配器模式,不要认为某段代码不是按照适配器模式的写法写下来的它就不是适配器模式了,记住这一点,你在学习设计模式的时候一定会对代码中用到的设计模式有更深入的理解。
1、深入理解Java虚拟机:JVM高级特性与最佳实践
如果你不满足于做一个只会写ifelse的Java程序员,而是希望更进一步,我随便举几个例子吧:
了解Java代码的底层运行机制
定位性能问题
对整个系统进行性能调优
解决各种奇奇怪怪的线上线下问题
更加高级别的,为自己的项目量身定做一款适合自己项目的虚拟机
那么Java虚拟机是你必学的一门技术。《深入理解Java虚拟机:JVM高级特性与最佳实践》作者是周志明,这本书可以说是国内写得最好的有关Java虚拟机的书籍,近半年,前前后后这本书我起码看了有5遍。国内写虚拟机的书除了这本,其实还有一些其他的,我也买过,不过粗略看下来,很多内容也是《深入理解Java虚拟机:JVM高神灶级特性与最佳实践》此书里面的。
另外值得一提的是,《深入理解Java虚拟机:JVM高级特性与最佳实践》这本书,有电子版的,网上搜一下就能下载到了。不过建议有兴趣的朋友还是去买书看,电子版本下载到的一般是比较老的版本,相比最新修订版的《深入理解Java虚拟机:JVM高级特性与最佳实践》,有很多作者新补充的知识点是没有的。
2、HotSpot实战
所有的Java虚拟机都是遵循着Java虚拟机规范来的,市面上的Java虚拟机几十款,《深入理解Java虚拟机:JVM高级特性与最佳实践》一书里面讲的虚拟机并不针对某种特定的虚拟机,而是从Java虚拟机规范的角度来讲解Java虚拟机。
我们平时使用的乃至商用的大多数Java虚拟机都是Sun公司的HotSpot,大家cmd进入命令行,使用”java-version”命令就可以看到了。如果希望在Java虚拟机规范的基础上更加深入地去理解虚拟机的一些细节是怎么实现的,就可以看一下《HotSpot实战》一书,作者是陈涛。不过由于HotSpot的源码都是C/C++写的,所以要求读者有非常好的C/C++基础,如果对这两门语言不是很熟悉的朋友,看这本书可能对你帮助不是很大。
最后提一句,如果有兴趣的朋友,不妨先去网上下载一个openJDK,HotSpot的源码就在里面。
3、Java并发编程实战
这本书常常被列入Java程序员必读十大书籍排行榜前几位,不过个人不是很推荐这本书。
《Java并发编程实战》作者是BrianGoetz,怎么说呢,这本书前前后后我也看了两遍左右,个人感受是:
文字多代码少
讲解多实践少
我觉得这可能就是老外写书的特点吧,因为Java是北美国家(加拿大、美国)开发和维护的,所以老外对Java方方面面的理论知识体系都掌握得是非常清楚和透彻的。翻开这本书看,多线程什么用、什么是死锁、什么是竞争、什么是线程安全等等,方方面面的知识点都用大量的文字篇幅讲解,不免让人感觉十分枯燥,也难让读者有实质性的进步。我这本书看了两遍也属于一目十行意思,有兴趣的地方就重点看一下。
无论如何,作为一本常常位于Jva程序员必读十大书籍排行榜前几名的书,还是一定要推荐给大家的。
4、java多线程编程核心技术
《Java多线程编程核心技术》作者高洪岩。想要学习多线程的朋友,这本书是我大力推荐的,我的个人博客里面二十多篇的多线程博文都是基于此书,并且在这本书的基础上进行提炼和总结而写出来的。
此书和《Java并发编程实战》相反,这本书的特点是大篇幅的代码+小篇幅的精讲解,可能这和中国人写的书比较偏向实用主义的风格有关。本书关于线程安全、synchronized、Reentrant、Timer等等都用详细的代码进行了讲解,而且每个大知识点下的多个小知识点都会详细讲解到,非常有实践价值。
有兴趣的朋友们,我相信只要你们跟着这本书里面的代码敲、运行、思考,三步走,对于多线程的使用与理解一定会进几大步。
不过这本书的缺点就是对于Java并发包下的一些类像CountDownLatch、Semphore、CyclicBarrier、Future、Callable等都没有讲到,重点的CAS和AQS也没有触及,重点类的实现原理也没有提。当然,这很深入了,在学习了这本书之后如果能再去对这些知识进行一些学习、研究的话,你一定会慢慢成长为一个很厉害的多线程高手。
5、EffectiveJava中文版
这是唯一一本我没有买的书。初识这本书,是在我的博文Java代码优化(长期更新)里面,底下评论的时候有朋友提到了这本书,当时我说要去买,不过这两个月一直都没时间去逛书店,甚是遗憾,之后肯定会找时间去买这本书的。
《EffectiveJava中文版》的作者是JoshuaBloch,这个人就很厉害了,他是谷歌的首席架构师,属于超级技术大牛级别了吧,呵呵。由于没有看过这本书,所以我不好发表评论,但是从这本书的知名度以及其作者的来头来看(多提一句,这本书也是Java之父JamesGosling博士推崇的一本书),我相信这一定是一本值得一看的好书。
好的代码是每个Java程序员都应该去追求的,不是说我今天写一段好代码相比写一段烂代码对性能会有多大的提升,更多的应该是提升了代码的可读性以及可以规避许多潜在的、未知的问题,避免代码上线之后出问题而花时间去维护—-无论从时间成本、人力成本还是风险成本来说,这都是非常高的。
6、深入分析JavaWeb技术内幕
《深入分析JavaWeb技术内幕》,作者许令波,淘宝工程师。
这本书我用一个字概括就是:全。真的非常全,HTTP、DNS、CDN、静态化、Jetty、Tomcat、Servlet、Spring、MyBatis等等,什么都有,涉及知识面非常广,但又不像专门精讲某个知识点的书籍一样讲得非常深入,感觉这本书就是尽量去用短的篇幅讲清楚一些JavaWeb使用到的技术的内幕,让读者对这些知识点的技术内幕有一个理性的认识。
不过,尽管每个知识点的篇幅都不多,但是重点都基本讲到了,是一本让人真正有收获的书。如果想进一步了解这些技术的技术内幕,就要自己去买相关书籍或者自己上网查资料了,有种抛砖引玉,或者说师傅领进门、修行在个人的感觉。
7、大型网站技术架构核心原理与案例分析
一个字评价这本书,_;两个字评价这本书,很_;三个字评价这本书,非常_。呵呵,好了,再说下去可能别人以为我是水军了。
《大型网站技术架构核心原理与案例分析》的作者是李智慧,原阿里巴巴技术专家。
Java的大多数应用都是用在Web上的,现在只要稍微大型一点的Web应用,都一定是一个分布式系统,那么一个分布式系统用到了哪些技术?一个大型网站是如何从一个小型网站成长起来的?如何保证你的网站安全?分布式系统使用到了缓存,有哪些缓存?缓存的使用有哪些值得注意的事项?
关于分布式的知识点,都在这本书里面有体现,只有你想不到,没有他写不到,而且写得非常易懂,基本属于看一两遍,再记一些笔记就知道是怎么一回事儿了。多看几遍,对分布式的理解一定会加深不少。而且里面不仅仅是分布式的知识,还非常接地气地写了如何做一个好的架构师,其实我认为这不仅仅是写给想做架构师的读者看的,就是给读者一些建议,如何更好地提出意见、如何更让别人关注你的声音、如何看到他人的优点,入木三分,让人获益匪浅。
8、大型网站系统与Java中间件实践
《大型网站系统与Java中间件实践》作者曾宪杰,是淘宝的技术总监,算起来应该在阿里有至少P8的级别了吧。
这本书的部分内容和上面一本李智慧的《大型网站技术架构核心原理与案例分析》有所重合,像分布式系统的演化、CDN、CAP理论和BASE理论等等,这也更说明这些都是分布式系统或者说是一个大型网站重点关注的内容,当作一次再学习也不错。
本书要突出的重点是中间件三个字,中间件是分布式系统中一个非常重要的东西,其最重要的作用应该就是解耦,降低模块与模块之间的强依赖,不同的模块之间的依赖度降低,便可以各自独立地开发自己的功能,这也可以说是软件工程发展的目标和驱动力。
因此,本书有一部分的内容就是基于中间件,详细讲解了中间件与JMS的各种知识,适合对分布式系统比较熟悉并且想要往中间件方面有一定研究的读者。
9、从Paxos到ZooKeeper分布式一致性原理与实践
《从Paxos到ZooKeeper分布式一致性原理与实践》,作者倪超,阿里巴巴工程师。
这本书是我最近在研读的一本书,和上面的《大型网站系统与Java中间件实践》一样,属于分布式组件的范畴,属于有些深入的内容,当然也是我自己的个人兴趣。当然,如果有志向做一个出色的大型网站架构师、公司的技术总监之类,这些知识当然是必须掌握的。
本书从分布式系统基本理论开始讲起,讲到Paxos算法,最后慢慢引入到Zookeeper,循序渐进。当然,更多的我目前还不方便发表什么看法,因为这本书的第二张Paxos算法我都还没有弄懂(Paxos算法确实有些难以理解和不太易懂),接下来的章节还没有看下去。
如果网友们所在的公司在使用Zookeeper,并且你又对Zookeeper感兴趣想要研究一下它的原理的,这本书将是不二之选。
10、MySQL5.6从零开始学
《MySQL5.6从零开始学》,作者刘增杰和李坤。
作为一名Java程序员,我认为我们千万不要觉得数据库是DBA的事情,数据库对一个Java程序员来说也是必须掌握的一门知识,丰富的数据库性能优化经验是一个顶尖程序员必备技能。
目前主流的数据库有Oracle和MySQL,当然推荐大家的是MySQL,主要原因我认为有两点:
1、MySQL相比Oracle更轻量级、更小、安装和卸载更方便,SQL其实都是差不多的,如果想学数据库,学MySQL就可以了,在家里面可以自己方便地研究,如果你的公司使用Oracle,只要再用对比学习法,关注一下Oracle和MySQL的差别即可
2、随着2009年阿里巴巴去IOE的运动的进行,目前国内的很多互联网公司都会选择MySQL作为它们使用的数据库,因为MySQL免费,所以既省钱又不需要出了问题就依赖甲骨文公司
MySQL学习我推荐的是这本我自己学习看的《MySQL5.6从零开始学》,我是觉得挺好的这本书,书里面的知识点很细致、很全面,读者选择书籍的标准大多不就是这两点吗?
11、Spring源码深度解析
《Spring源码深度解析》,作者郝佳。
Spring这个框架做得太好了,功能太强大了,以至于很多开发者都只知Spring,不知什么是工厂、什么是单例、什么是代理(我面试别人的真实体会)。这种功能强大的框架内部一定是很复杂的实现,这就导致一旦你的程序使用Spring,出了问题,可能是Error、可能是Exception、可能是程序运行结果不是你的预期的,出现诸如此类问题的时候,将会让你感到困惑,除了上网查资料或者问别人似乎没有更好的解决办法。
研读Spring的源代码不失为一种很好的学习方法,我个人认为这有很多好处:
理解框架内部的实现之后,可以主动去解决问题,而不需要依赖别人
Spring框架内部实现用到了很多设计模式,很好的代码设计思路,这将会对你写代码、对你理解设计模式有很大的提高
研究Spring框架将会大大增强你读代码的能力,我相信只要你能研究清楚Spring内部是如何实现的,其他任何一个框架的源代码都难不倒你
总而言之,我认为读代码的能力是一个普通的程序员和一个好的程序员之间最大的差别之一,前者只会把别人写好的东西拿来用,后者不仅能用好,还清楚知道别人写好的东西底层是如何实现的,在出现问题的时候可以轻松解决。
Spring源代码,个人推荐《Spring源码深度解析》一书,真要研究透并且写清楚Spring源代码,恐怕三四本书都不够,作者在近400页的篇幅中尽量去讲解Spring源代码是如何实现的,殊为不易,尽管无法讲得完全,但是相信作者的讲解配合上读者自己的研究,一定可以对Spring的实现有更深度的理解。
以上就是我对Java高级部分应该看的书籍的推荐,希望可以对你有所帮助。说一点我的建议,我们学Java技术更重要的还是看视频教程,我们只有看更多的视频教程,不断的练习,在脑海当中产生深刻的记忆。我永远坚信我的一句话:书籍能诠释的东西毕竟有限。
最后在这里推荐大家关注一下我的微信公众号:Java新手学习,给你准备了一套最新的Java基础精讲视频教程和Java系统学习路线,关注即可观看。
‘陆’ Spring事件监听机制源码解析
1.Spring事件监听体系包括三个组件:事件、事件监听器,事件广播器。
事件:定义事件类型和事件源,需要继承ApplicationEvent。
事件监听器:用来监听某一类的事件,并且执行具体业务逻辑,需要实现ApplicationListener 接口或者需要用@ListenerEvent(T)注解。好比观察者模式中的观察者。
事件多播器:负责广播通知所有监听器,所有的事件监听器都注册在了事件多播器中。好比观察者模式中的被观察者。Spring容器默认生成的是同步事件多播器。可以自定义事件多播器,定义为异步方式。
创建 的过程中,会执行refresh()中的()方法。该方法先获取bean工厂,然后判断工厂是否包含了beanName 为 applicationEventMulticaster的bean。如果包含了,则获取该bean,赋值给applicationEventMulticaster 属性。如果没有,则创建一个 对象,并且赋值给 applicationEventMulticaster 。实现了源码如下:
监听器的注册有两种,通过实现 ApplicationListener接口或者添加@EventListener注解。
注册的逻辑实现在refresh()中的registerListeners()方法里面。第一步,先获取当前ApplicationContext中已经添加的 applicationListeners(SpringMVC源码中有用到),遍历添加到多播器中。第二步,获取实现了ApplicationListener接口的listenerBeanNames集合,添加至多播器中。第三步,判断是否有早期事件,如果有则发起广播。
思考一下,上面的代码中第二步为啥添加的是listenerBeanName?
如果监听器是懒加载的话(即有@Lazy 注解)。那么在这个时候创建监听器显然是不对的,这个时候不能创建监听器。所以添加监听器到多播器的具体逻辑放在初始化具体的监听器之后。通过 BeanPostProcessor 的接口实现。具体的实现类是 ApplicationListenerDetector 。这个类是在 refreah()中prepareBeanFactory()方法中添加的。代码如下:
在创建 的构造方法中,会执行org.springframework.context.annotation.AnnotationConfigUtils#(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object) 方法。这个方法中会添加两个 beanDefs, 代码如下:
EventListenerMethodProcessor:事件监听器的BeanFactory后置处理器,在前期会创建 DefaultEventListenerFactory ,后期在创建好Bean之后,根据 EventListener 属性,调用DefaultEventListenerFactory创建具体的 。
DefaultEventListenerFactory:监听器的创建工厂,用来创建 。
EventListenerMethodProcessor 的类继承图如下:
在refreash的()中会调用 org.springframework.context.event.EventListenerMethodProcessor#postProcessBeanFactory方法,获取EventListenerFactory 类型的 Bean。代码如下:
在 org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons 方法中,创建完所有的单例Bean 之后,会遍历所有Bean是否实现了 SmartInitializingSingleton 接口。如果实现接口会执行该 Bean 的 afterSingletonsInstantiated() 方法。代码如下:
org.springframework.context.event.EventListenerMethodProcessor#afterSingletonsInstantiated 中会调用私有方法 processBean()进行 ApplicationEventAdatper 的创建。代码如下:
可以通过调用 org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object, org.springframework.core.ResolvableType) 方法进行事件的调用。代码如下:
中的 multicasEvent,invokeListener,doInvokeListener 三个方法代码如下:
SpringMVC中就是通过Spring的事件机制进行九大组件的初始化。
监听器定义在FrameworkServlet类中,作为内部类。代码如下:
监听器的添加在org.springframework.web.servlet.FrameworkServlet# 中进行。通过SourceFilteringListener进行包装。添加代码如下:
在refresh中的registerListeners方法进行添加,代码如下:
在refresh中的finishRefresh()方法中,会调用publishEvnet(new ContextRefreshedEvent(this))发布事件。进行多播器广播,代码如下
最终会调到FrameworkServlet.this.onApplicationEvent(event)。
‘柒’ [Spring boot源码解析] 2 启动流程分析
在了解 Spring Boot 的启动流程的时候,我们先看一下一个Spring Boot 应用是如何启动的,如下是一个简单的 SpringBoot 程序,非常的简洁,他是如何做到的呢,我们接下来就将一步步分解。
我们追踪 SpringApplication.run() 方法,其实最终它主要的逻辑是新建一个 SpringApplication ,然后调用他的 run 方法,如下:
我们先来看一下创建 SpringApplication 的方法:
在将Main class 设置 primarySources 后,调用了 WebApplicationType.deceFromClasspath() 方法,该方法是为了检查当前的应用类型,并设置给 webApplicationType 。 我们进入 deceFromClasspath 方法 :
这里主要是通过类加载器判断是否存在 REACTIVE 相关的类信息,假如有就代表是一个 REACTIVE 的应用,假如不是就检查是否存在 Servelt 和 ,假如都没有,就代表应用为非 WEB 类应用,返回 NONE ,默认返回 SERVLET 类型,我们这期以我们目前最常使用的 SERVLET 类型进行讲解,所以我们在应用中引入了 spring-boot-starter-web 作为依赖:
他会包含 Spring-mvc 的依赖,所以就包含了内嵌 tomcat 中的 Servlet 和 Spring-web 中的 ,因此返回了 SERVLET 类型。
回到刚才创建 SpringApplication 的构建方法中,我们设置完成应用类型后,就寻找所有的 Initializer 实现类,并设置到 SpringApplication 的 Initializers 中,这里先说一下 getSpringFactoriesInstances 方法,我们知道在我们使用 SpringBoot 程序中,会经常在 META-INF/spring.factories 目录下看到一些 EnableAutoConfiguration ,来出发 config 类注入到容器中,我们知道一般一个 config 类要想被 SpringBoot 扫描到需要使用 @CompnentScan 来扫描具体的路径,对于 jar 包来说这无疑是非常不方便的,所以 SpringBoot 提供了另外一种方式来实现,就是使用 spring.factories ,比如下面这个,我们从 Springboot-test 中找到的例子,这里先定义了一个ExampleAutoConfiguration,并加上了 Configuration 注解:
然后在 spring.factories 中定义如下:
那这种方式是怎么实现的你,这就要回到我们刚才的方法 getSpringFactoriesInstances :
我们先来看一下传入参数,这里需要注意的是 args,这个是初始化对应 type 的时候传入的构造参数,我们先看一下 SpringFactoriesLoader#loadFactoryNames 方法:
首先是会先检查缓存,假如缓存中存在就直接返回,假如没有就调用 classLoader#getResources 方法,传入 META-INF/spring.factories ,即获取所有 jar 包下的对应文件,并封装成 UrlResource ,然后使用 PropertiesLoaderUtils 将这些信息读取成一个对一对的 properties,我们观察一下 spring.factories 都是按 properties 格式排版的,假如有多个就用逗号隔开,所以这里还需要将逗号的多个类分隔开来,并加到 result 中,由于 result 是一个 LinkedMultiValueMap 类型,支持多个值插入,最后放回缓存中。最终完成加载 META-INF/spring.factories 中的配置,如下:
我们可以看一下我们找到的 initializer 有多少个:
在获取到所有的 Initializer 后接下来是调用 方法进行初始化。
这里的 names 就是我们上面通过类加载器加载到的类名,到这里会先通过反射生成 class 对象,然后判断该类是否继承与 ApplicationContextInitializer ,最后通过发射的方式获取这个类的构造方法,并调用该构造方法,传入已经定义好的构造参数,对于 ApplicationContextInitializer 是无参的构造方法,然后初始化实例并返回,回到原来的方法,这里会先对所有的 ApplicationContextInitializer 进行排序,调用 #sort(instances) 方法,这里就是根据 @Order 中的顺序进行排序。
接下来是设置 ApplicationListener ,我们跟进去就会发现这里和上面获取 ApplicationContextInitializer 的方法如出一辙,最终会加载到如图的 15 个 listener (这里除了 外,其他都是 SpringBoot 内部的 Listener):
在完成 SpringApplication 对象的初始化后,我们进入了他的 run 方法,这个方法几乎涵盖了 SpringBoot 生命周期的所有内容,主要分为九个步骤,每一个步骤这里都使用注解进行标识:
主要步骤如下:
第一步:获取 SpringApplicationRunListener, 然后调用他的 staring 方法启动监听器。
第二步:根据 SpringApplicationRunListeners以及参数来准备环境。
第三步:创建 Spring 容器。
第四步:Spring 容器的前置处理。
第五步:刷新 Spring 容器。
第六步: Spring 容器的后置处理器。
第七步:通知所有 listener 结束启动。
第八步:调用所有 runner 的 run 方法。
第九步:通知所有 listener running 事件。
我们接下来一一讲解这些内容。
我们首先看一下第一步,获取 SpringApplicationRunListener :
这里和上面获取 initializer 和 listener 的方式基本一致,都是通过 getSpringFactoriesInstances , 最终只找到一个类就是: org.springframework.boot.context.event.EventPublishingRunListener ,然后调用其构造方法并传入产生 args , 和 SpringApplication 本身:
我们先看一下构造函数,首先将我们获取到的 ApplicationListener 集合添加到initialMulticaster 中, 最后都是通过操作 来进行广播,我,他继承于 ,我们先看一下他的 addApplicationListener 方法:
我们可以看出,最后是放到了 applicationListenters 这个容器中。他是 defaultRetriever 的成员属性, defaultRetriever 则是 的私有类,我们简单看一下这个类:
我们只需要看一下这里的 getApplicationListeners 方法,它主要是到 beanFactory 中检查是否存在多的 ApplicationListener 和旧的 applicationListeners 组合并返回,接着执行 listener 的 start 方法,最后也是调用了 的 multicastEvent 查找支持对应的 ApplicationEvent 类型的通知的 ApplicationListener 的 onApplicationEvent 方法 ,这里除了会:
筛选的方法如下,都是调用了对应类型的 supportsEventType 方法 :
如图,我们可以看到对 org.springframework.boot.context.event.ApplicationStartingEvent 感兴趣的有5个 Listener
环境准备的具体方法如下:
首先是调用 getOrCreateEnvironment 方法来创建 environment ,我们跟进去可以发现这里是根据我们上面设置的环境的类型来进行选择的,当前环境会创建 StandardServletEnvironment
我们先来看一下 StandardServletEnvironment 的类继承关系图,我们可以看出他是继承了 AbstractEnvironment :
他会调用子类的 customizePropertySources 方法实现,首先是 StandardServletEnvironment 的实现如下,他会添加 servletConfigInitParams , servletContextInitParams , jndiProperties 三种 properties,当前调试环境没有配置 jndi properties,所以这里不会添加。接着调用父类的 customizePropertySources 方法,即调用到了 StandardEnvironment 。
我们看一下 StandardEnvironment#customizePropertySources 方法,与上面的三个 properties 创建不同,这两个是会进行赋值的,包括系统环境变量放入 systemEnvironment 中,jvm 先关参数放到 systemProperties 中:
这里会添加 systemEnvironment 和 systemProperties 这两个 properties,最终拿到的 properties 数量如下 4个:
在创建完成 Environment 后,接下来就到了调用 configureEnvironment 方法:
我们先看一下 configurePropertySources 方法,这里主要分两部分,首先是查询当前是否存在 defaultProperties ,假如不为空就会添加到 environment 的 propertySources 中,接着是处理命令行参数,将命令行参数作为一个 CompositePropertySource 或则 添加到 environment 的 propertySources 里面,
接着调用 ConfigurationPropertySources#attach 方法,他会先去 environment 中查找 configurationProperties , 假如寻找到了,先检查 configurationProperties 和当前 environment 是否匹配,假如不相等,就先去除,最后添加 configurationProperties 并将其 sources 属性设置进去。
回到我们的 prepareEnvironment 逻辑,下一步是通知观察者,发送 事件,调用的是 SpringApplicationRunListeners#environmentPrepared 方法,最终回到了 #multicastEvent 方法,我们通过 debug 找到最后对这个时间感兴趣的 Listener 如下:
其主要逻辑如下:
这个方法最后加载了 PropertySourceLoader , 这里主要是两种,一个是用于 Properties 的,一个是用于 YAML 的如下:
其中 apply 方法主要是加载 defaultProperties ,假如已经存在,就进行替换,而替换的目标 PropertySource 就是 load 这里最后的一个 consumer 函数加载出来的,这里列一下主要做的事情:
1、加载系统中设置的所有的 Profile 。
2、遍历所有的 Profile ,假如是默认的 Profile , 就将这个 Profile 加到 environment 中。
3、调用load 方法,加载配置,我们深入看一下这个方法:
他会先调用 getSearchLocations 方法,加载所有的需要加载的路径,最终有如下路径:
其核心方法是遍历所有的 propertySourceLoader ,也就是上面加载到两种 propertySourceLoader ,最红 loadForFileExtension 方法,加载配置文件,这里就不展开分析了,说一下主要的作用,因为每个 propertySourceLoader 都有自己可以加载的扩展名,默认扩展名有如下四个 properties, xml, yml, yaml,所以最终拿到文件名字,然后通过 - 拼接所有的真实的名字,然后加上路径一起加载。
接下来,我们分析 BackgroundPreinitializer ,这个方法在接收 ApplicationPrepareEnvironment 事件的时候真正调用了这份方法:
1、 ConversionServiceInitializer 主要负责将包括 日期,货币等一些默认的转换器注册到 formatterRegistry 中。
2、 ValidationInitializer 创建 validation 的匹配器。
3、 MessageConverterInitializer 主要是添加了一些 http 的 Message Converter。
4、 JacksonInitializer 主要用于生成 xml 转换器的。
接着回到我们将的主体方法, prepareEnvironment 在调用完成 listeners.environmentPrepared(environment) 方法后,调用 bindToSpringApplication(environment) 方法,将 environment 绑定到 SpirngApplication 中。
接着将 enviroment 转化为 StandardEnvironment 对象。
最后将 configurationProperties 加入到 enviroment 中, configurationProperties 其实是将 environment 中其他的 PropertySource 重新包装了一遍,并放到 environment 中,这里主要的作用是方便 进行解析。
它主要是检查是否存在 spring.beaninfo.ignore 配置,这个配置的主要作用是设置 javaBean 的内省模式,所谓内省就是应用程序在 Runtime 的时候能检查对象类型的能力,通常也可以称作运行时类型检查,区别于反射主要用于修改类属性,内省主要用户获取类属性。那么我们什么时候会使用到内省呢,java主要是通过内省工具 Introspector 来完成内省的工作,内省的结果通过一个 Beaninfo 对象返回,主要包括类的一些相关信息,而在 Spring中,主要是 BeanUtils#Properties 会使用到,Spring 对内省机制还进行了改进,有三种内省模式,如下图中红色框框的内容,默认情况下是使用 USE_ALL_BEANINFO。假如设置为true,就是改成第三中 IGNORE_ALL_BEANINFO
首先是检查 Application的类型,然后获取对应的 ApplicationContext 类,我们这里是获取到了 org.springframework.boot.web.servlet.context. 接着调用 BeanUtils.instantiateClass(contextClass); 方法进行对象的初始化。
最终其实是调用了 的默认构造方法。我们看一下这个方法做了什么事情。这里只是简单的设置了一个 reader 和一个 scanner,作用于 bean 的扫描工作。
我们再来看一下这个类的继承关系
这里获取 ExceptionReporter 的方式主要还是和之前 Listener 的方式一致,通过 getSpringFactoriesInstances 来获取所有的 SpringBootExceptionReporter 。
其主要方法执行如下:
‘捌’ Spring全家桶笔记:Spring+Spring Boot+Spring Cloud+Spring MVC
最近我整理了一下一线架构师的Spring全家桶笔记:Spring+Spring Boot+Spring Cloud+Spring MVC,分享给大家一起学习一下~ 文末免费获取哦
Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架。Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。
1.1 Spring面试必备题+解析
1.2 Spring学习笔记
(1)Spring源码深入解析
(2)Spring实战
1.3 Spring学习思维脑图
Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。
2.1 Spring Boot面试必备题+解析
2.2 Spring Boot学习笔记
(1)Spring Boot实践
(2)SpringBoot揭秘 快速构建微服务体系
2.3 SpringBoot学习思维脑图
springcloud是微服务架构的集大成者,将一系列优秀的组件进行了整合。基于springboot构建,对我们熟悉spring的程序员来说,上手比较容易。通过一些简单的注解,我们就可以快速的在应用中配置一下常用模块并构建庞大的分布式系统。
3.1 Spring Cloud面试必备题+解析
3.2 Spring Cloud学习笔记
(1)Spring Cloud参考指南
SpringMVC是一种基于Java的实现MVC设计模式的请求驱动类型的轻量级Web框架,使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发
4.1 Spring MVC面试必备题+解析
4.2 Spring MVC学习笔记
(1)看透Spring MVC源代码分析与实践
(2)精通Spring MVC
最后分享一下一份JAVA核心知识点整理(PDF)