标签: Java
Java JVM优化
jvm调优是日常工作中经常会使用的技巧,整理下。
JVM调优
为什么要调优,当默认配置参数不能很好的发挥程序性能的时候。
- Heap内存(老年代)持续上涨达到设置的最大内存值。
- Full GC 次数频繁。
- GC 停顿时间过长(超过1秒)。
- 应用出现OutOfMemory 等内存异常。
- 应用中有使用本地缓存且占用大量内存空间。
- 系统吞吐量与响应性能不高或下降。
SpringBoot MyBatis 批量
开发过程中经常会出现批量写入数据库的操作,特别是后台系统,在导入数据的场景下会对表性能造成一定影响。
Mybatis-ONE-SQL
SQL插入主要使用INSERT语句,有两种常见的用法。
逐条插入
- 如果插入的记录过多,比如大于20条记录,性能损耗非常严重。
INSERT INTO `table_data` ('field1','field2') VALUES ('data1','data2');
SpringBoot MyBatis
数据审计
部分业务需要记录用户对操作行为,如果给每张表都做一个记录表,感觉冗余数据太多了。所以采用审计表存储相关日志信息。
实现方案
基于Spring Aop 织入方式对关键方法进行拦截,也可以通过方法进行拦截。
- 基于注解,在方法上织入。
- 基于普通方法,在业务逻辑中进行调用。
- 批量写入、延时写入数据库可能会出现短时间部分数据的丢失,但是频繁写入会导致Mysql资源占用过多。
- 使用java.util.concurrent.ConcurrentLinkedQueue 作为消费列队。每次最多消费消费10条日志记录批量写入数据库。
- 在审计信息中添加业务执行链路标识、执行用户标识。方便排查问题。
- 基于MDC记录链路标识。
Java Netty
Netty是一款用于快速开发高性能的网络应用程序的Java框架,正是因为有 Netty 的存在,网络编程领域 Java 才得以与 C++ 并肩而立。
- Netty 官网给出了有关 Netty 的整体功能模块结构

- Core核心层
提供底层网络通信抽象和实现,其中包括了可扩展的时间模型、通信API、支持零拷贝的buf等。
SpringBoot MDC日志
日常在开发过程中方便排查文件,需要在日志中输出一些关键内容。
MDC
在茫茫日志中定位需要的信息很费时,MDC 全称是 Mapped Diagnostic Context.一个线程安全的存放诊断日志的容器。
演示代码
SpringBoot MyBatis 分析
日常开发中,需要对sql进行。为了提高效率,曾经使用mybatis扩展输出查询计划。
慢SQL
从编码角度来优化数据层的话,我首先会去查一下项目中运行的sql语句,定位到瓶颈是否出现在这里,首先去优化sql语句,而慢sql就是其中的主要优化对象,对于慢sql,顾名思义就是花费较多执行时间的语句,它带来的影响也比较恶劣,首先是执行时间过长影响数据的返回速度,其次,慢sql的长时间执行也会消耗和占用mysql的系统资源,影响其他的sql语句执行,过多的慢sql极其影响性能,如果系统流量或者并发量较大的情况下,过多的执行慢sql很有可能造成mysql的死锁以致于mysql服务无法正常使用。
SpringBoot Lucene
Lucene
在Java领域常用的搜索框架鼻祖Lucene,现在常用的Solr和ElasticSearch底层都是基于Lucene
SpringBoot 阻塞队列
之前在订单场景使用过DelayedQueue延时列队,实际上还有阻塞列队的用法。刚工作那会写爬虫的时候有使用过。这里总结下使用。
BlockingQueue
- 阻塞列队,BlockingQueue是java.util.concurrent包下的实现类。提供了线程安全的列队访问方式,当阻塞队列进行插入数据时,如果队列已满,线程将会阻塞等待直到队列非满;从阻塞队列取数据时,如果队列已空,线程将会阻塞等待直到队列非空。

SpringBoot 延时队列
突然发现公司订单小哥的消息列队是用redis做的,而且用的是list。这里自己也实现下简单的阻塞列队。用于处理延时消息的问题。
- 延时列队就是一种带有延迟功能的消息列队。通常具备消息存储、过期消息的实时获取、高可用。消费熔断。
- 业务场景
- 订单未支付超时。
- 订单发货提醒。
- 短信提醒。
- 自动收货。
- 自动评论。
- 自动取消订单,不发货的情况下。
- 常用的解决方案
- 定时轮询任务,比如jdk中TimerThread轮询数据库表、缓存中的数据。频繁的轮询容易出现过度资源消耗。对数据和缓存也有一定的影响。但是可以作为辅助手段,通常用于补偿或者初始化数据。
- ScheduledExecutorService 周期性线程池
- 时间轮(kafka、Netty的HashedWheelTimer)
- 使用mysql通常是定时扫描表,找出符合条件的数据进行处理。消费成功则更新数据。
- 使用redis可以使用zset,通过分值进行排序。定时轮询的方式去获取符合条件的记录。消费数据后删除消息。失败则重新进入队列。
- Java中java.util.concurrent.DelayQueue
- Jdk实现,列队处于jvm中,不支持分布式和消息持久化。
- Rocketmp延时列队
- 消息持久、重试、分布式等等特性。
- 不支持任意时间精度的,支持level级别的延时消息。
Java 雪花算法
Snowflake,雪花算法是由Twitter开源的分布式ID生成算法,以划分命名空间的方式将 64-bit位分割成多个部分,每个部分代表不同的含义。这种就是将64位划分为不同的段,每段代表不同的涵义,基本就是时间戳、机器ID和序列数,当然这种方案就是需要考虑时钟回拨的问题以及做一些 buffer的缓冲设计提高性能。
背景
Twitter 早期用 MySQL 存储数据,随着用户的增长,单一的 MySQL 实例没法承受海量的数据,开发团队就开始用 Cassandra 和 sharded MySQL 替代原有的系统。然而和 MySQL 不同的是,Cassandra 没有内置为每一条数据生成唯一 ID 的功能,因为在一个分布式环境下,很难有完美的 ID 生成方案。
Spring SPI
SPI 全称为 Service Provider Interface,是一种服务发现机制。SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。
-
本文对比JDK、Spring对SPI机制的实现。
-
在实际的应用场景。
- jdbc驱动,不同的数据有不同的驱动。

