车子的个人博客

正确的事情通常都是优雅的

Java IO流详解

IO概述

Java IO是Java中进行输入输出操作的基础包,包括字节流和字符流两大类。

分类

字节流

  • InputStream:输入字节流
  • OutputStream:输出字节流

字符流

  • Reader:输入字符流
  • Writer:输出字符流

常用类

字节流

1
2
3
4
5
6
7
// 文件字节流
FileInputStream fis = new FileInputStream("file.txt");
FileOutputStream fos = new FileOutputStream("file.txt");

// 缓冲字节流
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(fos);

字符流

1
2
3
4
5
6
7
// 文件字符流
FileReader fr = new FileReader("file.txt");
FileWriter fw = new FileWriter("file.txt");

// 缓冲字符流
BufferedReader br = new BufferedReader(fr);
BufferedWriter bw = new BufferedWriter(fw);

转换流

1
2
InputStreamReader isr = new InputStreamReader(System.in);
OutputStreamWriter osw = new OutputStreamWriter(System.out);

装饰器模式

1
2
3
4
5
6
// 层层包装
DataInputStream dis = new DataInputStream(
new BufferedInputStream(
new FileInputStream("file.txt")
)
);

NIO

1
2
3
Path path = Paths.get("file.txt");
byte[] data = Files.readAllBytes(path);
Files.write(path, data);

总结

Java IO体系庞大,核心是装饰器模式。实际开发中优先使用缓冲流和NIO提高性能。

Nginx使用技巧整理

常用命令

1
2
3
4
nginx -t            # 测试配置
nginx -s reload # 重载配置
nginx -s stop # 停止
nginx # 启动

配置文件结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
events {
worker_connections 1024;
}

http {
server {
listen 80;
server_name example.com;

location / {
proxy_pass http://localhost:8080;
}

location /static/ {
alias /path/to/static/;
}
}
}

常用功能

  • 反向代理
  • 负载均衡
  • 静态文件服务
  • SSL配置

总结

Nginx是高性能HTTP服务器。

HotSpot垃圾回收算法实现

serial收集器

  • 单线程收集
  • 停止所有用户线程
  • 新生代使用复制算法
  • 老年代使用标记-整理

ParNew收集器

  • Serial多线程版本
  • 新生代并行收集
  • 配合CMS使用

Parallel Scavenge

  • 吞吐量优先
  • 自适应调节
  • 新生代并行收集

CMS收集器

  • 并发收集,低停顿
  • 标记-清除算法
  • 步骤:初始标记、并发标记、重新标记、并发清除

G1收集器

  • 面向服务端的收集器
  • 化整为零
  • 可预测停顿时间

总结

不同收集器有不同特点,根据应用场景选择合适的收集器。

垃圾回收算法详解

标记-清除算法

  • 标记所有需要回收的对象
  • 统一清除被标记的对象

缺点:产生内存碎片

复制算法

  • 将内存分为两块
  • 每次只使用一块
  • 清理时复制存活对象到另一块

优点:无内存碎片
缺点:可用内存减半

标记-整理算法

  • 标记需要回收的对象
  • 移动存活对象到一端
  • 清除边界外的对象

优点:无内存碎片

分代收集算法

  • 新生代:复制算法
  • 老年代:标记-清除/整理

总结

不同算法适用于不同场景,现代JVM通常组合使用多种算法。

垃圾回收的可达性分析与引用类型

可达性分析

通过”GC Roots”向下搜索,搜索路径称为引用链。不在引用链上的对象可回收。

GC Roots对象

  • 虚拟机栈中引用的对象
  • 方法区中静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中JNI引用的对象

引用类型

强引用

1
Object obj = new Object(); // 永远不会被回收

软引用

1
2
SoftReference<Object> ref = new SoftReference<>(new Object());
// 内存不足时回收

弱引用

1
2
WeakReference<Object> ref = new WeakReference<>(new Object());
// 下次GC时回收

虚引用

1
2
PhantomReference<Object> ref = new PhantomReference<>(new Object(), queue);
// 随时可能被回收

finalize方法

  • 对象覆写finalize()
  • 第一次GC时调用
  • 可拯救自己(重新引用)

总结

可达性分析是垃圾回收的基础算法,引用类型决定了对象的回收时机。

Spring全家桶笔记:非关系型数据库

非关系型数据库概述

NoSQL(Not Only SQL)数据库是非关系型数据库的统称,主要分为以下几类:

  • 键值存储:Redis、Memcached
  • 文档数据库:MongoDB、Elasticsearch
  • 列式数据库:HBase、Cassandra
  • 图形数据库:Neo4j

Redis集成

Redis数据结构

类型 说明 典型应用
String 字符串 缓存、计数器
List 列表 消息队列
Hash 哈希 对象存储
Set 集合 标签、好友
ZSet 有序集合 排行榜

