本篇文章的目的是就自己阅读Spring代码和相关技术栈的一些心得体会做一些总结,方便快速上手Spring相关的技术栈,如Spring Cloud等,文章不长,大约花费5分钟时间。
(介绍一,可以略过)Spring强大的扩展能力,促进了其与新技术的融合,维护了它持久的生命力,熟悉Spring是软件特别是互联网开发人员的基本功之一,特别是在以Spring Boot为基础搭建的微服务大行其道的当下。
(介绍二,可以继续略过)Spring Boot是构建微服务的基础,它针对Spring较重的开发部署流程进行了简化,使得上下游不同框架的融合、配置开发、部署变得非常简单,但它的底层核心仍然是Spring。
Spring源码很复杂,网上相关文章也很多(建议对着文章读源码,先对整体流程主要是启动流程有个大体了解,然后再细化,以实践为导向),在此就其两大核心IOC和AOP开启两个传送门,感兴趣的同学可以看一下(文章很长,不适合碎片化阅读):
IOC:Spring IOC 容器源码分析
AOP:Spring-aop 全面解析
Spring整体来讲是个Bean的管理容器,最主要的核心就是Bean(Bean可以通过id或name区分 ,也可以通过class type区分),从XML文件或者注解声明中将Bean的定义抽象成Beandefinition(Beandefinition的来源多种多样,除了自己显示定义的,用于特殊处理的BeanDefinitionRegistryPostProcessor本身也是Beandefinition),Beandefinition通过Beanfactory管理,Beanfactory作为Applicationcontext 的内部属性,不同的Applicationcontext 之间有层级关系,在寻找bean的过程中可以沿着这种层级关系寻找(在自己内部的Beanfactory找不到的话再向上层父级寻找),然后通过Beandefinition来初始化Bean。
初始化过程中可以设立很多的扩展点(如初始化之前、之后),具体可以看BeanPostProcessor等扩展机制 (我们在开发过程中也可以结合自定义注解针对此做一些扩展开发)。
IOC的原理就是通过第三方也就是Spring容器将一个Bean注入到另一个Bean(即依赖注入),通过类型、名称、构造方法等方式,循环依赖可以关注一下。
AOP的原理就是在上文描述的扩展点(即beanpostprocessor的扩展点)通过动态代理(jdk dynamic proxy和cglib要重点了解)将一个Bean转换成动态代理Bean,而动态代理Bean就可以在原本Bean的执行代码前后加入一些自己的扩展(Spring caching和Transaction都是基于此实现的)。
Spring Boot和传统Spring开发一个显著的不同就是大量的注解,注解是什么呢,就是用来描述类、字段、方法的元数据,有些可能在编译之前就被去掉了,有些会被编译进class文件,注解本身是没有什么作用的,但是在Bean处理过程中根据这些元数据做一些特殊处理,就使得注解的作用威力无穷了。
Spring Boot的Autoconfiguration机制方便了与其他框架的融合,可以看我之前的一篇文章(Spring Boot之零),通过扫描classpath下面的spring.factory文件,可以方便的将扩展类添加到Bean definition中去,针对Bean definition的扩展,可以看几个很重要的注解:configuration、import及与其有关的*ConfigurationSelector,扩展方式非常灵活,但目的只有一个,就是将相关的Bean definition加入到Beanfactory中去。
其他框架整合进Spring的时候一般绕不过这几点,通过注解将相关Bean import进去,或者在原有Bean的基础上加一些自己的逻辑返回代理Bean,而Bean也可以获取Application的各种事件触发,从而构建起强大的功能。
在看一个Spring 相关框架的过程中,通过注意这几点内容,我觉得还是比较快的:
1、看框架的整体描述,拿到开关注解(如Enable*),看import进了哪些关键Bean,特别是注意跟扩展点有关的Bean,这些Bean往往会根据注解来做一些特殊处理;
2、看框架的整体功能,关心同/异步和长/短连接以及push/pull,针对功能做一些关键点搜索,找到关键实现;
3、根据关键实现再用intellij神器做反向追溯,快速理通整个流程或者找到测试类(如*Test),通过测试类Debug代码;
4、对于影响性能的关键技术实现,就要去抠细节了,主要和Threadlocal(保存请求上下文变量)、缓存、连接池、线程池、异步非阻塞、减少运行时反射处理等有关。
通过以上的几点,我快速理清了Spring Cloud技术栈(zuul/eureka/feign/ribbon/apollo)的源码大体处理流程,不过Spring Cloud中熔断器Hystrix大量使用了响应式编程(Rxjava),这个还是比较绕的,建议先看简单的例子,琢磨清楚了subscriber是如何向上传递的以及结果集是如何向下发射的,再加上subscribeon和observeon线程池对于数据传递的影响,再去看就比较容易了。
对于Rxjava再加上一个传送门:Rxjava