首页 > 应用开发 > > 18 道经典 Spring 面试题
这次整理了一下关于 Spring 的面试题,网上也翻了翻关于 Spring 的面试题,汇总了一下,基本都在这里了,当然,可能有些过于基本的概念我是直接整理到某一问当中了,就没有单独再开设一问,祝大家面试顺利~

工厂设计模式:比如通过 BeanFactory 和 ApplicationContext 来生产 Bean 对象;
代理设计模式:AOP 的实现方式就是通过代理来实现,Spring 主要是使用 JDK 动态代理和 CGLIB 代理;
单例设计模式:Spring 中的 Bean 默认都是单例的;
模板方法模式:Spring 中 jdbcTemplate 等以 Template 结尾的对数据库操作的类,都会使用到模板方法设计模式,一些通用的功能;
包装器设计模式:我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源;
观察者模式:Spring 事件驱动模型观察者模式的;
适配器模式:Spring AOP 的增强或通知(Advice)使用到了适配器模式。

Spring Core:Spring 核心,它是框架最基础的部分,提供 IOC 和依赖注入 DI 特性;
Spring Context:Spring 上下文容器,它是 BeanFactory 功能加强的一个子接口;
Spring Web:它提供 Web 应用开发的支持;
Spring MVC:它针对 Web 应用中 MVC 思想的实现;
Spring DAO:提供对 JDBC 抽象层,简化了 JDBC 编码。同时,编码更具有健壮性;
Spring ORM:它支持用于流行的 ORM 框架的整合,比如 Spring + Hibernate、Spring + iBatis、Spring + JDO 的整合等;
Spring AOP:即面向切面编程,它提供了与 AOP 联盟兼容的编程实现。

首先 IOC 是一个容器,是用来装载对象的,它的核心思想就是控制反转。
那么究竟什么是控制反转?
控制反转就是说,「把对象的控制权交给了 Spring,由 Spring 容器进行管理」,我们不进行任何操作。
那么为「什么需要控制反转」?
我们想象一下,没有控制反转的时候,我们需要自己去创建对象、配置对象,还要人工去处理对象与对象之间的各种复杂的依赖关系。
当一个工程的量起来之后,这种关系的维护是非常令人头痛的,所以就有了控制反转这个概念,将对象的创建、配置等一系列操作交给 Spring 去管理,我们在使用的时候只要去取就好了。
Spring 主要提供了「两种 IOC 容器」,一种是 BeanFactory,还有一种是 「ApplicationContext」。
它们的区别就在于,BeanFactory 只提供了最基本的实例化对象和获取对象的功能,而 ApplicationContext 是继承了 BeanFactory 所派生出来的产物,是其子类,它的作用更加的强大,比如支持注解注入、国际化等功能。
这两个是不同的产物
BeanFactory 是 IOC 容器,是用来承载对象的;
FactoryBean 是一个接口,为 Bean 提供了更加灵活的方式,通过代理一个Bean对象,对方法前后做一些操作。
这四个注解的本质都是一样的,都是将被该注解标识的对象放入 Spring 容器当中,只是为了在使用上区分不同的应用分层。
DI 就是依赖注入,其实和 IOC 大致相同,只不过是同一个概念使用了不同的角度去阐述。
DI 所描述的重点是在于依赖。我们说了 IOC 的核心功能就是在于在程序运行时动态的向某个对象提供其他的依赖对象,而这个功能就是依靠 DI 去完成的,比如我们需要注入一个对象 A,而这个对象 A 依赖一个对象 B,那么我们就需要把这个对象 B 注入到对象 A 中,这就是依赖注入。
Spring 有三种注入方式
AOP 意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。
AOP 是 「OOP(面向对象编程) 的延续」,是 Spring 框架中的一个重要内容,是函数式编程的一种衍生范型。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP 实现主要分为两类:

