为什么要使用spring

使用过Spring的同学都知道,"Spring是一个容器"。其实,这种说法不太准确,Spring提供的容器不止一种,例如有ClasspathXmlApplicationContext、XmlWebApplicationContext等多种容器,所有这些容器的父类都是BeanFactory。

但是为什么起名叫"工厂"呢?单纯的"容器"只起到一个存放对象的作用,如果只是想把对象存放起来,那么ArrayList,HashSet等Java集合类完全可以胜任,根本用不着Spring。Spring容器并不是单纯用于存放对象的,它存放对象定义(bean definition),而不止是存放对象(bean)。当需要一个对象时,我们从bean容器获取,而bean容器(BeanFactory)负责根据定义创建对象,所以说它是一个"工厂"。

 

反过来,它又为什么叫做"容器"?这是因为在大多数时候,bean都被定义为单例(singleton,与GoF中的singleton略有不同),且这些bean的类是Spring提供的ClassLoader加载的,单例的bean被实例化一次之后就一直保存在这个工厂中,以后每次请求获得这个bean都是同一个对象,相当于这个对象被放在BeanFactory中了,所以它又可以视为一个容器。

而对于非singleton的bean来说,例如scope等于prototype的bean,BeanFactory就主要表现为一个工厂了,每次请求都返回一个不同的实例。

既然说到scope,顺便分享一道常见的Spring面试题,"Spring中bean/对象的类型(scope)有哪些"?回答:取决于你所使用的具体容器。如果使用的是基本容器,例如ClasspathXmlApplicationContext,那么只有singleton和prototype可用;如果使用的是Web容器(例如WebXmlApplicationContext),那么就有singleton, prototype,request,session和global等可用;另外,scope还可以自定义。

Spring通过把自己设计成一个管理应用程序模块定义的容器以及工厂,而不是管理模块自身的容器,让模块可以分别独立开发,实现了模块之间的解耦。

深入理解Dependency Injection和Inversion of Control

依赖注入(Depdendency Injection)和控制反转(IoC,Inversion of Control)是同一个概念,Spring实践了这个思想,为Java Web应用程序建立起一个基本框架。换句话说,Spring是Java Web应用程序的基本框架。下次面试官如果问你,"为什么要使用Spring",你可以回答"它提供了一个Web应用程序的基本框架",然后说它是工厂和容器,提供了IoC,不要回答"用起来方便"

因为任何一个大型应用程序都包含很多组件(components),组件之间互相调用,并且在运行时并非所有组件都必须创建。如果没有一个整体的结构(框架),程序将会变得混乱、难以维护。假如不使用Spring,那么每次需要调用另一个组件的时候就new一个对象,或者getInstance得到一个实例。当组件越来越多,程序规模越来越大,这种方式会让组件之间的耦合度很高,难以维护。

Spring框架基于BeanFactory,把模块的配置信息(bean definition)统一管理起来(有的模块可以根据需要创建,若不调用则不创建),同时,还把模块的配置参数也统一管理(每个模块不必自己读配置参数,由Spring加载)。程序结构变清晰很多。在此基础上,加上依赖注入的功能,即Spring负责把模块依赖的其他模块推送(push)进来,而不是模块自己去拉取(pull),所以是一个"反转(IoC)",进一步简化了大型应用程序开发。

根据上面讨论,我们总结一下,为什么要使用Spring:

  1. Spring提供一个容器/工厂,统一管理模块的定义,根据需要创建。
  2. 把模块的配置参数统一管理,模块不需要自行读取配置。
  3. Spring提供依赖注入,把依赖的模块自动推送进来,不需要模块自己拉取。
  4. 此外,Spring提供了对很多其他第三方框架的集成功能,减少了样板代码(boilerplate)。

Spring中bean的生命周期

在Web应用程序启动过程中,Spring容器中的每个bean也有各自的初始化顺序。一个bean,从bean definition被加载到初始化完成,按照以下顺序执行:

1. BeanFactory加载完bean definition和class,实例化除了bean对象。

2. 检查有没有实现BeanNameAware,有则调用setBeanName(得到bean id)

3. 检查有没有实现BeanClassLoaderAware,有则调用setBeanClassLoader。

4. 检查有没有实现EnvironmentAware,有则调用setEnvironment。

5. 检查有没有实现EmbeddedValueResolverAware,有则调用setEmbeddedValueResolver。

6. 检查有没有实现ResourceLoaderAware,有则调用setResourceLoader。

7. 检查有没有实现ApplicationEventPublisherAware,有则调用setApplicationEventPublisher。

8. 检查有没有实现MessageSourceAware,有则调用setMessageSource。

9. 检查有没有实现ApplicationContextAware,有则调用setApplicationContext。

10. 检查有没有实现ServletContextAware,有则调用setServletContext。

11. 调用BeanPostProcessors中的所有postProcessBeforeInitialization,对bean进行一些更进一步的配置。

12. 调用InitializingBean接口中的afterPropertiesSet执行bean自身提供的初始化代码。

13. 调用通过其他方式指定的init-method方法,执行bean自身的初始化。

14. 调用BeanPostProcessors中的所有postProcessAfterInitialization方法。

经历了上述的14个步骤,spring bean才完整地创建出来,很不容易。从以上步骤可以了解到,在初始化方法中哪些资源是已经准备好可以访问的,哪些是还不能访问的。

 

作者:于斯
链接:https://zhuanlan.zhihu.com/p/67066409
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值