Spring源码解析一(框架梳理)
Posted KMSFan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring源码解析一(框架梳理)相关的知识,希望对你有一定的参考价值。
整体架构
打算开始写这个系列,不为上首页,也不为博取多少关注,只有一个目的:梳理知识,扩充思路;废话不多,开始吧。第一步,大家去spring的官方github下面去下载它的源码,具体的自己谷歌,我已经下下来了,然后spring的源码分为下面几个部分:
哈哈,大家是不是有一种头晕目眩的感觉,没事,我带你来分析源码,顺便给自己也做个总结。第一步是要理清楚各个层级关系之间的依赖,我把图画好,大家自己看看就好。所有的依赖都可以在gradle文件里面找到。为了效率,建议大家在idea里面下载一个插件,叫做gradle view,可以像Maven一样查看依赖树。其中大家接触的比较多的就是compile和optional了,compile对应的是当前项目的模块,而optional对应第三方依赖。其他的我相信用过maven的人都能理解。
如果是本项目的其他模块的话,会有一个project的关键字在里面,如下面的代码,画了思维导图,用XMind画的,今天就到这里吧,可累死我了。具体的XMind文件请到这里下载。大家如果想看大图,可以右键在新窗口打开图片,这样就清楚了。
compile(project(":spring-beans")) compile(project(\':spring-core\'))
那么继续,大家是不是有一种无从下手的感觉呢?有这种感觉就对了,因为你并不知道哪块是对你重要的,我的建议就是:选依赖项少的,并且被依赖项多的模块来作为首要模块来进行分析,大家可以打开项目自己去看看,我个人认为spring-core这个比较核心,而且其他的很多的项目都要依赖到这个模块,那么我们就从这个模块入手吧。当然并不是要大家一上来就把所有的细节都研究清楚,我们现在能做的,只是把模块和模块之间的架构关系理清楚,还没有深入到细节。我们打开spring-core可以发现有如下模块:
虽然说我也不知道哪个模块应该先去研究,不过依靠我直觉应该是core模块,下面的分析都是基于core模块向四周进行辐射。core包里面又有很多的子包,并且还有一堆类,虽然我现在并不知道这些类是做什么的。碰到这里,大家怎么进行分析呢?告诉大家一点方法:通过用法来进行分析,大家如果之前看过一些spring相关的文章,介绍里面的一些原理的文章,我觉得都可以回忆一下,因为这些文章所说到的思路,也许就是你正在寻找的答案。我这里是在分析架构,因为架构和架构是耦合在一起的而并非独立的个体,所以我的叙述很可以不会按照默认顺序来进行叙述,敬请理解。
AliasRegistry
Spring给这个类的一个解释就是《通用的别名管理器》,我们想一想:Spring当中什么是别名?Qualifier注解!那么我们来寻找一下,是否这个AliasRegistry和Qualifier有什么不可告人的秘密。因为Qualifier是一个注解,所以我要找和注解相关的实现类。AnnotationConfigApplicationContext,我们首先思考一个问题:AnnotationConfigApplicationContext和AliasRegistry是否存在直接的关系呢?我们可以回到这个问题,Qualifier注解是用在什么上面的?什么?这还用问,当然是Bean上面啊!于是乎,就有了下面的答案:
AliasRegistry其实你可以理解为一个抽象基接口,其实真正的用到的接口是BeanDefinitionRegistry,那么AnnotationConfigApplicationContext其实是被GenericApplicationContext所继承了,而GenericApplicationContext又实现了BeanDefinitionRegistry,并且这几个呗实现的方法,其内部结构都是交给了一个BeanFactory的工厂类,也就是我们常常说到的Spring的IOC相关的思想。
@Override public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException { this.beanFactory.removeBeanDefinition(beanName); } @Override public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException { return this.beanFactory.getBeanDefinition(beanName); }
是不是有点迷迷糊糊了?想睡觉了?别急,我画一张思维导图给大家醒醒脑,具体的思维导图可以到这里下载,如果有出错的地方,还请各位批评指正。
像上面这么分析的话,实在是太慢了,我需要找到一个可行的方法,尽快分析。大家其实也应该想到,利用网络,我们可以快速搜集到相关的知识点。有点小小的无奈,因为网上并没有详细的解答,可能是大家编程都只满足于会用就行了吧,真的太失望了。那么我还是从我认为的比较有代表性的类来跟大家分析吧。
MethodParameter
那么大家肯定会有一个疑问,这个MethodParameter到底是做什么的呢?从下面的图中,我们可以看到具体的子类实现,大部分是在messaging下面的。虽然说我不是很想跟大家去分析细节,不过我觉得这也是没办法的事情啊,因为细节就在那里,逃不掉的。
首先在这个类里面定义了一个私有的成员,叫做Executable,这个Executable可来头不小,它是Method的父类,也就是java.lang.reflect包里面的那个我们常常用到的Method.第二个成员变量是parameterIndex,还有一个参数是nestingLevel(内嵌级别),这个参数我暂时还没搞懂是做什么的,不过spring给出的官方解释是:the nesting level of the target type,它有一个为1的默认值。并且这3个成员变量组成了一个构造函数。
private final Executable executable; private final int parameterIndex; private int nestingLevel = 1; public MethodParameter(Method method, int parameterIndex, int nestingLevel) { Assert.notNull(method, "Method must not be null"); this.executable = method; this.parameterIndex = validateIndex(method, parameterIndex); this.nestingLevel = nestingLevel; }
虽然我们现在还不知道这个类是做什么的,不过Java我认为有一大优势就是它可以通过语义来猜这个类的用法,不像C++一样指针遍地飞,找不到方向;下面的代码就是这个类的属性,大家也许会说,我还没看到这个类的具体用法,我怎么可能知道这些属性是做什么的呢?非也非也,做事就是要有探索精神,编程不能吃老本,前人的经验固然重要,但是你的经验,你的直觉就不重要了吗?所以相信自己哦!
@Nullable private volatile Class<?> containingClass; @Nullable private volatile Class<?> parameterType; @Nullable private volatile Type genericParameterType;
@Nullable private volatile Annotation[] parameterAnnotations; @Nullable private volatile ParameterNameDiscoverer parameterNameDiscoverer; @Nullable private volatile String parameterName; @Nullable private volatile MethodParameter nestedMethodParameter;
我们来想这么一个问题,然后把这些问题串联起来,我有一个Method(方法),方法里面有一些参数(MethodParameter),这些参数不止一个,它可能是第一个,第二个参数(parameterIndex),每一个参数都有一个类型object.class(parameterType),参数前面有可能加上了注解(parameterAnnotation,并且这个注解可能还有多个),这个参数有它自己的名字,因为这个方法可能是一个复杂类型,所以可能有内部类,内部类当中可能有嵌套方法参数-nestedMethodParameter(还有待考证)当然还有一种可能性就是泛型当中可能还有泛型,这样层层嵌套,参见这篇文章,总之在答案出来之前,我不武断认为我的就是正确的。我画了一幅思维导图来总结一下自己的思路。文件可以在这里下载。
再来看一张更详细的图,这是从AttributeAccessor接口开始的。
以上是关于Spring源码解析一(框架梳理)的主要内容,如果未能解决你的问题,请参考以下文章