com.mysql.cj.jdbc.Driver- spring 也使用spi机制,用于扩展实现。

org.springframework.beans.BeanInfoFactory=org.springframework.beans.ExtendedBeanInfoFactory- dubbo也通过spi机制实现自定义扩展。
- 日志门面接口实现类加载,SLF4J加载不同提供商的日志是现类。
Java Zookeeper
Zookeeper概述
Zookeeper可以让企业的IT架构逐步从集中式向分布式过度,所谓的分布式是指:把一个计算任务分解成若干个计算单元,并且分派到若干不同的计算机中去执行,然后汇总计算结果的过程。
-
Zookeeper介绍
- Zookeeper是源代码开放的分布式协调服务,由雅虎创建,是Google Chubby开源实现。Zookeeper是一个高性能的分布式数据一致性解决方案,它将那些复杂、容易出错的分布式一致性服务封装起来,构成一个搞笑可靠的原语集,并提供一系列简单易用的接口给用户使用。
-
Zookeeper的典型应用场景
- 数据发布/订阅 顾名思义就是一方把数据发布出来,另一方通过某种手动可以得到这些数据。
- 通常数据订阅有两种方式:推模式和拉模式,推模式一般是服务器主动向客户端推送消息,拉模式是客户端主动去服务端获取数据(通常采用的是轮询的方式)。
- Zookeeper采用两种方式的结合。
- 发布者将数据发布到Zookeeper集群节点上,订阅者通过一定的方法告诉服务器,我对那个节点的数据感兴趣,那个服务器在这些节点的数据发送变化时,就通知客户端,客户端得到通知后可以去服务器获取数据信息。
- 分布式协调/通知
- 心跳检测:在分布式系统中,通常需要机器是否可以用,Zookeeper中我们让所有的机器都注册一个临时节点,所以只需要判断这个节点是否存在就可以了,不需要直接去连接需要检查的机器,降低系统的负载度(节点分为临时和持久)。
- 数据发布/订阅 顾名思义就是一方把数据发布出来,另一方通过某种手动可以得到这些数据。
-
Zookpeeper重量级使用
- Hadoop、HBase、Storm、Solr。
-
集群角色
- Leader、Follower、Observer
- Leader服务器是整个Zookeeper集群工作机制的核心
- Follower服务器是Zookeeper集群状态的跟随者
- Oserver服务器充当一个观察者的角色
- Leader、Follower设计模式,Observer观察者模式
- Leader、Follower、Observer
-
会话
- 会话是指客户端Zookeeper服务器的连接,Zookeeper中的会话叫Session,客户端与服务器建立TCP的长连接来维持一个Session,客户端在启动的时候首先会与服务器建立一个TCP连接,通过这个连接客户端能够通过心跳检测与服务器保持有效的会话,也能向Zookeeper服务器发送请求并获得响应。
-
数据节点
- Zookeeper中的节点有两类
- 集群中的一台机器称为一个节点
- 数据模型中的数据单元Znode,分别为持久节点和临时节点。(其实数据节点就是一个tree节点就是Znode)
- Zookeeper中的节点有两类
-
版本
- Zookeeper中的版本
- version
- 当前数据节点数据内容版本
- cversion
- 当前数据节点子节点的版本号
- aversion
- 当前数据节点ACL变更版本号
- version
- Zookeeper中的版本
-
watcher(事件监听器)
- Zookeeper允许用户在指定节点上注册一些Watcher,当数据节点发生变化的时候,Zookeeper服务器会把这个变化通知发送给感兴趣的客户端。
-
ACL权限控制
- ACL是Access Contril Lists 的缩写,Zookeeper采用ACL策略来进行权限控制,有以下权限:
- CREATE:创建子节点
- READ:获取子节点
- WRITE:更新子节点数据权限
- DELETE:删除子节点权限
- ADMIN:设置节点ACL权限
- ACL是Access Contril Lists 的缩写,Zookeeper采用ACL策略来进行权限控制,有以下权限:
SpringBoot JMH
尝试在spring test中使用基准测试。
演示代码
-
JMH 是一个用于在 JVM 上编写基准测试的 Java 工具库,它是作为 OpenJDK 项目的一部分开发的。
-
在与spring test集成过程中,只需要成功加载spring即可。
Console
- 当jmh先启动,在启动spring就正常使用了。
# JMH version: 1.21
# VM version: JDK 1.8.0_275, OpenJDK 64-Bit Server VM, 25.275-b01
# VM invoker: /Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre/bin/java
# VM options: -server
# Warmup: 1 iterations, 10 s each
# Measurement: 1 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: cn.z201.jmh.AppApplicationTest.environment
# Run progress: 0.00% complete, ETA 00:00:20
# Fork: N/A, test runs in the host VM
# *** WARNING: Non-forked runs may silently omit JVM options, mess up profilers, disable compiler hints, etc. ***
# *** WARNING: Use non-forked runs only for debugging purposes, not for actual performance runs. ***
# Warmup Iteration 1:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.4.5)
[cn.z201.jmh.AppApplicationTest.environment-jmh-worker-1] [StartupInfoLogger.java : 55] Starting application using Java 1.8.0_275 on z201MacBook-Pro.local with PID 23242 (started by zengqingfeng in /Users/zengqingfeng/word/code-example/SpringBoot-JMH)
[cn.z201.jmh.AppApplicationTest.environment-jmh-worker-1] [SpringApplication.java : 679] The following profiles are active: dev
[cn.z201.jmh.AppApplicationTest.environment-jmh-worker-1] [Bootstrap.java : 68] UT026010: Buffer pool was not set on WebSocketDeploymentInfo, the default pool will be used
[cn.z201.jmh.AppApplicationTest.environment-jmh-worker-1] [ServletContextImpl.java : 371] Initializing Spring embedded WebApplicationContext
[cn.z201.jmh.AppApplicationTest.environment-jmh-worker-1] [ServletWebServerApplicationContext.java : 289] Root WebApplicationContext: initialization completed in 809 ms
[cn.z201.jmh.AppApplicationTest.environment-jmh-worker-1] [ExecutorConfigurationSupport.java : 181] Initializing ExecutorService 'applicationTaskExecutor'
[cn.z201.jmh.AppApplicationTest.environment-jmh-worker-1] [Undertow.java : 120] starting server: Undertow - 2.2.7.Final
[cn.z201.jmh.AppApplicationTest.environment-jmh-worker-1] [Xnio.java : 95] XNIO version 3.8.0.Final
[cn.z201.jmh.AppApplicationTest.environment-jmh-worker-1] [NioXnio.java : 59] XNIO NIO Implementation Version 3.8.0.Final
[cn.z201.jmh.AppApplicationTest.environment-jmh-worker-1] [Version.java : 52] JBoss Threads version 3.1.0.Final
[cn.z201.jmh.AppApplicationTest.environment-jmh-worker-1] [UndertowWebServer.java : 133] Undertow started on port(s) 9031 (http)
[cn.z201.jmh.AppApplicationTest.environment-jmh-worker-1] [StartupInfoLogger.java : 61] Started application in 2.018 seconds (JVM running for 3.629)
[cn.z201.jmh.AppApplicationTest.environment-jmh-worker-1] [AppApplicationTest.java : 40] dev
Netty 源码环境搭建
0x00 阅读源代码
下载源代码
- 阅读版本号
netty-4.1.33.Final- 由于github下载速度是在太慢了,这里用gitee克隆一个镜像。
- 下载版本
git clone -b netty-4.1.33.Final git@gitee.com:Z201/netty.git
查看源代码结构
- 查看项目主要文件夹
tree -d -L 1
├── all
├── bom
├── buffer (Core netty定制的buffer)
├── codec (Protocol Support)
├── codec-dns (Protocol Support)
├── codec-haproxy (Protocol Support)
├── codec-http (Protocol Support)
├── codec-http2 (Protocol Support)
├── codec-memcache (Protocol Support)
├── codec-mqtt (Protocol Support 物联网)
├── codec-redis (Protocol Support )
├── codec-smtp (Protocol Support 邮件)
├── codec-socks (Protocol Support)
├── codec-stomp (Protocol Support ws)
├── codec-xml (Protocol Support)
├── common (Core)
├── dev-tools
├── docker
├── example (抄代码的地方)
├── handler (Protocol Support)
├── handler-proxy (Protocol Support)
├── license
├── microbench (测试用的)
├── resolver (Core)
├── resolver-dns (Core)
├── tarball
├── target
├── testsuite
├── testsuite-autobahn
├── testsuite-http2
├── testsuite-osgi
├── testsuite-shading
├── transport (Transport Services)
├── transport-native-epoll (Transport Servicesnative omitted - reserved keyword in Java)
├── transport-native-kqueue (Transport Servicesnative omitted - reserved keyword in Java)
├── transport-native-unix-common Transport Services native omitted - reserved keyword in Java)
├── transport-native-unix-common-tests
├── transport-rxtx (Transport Services 串口编程 作废)
├── transport-sctp (Transport Services )
└── transport-udt (Transport Services 作废)
CentOS7 Selenium运行环境
最近在编写爬虫程序,这里简单的做下笔记。
阅读注意事项
- 需要一台服务器(阿里ESC)这种,分配的公网ip。
- 这里使用的yum安装,所以环境配置都创建好了,不需要在手动修改。
准备工作
安装Java、maven、git、selenium运行环境
# 使用的机器是centos7.4
# 系统环境一个一个来安装。
# 1.检查是否安装jdk
-> yum install java-1.8.0-openjdk-devel.x86_64
-> java -version
openjdk version "1.8.0_262"
OpenJDK Runtime Environment (build 1.8.0_262-b10)
OpenJDK 64-Bit Server VM (build 25.262-b10, mixed mode)
-> yum install maven
-> mvn -version
Java version: 1.8.0_262, vendor: Oracle Corporation
Java home: /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.262.b10-0.el7_8.x86_64/jre
Default locale: zh_CN, platform encoding: UTF-8
OS name: "linux", version: "3.10.0-862.el7.x86_64", arch: "amd64", family: "unix"
-> yum install git
git version 1.8.3.1
# 查看是否生成过证书
-> ls -al ~/.ssh
# 这里配置下ssh公钥方便git拉去代码
-> ssh-keygen -t rsa -C “you email@gamil.com”
# 查看证书
-> cat ~/.ssh/id_rsa.pub
# 开始配置 selenium 运行环境
-> wget https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm
-> yum localinstall google-chrome-stable_current_x86_64.rpm
# 检查版本
-> google-chrome --version
Google Chrome 85.0.4183.83
# 安装 chromedriver
-> yum install chromedriver
-> chromedriver -version
ChromeDriver 84.0.4147.89
# 这里注意 chromedriver 可能与chrome的版本不一致,去官方网站下载后解压复制到/usr/bin中
# 下载地址 https://chromedriver.chromium.org/
Java JMH
Java Eureka 钉钉通知
本篇幅只是回顾使用eureka的时候如何钉钉告警。
Eureka钉钉告警
- 实例图

