Java进阶常见面试题整理

JVM 虚拟机

Java进阶常见面试题整理_第1张图片

JVM加载类机制

  • JVM类加载分为五个阶段:加载->验证->准备->解析->初始化 (->使用->卸载)。
  • JVM提供了3种类加载器:启动类加载器、扩展类加载器和应用类加载器。
  • 双亲委派机制核心:保障类的唯一性和安全性。
  • 打破双亲委派机制:自定义加载器继承ClassLoader类,重写loadclass方法和findclass方法。
  • 双亲委派类加载机制的类加载流程:

    Java进阶常见面试题整理_第2张图片

JVM中一次完整的GC流程是怎样的

  • 当创建一个新对象时,就需要为该对象申请内存空间。
  • 首先会判断Eden区是否有内存空间,如果此时有内存空间,则直接将新对象保存在Eden区
  • 但是如果此时Eden区的内存空间不足,那么会自动执行一个Minor GC操作,清理之后会继续判断Eden区的内存空间是否充足,如果内存空间充足,则在Eden区进行新对象的空间分配。
  • 如果执行了Minor GC之后发现Eden区的内存依然不足,那么这个时候会进行Survivor区判断,如果Survivor区有剩余空间,则将Eden区的部分活跃对象保存在Survivor区。随后继续判断Eden区的内存空间是否充足,如果充足,则在Eden区进行新对象的空间分配。
  • 如果此时Survivor区也已经没有内存空间了,则继续判断老年区,如果此时老年区空间充足,则将存活区中的活跃对象保存到老年代,而后Survivor区就会存现有空余空间,随后Eden区将活跃对象保存在Survivor区之中,而后在Eden区进行新对象的空间分配。
  • 如果这个时候老年代也满了,那么这个时候将产生Major GC(Full GC),进行老年代的内存清理。
  • 如果老年代执行了Full GC之后发现依然无法进行对象的保存,就会产生OOM异常“OutOfMemoryError”。

什么时候触发Full GC

  • 老年代空间不足(碎片,或者分配不足)。
  • 在执行CMS GC的过程中同时有对象要放入老年代,而此时老年代空间不足(concurrent mode failure)。
  • minor GC后晋升到老年代的平均大小大于老年代的空间。
  • 主动触发Full GC(System.gc() || jmap -histo:live [pid]) 来避免碎片问题。

JVM内存泄漏

  • 产生原因:持有对象的强引用,且没有及时释放,进而造成内存单元一直被占用。
  • 解决:提高程序的健壮型,因为内存泄露是纯代码层面的问题。
  • 和内存溢出的联系:1.内存泄露会最终会导致内存溢出。2.内存泄露可以通过完善代码来避免,内存溢出可以通过调整配置来减少发生频率,但无法彻底避免。

当出现内存溢出,怎么排错

  • 产生原因:JVM内存过小、程序不严密,产生过多的垃圾。
  • 首先控制台查看错误日志。
  • 然后使用jdk自带的jvisualvm工具查看系统的堆栈日志。
  • 定位出内存溢出的空间:堆,栈还是永久代(jdk8以后不会出现永久代的内存溢出)。
  • 如果是堆内存溢出,看是否创建了超大的对象。
  • 如果是栈内存溢出,看是否创建了超大的对象,或者产生了死循环。

Tomcat

  • 总体结构和工作原理
  • 类加载流程
  • 线程模型

Tomcat性能调优

  • Tomcat调优主要从四个方面考虑:1.吞吐量、2.Responsetime、3.Cpuload、4.MemoryUsage。
  • JVM调优

MySQL中存储引擎

  • MyISAM存储引擎:MyISAM基于ISAM存储引擎的扩展。它是在Web、数据仓储和其他应用环境下最常使用的存储引擎之一。MyISAM拥有较高的插入、查询速度,但不支持事务。
  • InnoDB存储引擎:InnoDB是事务型数据库的首选引擎,支持事务安全表(ACID),支持行锁定和外键,InnoDB是默认的MySQL引擎。
  • 区别:
  • 一是主索引的区别,InnoDB的数据文件本身就是索引文件。而MyISAM的索引和数据是分开的。
  • 二是辅助索引的区别:InnoDB的辅助索引data域存储相应记录主键的值而不是地址。而MyISAM的辅助索引和主索引没有多大区别。

