文章目录
- 1 前言
- 2 自我介绍
- 3 Java SE
-
- 3.1 Java访问控制修饰符
- 3.2 Java中抽象类与接口有何区别?
- 3.3 Java中super关键字与final关键字
- 3.4 final修饰的对象,有几种初始化方式
- 3.5 Java中方法的重载(Overload)与方法的覆盖(Override)
- 3.6 Java基础知识总结,干货来啦
- 3.7 Java基础面试题干货系列(一)
- 3.8 Java中的String是不可变的,Why?
- 3.9 Java反射基础入门,一篇就够啦
- 3.10 面向对象与面向过程
- 3.11 Java基础面试题干货系列(二)
- 3.12 理解Java中的多态机制,一篇就够啦
- 3.13 Java中参数传递(值传递还是引用传递)
- 3.14 Java编程思想之高内聚低耦合
- 3.15 Java基础面试题干货系列(三)
- 3.16 Java中的异常(Exception)
- 3.17 Java中设计模式的七大基本原则
- 3.18 Java中File类,你知道有哪些api方法吗?
- 3.19 计算机中字节、字、位、bai比特等单位之间的换算关系
- 3.20 HTTP请求状态码对照表
- 3.21 集合
-
- 3.21.1 集合顶层的接口类有哪些?集合常见的有哪几种?都有啥区别?
- 3.21.2 集合顶层的接口类有哪些?
- 3.21.3 集合常见的有哪几种?
- 3.21.4 请说明Collection和Collections的区别
- 3.21.5 ArrayList和Vector以及LinkedList三者有啥区别?
- 3.21.6 HashMap和HashTable有何区别?
- 3.21.7 HashTable和ConcurrentHashMap有何区别?
- 3.21.8 ConcurrentHashMap底层实现原理
- 4 Java EE
-
- 4.1 UML类和类之间的关系详解
- 4.2 UML图使用详解
- 4.3 SpringBoot和Spring Cloud有什么区别?
-
- 4.3.1 什么是SpringBoot?什么是Spring Cloud?
- 4.3.2 SpringBoot和Spring Cloud区别
- 4.4 什么是Spring?
- 4.5 使用Spring框架的好处是什么?
- 4.6 Spring 事务隔离级别和传播行为有哪些?都有什么区别?
-
- 4.6.1 Spring事务的隔离级别有哪些?
- 4.6.2 什么是事务的传播行为?
- 4.6.3 Spring事务的传播行为有哪些?
- 4.6.4 Spring事务的实现原理?
-
- 4.6.4.1 Spring事务的使用
- 4.6.4.2 Spring事务的实现原理
- 4.7 说一下Spring MVC执行流程?
- 4.8 请你说说对Spring IOC和Spring AOP的理解?
-
- 4.8.1 Spring IOC
- 4.8.2 Spring AOP
-
- 4.8.2.1 什么是 AOP?
- 4.8.2.2 什么是 Aspect?
- 4.8.2.3 连接点
- 4.8.2.4 什么是JoinPoint切点
- 4.8.2.5 什么是Advice通知?有哪些类型的Advice通知?
- 4.8.2.6 指出在Spring AOP中关注点(concern)和横切关注点(cross-cuttingconcern)的不同之处。
- 4.8.2.7 什么是引入? 什么是目标对象? 什么是代理? 有几种不同类型的自动代理?
- 4.8.2.8 什么是编织(Weaving)?
- 4.8.2.9 AOP有哪些实现方式?
- 4.8.2.10 Spring AOP和AspectJ AOP有什么区别?
- 4.8.2.11 如何理解Spring中的代理?
- 4.9 说一下BeanFactory和FactoryBean的区别?
- 4.10 @Component, @Controller, @Repository, @Service 有何区别?
- 4.11 你怎样定义类的作用域? Spring支持哪些bean的作用域
- 4.12 Spring框架中的单例bean是线程安全的吗?
- 4.13 解释Spring框架中bean的生命周期
- 说一下动态代理和静态代理?动态代理有JDK动态代理和Cglib动态代理,这两个代理如何实现的,有何区别?
- 5 设计模式
-
- 5.1 策略模式
- 5.2 项目中用到了那些设计模式?哪些好的框架里面有使用过这些设计模式?
-
- 5.2.1 项目中用到了那些设计模式
- 5.2.2 哪些好的框架里面有使用过这些设计模式?
- 6 MySQL总结
-
- 6.1 Java JDBC编程
- 6.2 MySQL使用总结以及MySQL性能优化
- 6.3 MySQL四大特性是什么(MySQL事务的基本要素(ACID)有哪些)?
- 6.4 MySQL隔离级别有几种,有什么区别?
-
- 6.4.1 MySQL四种隔离级别
- 6.4.2 MySQL事务的并发问题
- 6.5 影响数据库性能的因素
- 6.6 MySQL索引,主键索引与普通索引区别?
- 6.7 B+Tree索引结构底层实现原理?
- 6.8 MySQL如何进行性能优化?
- 6.9 MySQL什么情况下索引会失效?
- 6.10 说说MySQL的最左前缀原则?
- 6.11 什么是MySQL索引下推?
- 6.12 请说一说MySQL数据库三范式
- 7 JDK和JVM总结
-
- 7.1 Java8新特性有哪些?
- 7.2 Java类加载器
- 8 多线程总结
-
- 8.1 常用的线程池有哪些?
- 8.2 为什么不建议使用Executors静态工厂构建线程池
- 8.3 线程池常用参数有哪些?
- 8.4 ThreadLocal底层是如何实现的?
- 8.5 ThreadLocal的内存泄露?什么原因?如何避免?
- 9 分布式技术总结
-
- 9.1 Redis缓存穿透 && 缓存击穿 && 缓存雪崩
-
- 9.1.1 缓存处理流程
- 9.1.2 Redis缓存穿透
- 9.1.3 Redis缓存击穿
- 9.1.4 Redis缓存雪崩
- 9.2 Redis系列-Java面试题干货系列(四)
- 9.3 分布式系统如何保证系统数据一致性?有哪几种分布式锁实现方式?
- 9.4 redis有哪些数据类型?项目中使用了那些场景?
- 9.5 分布式事务怎么实现的?
- 9.6 Elasticsearch底层实现原理?
- 9.7 ELK如何搜集日志信息到Elasticsearch中的?
- 9.8 使用了消费组件有哪些?有哪些组件类?延迟队列有使用过吗?消息丢失怎么处理?
- 9.9 Nginx如何实现不同资源的转发访问?
- 9.10 Nginx如何实现负载均衡,有哪几种方式?
- 10 微服务总结
-
- 10.1 Spring Cloud使用了那些组件?负载均衡如何实现的?如何鉴权?
- 10.2 nacos服务注册如何实现的?
- 10.3 nacos服务配置动态刷新如何实现?底层如何实现的?
- 10.4 如何使用Hystrix进行熔断降级?
- 10.5 如何抗住高并发?
- 10.6 高并发海量数据,如何处理?
- 11 项目问题总结
-
- 11.1 Git使用总结
- 11.2 项目中使用的Spring Boot版本是什么?MySQL版本是哪个?Spring Cloud版本是哪个?
- 11.3 项目中使用的数据库连接池是哪个?常用的参数有哪些?
- 11.4 项目中遇到问题,如何排查?
- 11.5 解决线上bug问题,举一个印象最深刻的例子?
- 12 数据结构和算法
- 13 Linux常用命令有哪些
- 14 前端问题
-
- 14.1 Vue生命周期函数有哪些?
- 14.2 React生命周期函数有哪些?
- 15 有什么想要问的吗?
1 前言
工作久了就会发现,基础知识忘得差不多了。为了复习下基础的知识,同时为以后找工作做准备,这里简单总结一些常见的可能会被问到的问题。
2 自我介绍
自己根据实际情况发挥就行
3 Java SE
3.1 Java访问控制修饰符
Java访问控制修饰符
3.2 Java中抽象类与接口有何区别?
Java中抽象类与接口
3.3 Java中super关键字与final关键字
Java中super关键字与final关键字
3.4 final修饰的对象,有几种初始化方式
final修饰的对象,有几种初始化方式
3.5 Java中方法的重载(Overload)与方法的覆盖(Override)
Java中方法的重载与方法的覆盖
3.6 Java基础知识总结,干货来啦
Java基础知识总结,干货来啦
3.7 Java基础面试题干货系列(一)
Java基础面试题干货系列(一)
3.8 Java中的String是不可变的,Why
Java中的String是不可变的,Why?
3.9 Java反射基础入门,一篇就够啦
Java反射基础入门,一篇就够啦
3.10 面向对象与面向过程
面向对象与面向过程
3.11 Java基础面试题干货系列(二)
Java基础面试题干货系列(二)
3.12 理解Java中的多态机制,一篇就够啦
理解Java中的多态机制,一篇就够啦
3.13 Java中参数传递(值传递还是引用传递)
Java中参数传递(值传递还是引用传递)
3.14 Java编程思想之高内聚低耦合
Java编程思想之高内聚低耦合
3.15 Java基础面试题干货系列(三)
Java基础面试题干货系列(三)
3.16 Java中的异常(Exception)
Java中的异常(Exception)
3.17 Java中设计模式的七大基本原则
Java中设计模式的七大基本原则
3.18 Java中File类,你知道有哪些api方法吗?
Java中File类,你知道有哪些api方法吗?
3.19 计算机中字节、字、位、bai比特等单位之间的换算关系
计算机中字节、字、位、bai比特等单位之间的换算关系
3.20 HTTP请求状态码对照表
HTTP请求状态码对照表
3.21 集合
3.21.1 集合顶层的接口类有哪些?集合常见的有哪几种?都有啥区别?
集合类图:
![中高级Java程序员,你不得不掌握的基本功,挑战20k+_第1张图片](http://img.e-com-net.com/image/info8/1a827147c0104504b9e305182fa147f5.jpg)
- Collection接口
![中高级Java程序员,你不得不掌握的基本功,挑战20k+_第2张图片](http://img.e-com-net.com/image/info8/f3ed003e834642f9b4470d0afc3e2163.jpg)
- Map接口
![中高级Java程序员,你不得不掌握的基本功,挑战20k+_第3张图片](http://img.e-com-net.com/image/info8/4c7b9527c4494169b07a7f3f6bc6623d.jpg)
3.21.2 集合顶层的接口类有哪些?
集合的顶层接口,常见的主要有: Collection接口
、Map接口
3.21.3 集合常见的有哪几种?
和Collection相关的接口主要有: Collection
、List
和Set
接口
-
Collection接口
Collection是一个抽象出来的接口
,定义如下:
public interface Collection extends Iterable {}
其中包括了集合的基本操作,包括: 删除
、添加
、遍历
、大小
等
-
List接口
List接口继承自Collection,List中的元素的有序且允许重复的
。定义如下:
public interface List extends Collection {}
-
Set接口
Set接口继承自Collection,Set是数学中定义的集合,元素无需不允许重复
。定义如下:
public interface Set extends Collection {}
Map接口
,也是顶层接口,Map保存的是键值对映射,映射关系可以是一对一或者一对多。
参考资料: https://blog.csdn.net/weixin_34176694/article/details/88708182
3.21.4 请说明Collection和Collections的区别
Collection是集合类的顶级接口,继承与他的接口主要有List和Set。而Collections是针对集合类的一个工具类,它提供了一系列的静态方法实现对各种集合的搜索、排序、线程安全化等操作。
3.21.5 ArrayList和Vector以及LinkedList三者有啥区别?
-
ArrayList 和Vector底层都是使用数组方式存储数据
,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢
,Vector由于使用了synchronized方法(线程安全),通常性能上较ArrayList差,而LinkedList使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快
。
-
请说明ArrayList和LinkedList的区别?
ArrayList和LinkedList都实现了List接口,ArrayList是基于索引的数据接口,它的底层是数组。它可以以O(1)时间复杂度
对元素进行随机访问。而LinkedList是以元素列表的形式存储它的数据,每一个元素都和它的前一个和后一个元素链接在一起,在这种情况下,查找某个元素的时间复杂度是O(n)
。LinkedList的插入,添加,删除操作比ArrayList速度更快,因为当元素被添加到集合任意位置的时候,不需要像数组那样重新计算大小或者是更新索引。LinkedList比ArrayList更占内存,因为LinkedList为每一个节点存储了两个引用,一个指向前一个元素,一个指向下一个元素。
3.21.6 HashMap和HashTable有何区别?
-
HashTable
底层数组+链表实现,无论key还是value都不能为null,线程安全,适合于多线程环境
,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低
,ConcurrentHashMap做了相关优化
初始size为11,扩容:newsize = olesize*2+1
计算index的方法:index = (hash & 0x7FFFFFFF) % tab.length
-
HashMap
底层数组+链表实现,可以存储null键和null值,线程不安全,更适合于单线程环境
初始size为16,扩容:newsize = oldsize*2,size一定为2的n次幂
扩容针对整个Map,每次扩容时,原来数组中的元素依次重新计算存放位置,并重新插入元素后才判断该不该扩容,有可能无效扩容(插入后如果扩容,如果没有再次插入,就会产生无效扩容)
当Map中元素总数超过Entry数组的75%,触发扩容操作,为了减少链表长度,元素分配更均匀
计算index方法:index = hash & (tab.length – 1)
注:
在JDK1.6,JDK1.7中,HashMap采用位桶+链表实现
,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8中,HashMap采用位桶+链表+红黑树实现
,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。
更详细的介绍,可参考我的另一篇博客: HashMap、Hashtable、ConcurrentHashMap的区别和原理浅析
3.21.7 HashTable和ConcurrentHashMap有何区别?
-
相同点
Hashtable和ConcurrentHashMap都实现了Map接口,两者都是线程安全的
-
不同点
Java5提供了ConcurrentHashMap,它是HashTable的替代,ConcurrentHashMap比HashTable的扩展性更好,性能也大大提升了
-
为什么说ConcurrentHashMap性能大大提高了?
简单来说,ConcurrentHashMap底层有分段锁,类似于mysql中的行级锁,而Hashtable是锁整个hash表,类似于mysql中的表级锁
ConcurrentHashMap提供了与Hashtable和SynchronizedMap不同的锁机制。Hashtable中采用的锁机制是一次锁住整个hash表,从而在同一时刻只能由一个线程对其进行操作,而ConcurrentHashMap是使用了锁分段技术来保证线程安全的
,是一次锁住一个桶。
ConcurrentHashMap默认将hash表分为16个桶,诸如get、put、remove等常用操作只锁住当前需要用到的桶。这样,原来只能一个线程进入,现在却能同时有16个写线程执行,并发性能的提升是显而易见的。
锁分段技术: 首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问
。
3.21.8 ConcurrentHashMap底层实现原理
-
底层采用分段的数组+链表实现,是线程安全的
-
通过把整个Map分为N个Segment,可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。(读操作不加锁,由于HashEntry的value变量是 volatile的,也能保证读取到最新的值。)
-
Hashtable的synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术
-
有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁
-
扩容:段内扩容(段内元素超过该段对应Entry数组长度的75%触发扩容,不会对整个Map进行扩容),插入前检测需不需要扩容,可以有效避免无效扩容
4 Java EE
4.1 UML类和类之间的关系详解
UML类和类之间的关系详解
4.2 UML图使用详解
UML图使用详解
4.3 SpringBoot和Spring Cloud有什么区别?
4.3.1 什么是SpringBoot?什么是Spring Cloud?
-
SpringBoot
是一个快速开发框架,通过用Maven依赖的继承方式,帮助我们快速整合第三方常用框架
。比起传统的Spring,SpringBoot采用注解化的方式(使用注解方式启动SpringMVC),简化Xml配置,内置HTTP服务器(Tomcat,Jetty),最终以Java应用程序进行执行
。
-
SpringCloud
SpringCloud是一套目前比较完整的微服务框架,是分布式微服务架构下的一站式解决方案
,是各个微服务架构落地技术的结合体,俗称为微服务全家桶
。
它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过SpringBoot风格进行再次封装,屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂
、易部署
和易维护
的分布式系统开发工具包
。它基于SpringBoot提供了一套微服务(microservices)解决方案,包括服务注册与发现
、配置中心
、服务网关
、全链路监控
、负载均衡
、熔断断路器
等组件,都可以用SpringBoot的开发风格做到一键启动和部署。
4.3.2 SpringBoot和Spring Cloud区别
-
SpringBoot只是一个快速开发框架,使用注解大大简化了Spring的Xml配置,内置了Servlet容器,以Java应用程序进行执行。
-
SpringBoot专注于开发单应用微服务,而SpringCloud是一系列框架的集合,SpringCloud是微服务协调治理框架,它将SpringBoot开发的一个个单体微服务整合并管理起来
。
-
SpringBoot可以离开SpringCloud单独使用,而Spring Cloud很大的一部分是基于SpringBoot来实现的,所以说SpringCloud离不开SpringBoot
4.4 什么是Spring
Spring 是 个 java 企 业 级 应 用 的 开 源 开 发 框 架
。 Spring 主 要 用 来 开 发 Java 应 用 , 但 是 有 些 扩 展 是 针 对 构 建 J2EE 平 台 的 web 应用。Spring 框 架 目 标 是 简 化 Java 企 业 级 应 用 开 发 , 并 通 过 POJO 为 基 础 的 编 程 模 型 促 进 良 好 的 编 程 习 惯 。
4.5 使用Spring框架的好处是什么?
- 轻量: Spring 是轻量的,基本的版本大约 2MB
- 控制反转: Spring 通过控制反转实现了松散耦合,对象们给出它们的依 赖,而不是创建或查找依赖的对象们
- 面向切面的编程(AOP): Spring 支持面向切面的编程,并且把应用业务 逻辑和系统服务分开
- 容器: Spring 包含并管理应用中对象的生命周期和配置
- MVC 框架: Spring 的 WEB 框架是个精心设计的框架,是 Web 框架的 一个很好的替代品
- 事务管理: Spring 提供一个持续的事务管理接口,可以扩展到上至本地 事务下至全局事务(JTA)
- 异常处理: Spring 提供方便的 API 把具体技术相关的异常(比如由 JDBC, Hibernate or JDO 抛出的)转化为一致的 unchecked 异常
4.6 Spring 事务隔离级别和传播行为有哪些?都有什么区别?
Transactional 注解的属性:
- name 当在配置文件中有多个 TransactionManager , 可以用该属性指定选择哪个事务管理器
- propagation 事务的传播行为,默认值为 REQUIRED
- isolation 事务的隔离级别,默认值采用 DEFAULT
- timeout 事务的超时时间,默认值为-1。如果超过该时间限制但事务还没有完成,则自动回滚事务
- read-only 指定事务是否为只读事务,默认值为 false;为了忽略那些不需要事务的方法,比如读取数据,可以设置 read-only 为 true
- rollback-for 用于指定能够触发事务回滚的异常类型,如果有多个异常类型需要指定,各类型之间可以通过逗号分隔
- no-rollback- for 抛出 no-rollback-for 指定的异常类型,不回滚事务
4.6.1 Spring事务的隔离级别有哪些?
Spring在TransactionDefinition接口中定义这些属性,定义了五个不同的事务隔离级别:
Isolation 属性一共支持五种事务设置:
- DEFAULT 使用数据库设置的隔离级别 ( 默认 ) ,由 DBA 默认的设置来决定隔离级别
- READ_UNCOMMITTED 会出现脏读、不可重复读、幻读 ( 隔离级别最低,并发性能高 )
- READ_COMMITTED 会出现不可重复读、幻读问题(锁定正在读取的行)
- REPEATABLE_READ 会出幻读(锁定所读取的所有行)
- SERIALIZABLE 保证所有的情况不会发生(锁表)
表格总结如下:
类型
解释
ISOLATION_DEFAULT
这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别,另外四个与JDBC的隔离级别相对应
ISOLATION_READ_UNCOMMITTED
这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读
ISOLATION_READ_COMMITTED
保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读
ISOLATION_REPEATABLE_READ
这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了不可重复读
ISOLATION_SERIALIZABLE
这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行,除了防止脏读,不可重复读外,还避免了幻像读
4.6.2 什么是事务的传播行为?
事务传播行为指的是: 两个有事务的方法进行相互调用的时候,它的事务如何进行传播
4.6.3 Spring事务的传播行为有哪些?
在TransactionDefinition接口中定义了七个事务传播行为:
PROPAGATION_REQUIRED
如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务
PROPAGATION_REQUIRES_NEW
总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起
PROPAGATION_SUPPORTS
如果存在一个事务,支持当前事务。如果没有事务,则以非事务的执行。但是对于事务同步的事务管理器,PROPAGATION_SUPPORTS与不使用事务有少许不同
PROPAGATION_NOT_SUPPORTED
总是非事务地执行,并挂起任何存在的事务
PROPAGATION_NEVER
总是非事务地执行,如果存在一个活动事务,则抛出异常
PROPAGATION_MANDATORY
如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常
PROPAGATION_NESTED
如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行
propagation 属性(事务传播性)表格整理如下:
类型
解释
REQUIRED
默认的传播行为,REQUIRED 支持当前已经存在的事务,如果还没有事务,就创建一个新事务
REQUIRES_NEW
如果当前有事务,挂起当前事务,创建一个新事务,如果还没有事务,就简单地创建一个新事务
SUPPORTS
支持当前事务,有事务就加入事务,如果没有事务,那么就以非事务的方式运行
NOT_SUPPORTED
强制不在事务中运行,如果当前存在一个事务,则挂起该事务
NEVER
强制要求不在事务中运行,如果当前存在一个事务,则抛出异常
MANDATORY
支持当前已经存在的事务,如果还没有事务,就抛出一个异常
NESTED
在当前事务中创建一个嵌套事务,如果还没有事务,那么就简单地创建一个新事务
4.6.4 Spring事务的实现原理?
4.6.4.1 Spring事务的使用
Spring支持编程式事务管理
和声明式事务管理
两种方式
-
编程式事务
编程式事务使用TransactionTemplate
或者直接使用底层的PlatformTransactionManager
。对于编程式事务管理,Spring推荐使用TransactionTemplate
-
声明式事务
声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。
声明式事务管理使业务代码不受污染,显然声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式。通常,使用注解方式通过@Transactional
来使用事务。我们可以使用@EnableTransactionManagement
注解来启用事务管理功能,该注解可以加在启动类上或者单独加个配置类来处理。@Transactional
可以加在方法上
,表示对当前方法配置事务。也可以添加到类级别上
,当把@Transactional 注解放在类级别时,表示所有该类的公共方法都配置相同的事务属性信息。
4.6.4.2 Spring事务的实现原理
项目中是使用注解方式实现的事务,这里以这种场景进行说明:
Spring事务是使用了@Transactional注解,底层产生CGLIB动态代理对象来进行事物的管理
。如果一个service类没有产生动态代理对象的时候,那么它不会对事务进行管理。
声明式事务是建立在AOP之上的,通过注解方式或者是在xml文件中进行配置。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务
。
参考资料: https://www.cnblogs.com/kingsonfu/p/10413154.html
4.7 说一下Spring MVC执行流程?
![中高级Java程序员,你不得不掌握的基本功,挑战20k+_第4张图片](http://img.e-com-net.com/image/info8/3ec55553e46949ffb6b7ee8a5cc27112.jpg)
- 1、向服务器发送HTTP请求,请求被
前端控制器DispatcherServlet捕获
- 2、DispatcherServlet根据xxx-servlet.xml中的配置对请求的URL进行解析,得到请求资源标识符(URI),然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以
HandlerExecutionChain
对象的形式返回
- 3、DispatcherServlet根据获得的Handler,选择一个合适的
HandlerAdapter
(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(…)方法)
- 4、提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
数据转换: 对请求消息进行数据转换,如String转换成Integer、Double等
数据格式化: 对请求消息进行数据格式化,如将字符串转换成格式化数字或格式化日期等
数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
- 5、Handler(Controller)执行完成后,向DispatcherServlet返回一个
ModelAndView
对象
- 6、根据返回的ModelAndView,选择一个适合的视图解析器
ViewResolver
(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet
- 7、ViewResolver结合Model和View,来渲染视图
- 8、视图负责将渲染结果返回给客户端
4.8 请你说说对Spring IOC和Spring AOP的理解?
4.8.1 Spring IOC
4.8.2 Spring AOP
4.8.2.1 什么是 AOP?
AOP(Aspect-OrientedProgramming),即面向切面编程。它与OOP(Object-OrientedProgramming,面向对象编程)相辅相成,提供了与OOP不同的抽象软件结构的视角。在OOP中,我们以类(class)作为我们的基本单元,而AOP中的基本单元是Aspect(切面)。
AOP核心就是切面,它将多个类的通用行为封装成可重用的模块,该模块含有一组API提供横切功能
。比如,一个日志模块可以被称作日志的AOP切面。根据需求的不同,一个应用程序可以有若干切面。在SpringAOP中,切面通过带有@Aspect注解的类实现。
4.8.2.2 什么是 Aspect?
Aspect由pointcount切入点
和advice通知
组成,它既包含了横切逻辑的定义,也包括了连接点的定义。SpringAOP就是负责实施切面的框架,它将切面所定义的横切逻辑编织到切面所指定的连接点中。AOP的工作重心在于如何将增强编织到目标对象的连接点上
,这里包含两个工作:
- 如何通过pointcut和advice定位到特定的joinpoint上
- 如何在advice中编写切面代码
可以简单地认为,使用@Aspect注解的类就是切面
4.8.2.3 连接点
连接点代表一个应用程序的某个位置,在这个位置我们可以插入一个AOP切面,它实际上是个应用程序执行Spring AOP的位置。
比如我在我的业务方法上加入我的切面注解,进行日志切面处理:
/**
*
* 自定义日志存储注解
*
*
* @author smilehappiness
* @Date 2021/8/15 10:08
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OperateLog {
/**
* 日志操作信息
*/
String value() default "";
}
@OperateLog("切面日志处理")
@PostMapping(value = "/path1")
public Result