java面试知识点精华提炼(二)

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: java面试知识点精华提炼(二)

java面试知识点精华提炼(一)

https://developer.aliyun.com/article/1583801?spm=a2c6h.13148508.setting.17.3cca4f0enPJc3f


Spring Bean 作用域

Bean的五中作用域:singleton(单例)、prototype(原型)、request(请求)、session(会话)、global session(全局会话)

singleton:(默认)每一个Spring IoC容器都拥有唯一的一个实例对象,该模式在多线程下是不安全的。

prototype:每次通过 Spring 容器获取 prototype 定义的 bean 时,容器都将创建一个新的 Bean 实例,每个 Bean 实例都有自己的属性和状态,而 singleton 全局只有一个对象。根据经验,对有状态的bean使用prototype作用域,而对无状态的bean使用singleton作用域。

request:每个HTTP请求会产生一个Bean对象,Http 请求结束,该 bean实例也将会被销毁。只在基于web的SpringApplicationContext中可用。

session:限定一个Bean的作用域为HTTPsession的生命周期,session结束bean销毁,只有基于web的Spring ApplicationContext才能使用

global Session:限定一个Bean的作用域为全局HTTPSession的生命周期,只有基于web的SpringApplicationContext可用


Spring Bean 生命周期

Spring Bean的生命周期分为四个阶段和多个扩展点。扩展点又可以分为影响多个Bean和影响单个Bean

四个阶段

实例化 Instantiation:createBeanInstance()

属性赋值 Populate:populateBean()

初始化 Initialization:initializeBean()

销毁 Destruction:至于销毁,是在容器关闭时调用的,详见ConfigurableApplicationContext#close()

多个扩展点

生命周期:InitializingBean、DisposableBean

影响多个Bean:BeanPostProcessor、InstantiationAwareBeanPostProcessor

影响单个Bean:

Aware Group1:BeanNameAware、BeanClassLoaderAware、BeanFactoryAware

Aware Group2:EnvironmentAware、EmbeddedValueResolverAware、ApplicationContextAware(ResourceLoaderAware\ApplicationEventPublisherAware\MessageSourceAware)

Spring 依赖注入四种方式
  • 构造器注入、setter 方法注入、静态工厂注入、实例工厂


Spring 自动装配

Spring 装配包括手动装配和自动装配,手动装配是有基于 xml 装配、构造方法、setter 方法等。

自动装配有五种自动装配的方式,可以用来指导 Spring 容器用自动装配方式来进行依赖注入。


no:默认的方式是不进行自动装配,通过显式设置 ref 属性来进行装配。

byName:通过参数名自动装配,Spring 容器在配置文件中发现 bean 的 autowire 属性被设置成 byname,之后容器试图匹配、装配和该 bean 的属性具有相同名字的 bean。

byType:通过参数类型自动装配,Spring 容器在配置文件中发现 bean 的 autowire 属性被设置成 byType,之后容器试图匹配、装配和该 bean 的属性具有相同类型的 bean。如果有多个 bean 符合条件,则抛出错误。

constructor:这个方式类似于 byType, 但是要提供给构造器参数,如果没有确定的带参数的构造器参数类型,将会抛出异常。

autodetect:首先尝试使用 constructor 来自动装配,如果无法工作,则使用 byType 方式。


Spring AOP
AOP初始化时序图


AOP核心概念

切面(aspect):类是对物体特征的抽象,切面就是对横切关注点的抽象

横切关注点:对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点。

连接点(joinpoint):被拦截到的点,Spring 只支持方法类型的连接点,连接点指的是被拦截到的方法,连接点还可以是字段或者构造器。

切入点(pointcut):对连接点进行拦截的定义

通知(advice):所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类。

目标对象:代理的目标对象

织入(weave):将切面应用到目标对象并导致代理对象创建的过程

引入(introduction):在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段。


AOP 主要应用场景有

Authentication 权限