三个范式是什么

  • 第一范式:字段是最小的的单元不可再分。
  • 第二范式:满足第一范式,表中的字段必须完全依赖于全部主键而非部分主键。
  • 第三范式:满足第二范式,非主键外的所有字段必须互不依赖。

简单说一说drop、delete与truncate的区别

  • Delete用来删除表的全部或者一部分数据行,执行delete之后,用户需要提交(commmit)或者回滚(rollback)来执行删除或者撤销删除, delete命令会触发这个表上所有的delete触发器;
  • Truncate删除表中的所有数据,这个操作不能回滚,也不会触发这个表上的触发器,TRUNCATE比delete更快,占用的空间更小;
  • Drop命令从数据库中删除表,所有的数据行,索引和权限也会被删除,所有的DML触发器也不会被触发,这个命令也不能回滚。

什么是存储过程?有哪些优缺点?

  • 存储过程就像我们编程语言中的函数一样,封装了我们的代码(PLSQL、T-SQL)。
  • 优点:1.能够将代码封装起来、2.保存在数据库之中、3.让编程语言进行调用、4.存储过程是一个预编译的代码块,执行效率比较高、5.一个存储过程替代大量T_SQL语句 ,可以降低网络通信量,提高通信速率。
  • 缺点:1.每个数据库的存储过程语法几乎都不一样,十分难以维护(不通用)、2.业务逻辑放在数据库上,难以迭代。

索引是什么?什么时候用?

  • 什么是索引:1.是一种快速查询表中内容的机制,类似于新华字典的目录、2.运用在表中某个些字段上,但存储时,独立于表之外
  • 为什么索引会加快查询:因为索引其实就是一种优化查询的数据结构,比如Mysql中的索引是用B+树实现的,而B+树就是一种数据结构,可以优化查询速度,可以利用索引快速查找数据,所以能优化查询。
  • 创建索引规则:1.选择唯一性索引、2.限制索引数量、3.尽量使用数据量少的索引、4.尽量使用前缀来索引、5.尽量扩展现有索引。
  • 什么时候用:1.表经常进行 SELECT 操作、2.表很大(记录超多),记录内容分布范围很广、3.列名经常在 WHERE 语句、连接条件、排序字段、分组字段中出现。
  • 什么时候不用:1.表经常进行 INSERT/UPDATE/DELETE 操作、2.表很小(记录超少)、3.列名不经常作为连接条件或出现在 WHERE 子句中、4.数据分区不明显存在大量重复数据,如性别。
  • 为什么使用B+树:B+树是为了磁盘或其它存储设备而设计的一种平衡多路查找树(相对于二叉,B树每个内节点有多个分支),与红黑树相比,在相同的的节点的情况下,一颗B+树的高度远远小于红黑树的高度。B+树上操作的时间通常由存取磁盘的时间和CPU计算时间这两部分构成,而CPU的速度非常快,所以B树的操作效率取决于访问磁盘的次数,关键字总数相同的情况下B树的高度越小,磁盘I/O所花的时间越少。

索引优缺点

  • 索引加快数据库的检索速度
  • 索引降低了插入、删除、修改等维护任务的速度(虽然索引可以提高查询速度,但是它们也会导致数据库系统更新数据的性能下降,因为大部分数据更新需要同时更新索引)
  • 唯一索引可以确保每一行数据的唯一性,通过使用索引,可以在查询的过程中使用优化隐藏器,提高系统的性能
  • 索引需要占物理和数据空间

索引失效场景

  • 当使用or的情况下,如果不是每一列的条件都有索引,索引失效
  • 当使用多列索引的时候,没有匹配到第一部分,索引失效
  • 当使用like的时候,以%开头,索引失效
  • 当数据类型是字符串类型的时候,如果条件数据没有被引号引起来,索引失效
  • 反向查询,如 NOT IN,!=,<>
  • WHERE条件上使用运算函数

SQL语句优化

  • 为合适的字段添加索引,并且注意索引失效场景
  • 注意WHERE语句的连接顺序,先过滤数据
  • 避免SELECT *,不要返回用不到的任何字段
  • 如果知道只有一条记录使用limit提高效率,让数据库停止游标移动
  • 尽量避免NULL数据,因为它们使得索引运算比较复杂,建议使用空字符串或0