关键代码
@EventListener
public void listen(EurekaInstanceCanceledEvent event) {
log.error("告警通知 [{}] 服务注销 timestamp [{}] serverId [{}]",
event.getAppName(),
event.getTimestamp(),
event.getServerId());
if (!event.isReplication()) {
ServiceNotice serviceNotice = new ServiceNotice();
serviceNotice.setTitle("告警通知 服务下线");
serviceNotice.setAppName(event.getAppName());
serviceNotice.setTimestamp(event.getTimestamp());
serviceNotice.setServerId(event.getServerId());
serviceNotice.setProfiles(active);
alarmNoticeManage.createNotice(serviceNotice, "");
}
}
@EventListener
public void listen(EurekaInstanceRegisteredEvent event) {
log.info("告警通知 [{}] 服务注册 timestamp [{}] id [{}] ipAddr [{}] ",
event.getInstanceInfo().getAppName(),
event.getTimestamp(),
event.getInstanceInfo().getId(),
event.getInstanceInfo().getIPAddr()
);
if (!event.isReplication()) {
ServiceNotice serviceNotice = new ServiceNotice();
serviceNotice.setTitle("告警通知 服务上线");
serviceNotice.setAppName(event.getInstanceInfo().getAppName());
serviceNotice.setTimestamp(event.getTimestamp());
serviceNotice.setServerId(event.getInstanceInfo().getId());
serviceNotice.setProfiles(active);
alarmNoticeManage.createNotice(serviceNotice, "");
}
}
SpringBoot 错误钉钉通知
本篇幅只是回顾使用钉钉做异常告警需要那些关键业务信息。
为什么要做钉钉通知?
事情要从我入职上家公司说起,进入公司后把线上项目clone下来大致看了下。代码风格过于滞后、编码风格混乱。进入公司第一周就出现了线上故障,嗯。我去线上检查日志,emmmm竟然没有日志输出。这次故障是由客户反馈来的。当时我非常吃惊,大伙好像很淡定的样子,习以为常了?
想到当初面试的时候和总监的谈话,主要是带领团队落地微服务架构,看来必须大刀阔斧了。
首先想到的时候改进日志输出、定义全局异常级别,根据异常级别输出日志。
Java JVM
本章是整理知识内容,为强化知识长期更新。
JVM
JVM 全称 Java Virtual Machine,也就是我们耳熟能详的 Java 虚拟机。JVM 会翻译执行 Java 字节码,然后调用真正的操作系统函数,这些操作系统函数是与平台息息相关的。

