面试7_Spring

参考资料

  1. 优快云_Spring面试题
  2. 简书_Spring常见面试题
  3. 知乎_Spring面试题IOC系列
  4. 优快云_面试题 Spring IOC相关
  5. 有道云_面试3_Spring
  6. SpringBoot自动配置注解原理解析
  7. Cglib和jdk动态代理的区别
  8. Spring事务实现机制

一、spring概述

1. Spring组成模块

  1. 核心容器(Core Container)
  2. AOP(Aspect Oriented Programming)和设备支持(Instrmentation)
  3. 数据访问与集成(Data Access/Integeration)
  4. Web
  5. 消息(Messaging)
  6. Test

2. Spring使用的设计模式

  1. 工厂模式:BeanFactory,用来创建对象的实例;
  2. 单例模式:Bean默认为单例模式。
  3. 代理模式:AOP功能
  4. 模板方法:解决代码重复的问题
  5. 观察者模式

3. Spring事件类型

  1. 上下文更新事件:在调用ConfigurableApplicationContext 接口中的refresh()方法时被触发。
  2. 上下文开始事件:当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件。
  3. 上下文停止事件:当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件。
  4. 上下文关闭事件:当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁。
  5. 请求处理事件:在Web应用中,当一个http请求(request)结束触发该事件。

4. 核心容器模块详情

BeanFactory 是 任何以spring为基础的应用的核心。是工厂模式的一个实现,提供了控制反转功能。


二、IOC

1. IOC、DI

  1. IOC是 控制反转依赖对象的创建及维护是由外部容器负责的
  2. DI也就是 依赖注入实现IOC的方式之一。运行期间由外部容器动态地将依赖对象注入到组件

2. IOC作用

  1. 管理对象的创建依赖关系的维护
  2. 解耦,由容器去维护具体的对象
  3. 托管类产生过程
  • 容易测试,单元测试不再需要单例和JNDI查找机制
  • 支持加载服务时的饿汉式初始化懒加载

3. IOC支持的功能

  1. 依赖注入
  2. 依赖查找
  3. 自动装配
  4. 支持集合
  5. 指定初始化方法和销毁方法

4. IOC实现原理

**工厂模式 + 反射机制


5. IOC初始化

  1. Resource 定位
  2. Bean 注册
    1. BeanDefinitionReader 读取、解析bean的配置信息
    2. 將bean的配置信息转换为 BeanDefinition 对象,并保存在内存中
    3. registerBeanDefinition 将 BeanDefinition 注入到 Bean定义注册表
  3. Bean 实例化
    1. 遍历Bean定义注册表,调用getBean方法拿出Class对象通过反射机制进行实例化,保存在Bean缓存池中。

6. DI实现方式、区别

  1. 接口注入
  2. Setter方法注入
  3. 构造器注入
区别构造函数注入setter 注入
部分注入没有
覆盖 setter 属性不会
任意修改会创建新实例会 不会
适用范围适用于设置很多属性适用于设置少量属性

7. BeanFactory、 FactoryBean区别

  1. BeanFactory是IOC的底层容器,用于管理Bean,通过getBean进行依赖查找,若 Bean 未初始化,则从底层查找或构建。
  2. FactoryBean是特殊的 Bean,需注册到 IoC 容器,通过容器的getBean 获取 FactoryBean#getObject()方法的内容,作用主要是自定义实际Bean的产生过程

8. BeanFactory、ApplicationContext区别

  1. ApplicationContext实现BeanFactory接口,提供更多功能:

    1. 提供国际化的消息访问, MessageSource
    2. 统一的资源文件访问方式, ResourceLoader
    3. 事件传递:通过实现ApplicationContextAware接口。消息发送、响应机制(ApplicationEventPublisher)
    4. Bean的自动装配
    5. 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次。各种不同应用层的Context实现
  2. 区别

区别BeanFactoryApplicationContext
·加载方式·懒加载,使用时才被实例化启动时实例化
可以为Bean配置lazy-init=true来让Bean延迟实例化
能尽早的发现系统中的配置问题
·创建方式·编程式编程式 + 声明式
·注册方式·
BeanPostProcessor、BeanFactoryPostProcessor的使用
手动注册自动注册

9. Bean 自动装配

自动装配类型

  1. no:默认的方式是不进行自动装配的,通过手工设置ref属性来进行装配bean。
  2. byName:通过bean的名称进行自动装配,如果一个bean的 property 与另一bean 的name 相同,就进行自动装配。
  3. byType:通过参数的数据类型进行自动装配。
  4. constructor:利用构造函数进行装配,并且构造函数的参数通过byType进行装配。
  5. autodetect:自动探测,如果有构造方法,通过 construct的方式自动装配,否则使用 byType的方式自动装配。

