• Spring常考知识点(IOC、事务、容器等)


    作者:逍遥Sean
    简介:一个主修Java的Web网站\游戏服务器后端开发者
    主页:https://blog.csdn.net/Ureliable
    觉得博主文章不错的话,可以三连支持一下~ 如有需要我的支持,请私信或评论留言!


    Spring在面试中的 高频问题总结,码起来,面试之前复习一遍!!!

    谈谈你对IOC的理解

    通常,我们认为Spring有两⼤特性IoC和AOP,那到底该如何理解IoC呢?
    对于很多初学者来说,IoC这个概念给⼈的感觉就是我好像会,但是我说不出来
    那么IoC到底是什么,接下来来说说我的理解,实际上这是⼀个⾮常⼤的问题,所以我们就把它拆细了来回答,IoC表示控制反转,那么:

    1. 什么是控制?控制了什么?
    2. 什么是反转?反转之前是谁控制的?反转之后是谁控制的?如何控制的?
    3. 为什么要反转?反转之前有什么问题?反转之后有什么好处?

    这就是解决这⼀类⼤问题的思路,⼤⽽化⼩。
    那么,我们先来解决第⼀个问题:什么是控制?控制了什么?
    我们在⽤Spring的时候,我们需要做什么:

    1. 建⼀些类,⽐如UserService、OrderService
    2. ⽤⼀些注解,⽐如@Autowired

    但是,我们也知道,当程序运⾏时,⽤的是具体的UserService对象、OrderService对象,那这些对象是什么时候创建的?谁创建的?包括对象⾥的属性是什么时候赋的值?谁赋的?所有这些都是我们程序员做的,以为我们只是写了类⽽已,所有的这些都是Spring做的,它才是幕后⿊⼿。
    这就是控制:

    1. 控制对象的创建
    2. 控制对象内属性的赋值

    如果我们不⽤Spring,那我们得⾃⼰来做这两件事,反过来,我们⽤Spring,这两件事情就不⽤我们做了,我们要做的仅仅是定义类,以及定义哪些属性需要Spring来赋值(⽐如某个属性上加@Autowired),⽽这其实就是第⼆个问题的答案,这就是反转,表示⼀种对象控制权的转移。
    那反转有什么⽤,为什么要反转?
    如果我们⾃⼰来负责创建对象,⾃⼰来给对象中的属性赋值,会出现什么情况?
    ⽐如,现在有三个类:

    1. A类,A类⾥有⼀个属性C c;
    2. B类,B类⾥也有⼀个属性C c;
    3. C类

    现在程序要运⾏,这三个类的对象都需要创建出来,并且相应的属性都需要有值,那么除开定义这三个
    类之外,我们还得写:

    1. A a = new A();
    2. B b = new B();
    3. C c = new C();
    4. a.c = c;
    5. b.c = c;

    这五⾏代码是不⽤Spring的情况下多出来的代码,⽽且,如果类在多⼀些,类中的属性在多⼀些,那相应的代码会更多,⽽且代码会更复杂。所以我们可以发现,我们⾃⼰来控制⽐交给Spring来控制,我们的代码量以及代码复杂度是要⾼很多的,反⾔之,将对象交给Spring来控制,减轻了程序员的负担。
    总结⼀下,IoC表示控制反转,表示如果⽤Spring,那么Spring会负责来创建对象,以及给对象内的属性赋值,也就是如果⽤Spring,那么对象的控制权会转交给Spring。
    以上是SpringIOC的理解,参考这两篇文章可以更好地理解IOC原理:
    IOC概述及其实现原理
    理解Spring原理 - 手写IOC和DI

    单例Bean和单例模式

    单例模式表示JVM中某个类的对象只会存在唯⼀⼀个。
    ⽽单例Bean并不表示JVM中只能存在唯⼀的某个类的Bean对象。

    Spring事务传播机制

    多个事务⽅法相互调⽤时,事务如何在这些⽅法间传播,⽅法A是⼀个事务的⽅法,⽅法A执⾏过程中调⽤了⽅法B,那么⽅法B有⽆事务以及⽅法B对事务的要求不同都会对⽅法A的事务具体执⾏造成影响,同时⽅法A的事务对⽅法B的事务执⾏也有影响,这种影响具体是什么就由两个⽅法所定义的事务传播类型所决定。

    1. REQUIRED(Spring默认的事务传播类型):如果当前没有事务,则⾃⼰新建⼀个事务,如果当前存 在事务,则加⼊这个事务
    2. SUPPORTS:当前存在事务,则加⼊当前事务,如果当前没有事务,就以⾮事务⽅法执⾏
    3. MANDATORY:当前存在事务,则加⼊当前事务,如果当前事务不存在,则抛出异常。
    4. REQUIRES_NEW:创建⼀个新事务,如果存在当前事务,则挂起该事务。
    5. NOT_SUPPORTED:以⾮事务⽅式执⾏,如果当前存在事务,则挂起当前事务
    6. NEVER:不使⽤事务,如果当前事务存在,则抛出异常
    7. NESTED:如果当前事务存在,则在嵌套事务中执⾏,否则REQUIRED的操作⼀样(开启⼀个事
      务)

    Spring事务什么时候会失效

    spring事务的原理是AOP,进⾏了切⾯增强,那么失效的根本原因是这个AOP不起作⽤了!常⻅情况有如下⼏种

    1. 发⽣⾃调⽤,类⾥⾯使⽤this调⽤本类的⽅法(this通常省略),此时这个this对象不是代理类,⽽是UserService对象本身!解决⽅法很简单,让那个this变成UserService的代理类即可!
    2. ⽅法不是public的:@Transactional 只能⽤于 public 的⽅法上,否则事务不会失效,如果要⽤在⾮ public ⽅法上,可以开启 AspectJ 代理模式。
    3. 数据库不⽀持事务
    4. 没有被spring管理
    5. 异常被吃掉,事务不会回滚(或者抛出的异常没有被定义,默认为RuntimeException)

    Spring中的Bean创建的⽣命周期有哪些步骤

    Spring中⼀个Bean的创建⼤概分为以下⼏个步骤:

    1. 推断构造⽅法
    2. 实例化
    3. 填充属性,也就是依赖注⼊
    4. 处理Aware回调
    5. 初始化前,处理@PostConstruct注解
    6. 初始化,处理InitializingBean接⼝
    7. 初始化后,进⾏AOP

    Spring中Bean是线程安全的吗

    Spring本身并没有针对Bean做线程安全的处理,所以:

    1. 如果Bean是⽆状态的,那么Bean则是线程安全的
    2. 如果Bean是有状态的,那么Bean则不是线程安全的

    另外,Bean是不是线程安全,跟Bean的作⽤域没有关系,Bean的作⽤域只是表示Bean的⽣命周期范围,对于任何⽣命周期的Bean都是⼀个对象,这个对象是不是线程安全的,还是得看这个Bean对象本身。

    ApplicationContext和BeanFactory有什么区别

    BeanFactory是Spring中⾮常核⼼的组件,表示Bean⼯⼚,可以⽣成Bean,维护Bean,⽽ApplicationContext继承了BeanFactory,所以ApplicationContext拥有BeanFactory所有的特点,也是⼀个Bean⼯⼚,但是ApplicationContext除开继承了BeanFactory之外,还继承了诸如EnvironmentCapableMessageSourceApplicationEventPublisher等接⼝,从⽽ApplicationContext还有获取系统环境变量、国际化、事件发布等功能,这是BeanFactory所不具备的

    Spring中的事务是如何实现的

    1. Spring事务底层是基于数据库事务和AOP机制的
    2. ⾸先对于使⽤了@Transactional注解的Bean,Spring会创建⼀个代理对象作为Bean
    3. 当调⽤代理对象的⽅法时,会先判断该⽅法上是否加了@Transactional注解
    4. 如果加了,那么则利⽤事务管理器创建⼀个数据库连接
    5. 并且修改数据库连接的autocommit属性为false,禁⽌此连接的⾃动提交,这是实现Spring事务⾮常重要的⼀步
    6. 然后执⾏当前⽅法,⽅法中会执⾏sql
    7. 执⾏完当前⽅法后,如果没有出现异常就直接提交事务
    8. 如果出现了异常,并且这个异常是需要回滚的就会回滚事务,否则仍然提交事务
    9. Spring事务的隔离级别对应的就是数据库的隔离级别
    10. Spring事务的传播机制是Spring事务⾃⼰实现的,也是Spring事务中最复杂的
    11. Spring事务的传播机制是基于数据库连接来做的,⼀个数据库连接⼀个事务,如果传播机制配置为
      需要新开⼀个事务,那么实际上就是先建⽴⼀个数据库连接,在此新数据库连接上执⾏sql

    Spring中什么时候@Transactional会失效

    因为Spring事务是基于代理来实现的,所以某个加了@Transactional的⽅法只有是被代理对象调⽤时,那么这个注解才会⽣效,所以如果是被代理对象来调⽤这个⽅法,那么@Transactional是不会失效的。
    同时如果某个⽅法是private的,那么@Transactional也会失效,因为底层cglib是基于⽗⼦类来实现的,⼦类是不能重载⽗类的private⽅法的,所以⽆法很好的利⽤代理,也会导致@Transactianal失效

    1. 不是代理对象被调用
    2. 方法不可访问(private)

    Spring容器启动流程是怎样的

    在创建Spring容器,也就是启动Spring时:

    1. 扫描Bean。⾸先会进⾏扫描,扫描得到所有的BeanDefinition对象,并存在⼀个Map中
    2. 创建Bean。然后筛选出⾮懒加载的单例BeanDefinition进⾏创建Bean,对于多例Bean不需要在启动过程中去进⾏创建,对于多例Bean会在每次获取Bean时利⽤BeanDefinition去创建
    3. 构造Bean。利⽤BeanDefinition创建Bean就是Bean的创建⽣命周期,这期间包括了合并BeanDefinition、推断构造⽅法、实例化、属性填充、初始化前、初始化、初始化后等步骤,其中AOP就是发⽣在初始化
      后这⼀步骤中
    4. 启动容器。单例Bean创建完了之后,Spring会发布⼀个容器启动事件。Spring启动结束
    5. 在源码中会更复杂,⽐如源码中会提供⼀些模板⽅法,让⼦类来实现,⽐如源码中还涉及到⼀些BeanFactoryPostProcessor和BeanPostProcessor的注册,Spring的扫描就是通过BenaFactoryPostProcessor来实现的,依赖注⼊就是通过BeanPostProcessor来实现的
    6. 在Spring启动过程中还会去处理@Import等注解

    Spring⽤到了哪些设计模式

    1. 单例模式
    2. 工厂模式
    3. 模板方法模式
    4. 代理模式

    这些比较容易理解的,还有其他的比如:责任链模式,观察者模式,面试中只需要完整的说出几个并举例即可

  • 相关阅读:
    c++string类的赋值问题
    技术分享 | app自动化测试(Android)--显式等待机制
    中国传统节日春节网页HTML代码 春节大学生网页设计制作成品下载 学生网页课程设计期末作业下载 DW春节节日网页作业代码下载
    Gradle笔记 七 publishing 项目发布
    【信号处理】构建直接序列扩频系统模型(Matlab代码实现)
    项目管理构建工具——Maven(基础篇)
    《虚拟现实技术》教学上机实验报告
    全光网络技术发展与演进
    linux 应急响应工具整理列表
    用户增长常见分析模型
  • 原文地址:https://blog.csdn.net/Ureliable/article/details/133124061