- 如上图所示,通过JVM,Java实现了跨平台、只要class文件能正常执行,就可以在其他系统上面运行。 JVM 与操作系统之间的关系:JVM 上承开发语言,下接操作系统,它的中间接口就是字节码。
Skywalking 源码环境搭建
0x00 阅读源代码
长达9天的断网终于结束了。
下载源代码
- 代码仓库地址 https://gitee.com/Z201/skywalking.git
- 阅读版本号
v6.0.0-GA - 下载版本
git clone -b v6.0.0-GA https://github.com/apache/skywalking.git- 由于github下载速度是在太慢了,这里用gitee克隆一个镜像。
- 下载版本
git clone -b v6.0.0-GA https://gitee.com/Z201/skywalking.git
SpringBoot Redis 超时错误
最近在看项目的时候发现一个临时问题,就是redis.timeout设置0依然超时的问题。
- 代码适用版本
jedis:2.9.0,org.springframework.data.redis:1.8.1
timeout设置0的问题
spring.redis.timeout =0 如果设置成0 redis默认超时时间就是2秒.

Java Arthas
基础理论篇学习笔记
Arthas(阿尔萨斯) 能为你做什么?

Arthas 是Alibaba开源的Java诊断工具,深受开发者喜爱。
当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决:
- 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
- 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
- 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
- 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
- 是否有一个全局视角来查看系统的运行状况?
- 有什么办法可以监控到JVM的实时运行状态?
Spring Redis 字符串
本章是整理知识内容,为强化知识长期更新。
spring-redis-string
Spring-data-redis 有两个客户端,本章节主要使用lettuce来作为代码演示。尽可能面向redis编程。
- 参考文献redis-string
SpringBoot Dubbo
离职两个月,太久没写项目了,重新温故下。
-
这里的代码是最简单的演示效果。
-
项目下载地址
git cloen -b v1.0.0 https://github.com/z201/learning-spring-dubbo-micro-service.git -
v1.0.0分支dubbo xml 配置演示基于zk做注册中心。 -
v2.0.0分支dubbo annotation 配置演示基于zk做注册中心。 -
v3.0.0分支dubbo xml 配置演示基于nacos做注册中心。
Java Code 递归
上周的一道笔试题
递归计算
根据两组参数,使用递归完成编程。
递归方法
参数1 [1,3]
参数2 n
当参数2 < 小于参数1中元素个数的时候,不输出。
当n = 3 时 输出 [1,3,4]
当n = 4 时 输出 [1,3,4,7]
当 n = 11 使用递归程序输出
public static void test(List<Integer> list , Integer end) {
if(list.isEmpty() || list.size() < 1 || end == null || end < 0){
throw new RuntimeException("初始化参数异常");
}
if (list.size() < end) {
int length = list.size();
list.add(list.get(length - 1) + list.get(length - 2));
test(list , end);
}
}
public static void main(String[] args) {
Integer[] arr = new Integer[]{1,3};
List<Integer> list = new ArrayList(Arrays.asList(arr));
test(list , 11);
System.out.println(list.toString());
}
>>
[1, 3, 4, 7, 11, 18, 29, 47, 76, 123, 199]
Java Selenium
Selenium
Selenium是最广泛使用的开源Web UI(用户界面)自动化测试套件之一。它最初由Jason Huggins于2004年开发,作为Thought Works的内部工具。Selenium支持跨不同浏览器,平台和编程语言的自动化。
-
Selenium可以轻松部署在Windows,Linux,Solaris和Macintosh等平台上。此外,它支持iOS(iOS,Windows Mobile和Android)等移动应用程序的OS(操作系统)。
-
Selenium通过使用特定于每种语言的驱动程序支持各种编程语言.Selenium支持的语言包括C#,Java,Perl,PHP,Python和Ruby。目前,Selenium Web驱动程序最受Java和C#欢迎。Selenium测试脚本可以使用任何支持的编程语言进行编码,并且可以直接在大多数现代Web浏览器中运行。Selenium支持的浏览器包括Internet Explorer,Mozilla Firefox,Google Chrome和Safari。
Java JJWT JUnit4
Jjwt-Junit
本章内容主要是用来实际运行下jjwt的api,完成相应的单元测试。
<properties>
<junit.version>4.12</junit.version>
<jjwt.version>0.10.5</jjwt.version>
<lmbok.version>1.18.4</lmbok.version>
<h2.version>1.4.197</h2.version>
<slf4j.version>1.7.25</slf4j.version>
<logback.version>1.2.3</logback.version>
<!-- pom文件需要指定打包编码集,[WARNING] File encoding has not been set, using platform encoding GBK, i.e. build is platform dependent! -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>${jjwt.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>${jjwt.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>${jjwt.version}</version>
<scope>runtime</scope>
</dependency>
<!--log -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<!-- 测试框架 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
</dependency>
Spring 源码环境搭建
0x00 阅读源代码
下载源代码
- 代码仓库地址 https://gitee.com/Z201/spring-framework.git
- 阅读版本号
v5.1.5.RELEASE - 下载版本
git clone -b v5.1.5.RELEASE https://github.com/spring-projects/spring-framework.git- 由于github下载速度是在太慢了,这里用gitee克隆一个镜像。
- 下载版本
git clone -b v5.1.5.RELEASE https://gitee.com/Z201/spring-framework.git
- 官方提供的文档import-into-idea
Java JUnit4
本文主要是为了记录很久以前对Junit的回顾。
Junit
Java开发中使用的最多的测试框架,工作中经常会大量使用。
建议遵守约定
- 测试类在test包下(如果是maven结构的项目建议建议不要方在源码中,早期的项目很多是没有区分开的)
- 测试类命名xxxTest结尾。
- 方法命名testxxxx命名。
- 测试方法上必须使用@Test进行修饰。
- 测试方法必须使用public void 进行修饰,不能带任何的参数。
- 测试类的包应该和被测试类保持一致。
- 测试单元中的每个方法必须独立测试,测试方法间不能有任何的依赖。
Java Web JSON Token
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。也就是说JWT是Token的一种表述性声明规范。
JWT(Json Web Token)
- 官网地址:https://jwt.io/
- jwt github:https://github.com/jwtk/jjwt
Java XPath
了解Xpath之前先了解下XML、HTML。如果完全不知道是什么,建议系统学习HTML、XML下阅读下文。
XML
可扩展标记语言(英语:Extensible Markup Language,简称:XML),是一种标记语言。标记指计算机所能理解的信息符号,通过此种标记,计算机之间可以处理包含各种信息的文章等。如何定义这些标记,既可以选择国际通用的标记语言,比如HTML,也可以使用像XML这样由相关人士自由决定的标记语言,这就是语言的可扩展性。XML是从标准通用标记语言(SGML)中简化修改出来的。它主要用到的有可扩展标记语言、可扩展样式语言(XSL)、XBRL和XPath等。
MyBatis 源码环境搭建
mybatis学习笔记。
0x00 阅读源代码
下载源代码
- 代码仓库地址 https://github.com/mybatis/mybatis-3.git
- 阅读版本号
myabtis-3.5.0 - 下载版本
git clone -b mybatis-3.5.0 https://github.com/mybatis/mybatis-3.git- 由于github下载速度是在太慢了,这里用gitee克隆一个镜像。
- 下载版本
git clone -b mybatis-3.5.0 https://gitee.com/Z201/mybatis-3.git
Java SpringMVC
本章是整理知识内容,为强化知识长期更新。
Spring Web MVC
Spring Web 模型-视图-控制器 (MVC) 框架围绕
DispatcherServlet将请求分派给处理程序而设计。
常用注解
-
@Controller
- 声明在类上,该注解表明该类扮演控制器的角色,类似Action。
-
@RestController
- RestController是Controller超子集,相当于@RequestMapping方法默认采用@ResponseBody注解。
-
@RequestMapping
- 该注解是用来映射一个URL到一个类或一个特定的方处理法上。
- RequestMapping属性
- path / method 指定方法的映射路径
- params / headers 请求映射范围
- consumes / produces 请求与响应格式的限制范围
- Restfull风格的使用。
- restfull 支持的请求头GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE 。
- 通常情况下只使用 GET,PUT,POST,DELETE。
- GET 通常用来获取数据。
- PUT 通常用来新增数据。
- POST 通常用来更新数据。
- DELETE 通常用来删除数据。
@RequestMapping(value = "/get", method = RequestMethod.GET) public Object get(){ return "200"; } @RequestMapping(value = "/post", method = RequestMethod.POST) public Object post(){ return "200"; } @RequestMapping(value = "/delete", method = RequestMethod.DELETE) public Object delete(){ return "200"; } @RequestMapping(value = "/put", method = RequestMethod.PUT) public Object put(){ return "200"; }
Java Spring
本章是整理知识内容,为强化知识长期更新。

Spring
- Spring是一个轻量级的IoC和AOP容器框架。是为Java应用程序提供基础性服务的一套框架,目的是用于简化企业应用程序的开发,它使得开发者只需要关心业务需求。
Spring IOC = Spring Bean + Spring Context特性
Java MyBatis
本章是整理知识内容,为强化知识长期更新。
整体架构

基础层
处理层
接口层
Mybatis执行流程
- 获取sqlSessionFactory对象:解析文件的每一个信息保存在Configuration中,返回包含Configuration的DefaultSqlSession;注意:MappedStatement:代表一个增删改查的详细信息。
- 获取sqlSession对象,返回一个DefaultSQlSession对象,包含Executor和Configuration;这一步会创建Executor对象;
- 获取接口的代理对象(MapperProxy),getMapper,使用MapperProxyFactory创建一个MapperProxy的代理对象。
Java Maven
本章是整理知识内容,为强化知识长期更新。
Mavan常用命令以及用法
-
常用命令就要先了解Maven的生命周期
- Maven的生命周期就是对所有的构建过程进行抽象和统一。包含了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等几乎所有的构建步骤。
- Maven的生命周期是抽象的,即生命周期不做任何实际的工作,实际任务由插件完成,类似于设计模式中的模板方法。所以必须有对应的插件才能执行对于的步骤。
- Maven有三套相互独立的生命周期,分别是clean、default和site。每个生命周期包含一些阶段(phase),阶段是有顺序的,后面的阶段依赖于前面的阶段。
- clean生命周期:清理项目,包含三个phase。
- 1.)pre-clean:执行清理前需要完成的工作。
- 2)clean:清理上一次构建生成的文件。
- 3)post-clean:执行清理后需要完成的工作。
- default生命周期:构建项目,重要的phase如下。
- 1)validate:验证工程是否正确,所有需要的资源是否可用。
- 2)compile:编译项目的源代码。
- 3)test:使用合适的单元测试框架来测试已编译的源代码。这些测试不需要已打包和布署。
- 4)Package:把已编译的代码打包成可发布的格式,比如jar。
- 5)integration-test:如有需要,将包处理和发布到一个能够进行集成测试的环境。
- 6)verify:运行所有检查,验证包是否有效且达到质量标准。
- 7)install:把包安装到maven本地仓库,可以被其他工程作为依赖来使用。
- 8)Deploy:在集成或者发布环境下执行,将最终版本的包拷贝到远程的repository,使得其他的开发者或者工程可以共享。
- site生命周期:建立和发布项目站点,phase如下。
- 1)pre-site:生成项目站点之前需要完成的工作。
- 2)site:生成项目站点文档。
- 3)post-site:生成项目站点之后需要完成的工作。
- 4)site-deploy:将项目站点发布到服务器
- clean生命周期:清理项目,包含三个phase。
-
mvn clean
- 清理项目构建文件。调用clean生命周期的clean阶段,实际执行pre-clean和clean阶段。
-
mvn install
- 构建项目文件。实际执行pre-clean和clean,install以及之前所有阶段。
-
mvn install -Dmaven.test.skip=true
-
构建项目的时候不执行测试。也可以使用插件来配置。
<!-- surefire 插件用来在maven构建生命周期的test phase执行一个应用的单元测试 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.19.1</version> <configuration> <skipTests>true</skipTests> <forkMode>once</forkMode> <argLine>-Dfile.encoding=UTF-8</argLine> </configuration> <!-- 插件手动匹配JUnit 目前是使用4.10的版本--> <dependencies> <dependency> <groupId>org.apache.maven.surefire</groupId> <artifactId>surefire-junit47</artifactId> <version>2.19.1</version> </dependency> </dependencies> </plugin>
-
-
mvn eclipse:eclipse
- 将pom项目转换成eclipse格式项目。
-
mvn jetty:run -war
-
使用内置jetty启动项目,需要配置jetty扩展插件。也可以使用tomcat来作为插件。
<!-- 配置Maven插件(mvn jetty:run -war可以运行项目) --> <plugin> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>9.3.0.M1</version> <configuration> <!-- 指定访问端口 --> <httpConnector> <port>80</port> </httpConnector> <!-- 间隔x扫描一次,实现热部署 <scanIntervalSeconds>0</scanIntervalSeconds> --> <!-- 编写类文件之后,是否自动重启jetty;可选后面两个值[manual|automatic] <reload>manual</reload> --> <!-- 指定关闭端口 --> <stopPort>9998</stopPort> <stopKey>stop-jetty</stopKey> <webApp> <!-- 配置<contextPath>/</contextPath>,则访问路径为http://localhost:80 --> <contextPath>/</contextPath> <!-- 更改jetty默认webdefault.xml文件,主要修改了useFileMappedBuffer属性为false,使其不锁定静态文件 --> <!-- 此文件在C盘\用户目录\.m2\repository\org\eclipse\jetty\jetty-webapp\9.1.0.RC1\找到jar包,打开jar包目录org\eclipse\jetty\webapp\目录中 --> <!-- <defaultsDescriptor>webdefault.xml</defaultsDescriptor> --> <defaultsDescriptor>src/main/resources/webdefault.xml</defaultsDescriptor> </webApp> </configuration> </plugin>
-
Java Dubbo
本章是整理知识内容,为强化知识长期更新。
Dubbo概述
- 服务治理(SOA)治理框架
- Duboo是一个分布式服务框架
- 远程通讯:提供多种基于长链接的NIO框架抽象封装,包括多种线程模型、序列化“请求-响应”的信息交换方案。
- 集群容错:提供基于接口方法的透明远程调用过程,包括多协议支持、软负载均衡、失败容错、地址路由、动态配置等集群支持。
- 自动发现:基于注册中心目录服务,使服务消费方能动态地查找提供方,使地址透明,使服务提供方可以平滑增或减少机器。
- 介绍:
- 致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。
- Dubbo的命名:澳大利亚达博市
- 同类型框架:
- Apache Thrift、Hessian、RMI、WebService(原生)、HSF(淘宝,不开源)、JSF(京东,不开源)。
- Dubbo涉及的基础知识
- 远程调用方面:RMI、Hassion、WebService、Thrift进行底层调用。
- 通讯交互:HTTP、Mian、netty。
- 序列化:Hession2、Java、Json。
- 容器:Jetty、Spring。
- 负载均衡:zookeeper、Redis。(大部分都是zookeeper)
- 简单的使用场景
- 作为对内提供服务应用的容器。
- 拆分负载Web应用到服务容器。
- 应用负载均和协调。
- 引用服务处理。
Java 核心
本章是整理知识内容,为强化知识长期更新。
面向对象思想
- 面向对象是一个思想,时间万物皆可以被看做一个对象。
封装
- 隐藏对象的属性和实现的具体细节,只对外暴露公共访问方式。
继承
- 当多个类出现相同代码逻辑时,我们通常将相同的代码重构到一个类中,如果是绑定关系就可以使用继承。
- Java中类是单继承。多继承会导致棱形问题。
- 继承是面向对象的四大特性之一,用来表示类之间的 is-a 关系,可以解决代码复用的问题。虽然继承有诸多作用,但继承层次过深、过复杂,也会影响到代码的可维护性。
- 可以利用组合(composition)、接口、委托(delegation)三个技术手段,一块儿来解决刚刚继承存在的问题。
Java HashMap
本章属于持续学习、长期更修。
HashMap