获取解释计划

  • explain plan for "SQL" -> select * from table(dbms_xplan.display());
  • set autotrace [command] "SQL"
  • alter session set statistics_level=all -> SQL -> select * from table(dbms_xplan.display_cursor(null,null,'allstats ast'));
  • ……

什么是事务?

  • 简单来说:一个Session中所进行所有的操作,要么同时成功,要么同时失败
  • 四个基本要素:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。
  • 事务隔离级别:1、Serializable【可避免脏读,不可重复读,虚读】、2.Repeatable read【可避免脏读,不可重复读】、3.Read committed【可避免脏读】、4.Read uncommitted【级别最低,什么都避免不了】

数据库的乐观锁和悲观锁是什么?

悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作

  • 在查询完数据的时候就把事务锁起来,直到提交事务
  • 实现方式:使用数据库中的锁机制

乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。

  • 在修改数据的时候把事务锁起来,通过version的方式来进行锁定
  • 实现方式:使用version版本或者时间戳

数据表损坏的修复方式有哪些?

  • 使用 myisamchk 来修复,具体步骤:1.修复前将mysql服务停止。2.打开命令行方式,然后进入到mysql的/bin目录。3.执行myisamchk –recover 数据库所在路径/*.MYI
  • 使用repair table 或者 OPTIMIZE table命令来修复,REPAIR TABLE table_name 修复表 OPTIMIZE TABLE table_name 优化表 REPAIR TABLE 用于修复被破坏的表。

数据库优化的思路

SQL优化

  • SELECT子句中避免使用*号
  • 善用索引
  • 多使用内部函数提高SQL效率
  • 使用表或列的别名
  • 多使用commit

结构优化

  • 范式优化: 比如消除冗余(节省空间。。)
  • 反范式优化:比如适当加冗余等(减少join)
  • 拆分表: 垂直拆分和水平拆分

Redis和Memcached 对比分析

Memcached的优点:

  • Memcached可以利用多核优势,单实例吞吐量极高,可以达到几十万QPS(取决于key、value的字节大小以及服务器硬件性能,日常环境中QPS高峰大约在4-6w左右)。适用于最大程度扛量。
  • 支持直接配置为session handle。
  • 坑少。

Memcached的局限性:

  • 只支持简单的key/value数据结构,不像Redis可以支持丰富的数据类型。
  • 无法进行持久化,数据不能备份,只能用于缓存使用,且重启后数据全部丢失。
  • 无法进行数据同步,不能将MC中的数据迁移到其他MC实例中。
  • Memcached内存分配采用Slab Allocation机制管理内存,value大小分布差异较大时会造成内存利用率降低,并引发低利用率时依然出现踢出等问题。需要用户注重value设计。

Redis的优点:

  • 支持多种数据结构
  • 支持持久化操作,可以进行aof及rdb数据持久化到磁盘,从而进行数据备份或数据恢复等操作,较好的防止数据丢失的手段。
  • 支持通过Replication进行数据复制,通过master-slave机制,可以实时进行数据的同步复制,支持多级复制和增量复制,master-slave机制是Redis进行HA的重要手段。
  • 单线程请求,所有命令串行执行,并发情况下不需要考虑数据一致性问题。
  • 支持pub/sub消息订阅机制,可以用来进行消息订阅与通知。
  • 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除。

Redis的局限性:

  • Redis只能使用单线程,性能受限于CPU性能,故单实例CPU最高才可能达到5-6wQPS每秒(取决于数据结构,数据大小以及服务器硬件性能,日常环境中QPS高峰大约在1-2w左右)。
  • Redis在string类型上会消耗较多内存,可以使用hash表压缩存储以降低内存耗用。

Redis

  • 是什么:Redis 是一个使用 C 语言写成的非关系型数据库,使用 key-value 存储值。
  • 支持的类型:字符串String、字典Hash、列表List、集合Set、有序集合SortedSet、位图Bitmap。
  • 为什么用:因为传统的关系型数据库如Mysql已经不能适用所有的场景了,比如秒杀的库存扣减,APP首页的访问流量高峰等等,都很容易把数据库打崩,所以引入了缓存中间件。

Redis有哪些适合的场景?

  • 会话缓存(Session Cache)
  • 全页缓存(FPC)
  • 队列:Reids在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得Redis能作为一个很好的消息队列平台来使用。
  • 排行榜/计数器:Redis在内存中对数字进行递增或递减的操作实现的非常好。

Redis有哪些常见数据结构?说一下使用场景?

  • String:String数据结构是简单的key-value类型,value其实不仅可以是String,也可以是数字。 常规key-value缓存应用; 常规计数:微博数,粉丝数等。
  • Hash:Hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。 比如我们可以Hash数据结构来存储用户信息,商品信息等等。
  • List:list就是链表,Redis list的应用场景非常多,也是Redis最重要的数据结构之一,比如微博的关注列表,粉丝列表,最新消息排行等功能都可以用Redis的list结构来实现。
  • Set:set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的。
    当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。
  • Sorted Set:和set相比,sorted set增加了一个权重参数score,使得集合中的元素能够按score进行有序排列。

Redis集群数据复制过程

Java进阶常见面试题整理_第3张图片

Redis持久化

  • RDB(Redis DataBase):RDB在指定的时间间隔内对数据进行快照存储,在保存快照文件时父进程会fork出一个子进程,由子进程完成具体的持久化工作,所以可以最优化Redis的性能。
  • AOF(Append Of File):AOF持久化以独立日志的方式记录每次写命令,并在 Redis 重启时在重新执行 AOF 文件中的命令以达到恢复数据的目的。AOF 的主要作用是解决数据持久化的实时性。
  • 对比:
  • RDB 是一个紧凑压缩的二进制文件,非常适合备份,全量复制等场景。比如每6小时执行 bgsave 备份,并把 RDB 文件拷贝到远程机器或者文件系统中,用于灾难恢复。
  • Redis 加载 RDB 恢复数据远远快于 AOF 的方式。
  • RDB 方式数据没办法做到实时持久化,而 AOF 方式可以做到。

Redis集群模式和工作原理

  • Redis有三种集群模式:主从模式,哨兵模式和集群模式。
  • 主从模式:所有的写请求都被发送到主数据库上,再由主数据库将数据同步到从数据库上,从数据库主要用于执行读操作缓解系统的读压力。
  • 哨兵模式:在从数据库上添加了一个哨兵的角色来监控集群的运行状态。哨兵通过发送命令让Redis服务返回其运行状态。哨兵是一个独立运行的进程,在监测到Master宕机时将自动将Slave切换成Master,然后通过发布订阅模式通知其他从服务器修改配置文件,完成主备热切。
  • 集群模式:Redis集群实现在多个Redis节点之间进行数据分片和数据复制。基于数据自动分片能力,我们能够方便地对Redis集群进行横向扩展,以提高Redis集群的吞吐量。基于数据复制能力,在集群中的一部分节点失效或者无法进行通信时,Redsi仍然可以基于副本数据对外提供服务,这提高了集群的可用性。

是否使用过Redis集群,集群的高可用怎么保证,集群的原理是什么?

  • Redis Sentinal着眼于高可用,在master宕机时会自动将slave提升为master,继续提供服务。
  • Redis Cluster着眼于扩展性,在单个redis内存不足时,使用Cluster进行分片存储。

Redis的并发竞争问题如何解决?

  • Redis为单进程单线程模式,采用队列模式将并发访问变为串行访问。Redis本身没有锁的概念,Redis对于多个客户端连接并不存在竞争,但是在Jedis客户端对Redis进行并发访问时会发生连接超时、数据转换错误、阻塞、客户端关闭连接等问题,这些问题均是由于客户端连接混乱造成。对此有2种解决方法:
  • 客户端角度,为保证每个客户端间正常有序与Redis进行通信,对连接进行池化,同时对客户端读写Redis操作采用内部锁synchronized。
  • 服务器角度,利用setnx实现锁。

Redis分布式锁

  • 先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。
  • 如果在setnx之后执行expire之前进程意外crash或者要重启维护了,可以使用set指令把setnx和expire合成一条指令来用的。

Redis缓存淘汰策略、缓存击穿、缓存降级

  • 缓存淘汰策略:FIFO(先进先出)、LRU(最近最少使用)、LFU(最不经常使用)。

Redis缓存雪崩

  • 概念:在同一时刻由于大量缓存失效导致请求都去查数据库,可能会出现短暂的卡顿现象,严重的话会出现缓存雪崩。
  • 处理方法:
  • 设置不同的失效时间:为不同的数据设置不同的缓存失效时间,防止同一时刻有大量的数据失效。
  • 请求加锁:对于并发量不是很多的应用,使用请求加锁排队的方案防止过多请求数据库。
  • 失效更新:为每一个缓存数据都添加过期标记来记录缓存是否失效,如果标记失效,则更新数据缓存。

Redis缓存穿透

  • 概念:指由于缓存系统的故障或用户频繁查询系统中不存在的数据,而这时请求穿过缓存不断被发送到数据库,导致数据库过载。
  • 布隆过滤器:将所有可能存在的数据都映射到一个足够大的Bitmap中,在用户发请求时首先经过布隆过滤器的拦截,不存在的数据将被拦截。
  • cache null策略:如果一个查询返回的结果为null(数据不存在或系统故障),仍缓存这个null结果,但是过期时间较短(<5min),下次请求直接读取这个null值。

Redis缓存降级

  • 概念:指由于访问量剧增导致服务出现的问题,如果响应时间较慢,优先保障核心业务降级,减少或关闭非核心业务对资源的使用。
  • 写降级:在写请求增大时,可以只进行Cache的更新,然后将数据异步更新到数据库(从数据库降级到Cache)。
  • 读降级:在数据库服务负载或数据库系统故障时,可以只对Cache进行读取,并将结果返回给用户,适用于数据实时性不高的场景(从数据库降级为Cache)。

为什么要用消息队列

  • 异步:随着系统功能的增加,完成一个业务可能需要调用其他相关的业务,随着业务链越来越长,系统的响应时间也就越长。引入消息中间件就可以完美解决这个问题。虽然多线程也可以实现,但是需要写代码,且耦合度极高。

    Java进阶常见面试题整理_第4张图片

  • 解耦:A系统调用B系统和C系统,传统的调用是直接调用。为了实现解耦,引入消息队列,A将产生的数据丢到消息队列中,哪个系统需要,哪个系统就去取。
  • 消锋:当大量流量请求到系统A时,由于数据库的处理能力有限,造成数据库连接异常。使用消息队列,大量请求先丢到消息队列中,系统A使用按批拉数据的方式,批量处理数据,生产中,高峰期短暂的消息积压是允许的。

使用消息队列有什么缺点

  • 系统复杂性增加:加了消息队列,需要保证消息不会重复消费,需要保证消息的可靠性,需要保证消息队列的高可用。
  • 系统的可用性降低:如果消息队列挂了,那么系统也会受到影响。
  • 可能出现问题:重复消费、消息丢失、消息的顺序消费。  

如何保证消息消费顺序

  • 保证生产者 - MQServer - 消费者是一对一对一的关系

重复消费

  • 造成消息重复的根本原因是:网络不可达。只要通过网络交换数据,就无法避免这个问题。
  • 解决:
  • 消费端处理消息的业务逻辑保持幂等性。
  • 保证每条消息都有唯一编号且保证消息处理成功与去重表的日志同时出现。

消息如何保证不丢失(RabbitMQ)

  • 对于生产消息阶段:发送时使用confirm模式(就是回调模式),因为是异步的,吞吐量高。消息发送后,回调消息发送成功或者失败的接口。那么业务层面也就可以根据是否发送成功和失败做处理。
  • MQ存储消息:1.对queue进行持久化、2.对queue的数据进行持久化。
  • 消费者从MQ消费消息:一般出现在autoACK模式下,即收到消息就反馈给MQ已处理,但消费者本身还没有真正完成处理就挂了,那么这个消息就会丢失;解决方案:业务逻辑处理完后再手动对消息进行ACK。

消息队列积压

  • 当消费者出现异常,很容易引起队列积压,如果一秒钟1000个消息,那么一个小时就是几千万的消息积压。
  • 解决办法就是临时扩大consumer个数,让消息快速消费。

Nginx请求处理

  • Nginx在启动时会以守护进程(daemon)形式在后台运行,采用多进程+异步非阻塞IO事件模型来处理各种连接请求。多进程模型包括一个master进程,多个worker进程,一般worker进程个数是根据服务器CPU核数来决定的。master进程负责管理Nginx本身和其他worker进程。
  • Master进程的作用:读取并验证配置文件nginx.conf;管理worker进程;
  • Worker进程的作用:每一个Worker进程都维护一个线程(避免线程切换),处理连接和请求;注意Worker进程的个数由配置文件决定,一般和CPU个数相关(有利于进程切换),配置几个就有几个Worker进程。

    Java进阶常见面试题整理_第5张图片

Nginx反向代理优点

  • 保证了web服务器的资源安全
  • 减少WEB服务器压力,提高响应速度
  • 实现负载均衡
  • 解决Ajax跨域问题
  • 节约了有限的IP地址资源

Nginx负载均衡

  • Nginx的负载均衡模块采用两种方法:
  • 轮转法:每个请求按时间顺序逐一分配到不同的后端服务器,如果后端某台服务器宕机,则自动剔除故障机器,使用户访问不受影响(可按权重分配)。
  • IP哈希法:通过hash指令实现,在众多请求的情况下它确保来自同一个IP的请求会分发到相同的后端服务器;在需要对访问请求进行负载可控,或将访问请求转发到已经有数据缓存的应用服务的场景下,该算法会非常有用。

Nginx如何做到热部署

  1. 修改配置文件nginx.conf后,主进程master负责推送给woker进程更新配置信息,woker进程收到信息后,更新进程内部的线程信息。
  2. 修改配置文件nginx.conf后,重新生成新的worker进程,当然会以新的配置进行处理请求,而且新的请求必须都交给新的worker进程,至于老的worker进程,等把那些以前的请求处理完毕后,kill掉即可。

Nginx如何做到高并发下的高效处理

  • Nginx采用了Linux的epoll模型,epoll模型基于事件驱动机制,它可以监控多个事件是否准备完毕,如果OK,那么放入epoll队列中,这个过程是异步的。worker只需要从epoll队列循环处理即可。

Nginx挂了怎么办

  • 采用Keepalived+Nginx实现高可用。
  • Keepalived是以VRRP协议实现的一个高可用解决方案,主要是用来防止服务器单点发生故障,可以通过和Nginx配合来实现Web服务的高可用。
  • 请求不要直接打到Nginx上,应该先通过Keepalived(就是所谓虚拟IP,VIP)
  • Keepalived应该能监控Nginx的生命状态,提供一个用户自定义的脚本,定期检查Nginx进程状态,进行权重变化,,从而实现Nginx故障切换。

    Java进阶常见面试题整理_第6张图片

单例模式有几种实现方式

  • 概述:单例模式是保证系统实例唯一性的重要手段,通过私有化构造实现。
  • 懒汉模式:使用同步方法
  • 饿汉模式:直接实例化对象
  • 静态内部类:因为静态内部类在JVM中是唯一的
  • 双重校验锁:对象锁和方法锁

工厂方法模式和抽象工厂模式

  • 提供一种简单、快速、高效、安全的创建对象方式。
  • 工厂模式:定义一个用于创建对象的借口,让子类决定实例化哪一个类(产品单一)。
  • 抽象工厂模式:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类(产品多样)。

建造者模式(Builder)

  • 建造者模式就是如何一步步构建一个包含多个组成部件的对象,相同的构建过程可以创建不同的产品。

代理模式

  • 给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用

描述动态代理的几种实现方式,分别说出相应的优缺点

  • JDK动态代理:利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
  • CGlib动态代理:利用ASM(开源的Java字节码编辑库,操作字节码)开源包,将代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
  • 优点:动态代理的优势是实现无侵入式的代码扩展,在不用修改源码的情况下,增强一些方法。
  • 区别:JDK代理只能对实现接口的类生成代理;CGlib是针对类实现代理,对指定的类生成一个子类,并覆盖其中的方法,这种通过继承类的实现方式,不能代理final修饰的类。

你可能感兴趣的:(编程笔记)