Spring的核⼼组件详解
Spring 总共有⼗⼏个组件,但是真正核⼼的组件只有三个:Core、Context 和 Bean。它们构建起了整个 Spring的⾻骼架构,没有它们就不可能有 AOP、Web 等上层的特性功能。
⼀、Spring的设计理念
Bean组件是 Spring核⼼中的重点,Spring 就是⾯向Bean编程的(Bean Oriented Programming:BOP)就像Object 对OOP的意义⼀样,没有对象的概念就像没有⾯向对象的编程,在Spring中没有Bean也就没有Spring存在的意义。我们使⽤ Spring的主要⼀个原因就是 Spring会把对象之间的依赖关系转⽽⽤配置⽂件来管理。也就是依赖注⼊机制。⽽这个注⼊关系在⼀个叫 IOC的容器中管理,⽽IOC容器就是被Bean包裹的对象。Spring正是通过把对象包装在Bean中从⽽达到管理这些对象及做⼀系列额外操作的⽬的。
⼆、Bean组件
Bean组件在Spring的 org.springframework.beans 包下,在这个包下的所有类主要解决了3件事:Bean的定义、Bean的创建及对Bean的解析。对Spring使⽤者来说唯⼀需要关⼼的就是Bean的创建,其他两个由Spring在内部完成。BeanDefination:Bean的定义完整的描述了在 Spring配置⽂件中定义的<bean/>节点中所有的信息,包括各种⼦节点。当Spring成功解析 <bean/> 节点后,在Spring内部它就被转化成 BeanDefinition对象,以后所有操作都是对这个对象操作。
Bean的解析过程⾮常复杂,功能被分的很细。因为这⾥需要被扩展的地⽅很多,必须保证有⾜够的灵活性,以应对可能的变化。Bean的解析主要就是对Spring配置⽂件的解析。
三、Context组件
Context 在 Spring的 t 包下,给 Spring提供⼀个运⾏时的环境,⽤于保存各个对象的状态。ApplicationContext 是 Context 的⽗类,它除了能标识⼀个应⽤环境的基本信息外,还集成了5个接⼝来扩展 Context 的功能。例如:通过继承 BeanFactory 表明容器中运⾏的主体对象是 Bean,另外继承了ResourceLoader接⼝,使得 ApplicationContext可以访问外部资源(在Core中说明);
【1】ApplicationContext 的⼦类主要包含两个⽅⾯:
● ConfigurableApplicationContext 表⽰该 Context 是可修改的,也就是在构建 Context 中,⽤户可以动态添加或修改已有的配置信息,其中最经常使⽤的是可更新的Context,即 AbstractRefreshableApplicationContex类;
● WebApplicationContext 为Web装备的Context,可直接访问ServletContext;
【2】再往下分别就是构建 Context的⽂件类型,接着就是访问 Context的⽅式,这样⼀级⼀级构成了完
成的 Context等级层次。总体来说 ApplicationContext 必须要完成⼀下⼏件事情:
✔标识⼀个应⽤环境;
✔利⽤ BeanFactory创建Bean对象;
✔保存对象关系表;
✔能够捕捉各种事件;
Context 作为 Spring的IOC容器,基本上整合了 Spring的⼤部分功能,或者说是⼤部分功能的基础。
四、Core组件
Core 组件作为 Spring的核⼼组件,其中包含了很多关键类,例如:定义了资源的访问⽅式。这种将所有资源都抽象成⼀个接⼝的⽅式很值得以后的设计中拿来学习。
Context 与 Core之间的关系:⽐如 Context⼀般会把资源的加载、解析和描述⼯作委托给 ResourcePatternResolver类来完成,它相当于⼀个接头⼈,把资源的加载、解析和资源的定义整合在⼀起便于其他组件使⽤,在Core组件中还有很多类似的⽅式。
五、IOC容器如何⼯作
1 @Override
2public void refresh() throws BeansException, IllegalStateException {
3synchronized (this.startupShutdownMonitor) {
4// 为刷新做准备的 Context
5 prepareRefresh();
6// 刷新所有BeanFactory⼦容器
7 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
8// 创建BeanFactory
9 prepareBeanFactory(beanFactory);
10
11try {
12// 注册实现了BeanPostProcess接⼝的Bean
13 postProcessBeanFactory(beanFactory);
14// 初始化和执⾏BeanFactoryPostProcess beans
15 invokeBeanFactoryPostProcessors(beanFactory);
16// 初始化和执⾏BeanPostProcess beans
17 registerBeanPostProcessors(beanFactory);
18// 初始化 message source
19 initMessageSource();
20// 初始化 event multicaster
21 initApplicationEventMulticaster();
22// 刷新⼦类实现的⽅法
23 onRefresh();
24// 检查注册事件
25 registerListeners();
26// 初始化 (non-lazy-init) 单例Bean
27 finishBeanFactoryInitialization(beanFactory);
28// 执⾏Refresh()和ContextRefreshedEvent事件
29 finishRefresh();
30 }
31
32catch (BeansException ex) {
33 destroyBeans();//如果刷新失败那么就会将已经创建好的单例Bean销毁掉
34 cancelRefresh(ex);//重置context的活动状态
35throw ex;//抛出异常
36 }
37 }
38 }
这个⽅法就是构建整个 IOC容器过程的完整代码,了解⾥⾯的每⼀⾏代码,基本上就了解了⼤部分 Spring的原理和功能。这段主要包含⼀下步骤:
1)、构建BeanFactory,以便于产⽣所需的“演员”;
2)、注册可能感兴趣的事件;
3)、创建Bean实例对象;
4)、触发被监听的事件;
⾸先创建和配置BeanFactory《容器》,这⾥是refresh,也就是刷新配置。前⾯介绍了Context有可更新的⼦类,这⾥正是实现这个功能,当BeanFactory存在时就更新,如果不存在就新创建。更新BeanFactory的⽅法如下:
1 @Override
2protected final void refreshBeanFactory() throws BeansException {
3if (hasBeanFactory()) {//如果已经存在⼀个bean⼯⼚那么就将其销毁,关闭。
4 destroyBeans();
5 closeBeanFactory();
6 }
7try {
8 DefaultListableBeanFactory beanFactory = createBeanFactory();//新建⼀个Bean⼯⼚。
9 beanFactory.setSerializationId(getId());
10 customizeBeanFactory(beanFactory);//⾃定义bean⼯⼚。
11 loadBeanDefinitions(beanFactory);//加载BeanDefinition
12synchronized (this.beanFactoryMonitor) {
实例化bean的三种方式13this.beanFactory = beanFactory;//将创建好的bean⼯⼚的引⽤交给的context来管理。
14 }
15 }
16catch (IOException ex) {//加载bean定义资源的时候可能会抛出异常。
17throw new ApplicationContextException("I/O error parsing bean definition source for "
18 + getDisplayName(), ex);
19 }
20 }
从上图可以发现除了 BeanFactory相关类外,还发现与 Bean 的 register 相关的类。这在 refreshBeanFactory⽅法的loadBeanDefinitions(beanFactory) ⼀⾏将到答案,这个⽅
法将加载、解析Bean的定义,也就是把⽤户定义的数据结构转化为IOC容器中的特定数据结构。
创建好 BeanFactory后,添加⼀些 Spring本⾝需要的⼯具类,这个操作在 AbstractApplictionContext 的 prepareBeanFactory的prepareBeanFactory⽅法中完成。
在 AbstractApplicationContext中接下来的3⾏代码 Spring的功能扩展性能起了⾄关重要的作⽤。前两⾏主要是让你现在可以对已经构建的 BeanFactory的配置做修改,后⾯⼀⾏
就是让你可以对以后再创建 Bean的实例对象时添加⼀些⾃定义的操作。所以它们都扩展了 Spring的功能,要学习 Spring必须搞清楚这⼀部分。
其中在 invokeBeanFactoryPostProcessors⽅法中主要是获取实现 BeanFactoryPostProcess接⼝的⼦类,并执⾏它的postProcessBeanFactory⽅法,这个⽅法的声明如下:
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
它的参数是 beanFactory,说明可以对 beanFactory做修改,beanFactory是 ConfigurableListableBeanFactory类型的,这也印证了前⾯介绍的不同BeanFactory所使⽤的场合不
同,这⾥只能是可配置的 BeanFactory,防⽌⼀些数据被⽤户随意修改。
registerBeanPostProcess⽅法也可以获取⽤户定义的实现了BeanPostProcessor接⼝的⼦类,并把他们注册到 BeanFacotry对象中的 beanPostProcessor变量中。在
BeanPostProcessor中声明了两个⽅法:postProcessBeforeInitialization和postProcessAfterInitialization,分别⽤于 Bean对象初始化时执⾏,可以执⾏⽤户⾃定义的操作。后⾯
⼏⾏代码是初始化监听事件和对系统的其他监听者的注册,监听者必须是 ApplicationListener的⼦类。
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
//不使⽤TempClassLoader
beanFactory.setTempClassLoader(null);
//禁⽌修改当前Bean的配置信息
beanFactory.freezeConfiguration();
//实例化non-lazy-init类型的bean
beanFactory.preInstantiateSingletons();
}
从上⾯的代码中可以发现 Bean的实例化是在 BeanFactory中发⽣的。PreInstantiateSingletons⽅法的代码如下:
1 @Override
2public void preInstantiateSingletons() throws BeansException {
3if (this.logger.isDebugEnabled()) { //⽇志(这是⼀种好的⽇志处理⽅式,当没有开启debug级别时,就会省下⼀次字符串拼接),spring源码⾥到处都是这样的处理,可以学习。
4this.logger.debug("Pre-instantiating singletons in " + this);
5 }
6
7// Iterate over a copy to allow for init methods which in turn register new bean definitions.
8// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
9//拷贝⼀个新的list ,this.beanDefinitionNames ⼲嘛的,上⽂⼤概已有说明,可以结合《Spring 源码阅读 BeanFactory(⼆) 之registerBeanDefinition⽅法》⼀块看
10 List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
11
12// Trigger initialization of all non-lazy
13for (String beanName : beanNames) { //遍历beanName
14//这⾥先解释⼀下getMergedLocalBeanDefinition⽅法的含义,因为这个⽅法会常常看到。Bean定义公共的抽象类是AbstractBeanDefinition,普通的Bean在Spring加载Bean定义的时候,实例化出来的是GenericBeanDefinition,⽽Spring上下15 RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
16if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {//⾮抽象的,单例的,⾮懒加载的
17if (isFactoryBean(beanName)) { //Spring中有两种类型的Bean,⼀种是普通Bean,另⼀种是⼯⼚Bean,即FactoryBean, ⼯⼚Bean 再起炉灶
18final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
19boolean isEagerInit;
20if (SecurityManager() != null && factory instanceof SmartFactoryBean) {
21 isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
22 @Override
23public Boolean run() {
24return ((SmartFactoryBean<?>) factory).isEagerInit();
25 }
26 }, getAccessControlContext());
27 }
28else {
29 isEagerInit = (factory instanceof SmartFactoryBean &&
30 ((SmartFactoryBean<?>) factory).isEagerInit());
31 }
32if (isEagerInit) {
33 getBean(beanName);
34 }
35 }
36else { //⾮⼯⼚Bean 调⽤该⽅法
37 getBean(beanName);
38 }
39 }
40 }
41 }
这⾥出现了⼀个 Bean(Factory Bean),可以说 Spring有⼀⼤半的扩展功能与这个 Bean有关,它是⼀个⼯⼚Bean,⽤于产⽣Bean实例,如果⼀个类继承 FactoryBean,⽤户可
以⾃定义产⽣对象的⽅法,只需要实现它的 getObject⽅法即可。然⽽在Spring内部,这个Bean的实例对象是 FactoryBean通过调⽤这个对象的 getObject⽅法就能获取⽤户⾃定
义产⽣的对象,从⽽为Spring 提供了很好的扩展性。Spring 获取 FactoryBean本⾝的对象是通过在前⾯加上&来完成的。
六、IOC容器的扩展点
对 Spring的 IOC容器来说,主要有 BeanFactoryPostProcessor和 BeanPostProcessor,他们分别在构建 BeanFactory和构建Bean对象时调⽤。还有就是 InItializingBean 和
DisposableBean,他们分别在Bean创建和销毁时调⽤。⽤户可以实现在这些接⼝中定义的⽅法,Spring 会在适当的时候调⽤它们。还有⼀个是FactoryBean,它是个特殊的
Bean,可以被⽤户更多的控制。
这些扩展点通常也是我们使⽤ Spring来完成特殊任务的地⽅,如何精通Spring就看是否掌握好Spring有哪些扩展点,以及如何使⽤它们。要知道如何使⽤它们就必须了解它们内
在的机制。
何实现扩展点来得到我们想要的结果,在Spring中有很多例⼦,其中AOP的实现就是通过扩展点达到想要的特性功能,可以拿来参考。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论