Caching 缓存

Context passing 内容传递

Error handling 错误处理

Lazy loading 懒加载

Debugging 调试

logging, tracing, profiling and monitoring 记录跟踪 优化 校准

Performance optimization 性能优化

Persistence 持久化

Resource pooling 资源池

Synchronization 同步

Transactions 事务


AOP 两种代理方式

Spring 提供了两种方式来生成代理对象: JDKProxy 和 Cglib,具体使用哪种方式生成由AopProxyFactory 根据 AdvisedSupport 对象的配置来决定。默认的策略是如果目标类是接口,则使用 JDK 动态代理技术,否则使用 Cglib 来生成代理。


JDK 动态接口代理

JDK 动态代理主要涉及到 java.lang.reflect 包中的两个类:Proxy 和 InvocationHandler。InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编制在一起。Proxy 利用 InvocationHandler 动态创建一个符合某一接口的实例,生成目标类的代理对象。

CGLib 动态代理

CGLib 全称为 Code Generation Library,是一个强大的高性能,高质量的代码生成类库,可以在运行期扩展 Java 类与实现 Java 接口,CGLib 封装了 asm,可以再运行期动态生成新的 class。

和 JDK 动态代理相比较:JDK 创建代理有一个限制,就是只能为接口创建代理实例,而对于没有通过接口定义业务方法的类,则可以通过 CGLib 创建动态代理。

AOP简单使用

@Component
@Aspect
public class AspectText {
 
    /*
        aop的重点概念:
        Pointcut(切入点):被增强的方法
        Advice(通知/ 增强):封装增强业务逻辑的方法
        Aspect(切面):切点+通知
        Weaving(织入):将切点与通知结合的过程
        前置通知        <aop:before>            用于配置前置通知。指定增强的方法在切入点方法之前执行
        后置通知        <aop:after-returning>    用于配置后置通知。指定增强的方法在切入点方法之后执行
        环绕通知        <aop:around>            用于配置环绕通知。指定增强的方法在切入点方法之前和之后都执行
        异常抛出通知    <aop:throwing>            用于配置异常抛出通知。指定增强的方法在出现异常时执行
        最终通知        <aop:after>                用于配置最终通知。无论增强方式执行是否有异常都会执行
    * */
    @Before("execution(* com.sandwich.controller.admin.*(..))")
    public void before(){
        System.out.println("before增强方法");
    }
 
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("around增强前");
        Object proceed = pjp.proceed();
        System.out.println("around增强后");
        return proceed;
    }
 
    @AfterReturning("pointcut()")
    public void afterReturning(){
        System.out.println("afterReturning返回后");
    }
 
    //设置切点表达式:可以共用
    @Pointcut("execution(* com.sandwich.controller.admin.*(..))")
    public void pointcut(){ }
}

Spring MVC 框架

Spring MVC执行流程


Spring Boot

Spring Boot特性

快速创建基于Spring的独立应用程序。

内置Serverlet容器,无需单独部署Tomcat等服务器,可直接运行jar包。

提供约定的starter POM来简化Maven的配置,让Maven的配置变得更简单。

根据项目的Maven依赖配置,Spring Boot自动配置Spring、Spring MVC等等。

提供生产就绪型功能,如指标,健康检查和外部配置。

基本可以完全不使用XML配置文件,采用注解进行配置。


Spring Boot四大核心:

自动配置:针对很多Spring应用程序和常用的应用功能,Spring Boot能自动提供相关配置;

starter 组件:starter 是 SpringBoot 的一个重要的组成部分,它相当于一个集成的模块;

Actuator:让你能深入运行中的Spring Boot应用程序,监控程序的内部信息;

命令行界面:这个为Spring Boot的可选特性,主要是针对Groovy的。


Spring-Boot-starter

Mybatis 框架

Mybatis是如何进行分页的?分页插件的原理是什么?

Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页,可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。

 分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。

