学了一段时间的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、等等等等。。。。。。。