Spring 的模块
1 什么是IOC,什么是依赖注入,Spring IOC 如何实现
ans: IOC — Inversion of Control,即“控制反转”
DI — Dependency Injection,即“依赖注入”
在传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象。IOC/DI 的设计思想,是指由容器创建对象,由容器帮助装配,这样做的好处是接触了对象之间的耦合关系,便于我们复用和测试。
Spring中的 BeanFactory 和 ApplicationContext 是最常用的IOC容器,注入属性时,主要使用了JDK的反射和内省机制。
参考:https://jinnianshilongnian.iteye.com/blog/1413846
2 BeanFactory 和 ApplicationContext 有什么区别
ans:BeanFactory是一个最简单的容器,它主要的功能是为依赖注入 (DI) 提供支持。
ApplicationContext 是 BeanFactory 的子接口,也被成为 Spring 上下文。是 spring 中较高级的容器,不仅可以加载配置文件中定义的 bean,还添加了一些高级功能,比如从属性文件中解析文本信息和将事件传递给所指定的监听器。
一般使用的是 ApplicationContext,除非在资源比较紧张的情况下会选择 BeanFactory。
3 Spring注入bean的方式
ans: (1)基于构造函数的注入
(2)基于属性的setter方法注入
(3)基于工厂方法的注入
(4)基于注解的注入
参考:https://blog.csdn.net/qq1175421841/article/details/51884655
4 Spring AOP,动态代理(CGLIB 与 JDK)
ans: AOP(Aspect-Oriented Programming),面向方面编程。与OOP的通过继承扩展功能的方式不同,它是一种“横向”扩展的技术,常用于将公共行为插入不同的业务流程中,例如记录日志等。Spring AOP的核心有三部分:被通知的目标对象,切点(拦截位置)和 增强处理。
Spring AOP支持 前置、后置、环绕、返回、异常通知。可以用XML声明切面,也可以是使用注解。
Spring AOP 是由 IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。因此,AOP代理可以直接使用容器中的其它bean实例作为目标,这种关系可由IOC容器的依赖注入提供。Spring创建代理的规则为:
(1)默认使用Java动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了。
(2)当需要代理的类未实现任何接口的时候,Spring会切换为使用CGLIB实现。
Java动态代理:Java动态代理是利用反射机制,生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
CGLIB:CGLIB动态代理是利用asm开源包,将被代理对象类的class文件加载进来,通过修改其字节码,生成子类来处理。
5 Spring 事务实现方式,事务隔离级别和传播性
ans: ACID:
- 原子性(Atomicity):即事务是不可分割的最小工作单元,事务内的操作要么全做,要么全不做;
- 一致性(Consistency):在事务执行前数据库的数据处于正确的状态,而事务执行完成后数据库的数据还是应该处于正确的状态,即数据完整性约束没有被破坏;如银行转帐,A转帐给B,必须保证A的钱一定转给B,一定不会出现A的钱转了但B没收到,否则数据库的数据就处于不一致(不正确)的状态。
- 隔离性(Isolation):并发事务执行之间互不影响,在一个事务内部的操作对其他事务是不产生影响,这需要事务隔离级别来指定隔离性;
- 持久性(Durability):事务一旦执行成功,它对数据库的数据的改变必须是永久的,不会因比如遇到系统故障或断电造成数据不一致或丢失。
Spring事务实现分为两种:
- 编程式事务,代码中显示的使用事务管理器,
- 声明式事务,使用Spring的<tx:advice>定义事务通知与AOP相关配置实现,另为一种通过@Transactional实现事务管理实现。
脏读:如果一个事务对数据进行了更新,尚未提交的情况下另一个事务“看到了”这个未提交的结果,这可能造成的问题是,当事务回滚,那么第二个事务看到的数据就是脏数据。
不可重复读:是指在一个事务过程中,对同一个数据进行多次读取,每次的结果都不同,如事务1第一次读取数据,事务2尚未更新,而第二次读物数据时事务2已经更新了数据。
幻读:幻读针对的是多笔记录,与不可重复读类似,都是在一个事务过程中多次读取结果不同,幻读针对的是结果集有差异,可能多或少了一些记录。
Spring事务隔离级别:
- ISOLATION_DEFAULT:用底层数据库的默认隔离级别,数据库管理员设置什么就是什么
- ISOLATION_READ_UNCOMMITTED(未提交读):最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读)
- ISOLATION_READ_COMMITTED(提交读):一个事务提交后才能被其他事务读取到(该隔离级别禁止其他事务读取到未提交事务的数据、所以还是会造成幻读、不可重复读)
- ISOLATION_REPEATABLE_READ(可重复读):可重复读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(该隔离基本可防止脏读,不可重复读(重点在修改),但会出现幻读(重点在增加与删除))
- ISOLATION_SERIALIZABLE(序列化):代价最高最可靠的隔离级别(该隔离级别能防止脏读、不可重复读、幻读)
传播行为:
- PROPAGATION_REQUIRED:支持当前事务,如当前没有事务,则新建一个。
- PROPAGATION_SUPPORTS:支持当前事务,如当前没有事务,则直接执行。
- PROPAGATION_MANDATORY:强制要求当前存在一个事务,如果没有,则抛出异常。
- PROPAGATION_REQUIRES_NEW:不论当前是否存在事务,都会创建新事务,如当前原来有事务,则把原事务挂起。
- PROPAGATION_NOT_SUPPORTED:不支持当前事务,始终没有事务的情况下执行,如果当前存在事务,则挂起该事务。
- PROPAGATION_NEVER:不支持当前事务;如果当前存在事务,则引发异常。
- PROPAGATION_NESTED:如果当前事务存在,则在嵌套事务中执行,如果当前没有事务,则执行与 PROPAGATION_REQUIRED 类似的操作。
如果在事务中catch了抛出的异常,那么Spring无法感知到,也就不会回滚,此时可以:
- 在catch模块再次抛出异常(不推荐)
- 手动回滚 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
- 在注解里配置需要捕获的异常类型 (推荐)
@Transactional(readOnly = true, rollbackFor = Exception.class)
参考:《Spring揭秘》19.2.1
https://www.cnblogs.com/qjjazry/p/6366204.html
https://www.jianshu.com/p/42ce0f9250f5
https://blog.csdn.net/yipanbo/article/details/46048413
6 Spring是单例还是多例,怎么修改,Spring 的单例实现原理
ans: 在 Spring 中定义一个 bean 时,默认是单例方式,如果需要修改它的作用域,可以显示的定义“ scope” 属性。Spring支持5种作用域:
- singleton 单例
- prototype 每次返回一个新实例
- request 每次http请求都返回一个新实例,仅适用于WebApplicationContext环境
- session 同一个HTTP Session共享一个Bean,仅适用于 WebApplicationContext环境
- global-session 一般用于Portlet应用环境,仅适用于WebApplicationContext环境
参考:https://www.w3cschool.cn/wkspring/nukv1ice.html
7 Spring 框架中用到了哪些设计模式
ans: - MVC
- 前端控制器模式
- 单例模式
- 原型模式
-工厂方法模式 - 模板方法
- 代理
- builder
参考:http://www.javabench.in/2012/02/design-patterns-being-used-in-spring.html
https://blog.eduonix.com/java-programming-2/learn-design-patterns-used-spring-framework/
8 介绍下Mybatis的缓存机制。
ans: Mybatis提供两级缓存。
一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个(内存区域)数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。
二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession去操作数据库得到数据会存在二级缓存区域,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
Mybatis在多表查询时,极大可能会出现脏数据,有设计上的缺陷,安全使用的条件比较苛刻。
在分布式环境下,由于默认的Mybatis Cache实现都是基于本地的,分布式环境下必然会出现读取到脏数据,不如直接用Redis、Memcache实现业务上的缓存就好。
参考:https://www.cnblogs.com/zedosu/p/6709943.html
https://www.jianshu.com/p/c553169c5921
9 Mybatis的mapper文件中#和{variable} 可以插入一个不转义的字符串,但这样会导致潜在的 SQL 注入攻击!尽量避免这么做。
10 Mybatis的mapper文件中resultType和resultMap的区别。
ans: resultType用于指明 返回值的期望类型的类的完全限定名或别名
resultMap 主要用于将返回值映射到POJO对象上,解决列名不能自动匹配的问题。
11 Mybatis中DAO层接口没有写实现类,Mapper中的方法和DAO接口方法是怎么绑定到一起的,其内部是怎么实现的。
ans: mybatis通过Java动态代理,在启动加载配置文件时,根据配置mapper的xml去生成DAO的实现。
参考:https://blog.csdn.net/c_royi/article/details/79452255
网友评论