Spring源码学习笔记(十一、阶段总结)

学了一段时间的Spring源码,有些感触,虽然谈不上感触颇深但也有些体会,今天我把一些个人的感触记下来(才读了冰山一角,哈哈哈哈哈哈)。

1、面向接口编程

哎,这其实没啥好说的,这不是常态么。

但我个人认为有扩展可能的程序才需要定义接口,向那些短期内不会变化或变化维度过大,我个人认为最好不要定义接口吧(仅针对业务开发)。

因为你根本不知道需求会怎么变,你完全可以之后再重构,持续重构不香嘛。

当然如果是框架开发的话,需求还是比较明确的,使用面向接口编程还是很香的。

2、最小知道原则

通过阅读Spring源码后,我发现很多关键且通用的函数时无参的居多。

就比如Spring的核心refresh函数,其内部很多关键流程的代码就是无参的,有的话也只是一个factory,说明Spring封装做的非常好,只要把bean实例化出来后,很多东西就能够通过属性值来获取了。

 1 @Override
 2 public void refresh() throws BeansException, IllegalStateException {
 3     synchronized (this.startupShutdownMonitor) {
 4         // Prepare this context for refreshing.
 5         prepareRefresh();
 6 
 7         // Tell the subclass to refresh the internal bean factory.
 8         ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
 9 
10         // Prepare the bean factory for use in this context.
11         prepareBeanFactory(beanFactory);
12 
13         try {
14             // Allows post-processing of the bean factory in context subclasses.
15             postProcessBeanFactory(beanFactory);
16 
17             // Invoke factory processors registered as beans in the context.
18             invokeBeanFactoryPostProcessors(beanFactory);
19 
20             // Register bean processors that intercept bean creation.
21             registerBeanPostProcessors(beanFactory);
22 
23             // Initialize message source for this context.
24             initMessageSource();
25 
26             // Initialize event multicaster for this context.
27             initApplicationEventMulticaster();
28 
29             // Initialize other special beans in specific context subclasses.
30             onRefresh();
31 
32             // Check for listener beans and register them.
33             registerListeners();
34 
35             // Instantiate all remaining (non-lazy-init) singletons.
36             finishBeanFactoryInitialization(beanFactory);
37 
38             // Last step: publish corresponding event.
39             finishRefresh();
40         }
41 
42         catch (BeansException ex) {
43             if (logger.isWarnEnabled()) {
44                 logger.warn("Exception encountered during context initialization - " +
45                         "cancelling refresh attempt: " + ex);
46             }
47 
48             // Destroy already created singletons to avoid dangling resources.
49             destroyBeans();
50 
51             // Reset 'active' flag.
52             cancelRefresh(ex);
53 
54             // Propagate exception to caller.
55             throw ex;
56         }
57 
58         finally {
59             // Reset common introspection caches in Spring's core, since we
60             // might not ever need metadata for singleton beans anymore...
61             resetCommonCaches();
62         }
63     }
64 }

这点和推崇的充血模型还是比较像的,这种模型的开发方式可以让你在不了解系统整体的情况下,可以快速知道相关模块的业务逻辑。

当然这只适用于具有一定规模的系统,如果是小项目还是用贫血模型比较舒服,开发起来比较简单。

3、设计模式的灵活运用

哎,这点就不用说了吧,人尽皆知了,哈哈哈哈。

设计模式这个东西也需要你有长期的开发经验才能更深层次的体会。

4、接口定义

emmmmmmm,我其实想说单一职责的,但这个好像大伙都知道哦。

Spring的接口定义是非常简单的,一个接口该干什么就干什么,没有多余的定义,而需要扩展的话会再次定义。

如BeanFactory就是定义bean的相关操作,对父容器的扩展是通过HierarchicalBeanFactory接口来定义的。

这里要学学,而不是一开始就把接口定义的很模糊,然后往里面加一大堆东西,哈哈哈哈哈哈。

5、解决问题思路

循环依赖

循环依赖就是A依赖B,B又依赖A;因为在实例化A的时候需要用到B,所以肯定会先去把B实例化好,然后又发现B要实例化的时候又需要B,这样就形成了一个死循环。

既然会出现死循环,那么我们要解决的问题就是找到死循环的退出条件,这样循环依赖的问题不就迎刃而解了嘛(这就是解决问题的思路)。

那么Spring是如何解决循环依赖的呢,首先我们想想如果两个bean都是通过构造函数注入的话,肯定就是不行的,因为这样两个bean就都没办法实例化了,拿不到对方的对象。那么我们能不能先值注入只完成了实例化的bean呢,当然可以,而Spring也是这样做的。

Spring是提前暴露刚完成构造函数注入而未完成其它步骤(如setter注入)的bean来解决循环依赖的问题,采用了三级缓存实现,即singletonObjects、earlySingletonObjects和singletonFactories

6、等等等等。。。。。。。

 

你可能感兴趣的:(Spring源码学习笔记(十一、阶段总结))