特征
- HashMap 允许
null键和null值,null键哈西值为0. - HashMap 并不是有序的存放。在使用
iterate迭代的时候,并不能得到存放顺序。 - HashMap使用它的内部类Node <K,V>来存储映射。
- HashMap将
entries存储到多个单链表中,称为存储桶或存储桶。默认的箱数为16,默认负载因子0.75,它的扩展系数为2,当键值对数量大于阈值,则容量扩容到原来的2倍。 - HashMap不是线程安全的,对于多线程环境,您应该使用ConcurrentHashMap类或使用
Collections.synchronizedMap()方法获取同步映射。 - 底层实现是链表,但是jdk1.8后添加了红黑谁的转换。
- HashMap的Key用存放,所以key默认不允许重复的,如果想重复就重写key的hashcode和equals方法。
- 查找方法,根据 hash 值我们能够快速定位到数组的具体下标,但是之后的话,需要顺着链表一个个比较下去才能找到我们需要的,时间复杂度取决于链表的长度,为 O(n)。为了降低这部分的开销,在 Java8 中,当链表中的元素超过了 8 个以后,会将链表转换为红黑树,在这些位置进行查找的时候可以降低时间复杂度为 O(logN)。
Java HashSet
本章属于持续学习、长期更修。
HashSet

特性
- HashSet不允许重复数据。
- HashSet不允许null,因为null也是可以重复的。
- HashSet不保证数据的插入顺序。
- HashSet不是线程安全的,如果想使用线程的安全的HashSet可以通过
Collections.synchronizedSet来获取线程安全的HashSet。也可以使用CopyOnWriteArraySet。但是性能会有很大的损失。 - HashSet迭代器方法是快速失败的。因此,在创建迭代器之后对集合进行任何结构修改都会抛出ConcurrentModificationException。
- HashSet支持泛型,这是在运行时避免ClassCastException的推荐方法。
- HashSet使用
HashMap存储元素,因此对象应该提供hashCode()和equals()方法的良好实现,以避免不必要的结果。
Java Code 交换值
刚去杭州面试的第二家公司,做笔试的时候的时候遇到的。最近几天在整理以前的笔记发现了。简单记录下。
互换两个变量的值
int a=10; int b=12; // 通过两个变量之间的运算输出结果 a = 12 b = 10
Java Log4j
本章内容阐述个人理解,以及使用方法。若有不正确的内容欢迎斧正。睡觉之前赶快记录下来免得有忘记了。
什么是Log?
- 日志记录的是什么?市面上流行的软件基本都有日志记录功能,作为开发人员的好帮手。日志可以有效的记录程序运行的状态以及运行的异常,比如说操作系统蓝屏了、手机死机了、软件卡死、程序崩溃、写了BUG等等都会有对应的日志留下。
如何利用log?
- 笔者是一个Java开发人员,本章内容代码部分已Java代码用例。大家都知道日志非常重要,但是经验不足的开发人员往往忽视了这个重要的手段,比如在控制台输出日志,所有输出信息都集中在一起。排除问题非常困难,一旦出现了线上异常信息首先要看的就是日志信息。所以有必要就日志手段多了解下。
Java Stack
本章是整理知识内容,为强化知识长期更新。
Stack
- 栈是元素的集合,其包含了两个基本操作:push 操作可以用于将元素压入栈,pop 操作可以将栈顶元素移除。
- 遵循后入先出(LIFO)原则。
- 时间复杂度:
- 索引:
O(n)- 搜索:
O(n)- 插入:
O(1)- 移除:
O(1)
Java Vector
本章是整理知识内容,为强化知识长期更新。
Vector

