Spring的设计
在上一步,我们实现了自己的方案,并基于一些设想进行了扩展性优化,现在,我们就来认识一下实际上Spring的设计
那么,在Spring中又是由哪些"角色"构成的呢?
1、Bean: Spring作为一个IoC容器,最重要的当然是Bean咯
2、BeanFactory: 生产与管理Bean的工厂
3、BeanDefinition: Bean的定义,也就是我们方案中的Class,Spring对它进行了封装
4、BeanDefinitionRegistry: 类似于Bean与BeanFactory的关系,BeanDefinitionRegistry用于管理BeanDefinition
5、BeanDefinitionRegistryPostProcessor: 用于在解析配置类时的处理器,类似于我们方案中的ClassProcessor
6、BeanFactoryPostProcessor: BeanDefinitionRegistryPostProcessor父类,让我们可以再解析配置类之后进行后置处理
7、BeanPostProcessor: Bean的后置处理器,用于在生产Bean的过程中进行一些处理,比如依赖注入,类似我们的AutowiredAnnotationBeanProcessor
8、ApplicationContext: 如果说以上的角色都是在工厂中生产Bean的工人,那么ApplicationContext就是我们Spring的门面,ApplicationContext与BeanFactory是一种组合的关系,所以它完全扩展了BeanFactory的功能,并在其基础上添加了更多特定于企业的功能,比如我们熟知的ApplicationListener(事件监听器)
以上说的类似其实有一些本末倒置了,因为实际上应该是我们方案中的实现类似于Spring中的实现,这样说只是为了让大家更好的理解
我们在经历了自己方案的设计与优化后,对这些角色其实是非常容易理解的
接下来,我们就一个一个的详细了解一下
BeanFactory
BeanFactory是Spring中的一个顶级接口,它定义了获取Bean的方式,Spring中还有另一个接口叫SingletonBeanRegistry,它定义的是操作单例Bean的方式,这里我将这两个放在一起进行介绍,因为它们大体相同,SingletonBeanRegistry的注释上也写了可以与BeanFactory接口一起实现,方便统一管理。
BeanFactory
1、ListableBeanFactory:接口,定义了获取Bean/BeanDefinition列表相关的方法,如getBeansOfType(Class type)
2、AutowireCapableBeanFactory:接口,定义了Bean生命周期相关的方法,如创建bean, 依赖注入,初始化
3、AbstractBeanFactory:抽象类,基本上实现了所有有关Bean操作的方法,定义了Bean生命周期相关的抽象方法
4、AbstractAutowireCapableBeanFactory:抽象类,继承了AbstractBeanFactory,实现了Bean生命周期相关的内容,虽然是个抽象类,但它没有抽象方法
5、DefaultListableBeanFactory:继承与实现以上所有类和接口,是为Spring中最底层的BeanFactory, 自身实现了ListableBeanFactory接口
6、ApplicationContext:也是一个接口,我们会在下面有专门对它的介绍
SingletonBeanRegistry
1、DefaultSingletonBeanRegistry: 定义了Bean的缓存池,类似于我们的BeanMap,实现了有关单例的操作,比如getSingleton
(面试常问的三级缓存就在这里)
2、FactoryBeanRegistrySupport:提供了对FactoryBean的支持,比如从FactoryBean中获取Bean
BeanDefinition
BeanDefinition其实也是个接口(想不到吧),这里定义了许多和类信息相关的操作方法,方便在生产Bean的时候直接使用,比如getBeanClassName
它的大概结构如下(这里举例RootBeanDefinition子类):
里面的各种属性想必大家也绝不陌生
同样的,它也有许多实现类:
1、AnnotatedGenericBeanDefinition:解析配置类与解析Import注解带入的类时,就会使用它进行封装
2、ScannedGenericBeanDefinition:封装通过@ComponentScan扫描包所得到的类信息
3、ConfigurationClassBeanDefinition:封装通过@Bean注解所得到的类信息
4、RootBeanDefinition:ConfigurationClassBeanDefinition父类,一般在Spring内部使用,将其他的BeanDefition转化成该类
BeanDefinitionRegistry
定义了与BeanDefiniton相关的操作,如registerBeanDefinition
,getBeanDefinition
,在BeanFactory中,实现类就是DefaultListableBeanFactory
BeanDefinitionRegistryPostProcessor
插话:讲到这里,有没有发现Spring的命名极其规范,Spring团队曾言Spring中的类名都是反复推敲才确认的,真是名副其实呀,所以看Spring源码真的是一件很舒服的事情,看看类名方法名就能猜出它们的功能了。
该接口只定义了一个功能:处理BeanDefinitonRegistry,也就是解析配置类中的Import
、Component
、ComponentScan
等注解进行相应的处理,处理完毕后将这些类注册成对应的BeanDefinition
在Spring内部中,只有一个实现:ConfigurationClassPostProcessor
BeanFactoryPostProcessor
所谓BeanFactory的后置处理器,它定义了在解析完配置类后可以调用的处理逻辑,类似于一个插槽,如果我们想在配置类解析完后做点什么,就可以实现该接口。
在Spring内部中,同样只有ConfigurationClassPostProcessor实现了它:用于专门处理加了Configuration
注解的类
这里串场一个小问题,如知以下代码:
@Configuraiton public class MyConfiguration{ @Bean public Car car(){ return new Car(wheel()); } @Bean public Wheel wheel(){ return new Wheel(); } }
问:Wheel对象在Spring启动时,被new了几次?为什么?
BeanPostProcessor
江湖翻译:Bean的后置处理器
该后置处理器贯穿了Bean的生命周期整个过程,在Bean的创建过程中,一共被调用了9次,至于哪9次我们下次再来探究,以下介绍它的实现类以及作用
1、AutowiredAnnotationBeanPostProcessor:用于推断构造器进行实例化,以及处理Autowired和Value注解
2、CommonAnnotationBeanPostProcessor:处理Java规范中的注解,如Resource、PostConstruct
3、ApplicationListenerDetector: 在Bean的初始化后使用,将实现了ApplicationListener接口的bean添加到事件监听器列表中
4、ApplicationContextAwareProcessor:用于回调实现了Aware接口的Bean
5、ImportAwareBeanPostProcessor: 用于回调实现了ImportAware接口的Bean
ApplicationContext
ApplicationContext作为Spring的核心,以门面模式隔离了BeanFactory,以模板方法模式定义了Spring启动流程的骨架,又以策略模式调用了各式各样的Processor…实在是错综复杂又精妙绝伦!
它的实现类如下:
1、ConfigurableApplicationContext:接口,定义了配置与生命周期相关操作,如refresh
2、AbstractApplicationContext: 抽象类,实现了refresh方法,refresh方法作为Spring核心中的核心,可以说整个Spring皆在refresh之中,所有子类都通过refresh方法启动,在调用该方法之后,将实例化所有单例
3、AnnotationConfigApplicationContext: 在启动时使用相关的注解读取器与扫描器,往Spring容器中注册需要用的处理器,而后在refresh方法在被主流程调用即可
4、AnnotationConfigWebApplicationContext:实现loadBeanDefinitions方法,以期在refresh流程中被调用,从而加载BeanDefintion
5、ClassPathXmlApplicationContext: 同上
从子类的情况可以看出,子类的不同之处在于如何加载BeanDefiniton, AnnotationConfigApplicationContext是通过配置类处理器(ConfigurationClassPostProcessor)加载的,而AnnotationConfigWebApplicationContext与ClassPathXmlApplicationContext则是通过自己实现loadBeanDefinitions方法,其他流程则完全一致
Spring的流程
以上,我们已经清楚了Spring中的主要角色以及作用,现在我们尝试把它们组合起来,构建一个Spring的启动流程
同样以我们常用的AnnotationConfigApplicationContext为例
图中只画出了Spring中的部分大概流程,详细内容我们会在后面的章节展开