java面试知识点
2024-02-29 17:02:24 11 举报
AI智能生成
Java面试知识点包括Java基础、JVM、多线程并发、Spring原理、微服务、网络、数据库、数据结构与算法等。Java基础包括集合、异常、多线程I/O、反射等。JVM包括内存模型、类加载机制、垃圾回收算法等。多线程并发包括synchronized、volatile、ThreadLocal、CAS等。Spring原理包括AOP、IOC、事务管理等。微服务包括Spring Boot、Spring Cloud等。网络包括TCP/IP协议栈、HTTP协议等。数据库包括MySQL、Oracle等。数据结构与算法包括数组、链表、栈、队列、树、图等。
作者其他创作
大纲/内容
一、事务
分类 编程式事务、声明式事务
1、@Transactional注解可以作用于哪些地方?
@Transactional 可以作用在接口、类、类方法。
作用于类:当把@Transactional 注解放在类上时,表示所有该类的public方法都配置相同的事务属性信息。
作用于方法:当类配置了@Transactional,方法也配置了@Transactional,方法的事务会覆盖类的事务配置信息。
作用于接口:不推荐这种使用方法,因为一旦标注在Interface上并且配置了Spring AOP 使用CGLib动态代理,将会导致@Transactional注解失效
2、@Transactional注有哪些属性?
noRollbackFor属性
noRollbackFor:抛出指定的异常类型,不回滚事务,也可以指定多个异常类型。
rollbackFor 属性
rollbackFor :用于指定能够触发事务回滚的异常类型,可以指定多个异常类型。
readOnly 属性
readOnly :指定事务是否为只读事务,默认值为 false;为了忽略那些不需要事务的方法,比如读取数据,可以设置 read-only 为 true。
timeout 属性
timeout :事务的超时时间,默认值为 -1。如果超过该时间限制但事务还没有完成,则自动回滚事务。
isolation 属性
isolation :事务的隔离级别,默认值为 Isolation.DEFAULT。
Isolation.DEFAULT:使用底层数据库默认的隔离级别。
Isolation.READ_UNCOMMITTED(读未提交)
Isolation.READ_COMMITTED(读已提交)
Isolation.REPEATABLE_READ(可重复读)
Isolation.SERIALIZABLE(序列化)
propagation属性
propagation 代表事务的传播行为,默认值为 Propagation.REQUIRED,其他的属性信息如下
Propagation.REQUIRED:如果当前存在事务,则加入该事务,如果当前不存在事务,则创建一个新的事务。( 也就是说如果A方法和B方法都添加了注解,在默认传播模式下,A方法内部调用B方法,会把两个方法的事务合并为一个事务 )
Propagation.SUPPORTS:如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务的方式继续运行。
Propagation.MANDATORY:如果当前存在事务,则加入该事务;如果当前不存在事务,则抛出异常。
Propagation.REQUIRES_NEW:重新创建一个新的事务,如果当前存在事务,暂停当前的事务。( 当类A中的 a 方法用默认Propagation.REQUIRED模式,类B中的 b方法加上采用 Propagation.REQUIRES_NEW模式,然后在 a 方法中调用 b方法操作数据库,然而 a方法抛出异常后,b方法并没有进行回滚,因为Propagation.REQUIRES_NEW会暂停 a方法的事务 )
Propagation.NOT_SUPPORTED:以非事务的方式运行,如果当前存在事务,暂停当前的事务。
Propagation.NEVER:以非事务的方式运行,如果当前存在事务,则抛出异常。
Propagation.NESTED :如果当前存在事务,则当前事务做为子事务执行,父事务失败,子事务回滚。子事务失败,父事务不回滚。(嵌套事务)
3、@Transactional失效场景
a、@Transactional 应用在非 public 修饰的方法上
b、@Transactional 注解属性 rollbackFor 设置错误
rollbackFor 可以指定能够触发事务回滚的异常类型。Spring默认抛出了未检查unchecked异常(继承自 RuntimeException的异常)或者 Error才回滚事务;其他异常不会触发回滚事务。如果在事务中抛出其他类型的异常,但却期望 Spring 能够回滚事务,就需要指定 rollbackFor属性
c、同一个类中方法调用,导致@Transactional失效
开发中避免不了会对同一个类里面的方法调用,比如有一个类Test,它的一个方法A,A再调用本类的方法B(不论方法B是用public还是private修饰),但方法A没有声明注解事务,而B方法有。则外部调用方法A之后,方法B的事务是不会起作用的。这也是经常犯错误的一个地方。
那为啥会出现这种情况?其实这还是由于使用Spring AOP代理造成的,因为只有当事务方法被当前类以外的代码调用时,才会由Spring生成的代理对象来管理。
那为啥会出现这种情况?其实这还是由于使用Spring AOP代理造成的,因为只有当事务方法被当前类以外的代码调用时,才会由Spring生成的代理对象来管理。
d、异常被你的 catch“吃了”导致@Transactional失效
e、@Transactional 注解属性 propagation 设置错误
这种失效是由于配置错误,若是错误的配置以下三种 propagation,事务将不会发生回滚。
TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常
TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常
f、数据库引擎不支持事务
这种情况出现的概率并不高,事务能否生效数据库引擎是否支持事务是关键。常用的MySQL数据库默认使用支持事务的innodb引擎。一旦数据库引擎切换成不支持事务的myisam,那事务就从根本上失效了。
二、redis
Redis--过期键策略(惰性删除、定期删除)
expires字典的键指向数据库中的某个键,而值则记录了数据库键的过期时间,过期时间是一个以毫秒为单位的UNIx时间戳。
expires字典的键指向数据库中的某个键,而值则记录了数据库键的过期时间,过期时间是一个以毫秒为单位的UNIx时间戳。
Redis使用惰性删除和定期删除两种策略来删除过期的键:惰性删除策略只在碰到过期键时才进行删除操作,定期删除策略则每隔一段时间主动查找并删除过期键。
Redis使用惰性删除和定期删除两种策略来删除过期的键:惰性删除策略只在碰到过期键时才进行删除操作,定期删除策略则每隔一段时间主动查找并删除过期键。
执行SAVE命令或者 BGSAVE命令所产生的新RDB文件不会包含已经过期的键。
执行SAVE命令或者 BGSAVE命令所产生的新RDB文件不会包含已经过期的键。
子主题
执行 BGREWRITEAOF命令所产生的重写AOF文件不会包含已经过期的键。
执行 BGREWRITEAOF命令所产生的重写AOF文件不会包含已经过期的键。
当一个过期键被删除之后,服务器会追加一条DEL命令到现有AOF文件的末尾显式地删除过期键。
当一个过期键被删除之后,服务器会追加一条DEL命令到现有AOF文件的末尾显式地删除过期键。
当主服务器删除一个过期键之后,它会向所有从服务器发送一条DEL命令,显式地删除过期键
当主服务器删除一个过期键之后,它会向所有从服务器发送一条DEL命令,显式地删除过期键
从服务器即使发现过期键也不会自作主张地删除它,而是等待主节点发来DEL命令,这种统一、中心化的过期键删除策略可以保证主从服务器数据的一致性。
从服务器即使发现过期键也不会自作主张地删除它,而是等待主节点发来DEL命令,这种统一、中心化的过期键删除策略可以保证主从服务器数据的一致性。
缓存雪崩
缓存雪崩概念:Redis挂掉了,请求全部走数据库。
如何解决缓存雪崩?
在缓存的时候给过期时间加上一个随机值,这样就会大幅度的减少缓存在同一时间过期。
事发前:实现Redis的高可用(主从架构+Sentinel 或者Redis Cluster),尽量避免Redis挂掉这种情况发生。
事发中:万一Redis真的挂了,我们可以设置本地缓存(ehcache)+限流(hystrix),尽量避免数据库被干掉(起码能保证服务还是能正常工作的)
事发后:redis持久化,重启后自动从磁盘上加载数据,快速恢复缓存数据。
缓存穿透
缓存穿透概念:请求的数据在缓存大量不命中,导致请求走数据库
如何解决缓存穿透?
由于请求的参数是不合法的(每次都请求不存在的参数),可以使用布隆过滤器(BloomFilter)或者压缩filter提前拦截,不合法就不让这个请求到数据库层!
当我们从数据库找不到的时候,我们也将这个空对象设置到缓存里边去。下次再请求的时候,就可以从缓存里边获取了。这种情况一般会将空对象设置一个较短的过期时间。
缓存与数据库双写一致
从理论上说,只要我们设置了键的过期时间,我们就能保证缓存和数据库的数据最终是一致的。因为只要缓存数据过期了,就会被删除。随后读的时候,因为缓存里没有,就可以查数据库的数据,然后将数据库查出来的数据写入到缓存中。
除了设置过期时间,还需要做更多的措施来尽量避免数据库与缓存处于不一致的情况发生。
redis的连接工具jedis 和 redisson 的区别和相同点
区别
Jedis 只是简单的封装了 Redis 的API库,可以看作是Redis客户端,它的方法和Redis 的命令很类似。Jedis相比于Redisson 更原生一些,更灵活。
Redisson 不仅封装了 redis ,还封装了对更多数据结构的支持,以及锁等功能,相比于Jedis 更加大。
相同点
Jedis 和 Redisson 都是Java中对Redis操作的封装
三、注解
@Target 注解决定MyAnnotation注解可以加在哪些成分上,如加在类身上,或者属性身上,或者方法身上等成分
@Retention 作用是定义被它所注解的注解保留多久,一共有三种策略,定义在RetentionPolicy枚举中
source:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;被编译器忽略
class:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期
runtime:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
这3个生命周期分别对应于:Java源文件(.java文件) ---> .class文件 ---> 内存中的字节码。
@Param
使用@Param注解
当你使用了使用@Param注解来声明参数时,如果使用 #{} 或 ${} 的方式都可以。
当你不使用@Param注解来声明参数时,必须使用使用 #{}方式。如果使用 ${} 的方式,会报错。
不使用@Param注解
不使用@Param注解时,参数只能有一个,并且是Javabean。在SQL语句里可以引用JavaBean的属性,而且只能引用JavaBean的属性。
@Valid@Validated
@Valid和@Validated的区分
@Validated是@Valid 的一次封装,是Spring提供的校验机制使用。
@Valid不提供分组功能
@Validated不提供嵌套验证功能。嵌套验证需要在对应的嵌套属性前加@Valid
验证属性
@Null 限制只能为null
@NotNull 限制必须不为null
@NotEmpty 验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0)
@NotBlank 验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格
@Size(max,min) 限制字符长度必须在min到max之间
@Pattern(value) 限制必须符合指定的正则表达式
@Past 限制必须是一个过去的日期
@Min(value) 限制必须为一个不小于指定值的数字
@Max(value) 限制必须为一个不大于指定值的数字
@Future 限制必须是一个将来的日期
@Digits(integer,fraction) 限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
@DecimalMin(value) 限制必须为一个不小于指定值的数字
@DecimalMax(value) 限制必须为一个不大于指定值的数字
@AssertTrue 限制必须为true
@AssertFalse 限制必须为false
@Past 验证注解的元素值(日期类型)比当前时间早
@Email 验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式
@Order(-1)
注解@Order或者接口Ordered的作用是定义Spring IOC容器中Bean的执行顺序的优先级,而不是定义Bean的加载顺序,Bean的加载顺序不受@Order或Ordered接口的影响;
详解:https://blog.csdn.net/yaomingyang/article/details/86649072
@Aspect 切面
日志切面使用案例:https://gitee.com/futao127/otoc/blob/master/otoc-common/src/main/java/com/szeastroc/common/exception/ExceptionAspect.java
@Intercepts 拦截器 与 ZuulFilter过滤器
做为分页拦截器使用案例:https://gitee.com/futao127/otoc/blob/master/otoc-common/src/main/java/com/szeastroc/common/jdbc/page/PageInterceptor.java
zuul网关做登陆过滤器案例:
https://gitee.com/futao127/otoc/blob/master/otoc-api-gateway/src/main/java/com/szeastroc/gateway/filter/AuthorizedFilter.java
https://gitee.com/futao127/otoc/blob/master/otoc-gateway/src/main/java/com/szeastroc/gateway/filter/AuthorizedFilter.java
https://gitee.com/futao127/otoc/blob/master/otoc-api-gateway/src/main/java/com/szeastroc/gateway/service/impl/UserServiceImpl.java
与过滤器(filter)的区别:https://www.cnblogs.com/panxuejun/p/7715917.html
四、接口幂等
接口幂等概念:接口幂等性就是用户对同一操作发起了一次或多次请求的对数据的影响是一致不变的,不会因为多次的请求而产生副作用。
接口幂等性解决方案
1.token+redis 机制
1.1获取全局唯一token:接口处理生成唯一标识(token) 存储到redis中,并返回给调用客户端。
1.2发起支付操作并附带token
接口处理:
1.2.1 获得分布式锁(处理并发情况)
1.2.2 判断redis中是否存在token
1.2.3 存在 执行支付业务逻辑,否则返回该订单已经支付
1.2.4 释放分布式锁
1.2.1 获得分布式锁(处理并发情况)
1.2.2 判断redis中是否存在token
1.2.3 存在 执行支付业务逻辑,否则返回该订单已经支付
1.2.4 释放分布式锁
2.CAS 保证接口幂等性
查询、比对、更新
例如 电商订单,订单支付状态 0 待支付 , 1 支付中 , 3 支付成功 4 支付失败。
update order set status = 1 where status =0 and orderId = “201251487987”
该sql语句利用状态CAS 保证该操作的幂等。
update order set status = 1 where status =0 and orderId = “201251487987”
该sql语句利用状态CAS 保证该操作的幂等。
3 乐观锁实现幂等
获取版本号
借鉴数据库的乐观锁机制,如:
update t_goods set count = count -1 , version = version + 1 where good_id=2 and version = 1
update t_goods set count = count -1 , version = version + 1 where good_id=2 and version = 1
4 防重表
利用数据库建一张防重表(加唯一索引)
订单号插入防重表 成功 执行支付业务逻辑,失败说明已经支付过。
五、循环依赖微服务项目怎么启动
场景:注入方法用了@Async的对象早于AOP创建proxy类,当spring初始化applicationContext后,发现注入的对象并不是proxy类。
解决方案:注入heliPayChannelAsynService的地方加上 @Lazy(value = true)
@Transactional 使用的是自动代理创建器AbstractAutoProxyCreator,它实现了getEarlyBeanReference()方法从而很好的对循环依赖提供了支持。
六、bean容器的生命周期
七、jeecg-boot 学习文档http://www.jeecg.com/doc/quickstart
八、clickhouse、es、hbase区别比对
九、JVM实操 使用工具及调优
十、线程池
线程池详解:https://blog.csdn.net/weixin_40271838/article/details/79998327
线程池中常用的队列:LinkedBlockingQueue 和ArrayBlockingQueue
相同点:线程安全的阻塞队列、都实现了BlockingQueue接口
不同点
队列大小有所不同,ArrayBlockingQueue是有界的初始化必须指定大小,而LinkedBlockingQueue可以是有界的也可以是无界的(Integer.MAX_VALUE),(而且不会初始化就占用一大片内存)对于后者而言,当添加速度大于移除速度时,在无界的情况下,可能会造成内存溢出等问题
数据存储容器不同,ArrayBlockingQueue采用的是数组作为数据存储容器,而LinkedBlockingQueue采用的则是以Node节点作为连接对象的链表
由于ArrayBlockingQueue采用的是数组的存储容器,因此在插入或删除元素时不会产生或销毁任何额外的对象实例,而LinkedBlockingQueue则会生成一个额外的Node对象。这可能在长时间内需要高效并发地处理大批量数据的时,对于GC可能存在较大影响。
两者的实现队列添加或移除的锁不一样,ArrayBlockingQueue实现的队列中的锁是没有分离的,即添加操作和移除操作采用的同一个ReenterLock锁,而LinkedBlockingQueue实现的队列中的锁是分离的,其添加采用的是putLock,移除采用的则是takeLock,这样能大大提高队列的吞吐量,也意味着在高并发的情况下生产者和消费者可以并行地操作队列中的数据,以此来提高整个队列的并发性能。
十二、加解密算法 https://www.cnblogs.com/sochishun/p/7028056.html
对称性加密算法
概念:对称式加密就是加密和解密使用同一个密钥。信息接收双方都需事先知道密匙和加解密算法且其密匙是相同的,之后便是对数据进行加解密了。对称加密算法用来对敏感数据等信息进行加密。
DES(Data Encryption Standard):数据加密标准,速度较快,适用于加密大量数据的场合。
AES(Advanced Encryption Standard):高级加密标准,是下一代的加密算法标准,速度快,安全级别高;AES是一个使用128为分组块的分组加密算法,分组块和128、192或256位的密钥一起作为输入,对4×4的字节数组上进行操作。众所周之AES是种十分高效的算法,尤其在8位架构中,这源于它面向字节的设计。AES 适用于8位的小型单片机或者普通的32位微处理器,并且适合用专门的硬件实现,硬件实现能够使其吞吐量(每秒可以到达的加密/解密bit数)达到十亿量级。同样,其也适用于RFID系统。
非对称性算法
概念:非对称式加密就是加密和解密所使用的不是同一个密钥,通常有两个密钥,称为"公钥"和"私钥",它们两个必需配对使用,否则不能打开加密文件。发送双方A,B事先均生成一堆密匙,然后A将自己的公有密匙发送给B,B将自己的公有密匙发送给A,如果A要给B发送消 息,则先需要用B的公有密匙进行消息加密,然后发送给B端,此时B端再用自己的私有密匙进行消息解密,B向A发送消息时为同样的道理。
RSA:由 RSA 公司发明,是一个支持变长密钥的公共密钥算法,需要加密的文件块的长度也是可变的。RSA在国外早已进入实用阶段,已研制出多种高速的RSA的专用芯片。
散列算法
概念:散列算法,又称哈希函数,是一种单向加密算法。在信息安全技术中,经常需要验证消息的完整性,散列(Hash)函数提供了这一服务,它对不同长度的输入消息,产生固定长度的输出。这个固定长度的输出称为原输入消息的"散列"或"消息摘要"(Message digest)。散列算法不算加密算法,因为其结果是不可逆的,既然是不可逆的,那么当然不是用来加密的,而是签名。
MD5:MD5是一种不可逆的加密算法,目前是最牢靠的加密算法之一,尚没有能够逆运算的程序被开发出来,它对应任何字符串都可以加密成一段唯一的固定长度的代码。
其他常用算法
Base64:其实不是安全领域下的加密解密算法,只能算是一个编码算法,通常用于把二进制数据编码为可写的字符形式的数据,对数据内容进行编码来适合传输(可以对img图像编码用于传输)。这是一种可逆的编码方式。编码后的数据是一个字符串,其中包含的字符为:A-Z、a-z、0-9、+、/,共64个字符(26 + 26 + 10 + 1 + 1 = 64,其实是65个字符,“=”是填充字符。Base64编码是从二进制到字符的过程。
总结
加密算法是可逆的,用来对敏感数据进行保护。散列算法(签名算法、哈希算法)是不可逆的,主要用于身份验证。
对称加密算法使用同一个密匙加密和解密,速度快,适合给大量数据加密。对称加密客户端和服务端使用同一个密匙,存在被抓包破解的风险。
非对称加密算法使用公钥加密,私钥解密,私钥签名,公钥验签。安全性比对称加密高,但速度较慢。非对称加密使用两个密匙,服务端和客户端密匙不一样,私钥放在服务端,黑客一般是拿不到的,安全性高。
Base64不是安全领域下的加解密算法,只是一个编码算法,通常用于把二进制数据编码为可写的字符形式的数据,特别适合在http,mime协议下的网络快速传输数据。UTF-8和GBK中文的Base64编码结果是不同的。采用Base64编码不仅比较简短,同时也具有不可读性,即所编码的数据不会被人用肉眼所直接看到,但这种方式很初级,很简单。Base64可以对图片文件进行编码传输。
https协议广泛用于万维网上安全敏感的通讯,例如交易支付方面。它的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。
:采用非对称加密算法管理对称算法的密钥,然后用对称加密算法加密数据,这样我们就集成了两类加密算法的优点,既实现了加密速度快的优点,又实现了安全方便管理密钥的优点
MD5标准密钥长度128位(128位是指二进制位。二进制太长,所以一般都改写成16进制,每一位16进制数可以代替4位二进制数,所以128位二进制数写成16进制就变成了128/4=32位。16位加密就是从32位MD5散列中把中间16位提取出来);sha1标准密钥长度160位(比MD5摘要长32位),Base64转换后的字符串理论上将要比原来的长1/3。
使用案例
MD5、DES、DESede、Blowfish使用案例:https://ld246.com/article/1355409054037/comment/1357103831695
DES、DESede、Blowfish使用案例:https://gitee.com/futao127/otoc/blob/master/otoc-manage/src/main/java/com/pengxun/manager/base/utils/Encrypt3DESUtils.java
十三、监控
zabbix官方安装使用文档:https://www.zabbix.com/documentation/3.4/zh/manual/installation/containers
十三、shardingjdbc
十一、使用案例登陆账号
gitee 账号: futao127 密码:19940301a
自由主题
0 条评论
下一页
为你推荐
查看更多