自动装配注解原理

  • @SpringBootApplication:启动类
    • @EnableAutoConfiguration:开启自动配置类
      • @AutoConfigurationPackage:自动配置包
        • 返回当前主程序类的同级以及子级的包组件
      • @Import:导入自动配置的组件
        • 继承了 ImportSelector,来加载 **META-INF/spring.factories**外部文件

10. Bean 生命周期

在这里插入图片描述

  1. bean实例化
  2. 属性填充:将值和bean的引用注入到bean对应的属性中;
  3. 检查Aware相关接口并设置相关依赖
  4. BeanPostProcessor前置处理
  5. 调用InitializingBean接口的afterPropertiesSet()方法;
  6. BeanPostProcessor后置处理
  7. bean准备就绪
  8. 销毁bean
    1. 调用DisposableBean的destroy()方法。
    2. 调用定制的销毁方法

11. Bean 作用域

  • bean标签里面有scope属性 用于设置单实例还是多实例
  1. singleton 加载 spring 配置文件时就会创建单实例对象
  2. prototype 在调用getBean 方法时创建多实例对象
作用域说明
singleton在 Spring 容器中仅存在一个 bean 的实例,bean 以单例形式存在。
这是99默认的作用域99
prototype每次从容器中获取 bean 时,都将生成一个新的实例,
即相当于每次都执行 new xxxBean()
request在 HTTP 请求 (request) 的完整生命周期中,将创建并使用单个实例。
该作用域仅适用于 WebApplicatonContext 环境
session在 HTTP 会话 (session) 的完整生命周期中,将创建并使用单个实例。
该作用域仅适用于 WebApplicationContext 环境
global-Session在全局的 HTTP 会话 (session) 的完整生命周期中,将创建并使用单个实例。
该作用域仅适用于 WebApplicationContext 环境,且通常只能用在 Portlet 环境中。

12. 单例bean线程安全?

  1. 单例bean不是线程安全的
  2. 大部分时候 spring bean 无状态的,某种程度上来说 bean 也是安全的
  3. bean 有状态的话,要开发者去保证线程安全,改变 bean 的作用域,把“singleton”变更为“prototype”
    1. 有状态就是有数据存储功能。
    2. 无状态就是不会保存数据。

12. 如何保证 Controller 并发的安全

  • Controller对象是单例的,Spring 多线程请求过来调用的Controller对象都是同一个
    • 使用ThreadLocal来保存类变量
    • 添加注解@Scope(“prototype”)让Controller以多实例形式创建

13. 如何解决循环依赖

  • Spring三个缓存区
  • setter方法注入形成的单例循环依赖能够解决
  • 通过ObjectFactory提前曝光,放到三级缓存

14. 为什么需要三个缓存,而不是直接两个缓存?

  • 保证单例
  • 使用AOP情况下,只使用一级、三级缓存无法解决循环依赖的问题
    • 每次从三级缓存中拿到singleFactory对象,在执行getObject()时会产生新的代理对象
    • 产生的代理对象放到二级缓存中。然后把这个三级缓存删除掉,这样以后就使用二级缓存的同一个对象。

15. MVC 的工作原理


三、AOP

1. AOP的实现原理

  1. 静态代理的代表为 AspectJ
  2. 动态代理则以 Spring AOP 为代表

2. JDK动态代理、cglib动态代理

  1. JDK动态代理,拦截器+反射 ,Proxy利用InvokeHandler来生成目标类的代理对象,只能对实现了接口的类生成代理。
  2. cglib动态代理,通过修改其字节码生成子类来处理,覆盖其中特定方法并添加增强代码。

3. 关注点和横切关注的区别

  1. 关注点是应用中一个模块的行为,一个关注点可能会被定义成一个我们想实现的一个功能。
  2. 横切关注点是一个关注点,此关注点是整个应用都会使用的功能,并影响整个应用

4. 通知类型

  1. 前置通知(Before):在目标方法被调用之前调用通知功能;
  2. 后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么;
  3. 返回通知(After-returning ):在目标方法成功执行之后调用通知;
  4. 异常通知(After-throwing):在目标方法抛出异常后调用通知;
  5. 环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。
  • 同一个aspect,不同 advice的执行顺序
    1. around before advice
    2. before advice
    3. target method 执行
    4. around after advice
    5. after advice
    6. afterReturning | afterThrowing:异常发生

