JAVA学习
2023-01-30 11:28:43 1 举报
AI智能生成
java学习资料
作者其他创作
大纲/内容
ElasticSearch
概念
与关系型数据库比较
关系型数据库中的数据库(DataBase),等价于ES中的索引(Index)
一个数据库下面有N张表(Table),等价于1个索引Index下面有N多类型(Type)
在一个关系型数据库里面,schema定义了表、每个表的字段,还有表和字段之间的关系。 与之对应的,在ES中:Mapping定义索引下的Type的字段处理规则,即索引如何建立、索引类型、是否保存原始索引JSON文档、是否压缩原始JSON文档、是否需要分词处理、如何进行分词处理等。
在数据库中的增insert、删delete、改update、查search操作等价于ES中的增PUT/POST、删Delete、改_update、查GET.
与solr相比
实时性好,
随着数据量的增加sorl效率降低,ES不变
索引
倒排索引
简单地说就是根据value去找key
例如:id为1,3,4的几个的name都是‘张三’,那么根据张三这个名称可以找到【1,3,4】这个数据,进而找到对应的document.
子主题 2
子主题 2
子主题 3
子主题 4
websocket
一般用于聊天
onOpen
接收到客户端消息时触发的方法
向ConcurrentMap<String, MyWebSocketServer>中存储连接信息
onMessage
接收到客户端消息时触发的方法
根据连接信息进行相关的业务逻辑,调用sendMessage方法
onClose
关闭连接时调用的
删除ConcurrentMap<String, MyWebSocketServer>中的连接信息
onError
发生错误时触发的方法
sendMessage
MapUtil
基础知识
java基础
基本数据类型
byte
1个字节
1个字节8位
short
2个字节
char
2个字节
int
4个字节
float
4个字节
long
8个字节
double
8个字节
boolean
JVM规范指出boolean当做int处理,也就是4字节
反射
机制
JAVA反射机制是在运行状态中,对于任意一个类。都能都知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称之为java语言的反射机制
获取class对象的三种方法
对象.getClass
类.class
class.forName()
newInstance()方法 ---> 获取class类型之后,可以创建该类型的对象
hashmap与concurrentHashMap
hashMap
1.7
实现:数组+链表
线程不安全
Entry<K,V>存储
极限负载:0.75
高:可以降低hash表所占用的内存空间,但会增加查询数据的时间开销,而查询是最频繁的操作
低:会提高查询数据的性能,但会增加hash表所占用的内存开销
hash冲突
扩容代码(先扩容再赋值):
1.8
实现:数组+链表/红黑树
在jdk1.8中,如果链表长度大于8且节点数组长度大于64的时候,就把链表下所有的节点转为红黑树。
Node<K,V>
扩容代码(先赋值再扩容):
树化过程:先将单向链表转成双向链表,然后将双向链表转成红黑树
1.7和1.8扩容成环问题
concurrentHashMap
1.7
实现方式:Segment + HashEntry
1.8
实现方式:Node + CAS + Synchronized
各个集合之间的区别
hashtable
实现了Map,同时继承了Dictionary
集合类
Map
HashMap
LinkedHashMap
存储是有序的,参考文章
https://www.cnblogs.com/lyhc/p/10743550.html
TreeMap
Collection
list
ArrayList
数组
LinkedList
双向链表
Vector
与arrayList类似,线程安全的
Set(元素不重复)
HashSet
hash表结构
TreeSet
红黑树结构
Queue
docker
隔离的虚拟的容器,类似虚拟机但是比虚拟机更轻
因为docker是一个容器,所以镜像启动时需要指定端口映射
docker run -d --hostname my-rabbit --name rabbit -p 15672:15672 -p 5672:5672 rabbitmq:management
一些命令
docker pull(从网上拉去镜像)
docker images(查看下面有大写镜像)
docker ps (查看运行的容器)
docker exec -it 7d9750ee6e44 bash (进入容器内部)
使用exit退出来
docker stop 容器Id :停止docker
参考博客:https://blog.csdn.net/q610376681/article/details/90483576
分布式
分布式事务
子主题 1
子主题 2
子主题 3
唯一id的实现方式
分布式锁
基于数据库
基于表记录
乐观锁
悲观锁
redis分布式锁
思路:在redis中设置一个值表示加了锁,然后释放锁的时候就把这个key删除。
使用SET key value NX PX milliseconds 命令
分布式锁的实现还需要考虑redis集群部署的问题
redission
根据key获取锁对象,加锁并设置过期时间,业务流程完成后释放锁。
redlock原理
获取当前时间戳
client尝试按照顺序使用相同的key,value获取所有redis服务的锁,在获取锁的过程中的获取时间比锁过期时间短很多
client通过获取所有能获取的锁后的时间减去第一步的时间,这个时间差要小于TTL时间并且至少有3个redis实例成功获取锁,才算真正的获取锁成功
如果成功获取锁,则锁的真正有效时间是 TTL减去第三步的时间差 的时间
.如果客户端由于某些原因获取锁失败,便会开始解锁所有redis实例;因为可能已经获取了小于3个锁,必须释放,否则影响其他client获取锁
zookeeper
分布式锁算法流程
如果锁空间的根节点不存在,首先创建Znode根节点。
客户端如果需要占用锁,则在根节点下创建临时的且有序的子节点。
客户端如果需要占用锁,还需要判断,判断自己创建的子节点是否为当前子节点列表中序号最小的子节点。如果是则认为获得锁,否则监听前一个Znode子节点变更消息,获得子节点变更通知后重复此步骤直至获得锁;
获取锁后,开始处理业务流程。完成业务流程后,删除对应的子节点,完成释放锁的工作。以便后面的节点获得分布式锁。
curator
dubbo
springcloud
里面集成了哪些东西
注册中心:Eureka(还有consul和zookeeper)
负载均衡::Ribbon
容错处理:Hystrix
微服务网关:Zuul
简单的算法
RabbitMQ
Exchange
FanOut Exchange
Direct Exchange
Topic Exchange
Header Exchange/Default Exchange
一般用不到
消息确认
消息发送确认
配置文件
ConfirmCallback
ReturnCallback
消息接收确认
配置文件
ack
unack
重发
拒绝(消息不被退回队列,进入死信队列中)
死信队列和延时队列
高可用性
普通集群
镜像集群
常见问题
消息丢失
重复消费
大量消息堆积
JVM
java内存模型
堆
虚拟机栈
本地方法栈
程序计数器
常量池
垃圾收集器
收集算法
标记-清除算法
标记出所有需要回收的对象,标记完统一回收所有被标记的对象
效率不高
标记清除后容易产生空间碎片,分配较大的对象时无法找到连续的空间进行存储,所以不得已还得进行一次gc
标记整理算法(老年代)
首先也是进行标记,标记过后让所有对象向一端移动,直接清理掉边界以外的内存,不存在空间碎片
复制算法(新生代)
将内存分成两块,每次只是用一块,当一块用完后,将还存活的对象存储到另一块中,然后把一使用过的内存空间清理掉。
在新生代中一般用E区和一个S区作为存储空间,另一个S区作为收集还存活的对象,当另一个S区没有足够空间时,可以通过担保机制将这些对象分配到老年代。
垃圾收集器
Serial
单线程收集器,收集时必须停止其他线程。
优点:简单高效,对于单个CPU环境还说收集效率高。
ParNew(新生代)
Serial的多线程版本,第一款真正意义上的并发收集器
只有它可以和CMS共同工作
Parallel Scavenage(新生代)
控制最大垃圾收集停顿时间参数-XX:MaxGCPauseMillis
以及吞吐量大小参数-XX:GCTimeRatio
自适应调节策略
parallel Old(老年代)
一般与Parallel Scavenage一起使用
适用于注重吞吐量以及CPU敏感的场合
CMS(老年代)原理:标记-清除
获取最短回收停顿时间为目标的收集器
过程
初始标记:标记一下GC roots能关联到的对象,速度很快(仍需要停顿)
并发标记:就是进行GC Roots Tracing(其实就是从GC Roots开始找到它能引用的所有其它对象)
重新标记
修正并发标记期间因用户程序继续动作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短。
并发清除:除掉将要回收的对象
缺点
对CPU资源非常敏感
无法处理浮动垃圾
浮动垃圾:由于在并发清理过程中,用户线程还在执行,所以会随时产生新的垃圾,这一部分垃圾无法在本次清理过程中清理掉。
由于是标记-清除算法,所以会产生空间碎片。
解决方法
因为整理时候是无法并发的,所以停顿时间会增长。
G1
特点
并行与并发
分代收集
空间整合
可预测停顿
过程
初始标记
并发标记
最终标记
筛选回收
内存分配与回收策略
内存分配
默认在E区分配
大对象直接进老年代
-XX:PretenureSizeThreshold参数,令大于这个值的对象直接进老年代
长期存活的对象直接进老年代
空间分配担保
回收策略
Minor GC:新生代发生的垃圾收集动作
Full GC:老年代发生的垃圾收集动作
性能监控与故障处理
常用命令
jps
jstat
jinfo
jmap
jhat
jstack
可视化工具
JConsole
VisuallVM
BTrace
调优案例
类加载
机制
虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验/转换/解析和初始化,最终形成可以被虚拟机直接使用的Java类型
类加载过程
加载
做三件事
通过一个类的全限定名获取定义此类的二进制字节流
将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
在内存中生成一个代表这个类的class对象,作为方法区这个类的各种数据访问入口
数组类和非数组类的加载
子主题 1
数组类本身不通过类加载器创建,它是由Java虚拟机直接创建。但是数组类的元素类型最终是要靠类加载器去创建
连接
验证
目的
为了确保class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害到虚拟机自身的安全
class文件可以通过任意文件产生
几种验证动作
文件格式验证
元数据验证
字节码验证
符号引用验证
对于虚拟机来说验证阶段是一个非常重要但是不一定必要的阶段。如果可以确保自己的代码没有问题可以使用-Xverify:one关闭验证阶段。
准备
正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存将在方法区中进行分配。
这里说的内存分配仅包括类变量(被static修饰的变量),不包括实例变量,实例对象将会在对象实例化时随着对象一起分配到java堆中
设置初始值,并不会直接赋值,一般为零值
子主题 3
解析(可以在初始化之后开始)
将符号引用替换成直接引用的过程
符号引用
以一组符号来描述所引用的目标,符号可以是任何形式的字面变量,只要使用时能无歧义的定位到目标即可
直接引用
是直接指向目标指针、相对偏移量或者句柄
初始化
子主题 1
5种情况必须进行初始化
new 关键字实例化对象的时候、读取或设置一个类的静态字段以及调用一个类的静态方法的时候
使用反射的时候
初始化一个类时,其父类也必须初始化
虚拟机启动时,需要指定一个需要执行的主类,这个主类需要初始化
子主题 5
使用
卸载
类加载器
类型
启动类加载器
扩展类加载器
应用类加载器
双亲委派
原理
破坏双亲委派
JVM常用调优参数
Redis
基本定义
优点
单线程,线程安全
数据存在内存中,读写速度快(10W QPS)
支持多数据类型
支持数据持久化
主从/哨兵(高可用)
发布订阅(消息中间件)
基础数据结构
String
是一种 动态字符串,这意味着使用者可以修改,它的底层实现有点类似于 Java 中的 ArrayList,有一个字符数组
list(双向链表)
相当于 Java 语言中的 LinkedList
hash
类似hashmap中的key-value形式
sets
不重复的集合
sorted set
有序的不重复的集合
实现方式:跳表
bigKey危害(主要还是太大,导致各方面的阻塞问题)
内存空间不均匀
容易导致超时阻塞
迁移困难
redis缓存使用
RedisTemplate 来使用
redisTemplate.opsForSet()
redisTemplate.opsForHash()
redisTemplate.opsForList()
redisTemplate.opsForValue()
Spring Cache 集成 Redis(也就是注解的方式)后面看一下
持久化
RDB(默认)
快照形式是直接把内存中的数据保存到一个 dump 的文件中,定时保存,保存策略。
如何持久化的
定时备份数据,数据有可能会有缺失
AOF
把所有的对 Redis 的服务器进行修改的命令都存到一个文件里,命令的集合。
持久化
全程持久化
开启参数:appendonly yes
两者的优缺点
AOF的文件体积通常大于RDB的文件体积
AOF可以实时的但是这样巨大的写入会降低redis的性能
可以同时使用
当 Redis 重启的时候,它会优先使用 AOF 文件来还原数据集,因为 AOF 文件保存的数据集通常比 RDB 文件所保存的数据集更完整。
缓存雪崩、缓存击穿和缓存穿透
缓存击穿
定义:
处理方法
设置热点数据永不过期,或者加上互斥锁就搞定了。
加上互斥锁
缓存穿透
定义
处理方法
接口层增加校验(不合理的数据进行拦截)
采用布隆过滤器
原理
内部原理
缓存雪崩
定义
处理方法
缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
如果缓存数据库是分布式部署,将热点数据均匀分布在不同的缓存数据库中。
设置热点数据永远不过期。
缓存击穿和缓存雪崩类似:缓存雪崩大量key缓存击穿针对一个key大量并发
为什么是单线程的还这么快
Memcache的区别
memcache不能持久化
memcache支持的数据类型比较简单
底层实现方式以及与客户端之间通信的应用协议不一样。
使用缓存的问题:与数据库不一致问题
淘汰策略
noeviction: 不删除策略, 达到最大内存限制时, 如果需要更多内存, 直接返回错误信息。
allkeys-lru: 所有key通用; 优先删除最近最少使用(less recently used ,LRU) 的 key。
volatile-lru: 只限于设置了 expire 的部分; 优先删除最近最少使用(less recently used ,LRU) 的 key。
allkeys-random: 所有key通用; 随机删除一部分 key。
volatile-random: 只限于设置了 expire 的部分; 随机删除一部分 key。
volatile-ttl: 只限于设置了 expire 的部分; 优先删除剩余时间(time to live,TTL) 短的key。
集群
主从复制
三个阶段
连接建立阶段
建立连接为数据同步做准备
数据同步阶段
psync
全量复制
2.8以前发送sync命令,请求同步数据(全量的)
2.8以后发送psync命令同步数据,可能是全量也可能时部分的。
两种情况
从节点主动请求全量复制
从节点请求部分复制,但是主节点认为无法进行部分复制
过程
接收到命令--执行bgsave--生成RBD文件--将文件传给从节点
部分复制
用于处理网络中断时的数据同步。
依赖于
复制偏移量(就是判断那一部分数据该同步)
复制积压缓冲区
服务器运行ID(runid)
sync
参考博客:https://www.cnblogs.com/kismetv/p/9236731.html
命令传播阶段
发送写命令,主从节点还维持着心跳机制
读写分离有可能出现的问题
延迟与不一致问题
数据过期问题
故障切换问题(使用哨兵进行节点切换)
哨兵模式
核心功能是主节点的自动故障转移
功能
监控(Monitoring):哨兵会不断地检查主节点和从节点是否运作正常。
自动故障转移
配置提供者
通知(Notification):哨兵可以将故障转移的结果发送给客户端。
多线程
基础知识
基本的方法
start()
start与run的区别:start是创建一个线程并执行run方法,run的话时在当前线程中调用run方法,并执行其中的逻辑,并不会创建另一个线程
stop()
直接终止线程并释放锁,会破环对象的一致性(已被废弃)
interrupt()
Thread.interrupt()
通知线程中断,但不会立即中断,只是个线程标识而已,可以根据下面的方法判断,并写出对应的中断逻辑。
Thread.isInterrupt()
判断线程是否中断,可以根据返回的状态写出中断逻辑。
Thread.interrupted()
判断是否被中断,并清除当前中断状态
wait():object中的方法
使当前线程在这个对象上等待,会一直等待到其他线程调用了notify方法(可以利用同一个对象实现多线程之间的通信)
notify():object中的方法
唤醒当前对象的一个线程,如果有多个线程等待,随机唤醒一个。notifyAll()可以唤醒全部
suspend()和resume():挂起和继续执行
suspend导致线程暂停的同时,还不会释放任何锁资源,直到该线程进行了resume操作(方法已经废弃)
join()
阻塞当前线程,直至调用join的线程结束后,主线程才会继续执行。参数还可以加上最大等待时间。
yeild()
当前线程让出CPU然后再一起争夺资源
守护线程
当守护的线程不执行时,该线程会自动结束,设置是否是守护线程必须在start()方法之前。
创建线程方法
继承thread类
实现runnable()接口
实现callable()接口
volatile
主要用来保证变量的可见性,任意一线程对某一变量修改后,其他线程都会看到。但是有时也无法保证一些复合操作的原子性。
JDK并发包
可重入锁
有着显示的加锁过程,对逻辑控制的灵活性远远好于synchronized。
实现主要包括三个因素
原子状态,使用CAS操作来存储当前锁的状态,判断所是否已经被别的线程持有。
等待队列。所有未获得锁的线程,会进入等待队列进行等待,待有线程释放锁后,系统就能唤醒一个线程继续工作。
阻塞原语,用来挂起和恢复线程。
几种方法
lock():获得锁
tryLock():尝试获得锁,返回true或false
tryLocak(时间参数):在给定时间内获取锁
unlock():释放锁
condition条件
与Object中的wait和notify()方法大致相同
lock.newCondition()生成
方法
await():当前线程等待,同时释放锁
singal():唤醒
信号量(Semaphore):允许多个线程同时访问
一般来说,如果加锁的话,只允许一个线程访问,不需要再用其他锁,本身就是个锁
方法
acquire():尝试获得一个准入的许可
release():释放信号量
读写锁
两个锁,读时用读锁,写时用写锁,读的时候不阻塞,
倒计时器(CountDownLatch)
设置一个计树个数,当消耗完后,后面的逻辑才会执行。
主线程再CountDownLatch上等待,当所有检查任务都执行完后才能继续执行。
方法
countDown():计数减一
await():等待计数归零
使用场景:
循环栅栏
线程池
Executor--ExecutorService--AbstarctExecutorService--ThreadPoolExecutor
创建线程池的参数
corePoolSize
maxumumPoolSize
keepAliveTime
unit
workQueue
直接提交的队列(SynchronousQueue)
没有容量,不会保存任务,当进程数量达到最大时执行拒绝策略
newCacheThreadPool()
有界任务队列(ArrayBlockingQueue)
队列的构造函数必须带有一个最大容量的参数,当队列的容量到达最大参数时,在总线程数不大于max的情况下继续创建线程,若大于max了,则执行拒绝策略
无界任务队列(LinkedBlockingQueue)
与有界队列不同的是,队列没有容量限制,不存在入队列失败情况,直至内存耗尽。
newFixedThreadPool()
newSingleThreadExecutor()
优先任务队列(PriorityBlockingQueue)
是一个特殊的无界队列,只不过可以根据线程的优先级执行任务
ThreadFactory
线程工厂用默认的就行
handler(拒绝策略)
AbortPolicy:直接抛出异常
一般默认的处理策略
DiscardOledestPolicy:丢弃一个即将被执行的任务,并尝试再次提交当前任务。
DiscardPolicy:丢弃无法处理的任务,不做任何处理
CallerRunsPolicy:只要线程未关闭就会继续执行被丢弃的任务,并不会真的丢弃任务。
几种常见的线程池
newFixedThreadPool()
返回固定数量的线程池,该线程池的线程数量始终不变。
创建参数
无界任务队列
abortPolicy:直接抛出异常的拒绝策略
newSingleThreadExecutor()
返回一个只有一个线程的线程池
创建参数
无界任务队列
newCacheThreadPool()
可以根据实际情况调整数量的线程池,coresize为0,maxsize为无穷大的
创建参数
直接提交的队列
newSingleThreadScheduledExecutor()
newScheduledThreadPool()
子主题 1
创建参数
new DelayedWorkQueue()优先级队列
并发工具类
ConcurrentHashMap
CopyOnWriteArrayList
ConcurrentLinkedQueue
BlockingQueue
ConcurrentSkipListMap
多线程中的其他锁
可重入锁
读写锁
乐观锁和悲观锁(是一个思想,并不是技术)
悲观锁
乐观锁
版本号
CAS
原理
三要素
V:需要读写的内存值(操作时的值)
A:进行比较的内存之(操作之前的值)
B:最新的值
简单的说对一个值进行操作时,这个值操作前后不能改变。
CAS(比较并交换)是CPU指令级的操作,只有一步原子操作,所以非常快。
缺点
ABA问题
介绍
解决方法
AtomicStampedReference
DCAS
循环开销大
自旋锁
定义
子主题 2
锁的升级
synchronized 原理
四个阶段(synchronized )
无锁
偏向锁
通过对比 Mark Word 解决加锁问题,避免执行CAS操作。
轻量级锁
通过用 CAS 操作和自旋来解决加锁问题,避免线程阻塞和唤醒而影响性能。
重量级锁
拥有锁的线程以外的线程都阻塞。
锁升级过程
子主题 1
ThreadLocal
其他用到的类
原子类
synchrized
指定加锁对象
对指定对象加锁,进入同步代码前要获得指定对象的锁。
直接作用于实例方法
对当前实例加锁,进入同步代码前,要获得当前实例的锁
直接作用于静态方法
对当前类加锁,进入同步代码前要获得当前类的锁
MySql
事务
事务隔离级别
READ-UNCOMMITTED
READ-COMMITTED
避免了脏读
REPEATABLE-READ
mysql默认隔离级别
SERIALIZABLE
所有操作都加锁
可能出现的情况
脏读
不可重复读
幻读
幻读与不可重复读类似,不可重复读针对修改,幻读针对新增。
丢失修改
锁
粒度
表锁
行锁
读锁和写锁
读锁(共享锁)
写锁(排它锁)
MVCC和LBCC
MVCC(多版本并发控制)
LBCC
快照读和当前读
快照读
当前读
索引
类型
主键索引
唯一索引
普通索引
组合索引
innoDB索引结构
B+树(使用这个)
hash表
B树
二叉树
任意节点的左子树上所有节点值不大于根节点的值,任意节点的右子树上所有节点值不小于根节点的值
有可能成链状,不平衡
平衡二叉树
任意节点的左子树上所有节点值不大于根节点的值,任意节点的右子树上所有节点值不小于根节点的值
旋转耗时,实现平衡的关键在于旋转操作:插入和删除可能破坏二叉树的平衡,此时需要通过一次或多次树旋转来重新平衡这个树。
红黑树
如何实现平衡
确保从根到叶子的最长的可能路径不多于最短的可能路径的两倍长
与二叉平衡树对比
对于数据存储在内存中,红黑树表现是优异的,但是对于数据存储在硬盘上的数据来说,红黑树并不擅长,因为红黑树长得还是太高了
大表优化方案
单表优化
读写分离
缓存
表分区
垂直拆分
水平拆分
nosql数据库
主从同步
主服务器
子主题 1
从服务器
从主服务器中获取的两个参数(启动时两个必须一样,否则数据同步有问题或者无法同步)
MASTER_LOG_FILE='mysql-bin.000006'(日志文件)
MASTER_LOG_POS=489(类似偏移量之类的)
设置指定表同步
replicate-wild-do-table = test1.table2
有可能的问题
数据延迟
部分数据丢失
主从同步延迟解决方案
Spring
Spring
Bean的生命周期
过程
实例化
设置属性值
调用beanNameAware中setBeanName方法,嗲用beanFactoryAware中setBeanFactory方法
beanPostProcessor前置处理方法
InitializingBean中afterPropertiesSet方法
调用init-method中配置的初始化方法
beanPostProcessor前置处理方法
生存期(使用)
销毁
DisposableBean的destory方法以及是否配置自定义的销毁方法
一些相关接口
BeanNameAware
这个方法只是简单的返回我们当前的beanName(获得在配置文件中配置好的name)
BeanFactoryAware
与beanNameAware类似
BeanPostProcessor
对bean实例初始化的,前置处理以及后置处理
BeanFactoryPostProcessor
bean工厂的bean属性处理容器,说通俗一些就是可以管理我们的bean工厂内所有的beandefinition(未实例化)数据,可以随心所欲的修改属性。
InitializingBean
bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候都会执行该方法。
AOP(面向切面编程)
Aspect
在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。
Joint point
pointcut
表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。
可以针对某个包下面,方法以及注解
Advice
Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。
@Before :前置通知,在方法执行前执行
@After: 后置通知,在方法执行后执行(无论是否抛出异常都会执行)
@AfterRunning :返回通知,在方法返回结果之后执行(抛出异常不会执行)
@AfterThrowing: 异常通知,在方法抛出异常之后进行的操作(可以对异常进行统一的处理)
@Around : 环绕通知
Target
Weaving
IOC
一种设计思想:spring中的bean交给spring容器去管理,当用到时从容器中拿取
DI
注入方式
构造方法
set
注解
@Autowired
默认根据类型自动装配,如果想按找名称进行注入加上@Qualified注解
@Resource
默认按名称进行装配
动态代理
JDK
特点
通过java.lang.reflect.Proxy类来动态生成代理类;
代理类要实现InvocationHandler接口;
JDK代理只能基于接口进行动态代理;
由于java的单继承,动态生成的代理类已经继承了Proxy类的,就不能再继承其他的类,所以只能靠实现被代理类的接口的形式,故JDK的动态代理必须有接口。
使用过程
首先有需要代理的对象(就是接口)
创建代理类,实现InvocationHandler接口,在invoke方法中写增强的逻辑
用Proxy中的newProxyInstance 方法得到一个代理对象(三个参数)
ClassLoader:定义了由哪个ClassLoader对象来对生成的代理对象进行加载
Class<?>[] interfaces:new Class[]{Subject.class}
InvocationHandler(我们自己写的代理类)
CGLIB
使用过程
创建被代理类
代理类
执行
JDK和CGLIB区别
mybatis
为什么mapper中是接口也还可以使用
在调用接口时,使用了jdk动态代理生成了代理类,代理类中执行了相应的sql逻辑
SpringMVC
工作原理
发送请求到前端控制器DispatcherServlet
前端控制器调用处理器映射器
处理器映射器根据注解找到对应的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
DispatcherServlet调用HandlerAdapter处理器适配器。
HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
Controller执行完成返回ModelAndView。
HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
ViewReslover解析后返回具体View。
DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
DispatcherServlet响应用户。
springboot
自动配置如何实现的
@SpringBootApplication
@SpringBootConfiguration
底层是@Configuration注解,就是支持javaConfig代替xml配置
@EnableAutoConfiguration
自动配置注解,这个注解可以帮助我们自动载入应用程序所需要的所有默认配置。
内部实际上就去加载META-INF/spring.factories文件的信息,然后筛选出以EnableAutoConfiguration为key的数据,加载到IOC容器中,实现自动配置功能!
@ComponentScan
扫描注解,默认是扫描当前类下的package。@Controller/@Service/@Component/@Repository等注解加载到IOC容器中
子主题 2
子主题 3
子主题 2
子主题 3
设计模式
观察者模式
装饰着模式
工厂模式
单例模式
适配器模式
代理模式
模板方法模式
外观模式
状态模式
0 条评论
下一页