中高级Java程序员,你不得不掌握的基本功,挑战20k+
Posted 心动的偏执
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了中高级Java程序员,你不得不掌握的基本功,挑战20k+相关的知识,希望对你有一定的参考价值。
文章目录
- 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 集合
- 4 Java EE
-
- 4.1 UML类和类之间的关系详解
- 4.2 UML图使用详解
- 4.3 SpringBoot和Spring Cloud有什么区别?
- 4.4 什么是Spring?
- 4.5 使用Spring框架的好处是什么?
- 4.6 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 设计模式
- 6 MySQL总结
- 7 JDK和JVM总结
- 8 多线程总结
- 9 分布式技术总结
- 10 微服务总结
- 11 项目问题总结
- 12 数据结构和算法
- 13 Linux常用命令有哪些
- 14 前端问题
- 15 有什么想要问的吗?
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 集合顶层的接口类有哪些?集合常见的有哪几种?都有啥区别?
集合类图:
- Collection接口
- Map接口
3.21.2 集合顶层的接口类有哪些?
集合的顶层接口,常见的主要有: Collection接口
、Map接口
3.21.3 集合常见的有哪几种?
和Collection相关的接口主要有: Collection
、List
和Set
接口
-
Collection接口
Collection是一个抽象出来的接口
,定义如下:public interface Collection<E> extends Iterable<E>
其中包括了集合的基本操作,包括:
删除
、添加
、遍历
、大小
等 -
List接口
List接口继承自Collection,List中的元素的有序且允许重复的
。定义如下:public interface List<E> extends Collection<E>
-
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类和类之间的关系详解
4.2 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执行流程?
- 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的位置。
比如我在我的业务方法上加入我的切面注解,进行日志切面处理:
/**
* <p>
* 自定义日志存储注解
* <p/>
*
* @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<Object> path1(@RequestBody Dto dto)
// 省略业务代码....
return 结果;
4.8.2.4 什么是JoinPoint切点
切入点JoinPoint
是一个或一组连接点,是程序运行中的一些时间点,通知将在这些位置执行,可以通过表达式或匹配的方式指明切入点,例如一个方法的执行,或者是一个异常的处理。在Spring AOP中,joinpoint总是方法的执行点。
例如:
/**
* 使用@Pointcut定义切点,在加注解的位置切入代码
*/
@Pointcut("@annotation(com.smilehappiness.aspect.operate.OperateLog)")
public void logPointCut()
4.8.2.5 什么是Advice通知?有哪些类型的Advice通知?
-
Advice概念
特定JoinPoint处的Aspect所采取的动作称为Advice,通知是个在方法执行前或执行后要做的动作,实际上是程序执行时要通过SpringAOP框架触发的代码段。
。SpringAOP使用一个Advice作为拦截器,在JoinPoint“周围”维护一系列的拦截器。 -
有哪些类型的通知(Advice)
Spring切面可以应用五种类型的通知:切面通知类型
解释
Before
前置通知
,在一个方法执行前被调用,该类型的Advice在joinpoint方法之前执行,使用@Before注解标记进行配置After
后置通知
,在连接点方法执行之后调用的通知,无论方法执行是否成功,使用@After注解标记进行配置Around
环绕通知
,在连接点方法执行之前和之后调用的通知,使用@Around注解标记进行配置。目标方法的调用由环绕通知决定,即你可以决定是否调用目标方法,joinPoint.procced()就是执行目标方法的代码 。环绕通知可以控制返回对象
AfterReturning
返回通知
,在连接点方法正常执行后执行,仅当方法成功完成后执行的通知,使用@AfterReturning注解标记进行配置AfterThrowing
异常通知
,仅在joinpoint方法抛出异常退出时执行的通知,使用@AfterThrowing注解标记配置时执行
4.8.2.6 指出在Spring AOP中关注点(concern)和横切关注点(cross-cuttingconcern)的不同之处。
关注点-concern是我们想要在应用程序的特定模块中定义的行为,一个关注点可能会被定义成一个我们想要实现的一个功能。横切关注点-cross-cuttingconcern是一个关注点,此关注点是整个应用都会使用的功能,并影响整个应用程序
,比如日志
,安全性
和数据传输
,是应用程序几乎每个模块都需要关注的问题,因此它们是跨领域的问题,这些都属于横切关注点。
4.8.2.7 什么是引入 什么是目标对象 什么是代理 有几种不同类型的自动代理?
- 引入
引入允许我们在已存在的类中增加新的方法和属性 - 目标对象
被一个或者多个切面所通知的对象,它通常是一个代理对象,也指被通知(advised)对象 - 代理
代理是通知目标对象后创建的对象(底层其实是动态代理),从客户端的角度看,代理对象和目标对象是一样的 - 有几种不同类型的自动代理
BeanNameAutoProxyCreator、DefaultAdvisorAutoProxyCreator、Metadata AutoProxying
4.8.2.8 什么是编织(Weaving)?
Weaving编织也叫做织入,为了创建一个advice通知对象而链接一个aspect和其它应用类型或对象的过程。织入可以在编译时,加载时,或运行时完成
,比如说,在SpringAOP中,编织在运行时执行。
简单来说,织入是将切面和其他应用类型或对象连接或创建一个被通知对象的过程
。
4.8.2.9 AOP有哪些实现方式?
- 基于XMLSchema方式的切面实现
在这种情况下,切面由常规类以及基于XML的配置实现 - 基于注解的切面实现
在这种情况下(基于@AspectJ的实现)
实现AOP的技术,主要分为两大类:
-
静态代理
指使用AOP框架提供的命令进行编译,从而在编译阶段就可生成AOP代理类,因此也称为编译时增强
。编译时编织类(特殊编译器实现)加载时进行编织(特殊的类加载器实现)。 -
动态代理
在运行时在内存中“临时”生成AOP动态代理类,因此也被称为运行时增强
。主要有JDK动态代理
和CGLIB动态代理
两种方式
4.8.2.10 Spring AOP和AspectJ AOP有什么区别?
SpringAOP基于动态代理方式实现,AspectJ基于静态代理方式实现
。另外,SpringAOP仅支持方法级别的PointCut,提供了完全的AOP支持,它还支持属性级别的PointCut,功能更加强大
。
4.8.2.11 如何理解Spring中的代理?
将Advice通知
应用于目标对象
后创建的对象称为代理,代理是通知目标对象后创建的对象
,在客户端对象的情况下,目标对象和代理对象是相同的。
AOP底层是使用cglib动态代理来实现,而cglib是创建动态子类继承了业务方法类,在业务方法操作之前,来完成功能的前置或者后置增强
Advice+TargetObject=Proxy
4.9 说一下BeanFactory和FactoryBean的区别?
- BeanFacotry是spring中比较原始的Factory,BeanFactory是接口,提供了IOC容器最基本的形式,给具体的IOC容器的实现提供了规范。
- FactoryBean也是接口,为IOC容器中Bean的实现提供了更加灵活的方式,FactoryBean在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式,我们可以在getObject()方法中灵活配置。
相同点:
都是接口
主要区别: BeanFactory是个Factory,也就是IOC容器或对象工厂,FactoryBean是个Bean
。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。但对FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似
详细的内容可以参考资料: https://www.cnblogs.com/aspirant/p/9082858.html
4.10 @Component, @Controller, @Repository, @Service 有何区别?
从源码级别来看, @Repository、@Service、@Controller是@Component的别名
,@Service用于标注业务层组件
,@Controller用于标注控制层组件
(如struts中的action),@Repository用于标注数据访问组件
,即Dao组件,@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注
。
参看源码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository
@AliasFor(
annotation = Component.class
)
String value() default "";
注:
@Repository这个注解是具有类似用途和功能的@Component注解的特化 。@Repository为DAO提供了额外的好处,它将DAO导入IoC容器,并使未经检查的异常有资格转换为Spring DataAccessException
4.11 你怎样定义类的作用域 Spring支持哪些bean的作用域
Spring中,我们可以给bean实例声明一个作用域,我们可以通过bean定义中的scope属性来定义
。
比如,当Spring要在需要的时候每次生产一个新的bean实例,bean的scope属性被指定为prototype
。如果一个bean每次使用的时候必须返回同一个实例,这个bean的scope属性必须设为singleton
。
Spring默认的Springbean的scop作用域是Singleton
Spring框架支持以下五种bean的作用域:
- singleton
bean在每个Springioc容器中只有一个实例 - prototype
一个bean的定义可以有多个实例 - request
每次http请求都会创建一个bean,该作用域仅在基于web的SpringApplicationContext情形下有效 - session
在一个HTTPSession中,一个bean定义对应一个实例。该作用域仅在基于web的SpringApplicationContext情形下有效 - global-session
在一个全局的HTTPSession中,一个bean定义对应一个实例。该作用域仅在基于web的SpringApplicationContext情形下有效
4.12 Spring框架中的单例bean是线程安全的吗
答: Spring 框架中的单例bean不是线程安全的
Spring框架并没有对单例bean进行任何多线程的封装处理,关于单例bean的线程安全和并发问题需要开发者自行去搞定。最简单的有效解决办法就是:将多态bean的作用域由“singleton”变更为“prototype”
。
- 在@Controller或者@Service等容器中,默认情况下,scope值是singleton单例的,也是线程不安全的
- 尽量不要在@Controller或者@Service等容器中定义静态变量,不论是单例(singleton)还是多实例(prototype)他都是线程不安全的。
- 默认注入的Bean对象,在不设置scope的时候他也是线程不安全的。
一定要定义变量的话,用ThreadLocal来封装,这个是线程安全的
eg:ThreadLocal<Integer> threadLocal = new ThreadLocal<>(); // 用ThreadLocal来封装变量
参考资料: Spring框架中的单例bean是线程安全的吗
4.13 解释Spring框架中bean的生命周期
- Spring容器从XML文件中读取bean的定义,并实例化bean
- Spring根据bean的定义填充所有的属性
- 如果bean实现了BeanNameAware接口,Spring传递bean的ID到setBeanName方法。如果Bean实现了BeanFactoryAware接口,Spring传递beanfactory给setBeanFactory方法
- 如果有任何与bean相关联的BeanPostProcessors,Spring会在postProcesserBeforeInitialization()方法内调用它们
- 如果bean实现IntializingBean了,调用它的afterPropertySet方法,如果bean声明了初始化方法,调用此初始化方法
- 如果有BeanPostProcessors和bean关联,这些bean的postProcessAfterInitialization()方法将被调用
- 如果bean实现了DisposableBean,它将调用destroy()方法。
说一下动态代理和静态代理?动态代理有JDK动态代理和Cglib动态代理,这两个代理如何实现的,有何区别?
5 设计模式
5.1 策略模式
在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。
意图: 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换
主要解决: 在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护
何时使用: 一个系统有许多许多类,而区分它们的只是他们直接的行为
如何解决: 将这些算法封装成一个一个的类,任意地替换
关键代码: 实现同一个接口
应用实例:
1、诸葛亮的锦囊妙计,每一个锦囊就是一个策略
2、旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略
3、JAVA AWT 中的 LayoutManager。
优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。
缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。
使用场景:
1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为
2、一个系统需要动态地在几种算法中选择一种
3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现
注意事项: 如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题
5.2 项目中用到了那些设计模式?哪些好的框架里面有使用过这些设计模式?
这个根据实际情况回答即可
5.2.1 项目中用到了那些设计模式
-
示例1: 我在项目中,做日志管理模块时,使用了一个
代理模式
。在访问业务方法时,基于AOP切面,对业务进行了拦截。
具体操作大致如下:
首先我自定义了OperateLog
注解,然后设计了日志切面管理类
,使用@Pointcut定义切入点
,在加注解的位置切入代码,使用了@Around环绕通知
,在业务操作前进行Api基本信息的存储,当业务方法执行完成后,存储了相应结果JSON报文,以及Api请求到响应的耗时时间。 -
示例2: 我在做车辆发行时,多线程执行job任务时,使用了单例模式,封装了一个线程操作工具类,代码示例如下:
package com.smilehappiness.service.common.utils; import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.util.concurrent.*; /** * <p> * 线程工具类 * <p/> * * @author smilehappiness * @Date 2018/10/27 10:05 */ public class ThreadUtil private static volatile ThreadPoolExecutor THREAD_POOL = null; private ThreadUtil() static //如果实例为空,创建实例 if (THREAD_POOL == null) synchronized (ThreadUtil.class) if (THREAD_POOL == null) int corePoolSize = Runtime.getRuntime().availableProcessors() * 2; ThreadFactory nameThreadFactory = new ThreadFactoryBuilder().setNameFormat("vehicle-pool-%d").build(); THREAD_POOL = new ThreadPoolExecutor(corePoolSize , corePoolSize + 1, 30, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100000), nameThreadFactory); public static void execute(Runnable runnable) THREAD_POOL.execute(runnable); /** * <p> * 返回结果 * <p/> * * @param runnable * @return java.util.concurrent.Future<?> * @Date 2018/10/27 11:36 */ public static <T> Future<T> submit(Runnable runnable, T result) return THREAD_POOL.submit(runnable, result); public static <T> Future<T> submit(Callable<T> task) return THREAD_POOL.submit(task); /** * <p> * 通知关闭线程池 * <p/> * * @param * @return void * @Date 2018/10/27 11:07 */ public static void shutdown() THREAD_POOL.shutdown(); public static ThreadPoolExecutor getExecutorObject() return THREAD_POOL;
-
示例3:
再做医疗供应链保理时,搜集票据
和单据
时,我使用了策略模式,不同的excel数据,我使用不同的模板策略去解析处理
5.2.2 哪些好的框架里面有使用过这些设计模式?
优秀的Spring Boot框架大量使用了这些设计模式
6 MySQL总结
6.1 Java JDBC编程
6.2 MySQL使用总结以及MySQL性能优化
6.3 MySQL四大特性是什么(MySQL事务的基本要素(ACID)有哪些)?
-
原子性(Atomicity)
事务开始后所有操作,要么全部做完(要么都成功),要么全部不做(要么都失败),不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。 -
一致性(Consistency)
事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。 -
隔离性(Isolation)
同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程中,B不能向这张卡转账。 -
持久性(Durability)
事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。
6.4 MySQL隔离级别有几种,有什么区别?
6.4.1 MySQL四种隔离级别
MySQL默认的隔离级别是可重复读(repeatable-read)
,MySQL事务隔离级别有以下四种:
事务隔离级别
脏读
不可重复读
幻读
读未提交(read-uncommitted)
是
是
是
读已提交(read-committed)
否
是
是
可重复读(repeatable-read)
否
否
是
串行化(serializable)
否
否
以上是关于中高级Java程序员,你不得不掌握的基本功,挑战20k+的主要内容,如果未能解决你的问题,请参考以下文章