静态 AOP 实现:AOP 框架在编译阶段对程序源代码进行修改,生成了静态的 AOP 代理类(生成的 *.class 文件已经被改掉了,需要使用特定的编译器),比如 AspectJ;
动态 AOP 实现:AOP 框架在运行阶段对动态生成代理对象。在内存中以 JDK 动态代理或 CGlib 动态地生成 AOP 代理类,如 Spring AOP。
Spring 的 AOP 实现是通过动态代理实现的。如果实现了接口就会使用 JDK 动态代理,否则就使用 CGLIB 代理。

有 5 种通知类型
静态代理
动态代理
JDK 动态代理时业务类必须要实现某个接口,它是基于反射的机制实现的。生成一个实现同样接口的一个代理类,然后通过重写方法的方式,实现对代码的增强。
CGLIB 动态代理是使用字节码处理框架 ASM,其原理是通过字节码技术为一个类创建子类,然后重写父类的方法,实现对代码的增强。
Spring AOP 属于运行时增强,是通过动态代理实现的。
AspectJ AOP 是编译时增强,需要特殊的编译器才可以完成,是通过修改代码来实现的,支持三种织入方式。


Spring Bean 生命周期大致分为 4 个阶段:

实例化:实例化该 Bean 对象;
填充属性:给该 Bean 赋值;
初始化
如果实现了 Aware 接口,会通过其接口获取容器资源;
如果实现了 BeanPostProcessor 接口,则会回调该接口的前置和后置处理增强;
如果配置了 init-method 方法,会执行该方法。
销毁
如果实现了 DisposableBean 接口,则会回调该接口的 destroy 方法;
如果配置了 destroy-method 方法,则会执行 destroy-method 配置的方法。

循环依赖就是说两个对象相互依赖,形成了一个环形的调用链路。
Spring 使用三级缓存去解决循环依赖的,其核心逻辑就是把实例化和初始化的步骤分开,然后放入缓存中,供另一个对象调用:
当 A、B 两个类发生循环引用时的大致流程:
Spring 解决循环依赖有两个前提条件:
可以。三级缓存的功能是只有真正发生循环依赖的时候,才去提前生成代理对象,否则只会创建一个工厂并将其放入到三级缓存中,但是不会去通过这个工厂去真正创建对象。
如果使用二级缓存解决循环依赖,意味着所有 Bean 在实例化后就要完成 AOP 代理,这样违背了 Spring 设计的原则。Spring 在设计之初就是在 Bean 生命周期的最后一步来完成 AOP 代理,而不是在实例化后就立马进行 AOP 代理。
@Resource 是 Java 自己的注解。@Resource 有两个属性是比较重要的,分是 name 和 type。Spring 将 @Resource 注解的 name 属性解析为 bean 的名字,而 type 属性则解析为 bean 的类型。
所以,如果使用 name 属性,则使用 byName 的自动注入策略,而使用 type 属性时则使用 byType 自动注入策略。
如果既不指定 name 也不指定 type 属性,这时将通过反射机制使用 byName 自动注入策略。
@Autowired 是 Spring 的注解,是 Spring2.5 版本引入的。
Autowired 只根据 type 进行注入,不会去匹配 name;
如果涉及到 type 无法辨别注入对象时,那需要依赖 @Qualifier 或 @Primary 注解一起来修饰。



容器在启动的时候会调用 EnableAutoConfigurationImportSelector.class 的 selectImports方法获取一个全面的常用 BeanConfiguration 列表;
之后会读取 spring-boot-autoconfigure.jar 下面的 spring.factories,获取到所有的 Spring 相关的 Bean 的全限定名 ClassName;
之后继续调用 filter 来一一筛选,过滤掉一些我们不需要不符合条件的 Bean;
最后把符合条件的 BeanConfiguration 注入默认的 EnableConfigurationPropertie 类里面的属性值,并且注入到 IOC 环境当中。
- EOF -
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/1343/viewspace-3123692/ ,如需转载,请注明出处,否则将追究法律责任。