「《面试八股文》之 Spring 18卷」 又新鲜出炉了,这次整理了一下关于 spring 的面试题,网上也翻了翻关于 spring 的面试题,汇总了一下,基本都在这里了,当然可能有些过于基本的概念我是直接整理到某一问当中了,就没有单独再开设一问,祝大家面试顺利~
1.spring 中都用到了哪些设计模式?
2.spring 中有哪些核心模块?
3.说一下你理解的 IOC 是什么?
4.spring 中的 IOC 容器有哪些?有什么区别?
5.那 BeanFactory 和 FactoryBean 又有什么区别?
6.@Repository、@Service、@Compent、@Controller它们有什么区别?
7.那么 DI 又是什么?
8.说说 AOP 是什么?
9.动态代理和静态代理有什么区别?
10.JDK 动态代理和 CGLIB 代理有什么区别?
11.Spring AOP 和 AspectJ AOP 有什么区别?
12.spring 中 Bean 的生命周期是怎样的?
13.spring 是怎么解决循环依赖的?
14.为什么要使用三级缓存,二级缓存不能解决吗?
15.@Autowired 和 @Resource 有什么区别?
16.spring 事务隔离级别有哪些?
17.spring 事务的传播机制有哪些?
18.springBoot 自动装配原理?
首先 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 实现主要分为两类:」
spring 中 AOP 的实现是「通过动态代理实现的」,如果是实现了接口就会使用 JDK 动态代理,否则就使用 CGLIB 代理。
「有 5 种通知类型:」
「静态代理」
「动态代理」
JDK 动态代理时业务类「必须要实现某个接口」,它是「基于反射的机制实现的」,生成一个实现同样接口的一个代理类,然后通过重写方法的方式,实现对代码的增强。
CGLIB 动态代理是使用字节码处理框架 ASM,其原理是通过字节码技术为一个类「创建子类,然后重写父类的方法」,实现对代码的增强。
Spring AOP 是运行时增强,是通过「动态代理实现」的
AspectJ AOP 是编译时增强,需要特殊的编译器才可以完成,是通过「修改代码来实现」的,支持「三种织入方式」
主要区别 | Spring AOP | AspecjtJ AOP |
---|---|---|
增强方式 | 运行时增强 | 编译时增强 |
实现方式 | 动态代理 | 修改代码 |
编译器 | javac | 特殊的编译器 ajc |
效率 | 较低(运行时反射损耗性能) | 较高 |
织入方式 | 运行时 | 编译时、编译后、类加载时 |
SpringBean 生命周期大致分为4个阶段:
循环依赖就是说两个对象相互依赖,形成了一个环形的调用链路
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 注解一起来修饰。
1.容器在启动的时候会调用 EnableAutoConfigurationImportSelector.class 的 selectImports方法「获取一个全面的常用 BeanConfiguration 列表」
2.之后会读取 spring-boot-autoconfigure.jar 下面的spring.factories,「获取到所有的 Spring 相关的 Bean 的全限定名 ClassName」
3.之后继续「调用 filter 来一一筛选」,过滤掉一些我们不需要不符合条件的 Bean
4.最后把符合条件的 BeanConfiguration 注入默认的 EnableConfigurationPropertie 类里面的属性值,并且「注入到 IOC 环境当中」
以上是《面试八股文》之 Spring 18卷的详细内容。更多信息请关注PHP中文网其他相关文章!