四、Spring数据访问

1. 数据持久化、多数据源配置

  1. 数据持久化

    1. Spring Boot整合JdbcTemplate
    2. Spring Boot整合MyBatis
    3. Spring Boot整合Jpa
  2. MyBatis多数据源配置

    1. pom.xml修改 druid-spring-boot-starter 依赖
    2. application.yml添加数据库信息
    3. 编写配置文件来处理各自的mapper
      1. 配置DataSourceConfig
      2. 配置多个MyBatisConfig来对应不同的mapper

2. 分页

五、Spring事务

1. 事务管理类型

  1. 编程式事务管理
  2. 声明式事务管理:将代码和事务管理分离。

2. Spring 事务管理机制

  1. spring 事务底层是基于数据库事务aop 机制实现的
  2. spring 会对使用了@Transaction 注解的 Bean,通过 aop 的方式创建一个代理对象
  3. 当调用代理对象的方法的时候,会进入到 spring 事务拦截器中,这里面会先判断方法上是否有@Transaction 注解
  4. 如果加了,那么会利用事务管理器创建一个数据库连接
  5. 并且修改数据库的连接的 autocommit 属性为 false,也就是禁止此链接自动提交,这是实现 spring 事务非常重要的一步
  6. 然后将会将这个连接放在 ThreadLocal 中,这里也是一个关键点,最终执行 sql 的连接需要和 spring 事务中的连接是同一个连接,就通过 ThreadLocal 共享连接的
  7. 然后执行当前业务方法,方法中准备执行 sql,通常我们会使用 orm 框架去执行 sql,比如我们常用的 mybatis、hibernate 等,当这些框架执行 sql 的时候,会从上面的 ThreadLocal 中拿到刚才创建的数据库连接,然后使用这个连接去执行 sql
  8. 执行完业务方法之后,如果没有异常则 spring 会直接提交事务
  9. 如果出现了异常,且这个异常是需要回滚的,则会回滚事务,否则仍然会提交事务
  10. spring 事务中的隔离级别其实对应的就是数据库的隔离级别,spring 会通过数据库的连接来设置隔离级别
  11. spring 事务的传播机制是基于数据库连接来做的,一个数据库连接对应一个事务,如果传播机制配置为需要新开一个事务,那么实际上就会新建一个连接,在这个新的连接上去执行 sql
  12. 上面说的这个过程稍微是简化版的,如果大家有兴趣的话,可以去研究一下@EnableTransactionManagement,这个注解的作用是启用
    spring 事务管理的功能,会对需要 spring 管理事务的 bean 创建代理对象,上面还提到了 spring 事务拦截器,也是非常重要的一个点,他会拦截事务方法的执行,事务的所有操作都是在这个拦截器中完成的,对应的类是:TransactionInterceptor

3. Spring 事务传播行为及其作用

传播类型作用
PROPAGATION_REQUIRED如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。
PROPAGATION_SUPPORTS支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。
PROPAGATION_MANDATORY支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
PROPAGATION_REQUIRES_NEW创建新事务,无论当前存不存在事务,都创建新事务。
PROPAGATION_NOT_SUPPORTED以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。

4. spring 事务隔离级别

  1. ISOLATION_DEFAULT:默认值,用底层数据库的设置隔离级别,数据库设置的是什么我就用什么;
  2. ISOLATION_READ_UNCOMMITTED:未提交读,最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读);
  3. ISOLATION_READ_COMMITTED:提交读,一个事务提交后才能被其他事务读取到(会造成幻读、不可重复读),SQL server 的默认级别;
  4. ISOLATION_REPEATABLE_READ:可重复读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读),MySQL 的默认级别;
  5. ISOLATION_SERIALIZABLE:序列化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读。

六、Spring注解

1. @Component, @Controller, @Repository, @Service

将 java 类标记为 bean,@Component为父接口

2. @Required

bean的属性必须在配置时设置,通过一个bean定义的显式的属性值或通过自动装配

3. @Autowired、@Resource的区别

  1. @Autowired可用于:构造函数、成员变量、Setter方法

  2. @Autowired默认按类型装配注入,默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。

  3. @Resource默认按名称装配注入,找不到才按类型装配注入。

4. @Qualifier

创建多个相同类型的 bean 并希望仅使用属性装配其中一个 bean 时,使用@Qualifier 注解和 @Autowired 通过指定应装配确切的 bean 来消除歧义

5. @RequestMapping

  1. 将特定 HTTP 请求方法映射到将处理相应请求的控制器中的特定类/方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值