举例:select * from student,拦截sql后重写为:select t.* from (select * from student)t limit 0,10


当实体类中的属性名和表中的字段名不一样 ,怎么办 ?

第1种: 通过在查询的sql语句中定义字段名的别名,让字段名的别名和实体类的属性名一致。

第2种: 通过来映射字段名和实体类属性名的一一对应的关系。


Mybatis动态sql是做什么的?都有哪些动态sql?能简述一下动态sql的执行原理不?

Mybatis动态sql可以让我们在Xml映射文件内,以标签的形式编写动态sql,完成逻辑判断和动态拼接sql的功能。

Mybatis提供了9种动态sql标签:trim|where|set|foreach|if|choose|when|otherwise|bind。

其执行原理为,使用OGNL从sql参数对象中计算表达式的值,根据表达式的值动态拼接sql,以此来完成动态sql的功能。


Mybatis的Xml映射文件中,不同的Xml映射文件,id是否可以重复?

如果配置了namespace那么当然是可以重复的,因为我们的Statement实际上就是namespace+id

如果没有配置namespace的话,那么相同的id就会导致覆盖了。


Mybatis 缓存


Mybatis 的一级缓存原理(sqlsession 级别)

第一次查询 sql,sql 查询结果写入 sqlsession 的一级缓存中,缓存使用的数据结构是一个 map。


key:MapperID+offset+limit+Sql+所有的入参,value:用户信息


同一个 sqlsession 再次发出相同的 sql,就从缓存中取出数据。如果两次中间出现 commit 操作(修改、添加、删除),


本 sqlsession 中的一级缓存区域全部清空,缓存中查询不到从数据库查询,从数据库查询到再写入缓存。


二级缓存原理(mapper 基本)

二级缓存的范围是 mapper 级别(mapper 同一个命名空间),mapper 以命名空间为单位创建缓存数据结构,结构是 map。

mybatis 的二级缓存是通过 CacheExecutor 实现的。CacheExecutor其实是 Executor 的代理对象。

所有的查询操作,在 CacheExecutor 中都会先匹配缓存中是否存在,不存在则查询数据库。

key:MapperID+offset+limit+Sql+所有的入参

具体使用需要配置:

Mybatis 全局配置中启用二级缓存配置

在对应的 Mapper.xml 中配置 cache 节点

在对应的 select 查询节点中添加 useCache=true


mysql数据库

聚集索引(clustered index):聚集索引决定数据在磁盘上的物理排序,一个表只能有一个聚集索引,一般用primary key来约束。


非聚集索引(non-clustered index):它并不决定数据在磁盘上的物理排序,索引上只包含被建立索引的数据,以及一个行定位符row-locator,这个行定位符,可以理解为一个聚集索引物理排序的指针,通过这个指针,可以找到行数据。


联合索引:多个字段上建立的索引,能够加速复合查询条件的检索。


索引覆盖:被查询的列,数据能从索引中取得,而不是通过行定位符row-locator再到row上获取,即“被查询列要被所建的索引覆盖”,这能够加速查询速度。


事务隔离级别

事务的基本要素(ACID):原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)

原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。

一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。

隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。

持久性(Durability):事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。


事务的并发问题

脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据

不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。

幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

image.png

sql优化的几种方式

尽量避免全表扫描,应考虑在 where 及 order by 涉及的列上建立索引。

尽量避免在where子句中使用以下查询,会导致放弃索引全表扫描。

is null :使用字段默认值代替

!=或<>操作符:

or :使用 union all 代替

in 和 not in:连续数值使用 between 代替in,或者使用 exists 代替 in

where name like ‘%abc%’ :

where num/2=100 : 应该为 where num=100*2 ,不要在“=”左边进行函数、算术运算或其他表达式运算

当索引列有大量数据重复时,SQL查询可能不会去利用索引。

一个表的索引数最好不要超过6个,因为 insert 或 update 时有可能会重建索引,执行效率会下降。