Spring Data Redis

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Configuration
public class RedisConfig {

@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);

// 使用Jackson2JsonRedisSerializer序列化
Jackson2JsonRedisSerializer<Object> serializer =
new Jackson2JsonRedisSerializer<>(Object.class);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(serializer);
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(serializer);

return template;
}
}

基本操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Service
public class UserCacheService {

@Autowired
private RedisTemplate<String, Object> redisTemplate;

// String操作
public void set(String key, Object value) {
redisTemplate.opsForValue().set(key, value);
}

public Object get(String key) {
return redisTemplate.opsForValue().get(key);
}

// Hash操作
public void hSet(String key, String field, Object value) {
redisTemplate.opsForHash().put(key, field, value);
}

public Object hGet(String key, String field) {
return redisTemplate.opsForHash().get(key, field);
}

// List操作
public void lPush(String key, Object value) {
redisTemplate.opsForList().leftPush(key, value);
}

public Object lPop(String key) {
return redisTemplate.opsForList().leftPop(key);
}
}

缓存注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Service
public class UserService {

@Cacheable(value = "user", key = "#id")
public User getUserById(Long id) {
return userDao.findById(id);
}

@CachePut(value = "user", key = "#user.id")
public User updateUser(User user) {
return userDao.save(user);
}

@CacheEvict(value = "user", key = "#id")
public void deleteUser(Long id) {}

@CacheEvict(value = "user", allEntries = true)
public void clearCache() {}
}

MongoDB集成

Spring Data MongoDB

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Entity
@Document(collection = "users")
public class User {

@Id
private String id;

@Field("username")
private String username;

private Integer age;

private Address address;
}

@Document
public class Address {
private String city;
private String province;
}

Repository

1
2
3
4
5
6
7
8
9
public interface UserRepository extends MongoRepository<User, String> {

User findByUsername(String username);

List<User> findByAgeGreaterThan(Integer age);

@Query("{ 'username': { $regex: ?0 } }")
List<User> findByUsernameRegex(String regex);
}

MongoTemplate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Service
public class UserService {

@Autowired
private MongoTemplate mongoTemplate;

public User save(User user) {
return mongoTemplate.save(user);
}

public List<User> findByCondition(Query query) {
return mongoTemplate.find(query, User.class);
}

public void update(Update update, Query query) {
mongoTemplate.updateMulti(query, update, User.class);
}
}

Elasticsearch集成

Spring Data Elasticsearch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Document(indexName = "product")
public class Product {

@Id
private String id;

@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String name;

@Field(type = FieldType.Keyword)
private String category;

private BigDecimal price;
}

Repository

1
2
3
4
5
6
7
public interface ProductRepository extends ElasticsearchRepository<Product, String> {

List<Product> findByNameContaining(String name);

@Query("{\"match\": {\"name\": {\"query\": \"?0\"}}}")
List<Product> searchByName(String keyword);
}

缓存策略

缓存穿透

  • 问题:查询不存在的数据导致频繁查询数据库
  • 解决方案:布隆过滤器、空值缓存

缓存击穿

  • 问题:热点key失效时大量请求涌入
  • 解决方案:互斥锁、永不过期

缓存雪崩

  • 问题:大量key同时失效
  • 解决方案:随机过期时间、持久化

实际应用建议

  1. 根据业务场景选择合适的NoSQL
  2. 合理设计数据模型
  3. 做好容量规划
  4. 配置合理的过期策略
  5. 做好数据备份和恢复

总结

非关系型数据库在特定场景下有显著优势,Spring Data提供了统一的整合方式。选择时需要根据数据特点、查询模式、一致性要求等因素综合考虑。

OOM问题定位与解决

OOM类型

Java堆内存溢出

1
2
3
4
5
// 不断创建对象
List<byte[]> list = new ArrayList<>();
while (true) {
list.add(new byte[1024 * 1024]);
}

虚拟机栈溢出

1
2
3
4
// 递归调用
public void stackOverflow() {
stackOverflow();
}

方法区溢出

1
2
3
4
5
6
7
8
9
10
11
12
// 动态生成大量类
for (int i = 0; i < 100000; i++) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOMObject.class);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
return proxy.invokeSuper(obj, args);
}
});
enhancer.create();
}

定位工具

jmap

1
2
jmap -heap pid   # 堆信息
jmap -dump:format=b,file=heap.hprof pid # 导出堆

jstat

1
jstat -gc pid 1000  # 每秒GC信息

解决方案

  • 堆溢出:调整-Xmx,检查内存泄漏
  • 栈溢出:检查递归,检查-Xss
  • 方法区:减少动态类生成

总结

OOM问题需要结合工具和代码分析,找出根本原因才能有效解决。