概述
- Vector是Java Collection Franmework成员。
- 列队允许添加重复元素
- 列队允许null的存在
- 列队从0开始,也就是列队头部的下标是0。
- 列队支持泛型,这样可以避免
ClassCastException异常。
Java Eureka Zookeeper
服务注册中心,给客户端提供可供调用的服务列表,客户端在进行远程服务调用时,根据服务列表然后选择服务提供方的服务地址进行服务调用。服务注册中心在分布式系统中大量应用,是分布式系统中不可或缺的组件,例如rocketmq的name server,hdfs中的namenode,dubbo中的zk注册中心,spring cloud中的服务注册中心eureka。 在spring cloud中,除了可以使用eureka作为注册中心外,还可以通过配置的方式使用zookeeper作为注册中心。既然这样,我们该如何选择注册中心的实现呢?
CAP定理
Java LinkedList
本章是整理知识内容,为强化知识长期更新。
Linked List
- 链表即是由节点(Node)组成的线性集合,每个节点可以利用指针指向其他节点。它是一种包含了多个节点的、能够用于表示序列的数据结构。
- 单向链表: 链表中的节点仅指向下一个节点,并且最后一个节点指向空。
- 双向链表: 其中每个节点具有两个指针 p、n,使得 p 指向先前节点并且 n 指向下一个节点;最后一个节点的 n 指针指向 null。
- 循环链表:每个节点指向下一个节点并且最后一个节点指向第一个节点的链表。
- 时间复杂度:
- 索引:
O(n)- 搜索:
O(n)- 插入:
O(1)- 移除:
O(1)
Java ArrayList
本章是整理知识内容,为强化知识长期更新。
List 是是一个有序的集合,是Collection的实现类之一。
概述
- list接口是Java Collection Framework的成员。
- 列队允许添加重复的元素。
- 列队允许null存在。
- 列队是从0开始,也就是列队头元素的下标是0。
- 列队支持泛型,这样可以避免
ClassCastException异常。