用具体的字段列表代替“*”,不要返回用不到的任何字段。

.尽量避免大事务操作,提高系统并发能力。

在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致

尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。

这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。

使用 varchar 代替 char ,长字段存储空间小,节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。

Redis

简单介绍一下 redis
  • redis是一个key-value类型的非关系型数据库,基于内存也可持久化的数据库,相对于关系 型数据库(数据主要存在硬盘中),性能高,因此我们一般用redis来做缓存使用;
  • Redis支持5种数据类型,string、hash、list、set、zset(sorted set);
Redis key过期的方式

被动删除:当读/写一个已经过期的key时,会触发惰性删除策略,直接删除掉这个过期key。

只有key被操作时(如GET),REDIS才会被动检查该key是否过期,如果过期则删除之并且返回NIL。

主动删除:由于惰性删除策略无法保证冷数据被及时删掉,所以Redis会定期主动淘汰一批已过期的key。

maxmemory当前已用内存超过maxmemory限定时,触发主动清理策略。

volatile-lru:只对设置了过期时间的key进行LRU(默认值)

allkeys-lru : 删除lru算法的key

volatile-random:随机删除即将过期key

allkeys-random:随机删除

volatile-ttl : 删除即将过期的

noeviction : 永不过期


基于 redis 的分布式锁

获取锁的时候调用 setnx,如果返回 0,则该锁正在被别人使用,返回 1 则成功获取 锁。 还设置一个获取的超时时间,若超过这个时间则放弃获取锁。


redis集群同步数据

一个集群只能有16384个槽,编号0-16383。这些槽会分配给集群中的所有主节点,分配策略没有要求。可以指定哪些编号的槽分配给哪个主节点。集群会记录节点和槽的对应关系。

接下来就需要对key求哈希值,然后对16384取余,余数是几key就落入对应的槽里。slot = CRC16(key) % 16384。

以槽为单位移动数据,因为槽的数目是固定的,处理起来比较容易,这样数据移动问题就解决了。

使用哈希函数计算出key的哈希值,这样就可以算出它对应的槽,然后利用集群存储的槽和节点的映射关系查询出槽所在的节点,于是数据和节点就映射起来了,这样数据分配问题就解决了。


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
10天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
35 2
|
15天前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
20天前
|
存储 缓存 Oracle
Java I/O流面试之道
NIO的出现在于提高IO的速度,它相比传统的输入/输出流速度更快。NIO通过管道Channel和缓冲器Buffer来处理数据,可以把管道当成一个矿藏,缓冲器就是矿藏里的卡车。程序通过管道里的缓冲器进行数据交互,而不直接处理数据。程序要么从缓冲器获取数据,要么输入数据到缓冲器。
Java I/O流面试之道
|
16天前
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
41 4
|
17天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
59 4
|
29天前
|
存储 Java 程序员
Java面试加分点!一文读懂HashMap底层实现与扩容机制
本文详细解析了Java中经典的HashMap数据结构,包括其底层实现、扩容机制、put和查找过程、哈希函数以及JDK 1.7与1.8的差异。通过数组、链表和红黑树的组合,HashMap实现了高效的键值对存储与检索。文章还介绍了HashMap在不同版本中的优化,帮助读者更好地理解和应用这一重要工具。
55 5
|
28天前
|
存储 Java
[Java]面试官:你对异常处理了解多少,例如,finally中可以有return吗?
本文介绍了Java中`try...catch...finally`语句的使用细节及返回值问题,并探讨了JDK1.7引入的`try...with...resources`新特性,强调了异常处理机制及资源自动关闭的优势。
21 1
|
29天前
|
Android开发
Android面试高频知识点(1) 图解Android事件分发机制
Android面试高频知识点(1) 图解Android事件分发机制
|
29天前
|
消息中间件 存储 Java
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
|
29天前
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
下一篇
无影云桌面