Java学习
2023-09-08 16:01:27 0 举报
AI智能生成
Java知识点学习总结
作者其他创作
大纲/内容
组件
KAFKA
MQ
RocketMQ
定义
RocketMQ是一个纯Java、分布式、队列模型的开源消息中间件,具有高性能、高可靠、高实时、分布式特点。
四大核心组成部分
producer
nameserver
broker
topic
commitLog
MessageQueue
consumer
面试题
1.rokcetMQ怎么保证可靠性传输和幂等性
重复消费原因
反馈机制返回的消息超时或者失败,消息队列就会认为消息没有被消费成功,就会再次把消息分派给其他消费者消费。
解决方法
为每条消息加一个唯一id
插入业务的话,可以用数据库唯一约束
消费消息的话可以用redis的setNX命令
怎么保证消息不丢失
producer生产消息阶段
1.提供sync的消息发送方式,等待broker的返回结果
2.发送消息如果失败或者超时,就重新发送
3.broker提供多master模式
broker处理消息阶段
1.提供同步刷盘策略,刷盘成功才返回producer成功
2.提供主从模式,主从支持同步双写
consumer消费消息阶段
1.consumer默认提供的是at least once机制
消费消息重试机制
如何保证消息有序
producer
将消息路由到特定的分区,通过messageQueueSelector实现,对msgqueue的size进行取余,以确保消息发送到同一个分区中
consumer
消息消费的时候保证读取顺序,可以采用单线程读取的方式
RabbitMQ
Ribbon
定义
使用
@LoadBalanced注解搭配RestTemplate使用
配置文件直接配置
负载均衡算法
RandomRule
RoundRobinRule
AvailabiltyFilterRule
WeightedResponseTimeRule
ZoneAvoidenceRule
feign
定义
zuul
优点
1.统一鉴权
动态路由
压力测试
负载卸载
静态资源访问
性能监控
如何创建filter
1)extends zuulfilter
2)重写接口
filterType
pre
route
post
error
filterOrder
shouldFilter
run
3)修改启动类
hystrix
微服务容错
微服务容错三板斧
超时时间
舱壁模式
断路保护
介绍
功能
服务降级
服务熔断
服务限流
FeignClient实现方式
1)FeignClient注解中增加fallbackFactory的接口
2)创建fallback实现类实现fallBackFactory接口
面试题
1.hystrix怎么配置超时时间
开始hystrix的注解@EnableCircuitBeaker
feign.hystrix.enabled=true
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=30000
配置中心
Zookeeper
Eureka
基本原理
组件
注册中心Eureka Server
Eureka Client:服务提供者、服务消费者
自我保护模式
Eureka和Zookeeper的区别
zookeeper强调的是CP
Eureka强调的是AP
Eureka和Nacos的区别
宏观
1.Eureka是Springcloud的产品,而Nacos是SpringCloudAlibaba的产品
2.nacos的实例有临时实例和非临时实例的区别,而Eureka没有区别
3.nacos和业务隔离,通过直接引入jar就可以,但是Eureka要创建Eureka Server的服务
微观
1.nacos支持主动检测提供者的状态,临时实例采用心跳模式,非临时实例采用主动检测的方式
2.nacos中临时实例心跳不正常会被剔除,非临时实例不会。
3.nacos支持服务列表变更的消息推送,服务列表更新更及时
Nacos
配置中心
文件的执行顺序
RPC
nginx
反向代理
负载均衡
动静分离
高并发
docker
docker命令
docker问题
缓存中间件
Memcache
支持简单的数据类型
不支持数据持久化存储
不支持主从同步
不支持分片
Redis
特性
数据类型丰富
支持数据磁盘持久化存储
支持主从
支持分片3.0后
多路I/O复用模型
数据类型
String
Hash
List
Set
Sorted Set
常见面试题
模糊查询
keys pattern
keys指令一次性返回所有匹配的key
键的数量过大会使服务卡顿
scan
每次只会返回少量数据,
基于游标迭代器,
以0作为游标开始一次新的迭代
并不保证每次返回给定数量的元素,支持模糊查询
分布式锁
setnx
无创建
有失败
expire key seconds
设置key的过期时间,过期删除
缺点:原子性得不到满足
set key value[ex s][px milis][nx][xx]
异步队列
list
rpush
lpop
blpop key timeout
pub/sub:主题订阅模式
缺点:无法保证消息可达
持久化
RDB(快照)持久化
手动方式
save
阻塞
bgsave
lastsave
自动方式
redis.conf
主从复制
Debug Reload
Shutdown且没开启AOF持久化
AOF(append only file)
redis.conf
aof持久化(重写aof文件)
fork
新aof-》临时文件
主线程-》内存,主线程-》旧aof文件
子线程完成-》主线程,主线程增量-》新aof
新aof-》旧aof
rdb-aof混合持久化
最推荐:rdb做全量持久化,aof做增量持久化
同步机制
主从同步
全同步
1.Slave发送sync命令到Master
2.Master启动一个后台进程,将Redis中的数据快照保存到文件中
3.Master将保存数据快照期间接收到的写命令缓存起来
4.Master完成写文件操作后(2操作完成后),将该文件发送给Slave
5.使用新的AOF文件替换旧的AOF文件
6.Master将期间收集到的增量写命令发送给slave
增量同步
1.Master接收用户指令后,判断是否需要传播到slave
2.将操作记录追加到AOF文件
3.将操作传播到其他slave:1对齐主从库2、往响应缓存写入指令
4.将缓存中的数据发送给slave
redis sentinel
监控:检查主从服务器是否运行正常
提醒:通过API向管理员或其他应用程序发送故障通知
自动故障迁移:主从切换
gossip
每个节点都随机与对方通信,最终所有节点的状态达成一致
种子节点定期随机向其他节点发送节点列表以及需要传播的消息
不保证信息一定会传递给所有节点,但最终会趋于一致
redis集群原理
分片:按照某种规则去划分数据,分片存储在多个节点上
常规的按照哈希划分,无法实现节点的动态增减
一致性哈希算法
将数据key使用相同的函数hash计算出哈希值
具有较好的一致性和容错性
Hash环数据倾斜问题
引入虚拟节点
面试
缓存雪崩
同一时间大量失效
缓存击穿
击穿某一热点key
缓存穿透
访问缓存中没有的数据【黑客攻击】
redis有遇到过大key的问题吗?
定义
大key的危害
客户端超时等待
引发网络阻塞
阻塞工作线程
内存分布不均匀
定位大key
redis-cli --bigkeys
缺点
1.只能得到每种类型中最大的key,而不是排名前N的key
集合中返回的是元素最多的key,但是元素最多占用内存不一定就是最大的
用scan进行全表扫描,然后用type获取key的类型
string类型的,直接strlen
集合类型的直接memory usage
使用RDBTools,直接扫描redis快照,找到其中的大key
删除大key
主动删除
分批删除
异步删除
用unlink代替del命令,不会阻塞主线程
被动删除(配置)
lazyfree-lazy-eviction超过redis内存
lazyfree-lazy-expire超过时间
lazyfree-lazy-server-del隐式del
slave-lazy-flush
如何避免大key
对大key进行拆分,通过拆分为多个小key
对大key进行删除
redis4.0有一个unlink命令可以实现异步删除而不阻塞主线程
监控redis内存、网络带宽和超时指标
通过设置合理的阈值来监控大key的产生
:Redis内存使用率超过70%,Redis内存1小时内增长率超过20%等。
压缩value:
pipeline
JAVA
接口和抽象类
关键字
static
spring
谈谈对java的理解
平台无关
JVM
Class Loader
依据特定格式,加载class文件到内存
BootStrap ClassLoader
ExtClassLoader
AppClassLoader
自定义classloader
Runtime Data Area
JVM内存结构模型
Execution Engine
对命令进行解析
Native Interface
融合不同开发语言的原生库为java所用
反射机制
Class.forName
Method.getDeclareMethod
双亲委派原则
定义
避免多份同样字节码的加载【节省内存】
类的加载方式
new隐式加载
支持构造参数
无需newInstance
显示加载
Classloder.loadClass
不初始化类,得到的类是还没有链接的
Class.forName
得到的类是初始化完成的
com.mysql.jdbc.Driver
事务
事务特性
扩展点
定时器
linux->crontab
Thread
Timer
ScheduledExecutorService
spring task
spring quartz
xxl-job
elastic-job
日志
logback
常用配置项
configuration根节点
scan
scanperiod
debug
property
name
value
contextName
设置日志上下文的名称,区别不同的应用程序
appender
写日志:确定日志输出的位置和策略
filter
过滤指定级别的日志
root
level
设置打印日志的级别
logger
用来指定某个特定包下日志打印的级别,否则使用root定义的
log4j
数据库
索引
索引数据结构
B树
B+树【主流】
Hash和BitMap【mysql不支持】
索引分类
密集索引
InnoDB
稀疏索引
MyIsan
索引调优
1.定位慢sql
1.慢日志定位
2.explain工具分析
type
index/all【全表扫描】
extra
using filesort【不用索引】
using temporary【使用临时表】
3.修改sql,尽量走索引
索引调优
索引面试题
1.怎么考虑索引加在什么字段上?
1.频繁查询的字段应该创建索引
2.频繁更新的字段避免创建索引
3.唯一性太差的字段避免创建索引
4.不在where条件后的字段不创建索引
索引失效
or
like 左%
全表扫描更快
没遵循最左原则
一直向右匹配直到遇到范围查询
where索引列有运算
索引列使用了函数
需要类型转换
锁
MyIsAM
默认表级锁,不支持行锁
适合频繁执行全表count语句
对数据进行增删改频率不高,查询非常频繁
没有事务
InnoDB
默认行级锁,也支持表锁
数据增删改查都相当频繁
可靠性要求比较高,要求支持事务
当前读
快照读
GAP锁
主键索引/唯一索引
非唯一锁
不走索引
事务特性
原子性Atomic
一致性Consistency
事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行之前和执行之后,数据库都必须处于一致性状态。
隔离性Isolation
指在并发环境中,并发的事务时相互隔离的,一个事务的执行不能不被其他事务干扰。
持久性Durability
一旦事务提交,那么它对数据库中的对应数据的状态的变更就会永久保存到数据库中。
mysql的事务隔离级别
目的
为了解决脏读,不可重复读,幻读的问题
分类Mysql都支持
读未提交Read Uncommited
有脏读/不可重复读/幻读的问题
性能最好:因为根本没加锁,可以理解为根本没有隔离
读提交Read Commited
解决脏读的问题
可重复读Repeatable Read
解决脏读和不可重复读的问题
InnoDB默认的事务隔离:且使用了Next-key lock算法,因此避免了幻读的发生
串行化Serializable
解决了脏读/不可重复读/幻读的问题
读的时候加共享锁,其他事务可以并发读,但是不能写
写的时候加排他锁,其他事务不能读也不能写
并发访问问题
更新丢失
脏读
不可重复读
幻读
mybatis
缓存机制
一级缓存(本地缓存)
SqlSession
执行方法+参数=键值,返回结果value,已Map的形式存在sqlsession中
同一个sqlsession如果同方法同参数,则直接返回查询结果
二级缓存
sqlSessionFactory级别的缓存
setting中有个cacheEnabled=true的全局开关
mapper.xml中的namespace,只要namespace一样就可以共享缓存
select语句会被缓存,delete/update/insert语句会刷新缓存
面试
语法
group by
having
跟group by一起使用
where过滤行,having过滤组
出现在同一sql顺序:where》group by》haviing
union和unionAll
区别
1.显示结果不同
union会压缩重复数据,而union all会将所有数据都显示出来
2.对排序处理不同
union会按照字段顺序排列,但是union all是直接将结果拼接,所以union all的效率要优于union
注意事项
1.保证各个select结果集的列数相同且每列的类型一样,列名可以不同,union会将第一个列的列名作为结果列名
left join/right join/inner join 的区别
1.返回不同
left返回左边所有的记录和右表中联结字段相等的记录
right返回右表中所有的记录和左表联结字段相等的记录
inner只返回俩表之间联结字段相等的记录
2.记录属性不同
inner不同的记录会被丢弃
right和left不同的记录会用null填充
full join
左右表联结一致的数据在同一行,不一致的数据单独一行
监控报警
排查慢SQL
sql调优
1.避免使用select *
2.用union all代替union
3.小表驱动大表
in:里面小表
exist外面是大表
4.批量插入
INSERT INTO 表名 (字段1, 字段2, …) VALUES (值1, (值1, (值1, …
5.使用limit
在不需要获取全部数据的时候,用limit限定返回的数量
6.in中值太多
限制一次性最大的查询条数,还可以用多线程,最后数量汇总
7.高效的分页
limit10000,20会查询10020条然后丢弃前面的一万条
改用id>10000 limit 20
8.连接查询代替子查询
子查询可以通过in实现,实现简单,但是查询的时候需要创建临时表,查询完后再删除,需要额外的开销
分库分表
JVM
JVM内存模型
类加载子系统
根据指定的全限定名来加载类和接口
执行引擎
执行被载入类的方法中的指令
运行时数据区
线程私有
程序计数器
当前线程所执行的字节码行号指示器(逻辑)
改变计数器的值来选取下一条需要执行的字节码指令
和线程是一对一的关系,即线程私有
对java方法计数,如果是native方法则计数器值为undefined
不会发生内存泄漏
虚拟机栈
java方法执行的内存模型
包含多个栈帧
本地方法栈
线程共享
元数据MetaSpace(方法区)
与永久代的区别
元空间使用的使本地内存
永久代使用的是JVM内存
java堆
对象实例的分配区域
GC管理的主要区域
常见的面试题
1.JVM三大性能调优参数
-Xms
堆的初始值
-Xmx
堆能达到的最大值
-Xss
规定了每个虚拟机栈的大小
2.堆和栈的区别
内存分配策略
静态存储
编译时确定每个目标数据在运行时的存储空间需求
栈式存储
编译时未知,运行时模块入口前确定
堆式存储
动态分配
管理方式:栈自动释放,堆需要GC
空间大小:栈比堆小
碎片相关:栈产生的碎片远小于堆
分配方式:栈支持静态分配和动态分配,而堆仅支持动态分配
效率:栈的效率比堆高
不同jdk版本之间的intern()方法的区别(6vs6+)
6:如果常量池先前已创建出该字符串对象,则返回池中该字符串的引用,否则将该字符串-》常量池-》返回
6+:如果常量池=》返回,否则,java堆中=》常量池=》返回,再否,则在池中创建该字符串并返回其引用
垃圾回收
判断垃圾
引用计数算法
优点:执行效率高,程序执行受影响较小
缺点:无法检测出循环引用的情况,导致内存泄漏
可达性分析算法
可作为Root的对象
垃圾回收算法
标记清除算法
缺点:大量内存碎片
复制算法
优点:解决碎片化问题
顺序分配内存,简单高效
使用对象存活率低的场景
标记整理算法
避免内存的不连续行
不用设置俩块内存的互换
适用于存活率高的场景
分代收集算法
垃圾回收算法的组合拳
提高JVM,GC回收的效率
分区
年轻代
MinorGC
Eden区
俩个Survivor区
老年代
FullGC
常用的调优参数:
-XX:SurvivorRatio
-XX:NewRatio
-XX:MaxTenuringThreshold
垃圾收集器
Serial收集器(复制算法)
单线程,必须暂停所有工作线程
简单高效,Client模式下默认的年轻代收集器
ParNew收集器(复制算法)
多线程
单核执行效率不如Serial,在多核下执行才有优势
Parallel Scavenge收集器(复制算法)
Serial Old
单线程、简单高效,client模式下默认的老年代收集器
Parallel OLd
多线程:标记整理算法,吞吐量优先
CMS收集器
标记-清除算法
初始标记
stop-the-world
并发标记
并发追溯标记,程序不会停顿
并发预清理
查找执行并发标记阶段从年轻代晋升到老年代的对象
重新标记
暂停虚拟机,扫描CMS堆中的剩余对象
并发清理
清理垃圾对象,程序不会停顿
并发重置
重置cms收集器的数据结构
G1收集器
复制+标记-整理算法
并行和并发
分代收集
空间整合
可预测的停顿
相关面试题
1.finalize()方法和C++的析构函数的作用相同?
2.Java中的强引用,软引用,弱引用,虚引用有什么用?
ruoyi开源框架
线程
线程池
定义
事先创建若干个可执行的线程放入一个池中,需要的时候从池中取线程而不用自行创建,使用完毕后不用销毁线程而是返回池中,从而减少线程对象创建和销毁的开销。
优点
降低资源消耗
通过重复利用已创建的线程降低线程创建和销毁造成的消耗
提高响应速度
任务过来时,不用等待线程创建就可立即执行
统一管理,便于调优和监控
创建方式
通过 ThreadPoolExecutor 创建的线程池;
通过Executors创建线程池
类型
newCachedThreadPool
可缓存的线程池,线程池的容量不限制,当任务超过线程池容量就创建线程,当任务小于线程池容量就回收空闲线程
newFixedThreadPool
固定数目的线程池,每提交一个任务就创建一个线程,直到达到最大线程数为止
newScheduledThreadPool
支持定时及周期性执行任务的线程池,可以用来替代Timer类
newSingleThreadPool
单线程的Executor,线程遇到异常会创建新线程执行,保证按照指定顺序执行
核心参数
1.核心线程大小
4.最大线程数
2.线程的空闲时间
3.任务队列的容量
5.是否允许核心线程超时
6.任务的拒绝策略
处理任务的流程
1.判断线程数是否到达核心线程数,如果没有,创建新线程否则执行下一步
2.判断等待队列是否已满,没满的话放入等待队列中,否则执行下一步
3.判断线程是否到达最大线程数,如果没有创建新线程执行任务,否则执行下一步
4.采用初始化线程池制定的任务拒绝策略,拒绝执行该任务
5.新建的线程处理完当前任务后,会继续处理等待队列中的任务
6如果空闲线程达到keepAliveTime后,会销毁一部分线程,将线程数收缩至corePoolSize
生命周期
Running -1
线程池正在运行
shutdown 0
执行shutdown()方法时会进入此状态,此时任务队列不会清空,会等待任务执行完成
stop 1
执行shutdownNow()方法进入此状态,此时任务队列会清空,不会等待任务执行。
tiding 2
当线程池和队列为空时会进入该状态
terminated 3
表示线程池死亡
线程池面试题
submit()和execute()的区别
相同点
都可以执行任务
都支持Runable
不同点
submit支持Callable支持接收返回值
execute里面的异常必须捕获不能向上抛出
submit里的callable支持向上抛出异常,需要返回值.get获取
线程
五种状态
新建new
创建后尚未启动
就绪Runnable
调用start方法
等待获取CPU资源
运行running
处于就绪的线程获取到CPU资源后进入运行状态
等待
无限期等待
不会被分配CPU执行时间,需要显示唤醒
wait没设置等待时间
join没设置等待时间
ockSupport.park()方法
限期等待
在一定时间后会由系统自动唤醒
Thread.sleep方法
设置时间参数的wait和join
阻塞block
同步阻塞:等待获取排他锁
等待阻塞:
notify或notifyall
因为某些原因放弃了CPU资源,暂时停止运行
结束Terminated
已终止线程的状态,线程已经结束执行
run方法运行结束
创建方式
继承Thread类
实现Runable接口
实现Callable接口
线程池
线程相关面试题
线程和进程的区别
1、线程不能看作独立应用,但是进程可以
2.进程有独立的地址空间,相互之间不影响,而线程只是进程的不同执行路径
3.进程的切换比线程的切换开销大
start和run
start会创建一个新的子线程并启动
run方法只是Thread的一个普通方法调用,不能创建新线程还是在主线程中调用的
Thread和Runable
Runable是接口,Thread是实现Runable的类
因为类的单一继承关系,推荐多使用Runable
Thread创建线程步骤简单,Runnable创建线程相对繁琐
线程获取返回值的方法
主线程等待法
join方法
FutureTask或线程池控制
isDone
get
sleep和wait的区别
notify和notifyAll的区别
yield
锁
死锁四个条件
互斥性
一个资源一个线程获取
请求与保持
请求资源阻塞时,不释放获取的资源
解决:一次性获取所有锁
不可剥夺
线程获取的资源,不可被其他线程强行剥夺
解决:主动释放
循环等待
多个线程形成循环等待获取资源的环
解决:顺序获取资源,反序释放资源锁
数据结构
二叉树
前序遍历
中序遍历
后序遍历
队列
集合
List(有序,可重复)
ArrayList
结构
动态数组
非线程安全
LinkedList
结构
双向链表
非线程安全
Vector
结构
线程安全
Queue(有序可重复)
Dqueue
ArrayQueue
LinkedList
PriorityQueue
Set(无序不可重复)
HashSet
LinkedHashSet
SortedSet
TreeSet
Map(无序key不能重复)
HashMap
LinkedHashMap
结构
非线程安全
ConcurrentHashMap
结构
线程安全
TreeMap
HashTable
结构
线程安全
算法逻辑
并发
Linux
体系结构
用户态
内核态
内核的访问接口
公用的函数库
Shell
命令解释器,可编程
如何查找特定的文件
find
-name/-iname
man find
检索文件内容
grep
只筛选目标字符串所在的行
对文件内容做统计
awk
NR【按照分隔符读取记录的次数】
批量替换文件内容
sed
设计模式23种
六个原则
单一职责原则
水果
火龙果
橘子
香蕉
优点
降低类的复杂度
提高类的可读性
降低变更风险
提高系统可维护性
开闭原则
面积精度
里氏替换原则
优点
约束继承泛滥
提高代码重用性
降低系统出错率
健壮程序
迪米特法则
优点
降低类之间的耦合性,提高模块的相对独立性
提高类的可复用性和系统的扩展性
缺点
类之间尽量不直接通信,需要依赖第三方,会出现大量中介类
增加系统复杂度。【依赖倒转原则】
接口隔离原则
例子:水果【将接口分开】
依赖倒置原则
例子:司机开车【车抽象,司机抽象,这样司机想开什么车都可以】
创建型模式
单例模式
饿汉模式
懒汉模式
双重检查锁模式
静态内部类
spring框架中的Bean容器(ApplicationContext)就采用了单例模式,保证了在整个应用中只有一个容器实例。
工厂方法模式
优点:解耦
简单工厂模式
例子:咖啡店,咖啡
工厂方法模式
抽象工厂模式
咖啡、甜点
Spring提供了BeanFactory接口和ApplicationContext接口作为Bean容器的工厂,通过配置文件或注解配置,我们可以方便地创建和管理Bean实例。
抽象
建造者模式
优点:实现了构建算法、装配算法的解耦,实现了更好的复用。
例子:手机(苹果/华为)
原型模式
优点:可以使用原型模式快捷创建对象
证书
结构型模式
适配器模式
类
Target
Adaptee
Adapter
Spring MVC中的Controller适配器(ControllerAdapter)负责将请求转发给相应的Controller进行处理,实现了请求和Controller之间的适配。适配器模式在Spring MVC中起到了很重要的桥梁作用。
桥接模式
优点
抽象和实现分离,扩展能力强
符合开闭原则
缺点
能正确识别独立变化的维度,增加对系统的理解与设计难度
例子:
不同型号的毛笔和颜料盘
在Spring的JDBC模块中,我们可以选择不同的数据库驱动,而不需要修改应用程序的代码,实现了抽象和实现的分离。
组合模式
优点
调用者不关心调用的是局部还是整体,没差
结点自由增加,使用组合模式。符合开闭原则
缺点
树枝树叶节点直接使用实现类,违背依赖倒置原则
例子
文件系统:迭代
装饰器模式(包装模式)
面试题:久雅科技7/14
Springboot哪些地方用到了装饰者模式?框架里哪些部分用到了
我们可以通过AOP的方式为某个方法添加日志记录或事务管理的功能,而不需要修改原始方法的代码。
定义
不改变原有对象的基础上将功能添加到类上,提供了比继承更灵活替代方案(扩展原有对象的功能)
例子
公共接口网吧(冲浪)
音乐网吧(冲浪)
复古网吧(冲浪)
外观模式
享元模式
代理模式
spring中的AOP
行为型模式
策略模式
在Spring的事务管理中,可以根据配置选择不同的事务策略,如基于注解的事务策略、基于XML配置的事务策略等。
模板方法模式
Spring框架中的JdbcTemplate是一个经典的应用了模板方法模式的例子。
JdbcTemplate封装了执行SQL语句的公共代码,并留出抽象方法供用户自定义。
定义
使用模板方法模式,我们可以将重复的代码逻辑提取出来,提高代码的复用性和可维护性。
观察者模式-发布订阅模式
定义:事件驱动机制
通过定义事件监听器和发布事件,我们可以在应用中实现一对多的通信。
Spring中的ApplicationEvent和ApplicationListener接口就是用于实现观察者模式。
小丑表演,摸鱼、新闻【抖音、微博】
责任链模式
迭代子模式
命令模式
备忘录模式
状态模式
访问者模式
在Spring Data模块中,我们可以通过定义不同的访问者类来实现对不同数据源的访问。
中介者模式
解释器模式
0 条评论
下一页