新手从零软路由系列
设计模式
背景
废话少说,面试常问的直接端上来
一些知识点
一、单例模式
- 实现方式与线程安全
饿汉式:类加载时初始化实例,线程安全但可能浪费资源1
2
3
4
5public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() { return INSTANCE; }
}
- 双重检查锁:延迟加载且线程安全,需用
volatile防止指令重排序 136枚举实现:Java5+推荐方式,天然线程安全且防反射攻击1
2
3
4
5
6
7
8
9
10
11
12public class Singleton {
private volatile static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) instance = new Singleton();
}
}
return instance;
}
}
- 应用场景
频繁创建/销毁的对象(如线程池、数据库连接池)
需要全局唯一访问点的配置管理类
二、工厂模式
1. 分类与核心思想
简单工厂:通过参数动态创建对象,但违反开闭原则
public class CoffeeFactory {
public static Coffee createCoffee(String type) {
if (“Latte”.equals(type)) return new Latte();
else if (“Americano”.equals(type)) return new Americano();
throw new IllegalArgumentException(“Invalid type”);
}
}
2. JDK应用示例
三、代理模式
1. 类型与实现
- 静态代理:手动编写代理类,如AOP切面 14
- 动态代理:
- JDK动态代理:基于接口,通过
InvocationHandler实现(如Motan RPC) 14 - CGLIB代理:基于继承,无需接口(如Spring AOP) 36
2. 应用场景
四、观察者模式
1. 结构与实现
2. 优缺点
五、适配器模式
1. 类型与场景
2. 典型应用
六、装饰模式
1. 特点与实现
- 动态扩展对象功能:通过组合替代继承 26
- JDK示例:Java IO的
BufferedReader装饰FileReader561
Reader reader = new BufferedReader(new FileReader("file.txt"));
七、模板方法模式
- 核心思想
定义算法骨架:子类重写特定步骤(如JdbcTemplate)1
2
3
4
5
6
7
8
9
10public abstract class AbstractTemplate {
public void process() {
step1();
step2(); // 子类实现
step3();
}
private void step1() { /*...*/ }
protected abstract void step2();
private void step3() { /*...*/ }
}
八、高频进阶问题
- 设计模式分类:
- 创建型(5种):单例、工厂、建造者等
- 结构型(7种):代理、适配器、装饰者等
- 行为型(11种):观察者、策略、模板方法等
- 设计原则:
- 开闭原则、里氏替换原则、依赖倒置原则等
- 框架中的应用:
- Spring的单例Bean、AOP代理
- MyBatis的Executor模板方法
MySQL相关读书笔记
Good code is its own best documentation. As you’re about to add a comment, ask yourself, “How can I improve the code so that this comment isn’t needed?”
Steve McConnell
Effective MySQL之SQL语句最优化
MySQL索引
MySQL主要用到的索引数据结构有:
- B-树:B-树
- B+树:B+树
- 散列:散列
- 通信R-树:R-树
- 全文本:全文本
MySQL不同存储引擎数据结构
MyISAM
MyISAM存储引擎使用B-树数据结构来实现主码索引、唯一索引以及非主码索引。
MyISAM索引是在内存的一个公共键缓存中管理的,这个缓存大小可以通过key_buffer_size或者其他命名键缓存来定义。InnoDB
B+树聚簇主码
InnoDB用聚簇主码存储数据,底层信息占用的磁盘空间的大小很大程度上取决于页面的填充因子;所有InnoDB数据和索引都是在内存中通过innodb_buffer_pool_size设置选项定义InnoDB缓冲池进行管理。B-树非主码
非主码索引使用B-树数据结构,与MyISAM区别在于,InnoDB中,非主码索引存储的是主码实际值,而在MyISAM中,非主码索引存储的是包含主码值的数据的指针。内存散列索引
只有MEMORY引擎支持散列的数据结构。
CAT监控学习与使用
测试部署
Ubuntu相关系列
背景
又是一个熬夜的夜晚,凌晨2点半,新晋小备机工作站基本搞定了。 Yeah!
Ubuntu安装与初始化配置
安装
机械硬盘挂载
切换数据源为阿里云
1 | #备份source.list |
通过vi/vim修改sources.list
将原有的都注释了,把下面的数据源新增在文件末尾即可:
1 | deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse |
保存之后,记得:sudo apt-get update
更新数据源即可
首次登录设置root密码
打开终端,输入sudo passwd root,
在[sudo] password for wheat:后输入当前用户的密码当前用户密码验证通过后
输入需要设置的root超级管理员账户密码Enter new UNIX password:
验证输入的密码Retype new UNIX password:出现passwd: password updated successfully字样,表示超级管理员root账户密码设置成功
验证:输入su,后输入超级管理员账户的密码,验证通过则成功切换到root账户root
安装jdk并一键切换版本
首次运行下面命令,会显示下面的内容
1 | kemi@datacenter:~$ java -version |
提示你找不到java命令,需要安装。这里就是ubuntu仓库中各个版本的代号,按需安装即可。例如我默认安装的是jdk8,即:
1 | sudo apt install openjdk-8-jre-headless |
安装多个版本jdk
通过如下命令,可以查看当前安装的jdk版本
1 | kemi@middileware:~$ sudo dpkg -l | grep 'jdk\|jre' |
通过下述命令,可以切换不同版本的jdk
1 | kemi@middileware:~$ sudo update-alternatives --config java |
如上所示:我选择了2,则前面会有一个星号,代码当前默认的版本,再次通过java -version可以确认
配置JAVA_HOME
直接
1 | sudo vim /etc/environment |
配置好之后,记得刷新
1 | source /etc/environment |
卸载jdk
- 找到JDK包:
sudo dpkg -l | grep 'jdk\|jre' - 使用以下命令卸载这些包,将包名替换为你找到的实际包名:
1
sudo apt purge default-jdk default-jdk-headless default-jre default-jre-headless openjdk-21-jdk openjdk-21-jdk-headless openjdk-21-jre openjdk-21-jre-headless
- 卸载完成后,使用以下命令清除剩余的依赖项:
1
sudo apt autoremove --purge
- 从/etc/environment文件中删除包含JAVA_HOME变量的行,并保存文件。
碰到通过useradd之后的用户问题
执行su命令之后,使用的是dash而不是bash,如下所示:
1 | # 结尾是sh |
设置常见时区
1 | # 中国标准时间 |
为自定义添加的用户添加sudo权限
1 | # 方法A:添加到 sudo 组(推荐) |
固定IP
直接修改netplan
1 | vim /etc/netplan/50-cloud-init.yaml |
修改成如下形式,ip按照你的实际来
1 | network: |
修改之后:netplan apply 生效
在通过如下命令检查配置是否生效:
1 | ip addr show |
安装mysql
在线安装
确认ubuntu系统版本
1 | kemi@datacenter:~$ lsb_release -a |
更新国内镜像源
不然 sudo apt update 可能会失败。
- 备份原来的镜像文件
1
sudo cp /etc/apt/sources.list.d/ubuntu.sources /etc/apt/ubuntu.sources.backup
- 编辑 /etc/apt/sources.list.d/ubuntu.sources 文件
1
sudo vim /etc/apt/sources.list.d/ubuntu.sources
- 替换镜像源后的内容
1
2
3
4
5
6
7
8
9
10
11
12Types: deb
URIs: http://mirrors.aliyun.com/ubuntu/
Suites: noble noble-updates noble-backports
Components: main restricted universe multiverse
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg
Types: deb
URIs: http://mirrors.aliyun.com/ubuntu/
Suites: noble-security
Components: main restricted universe multiverse
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg更新软件包
1
2
3
4
5
6# 更新本地的“软件包索引缓存”,获取镜像源地址中最新的软件版本
sudo apt update
# 更新升级 apt update 得到的新版本,更新安装这些新版本到我们的服务器上
sudo apt upgrade -y
手动添加官方 MySQL APT 源
官网地址:
https://dev.mysql.com/doc/refman/8.4/en/linux-installation-apt-repo.html
下载最新的apt配置包:
文件版本号直接在下面的网址中查看即可:
https://dev.mysql.com/downloads/repo/apt/1
wget https://dev.mysql.com/get/mysql-apt-config_0.8.36-1_all.deb
安装 MySQL APT 配置包
1
sudo dpkg -i mysql-apt-config_0.8.36-1_all.deb
可以确认下面的安装内容,如果需要选择特定版本:
![apt配置页面]()
一般默认即可:
![选择指定版本]()
按上下键把光标移动到 OK,按回车保存退出。
更新 APT 缓存
1
sudo apt update
重新查询本地可以用的MySQL版本
1
2
3
4
5
6
7apt-cache madison mysql-server
kemi@datacenter:~$ apt-cache madison mysql-server
mysql-server | 8.4.8-1ubuntu24.04 | http://repo.mysql.com/apt/ubuntu noble/mysql-8.4-lts amd64 Packages
mysql-server | 8.0.44-0ubuntu0.24.04.2 | http://mirrors.aliyun.com/ubuntu noble-updates/main amd64 Packages
mysql-server | 8.0.44-0ubuntu0.24.04.1 | http://mirrors.aliyun.com/ubuntu noble-security/main amd64 Packages
mysql-server | 8.0.36-2ubuntu3 | http://mirrors.aliyun.com/ubuntu noble/main amd64 Packages
mysql-community | 8.4.8-1ubuntu24.04 | http://repo.mysql.com/apt/ubuntu noble/mysql-8.4-lts Sources
安装 MySQL Server
安装指定版本的mysql
1 | sudo apt install -y mysql-server=8.4.8-1ubuntu24.04 |
如下图所示,设置好root密码即可安装:
卸载MySQL
先查询mysql所有已安装的包
1
dpkg -l | grep mysql
如下图所示:
![所有安装版本]()
使用 sudo apt-get remove 命令,卸载掉上面查询到的所有安装的包
1
sudo apt-get remove --purge -y mysql-apt-config mysql-server mysql-client mysql-common mysql-community-server mysql-community-client mysql-community-client-core mysql-community-server-core mysql-community-client-plugins
删除配置文件和数据文件
1
sudo rm -rf /etc/mysql /var/lib/mysql /var/log/mysql /var/log/mysql.*
清理无用依赖和缓存
1
2sudo apt-get -y autoremove
sudo apt-get -y autoclean查询是否还有mysql的包
远程连接mysql
修改 mysqld.cnf 配置文件:
1 | sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf |
修改 bind-address 属性,属性不存在就添加在[mysqld]块中(如果只需要指定的 ip 访问,使用防火墙控制)
1 | bind-address = 0.0.0.0 |
重启服务后,通过如下命令连接mysql
1 | sudo mysql -u root -p |
创建指定用户并授权
1 | # 把username换成你所需的用户名即可 |
其它MySQL相关命令
查看 MySQL 服务状态:sudo systemctl status mysql
停止 MySQL 服务:sudo systemctl stop mysql
启动 MySQL 服务:sudo systemctl start mysql
重启 MySQL 服务:sudo systemctl restart mysql
查看 MySQL 的开机自启状态:systemctl is-enabled mysql ,enable:启用,disable:禁用
启动 MySQL 开机自启动:sudo systemctl enable mysql
禁用 MySQL 开机自启动:sudo systemctl disable mysql
系列话题
在ubuntu下编译openjdk
编译方法来自于《深入理解JAVA虚拟机 第三版》,详细请参考该书中第一章,1.6小节的相关说明
准备源码包
根据书中的说明,推荐直接通过网页下载,具体方法如下:
去链接https://hg.openjdk.java.net/jdk/jdk12/ 访问,点击左侧的Browse后,在下方有个zip压缩包,直接点击下载即可。如下图所示:
系统需求
相关命令
参考
SpringBoot实战读书笔记
前言
以历代Spring Framework的进步为基础,Spring Boot实现了自动配置,这让Spring能够智能探
测正在构建何种应用程序,自动配置必要的组件以满足应用程序的需要。对于那些常见的配置场
景,不再需要显式地编写配置了,Spring会替你料理好一切。
第一章 入门
Spring Boot 精要
- 自动配置:针对很多Spring应用程序常见的应用功能,Spring Boot能自动提供相关配置。
- 起步依赖:告诉Spring Boot需要什么功能,它就能引入需要的库。
- 命令行界面:这是Spring Boot的可选特性,借此你只需写代码就能完成完整的应用程序,
无需传统项目构建。 - Actuator:让你能够深入运行中的Spring Boot应用程序,一探究竟。
自动配置
Spring Boot的自动配置远不止嵌入式数据库和JdbcTemplate,它有大把的办法帮你减轻配置负担,这些自动配置涉及Java持久化API(Java Persistence API,JPA)、Thymeleaf模板、安全和Spring MVC。
起步依赖
起步依赖其实就是特殊的Maven依赖和```Gradle``依赖,利用了传递依赖解析,把常用库聚合在一起,组成了几个为特定功能而定制的依赖。
命令行界面
Spring Boot CLI利用了起步依赖和自动配置,让你专注于代码本身。
Actuator
Spring Boot的最后一块“拼图”是Actuator,其他几个部分旨在简化Spring开发,而Actuator则要提供在运行时检视应用程序内部情况的能力。提供如下细节:
- Spring应用程序上下文里配置的Bean
- Spring Boot的自动配置做的决策
- 应用程序取到的环境变量、系统属性、配置属性和命令行参数
- 应用程序里线程的当前状态
- 应用程序最近处理过的HTTP请求的追踪情况
- 各种和内存用量、垃圾回收、Web请求以及数据源用量相关的指标
响应式架构(消息模式Actor实现与Scala、Akka应用集成)
背景
原书《Reactive Messaging Patterns with the Actor Model Applications and Integration in Scala and Akka》,作者:Vaughn Vernon,是《实现领域驱动设计》(Implementing Domain Driven Design)一书的作者。因而,本书值得一看。本文随笔笔记,记录本书中的主要点,以便后续查看翻阅。
书章节小记
推荐序
注:本书推荐序是由Akka项目创始人所作。
- Actor是异步驱动、可以并行和分布式部署及运行的最小颗粒。
- Akka的Acotr模式本身可以保证单个Actor实例中每个行为的原子性,并行的粒度可以细化到单个Actor实例。
- 从架构层面看,Actor能同时担当实体Beans和中间缓存的角色,并且是异步驱动的,且具备分片集群下的水平扩展能力。
- 从业务领域来看,Actor可以非常自然地直接对应到业务实体。
译者序
Actor模型拥有以下优点:
- 大幅度降低应用程序内部的耦合性
- Actor模型的消息传递形式简化了并行程序的开发工作,使开发人员无须与并发编程基础元素打交道
- 在高动态环境中,Actor模型既可以利用顺序编程技巧,也可以利用函数编程技巧
- Actor模型可以解决许多并发编程难题,如死锁、活锁、互斥体等等
- Actor模型能够大幅度提高调用方法的安全性和速度
第一章 Actor模型和企业级软件概述
effective-javascript
前言
- 本文默认JS即为JavaScript语言
- “注:”为本人理解内容
第2条:理解JavaScript的浮点数
- 不管是整数还是浮点数,JavaScript都将它们简单归类为数字。事实上,所有的数字都是双精度浮点数
- 位运算符将数字视为32位的有符号整数
- 当心浮点运算中的精度陷阱
1 | (0.1 + 0.2) + 0.3; // 0.6000000000000001 |
第3条 当心隐式强制转换
- 特别注意字符强制转换的问题:结果为null的变量在算术运算中不会导致失败,而是被隐式转换为0
- 测试某个值是否是NaN,在JS中唯一一个不等于其自身的值,因此,可以随时通过检查一个值是否等于其自身的方式来测试该值是否是NaN
1 | var a = NaN; |
第5条:避免对混合类型使用==运算符
一个好的替代方法是使用严格相等运算符


