For investors
股价:
5.36 美元 %For investors
股价:
5.36 美元 %认真做教育 专心促就业
1. 什么是 Spring Framework?
这个问题很难回答,在 Spring 官方文档中的描述也很抽象,答案在于你对 Spring 是如何理解的,想必每个人都有自己的回答方式,以下是我个人对于 Spring 的理解:
整个 Spring 生态在涉及到 Java 的项目中被广泛应用,它提供了非常多的组件,能够让你在开发 Java 应用的过程变得更加容易,弹性地支持其他软件框架,可以比作一个“排插座”,其他软件框架简单地“插上”即可结合 Spring 一起使用,给开发人员带来了非常多的便利。Spring 底层 IoC 容器的设计实现也是非常完美的,在整个 Spring 应用上下文的生命周期和 Spring Bean 的生命周期的许多阶段提供了相应的扩展点,供开发者自行扩展,使得框架非常的灵活。
2. Spring Framework 的优势和不足?
优势:Spring 面向模块进行开发,根据不同的功能进行划分,根据需求引入对应的模块即可,对于开发人员非常友好。例如 Spring IoC 容器,将我们的 Java 对象作为 Spring Bean 进行管理,管理着 Bean 的整个生命周期;Spring MVC 提供“模型-视图-控制器”(Model-View-Controller)架构和随时可用的组件,用于开发灵活且松散耦合的 Web 应用程序;Spring AOP 提供面向切面编程的接口,可以很方便的使用;还有许多其他的功能模块,就不一一讲述了。
不足:整个 Spring 体系比较复杂,对于开发人员需要一定的学习成本,遇到相关问题时需要对底层实现有充分的了解,这也就需要开发人员投入更多的时间和精力去学习。当然,如今 Spring 体系整合了 Java 生态非常多的东西,为开发人员带来的便利远大于这些不足,我觉得是有必要对 Spring 进行充分的学习,去了解 Spring 的贡献者们的设计思路,对自身也会有很大的提升,从中可以学习到许多的东西。
3. 你对 IoC 的理解?
Inversion of Control(IoC)是面向对象中的一种编程思想或原则。可以先回到传统方式,当我依赖一个对象,我需要主动去创建它并进行属性赋值,然后我才能去使用这个对象。对于 IoC 这种方式来说,它使得对象或者组件的创建更为透明,你不需要过多地关注细节,如创建对象、属性赋值,这些工作交都由 IoC 容器来完成,已达到解耦的目的。
IoC 控制反转,简单来理解其实就是把获取依赖对象的方式,交由 IoC 容器来实现,由“主动拉取”变为“被动获取”。
4. 为什么需要 IoC ?
实际上,IoC 是为了屏蔽构造细节。例如 new 出来的对象的生命周期中的所有细节对于使用端都是知道的,如果在没有 IoC 容器的前提下,IoC 是没有存在的必要,不过在复杂的系统中,我们的应用更应该关注的是对象的运用,而非它的构造和初始化等细节。
5. IoC 和 DI 的区别?
DI 依赖注入不完全等同于 IoC,更应该说 DI 依赖注入是 IoC 的一种实现方式或策略。
依赖查找和依赖注入都是 IoC 的实现策略。依赖查找就是在应用程序里面主动调用 IoC 容器提供的接口去获取对应的 Bean 对象,而依赖注入是在 IoC 容器启动或者初始化的时候,通过构造器、字段、setter 方法或者接口等方式注入依赖。依赖查找相比于依赖注入对于开发者而言更加繁琐,具有一定的代码入侵性,需要借助 IoC 容器提供的接口,所以我们总是强调后者。依赖注入在 IoC 容器中的实现也是调用相关的接口获取 Bean 对象,只不过这些工作都是在 IoC 容器启动时由容器帮你实现了,在应用程序中我们通常很少主动去调用接口获取 Bean 对象。
6. IoC 容器的职责?
主要有以下职责:
依赖处理,通过依赖查找或者依赖注入
管理托管的资源(Java Bean 或其他资源)的生命周期
管理配置(容器配置、外部化配置、托管的资源的配置)
IoC 容器有非常多,例如 JDK 的 Java Beans,Java EE 的 EJB,Apache Avalon,Google guice,Spring,其中 Spring 是最成功的的一个,目前被广泛应用。
其中 Spring 借鉴了 JDK 的 Java Beans 设计思想,也使用到其中相关类(例如 java.beans.PropertyEditor 属性编辑器),开发过 IDE 的 GUI 界面的伙伴应该对 Java Beans 比较熟悉。
7. 什么是 Spring IoC 容器?
Spring 框架是一个 IoC 容器的实现,DI 依赖注入是它的实现的一个原则,提供依赖查找和依赖注入两种依赖处理,管理着 Bean 的生命周期。Spring 还提供了 AOP 抽象、事件抽象、事件监听机制、SPI 机制、强大的第三方整合、易测试性等其他特性。
8. 构造器注入和 Setter 注入
构造器注入:通过构造器的参数注入相关依赖对象
Setter 注入:通过 Setter 方法注入依赖对象,也可以理解为字段注入
对于两种注入方式的看法:
构造器注入可以避免一些尴尬的问题,比如说状态不确定性地被修改,在初始化该对象时才会注入依赖对象,一定程度上保证了 Bean 初始化后就是不变的对象,这样对于我们的程序和维护性都会带来更多的便利;
构造器注入不允许出现循环依赖,因为它要求被注入的对象都是成熟态,保证能够实例化,而 Setter 注入或字段注入没有这样的要求;
构造器注入可以保证依赖的对象能够有序的被注入,而 Setter 注入或字段注入底层是通过反射机制进行注入,无法完全保证注入的顺序;
如果构造器注入出现比较多的依赖导致代码不够优雅,我们应该考虑自身代码的设计是否存在问题,是否需要重构代码结构。
除了上面的注入方式外,Spring 还提供了接口回调注入,通过实现 Aware 接口(例如 BeanNameAware、ApplicationContextAware)可以注入相关对象,Spring 在初始化这类 Bean 时会调用其 setXxx 方法注入对象,例如注入 beanName、ApplicationContext
9. BeanFactory 和 ApplicationContext 谁才是 Spring IoC 容器?
BeanFactory 是 Spring 底层 IoC 容器,ApplicationContext 是 BeanFactory 的子接口,是 BeanFactory 的一个超集,提供 IoC 容器以外更多的功能。ApplicationContext 除了扮演 IoC 容器角色,还提供了这些企业特性:面向切面(AOP)、配置元信息、资源管理、事件机制、国际化、注解、Environment 抽象等。我们一般称 ApplicationContext 是 Spring 应用上下文,BeanFactory 为 Spring 底层 IoC 容器。
10. Spring Bean 的生命周期?
生命周期:
Spring Bean 元信息配置阶段,可以通过面向资源(XML 或 Properties)、面向注解、面向 API 进行配置
Spring Bean 元信息解析阶段,对上一步的配置元信息进行解析,解析成 BeanDefinition 对象,该对象包含定义 Bean 的所有信息,用于实例化一个 Spring Bean
Spring Bean 元信息注册阶段,将 BeanDefinition 配置元信息 保存至 BeanDefinitionRegistry 的 ConcurrentHashMap 集合中
Spring BeanDefinition 合并阶段,定义的 Bean 可能存在层次性关系,则需要将它们进行合并,存在相同配置则覆盖父属性,最终生成一个 RootBeanDefinition 对象
Spring Bean 的实例化阶段,首先的通过类加载器加载出一个 Class 对象,通过这个 Class 对象的构造器创建一个实例对象,构造器注入在此处会完成。在实例化阶段 Spring 提供了实例化前后两个扩展点(InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation、postProcessAfterInstantiation 方法)
Spring Bean 属性赋值阶段,在 Spring 实例化后,需要对其相关属性进行赋值,注入依赖的对象。首先获取该对象所有属性与属性值的映射,可能已定义,也可能需要注入,在这里都会进行赋值(反射机制)。提示一下,依赖注入的实现通过 CommonAnnotationBeanPostProcessor(@Resource、@PostConstruct、@PreDestroy)和 AutowiredAnnotationBeanPostProcessor(@Autowired、@Value)两个处理器实现的。
Aware 接口回调阶段,如果 Spring Bean 是 Spring 提供的 Aware 接口类型(例如 BeanNameAware、ApplicationContextAware),这里会进行接口的回调,注入相关对象(例如 beanName、ApplicationContext)
Spring Bean 初始化阶段,这里会调用 Spring Bean 配置的初始化方法,执行顺序:@PostConstruct 标注方法、实现 InitializingBean 接口的 afterPropertiesSet() 方法、自定义初始化方法。在初始化阶段 Spring 提供了初始化前后两个扩展点(BeanPostProcessor 的 postProcessBeforeInitialization、postProcessAfterInitialization 方法)
Spring Bean 初始化完成阶段,在所有的 Bean(不是抽象、单例模式、不是懒加载方式)初始化后,Spring 会再次遍历所有初始化好的单例 Bean 对象,如果是 SmartInitializingSingleton 类型则调用其 afterSingletonsInstantiated() 方法,这里也属于 Spring 提供的一个扩展点
Spring Bean 销毁阶段,当 Spring 应用上下文关闭或者你主动销毁某个 Bean 时则进入 Spring Bean 的销毁阶段,执行顺序:@PreDestroy 注解的销毁动作、实现了 DisposableBean 接口的 Bean 的回调、destroy-method 自定义的销毁方法。这里也有一个销毁前阶段,也属于 Spring 提供的一个扩展点,@PreDestroy 就是基于这个实现的