Spring全家桶笔记十二:微服务架构与Spring Cloud

微服务概述

微服务是一种架构风格,将单一应用程序划分为一组小的服务,服务之间互相协调、互相配合。

优点

  • 独立部署
  • 技术多样性
  • 故障隔离
  • 快速迭代

挑战

  • 运维复杂度
  • 分布式事务
  • 服务通信
  • 监控排查

Spring Cloud组件

组件 说明
Eureka 服务注册与发现
Ribbon 负载均衡
Feign 声明式HTTP客户端
Hystrix 服务熔断
Zuul API网关
Config 配置中心

服务注册与发现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Eureka Server
spring:
application:
name: eureka-server
server:
port: 8761

# Provider
spring:
application:
name: user-service
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true

服务调用

1
2
3
4
5
@FeignClient(name = "order-service")
public interface OrderClient {
@GetMapping("/order/{id}")
Order getOrder(@PathVariable("id") Long id);
}

配置中心

1
2
3
4
5
6
7
8
9
spring:
cloud:
config:
server:
git:
uri: https://github.com/config-repo
discovery:
enabled: true
service-id: config-server

服务网关

1
2
3
4
5
6
zuul:
routes:
user-service:
path: /user/**
url: http://localhost:8080
prefix: /api

总结

Spring Cloud提供了完整的微服务解决方案,帮助开发者快速构建分布式系统。

对象内存布局详解

对象结构

对象头(Header)

  • Mark Word:哈希码、GC分代年龄、锁状态等
  • Klass Pointer:指向类元数据的指针
  • 数组长度(数组对象特有)

实例数据(Instance Data)

  • 父类继承的字段
  • 本类声明的字段

对齐填充(Padding)

  • 8字节对齐
  • 不是必须存在

对象创建过程

  1. 检查类是否加载
  2. 分配内存
  3. 初始化零值
  4. 设置对象头
  5. 执行

内存分配方式

  • 指针碰撞:规整内存
  • 空闲列表:不规整内存

总结

了解对象内存布局有助于理解对象创建过程和内存分配原理。

Spring Cloud服务熔断详解

什么是服务熔断

服务熔断是指当某个服务调用失败或响应超时时,为了防止故障蔓延,暂时停止对该服务的调用并返回降级响应。类似于电路中的保险丝,当电流过大时自动断开以保护电路。

为什么要熔断

  1. 防止雪崩:避免一个服务故障导致整个系统不可用
  2. 快速失败:减少等待时间,快速返回降级结果
  3. 保护资源:防止过多请求堆积导致资源耗尽

熔断器原理

熔断器有三种状态:

  • Closed(关闭):正常状态,请求正常通过,失败计数
  • Open(打开):熔断状态,直接返回降级,不执行请求
  • Half-Open(半开):尝试恢复,允许少量请求通过

核心参数

  • 失败阈值:连续失败多少次后打开熔断器
  • 熔断时长:打开状态持续多长时间后进入半开状态
  • 请求阈值:半开状态下允许通过的请求数

Spring Cloud中的实现

1. Hystrix(已停止维护)

1
2
3
4
5
6
7
8
@HystrixCommand(fallbackMethod = "fallback")
public String getData() {
return restTemplate.getForObject(url, String.class);
}

public String fallback() {
return "降级响应";
}

2. Resilience4j(推荐)

1
2
3
4
@CircuitBreaker(name = "serviceA", fallbackMethod = "fallback")
public String getData() {
return restTemplate.getForObject(url, String.class);
}

配置:

1
2
3
4
5
6
7
8
9
10
11
resilience4j:
circuitbreaker:
instances:
serviceA:
registerHealthIndicator: true
slidingWindowSize: 10
minimumNumberOfCalls: 5
permittedNumberOfCallsInHalfOpenState: 3
automaticTransitionFromOpenToHalfOpenEnabled: true
waitDurationInOpenState: 5s
failureRateThreshold: 50

3. Sentinel( Alibaba)

1
2
3
4
@SentinelResource(value = "getData", fallback = "fallback")
public String getData() {
return restTemplate.getForObject(url, String.class);
}

降级策略

  1. 返回默认值:如空列表、空对象
  2. 返回缓存:从缓存中获取旧数据
  3. 返回友好提示:如”服务暂时不可用”
  4. 重定向:引导用户到其他页面

实际使用建议

  1. 合理设置超时时间
  2. 根据业务设置熔断参数
  3. 提供有效的fallback方法
  4. 监控熔断器状态
  5. 优先考虑Sentinel或Resilience4j

总结

服务熔断是微服务架构中保障系统稳定性的重要手段。在实际应用中,需要根据业务场景合理配置熔断策略,在保证系统稳定的同时也要避免过度熔断影响用户体验。

0%