第43章 Java 能做什么——各领域应用场景详解
第四十三章 Java 能做什么——各领域应用场景详解

想象一下,Java就像IT界的"瑞士军刀"——不是最酷的,但不是万能的,而是什么都能干的那种。本章我们就来扒一扒Java在各个领域是如何大显神通的。
43.1 Web 后端开发
Web后端开发是什么?简单说就是:当你在浏览器里点个按钮、提交个表单,背后那个默默处理请求、查询数据库、返回结果的东西,就叫后端。而Java在这方面堪称"老黄牛"——稳重、可靠、任劳任怨。
43.1.1 为什么Java适合做Web后端?
Java做Web后端有几大法宝:
- 跨平台:一次编写,到处运行(Write Once, Run Anywhere)。服务器装个JVM就行,管它是Linux还是Windows。
- 生态丰富:Spring、Spring Boot、Spring Cloud这些框架让Web开发像搭积木一样简单。
- 性能稳定:经过二十多年的优化,JVM的性能调优已经非常成熟。
- 人才众多:Java开发者满地跑,招人容易,维护也容易。
打个比方:如果你要建一座大楼,Java就是那个能搬砖、能砌墙、能刷漆的全能工人,而且从来不罢工。
43.1.2 经典组合:Spring Boot + MySQL
来一个最经典的Web后端架构——用Spring Boot写一个简单的用户管理接口:
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
| // 引入Spring Boot核心依赖
// Spring Boot自动配置,妈妈再也不用担心我的配置文件
package com.example.demo.controller;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.*;
import org.springframework.stereotype.Component;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
// 启动类,整个应用的入口
@SpringBootApplication
public class WebBackendApplication {
public static void main(String[] args) {
// SpringApplication.run() 会启动内嵌的Tomcat服务器
// 默认端口8080,一个方法搞定前后端分离开发
SpringApplication.run(WebBackendApplication.class, args);
System.out.println("🚀 Web后端服务已启动,访问 http://localhost:8080");
}
}
// 用户实体类
class User {
private Long id;
private String name;
private String email;
// 省略getter/setter,实际开发用Lombok更香
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
// 用户服务层,负责业务逻辑
@Component
class UserService {
// 使用ConcurrentHashMap模拟数据库,真实项目当然用MySQL/PostgreSQL
private final Map<Long, User> userDB = new ConcurrentHashMap<>();
private volatile Long nextId = 1L;
// 添加用户
public User createUser(String name, String email) {
User user = new User();
user.setId(nextId++);
user.setName(name);
user.setEmail(email);
userDB.put(user.getId(), user);
System.out.println("✅ 新用户注册:" + name);
return user;
}
// 查询用户
public User getUser(Long id) {
return userDB.get(id);
}
// 获取所有用户
public Map<Long, User> getAllUsers() {
return userDB;
}
}
// REST控制器,处理HTTP请求
// @RestController = @Controller + @ResponseBody
// 每个方法返回JSON,不用手动序列化
@RestController
@RequestMapping("/api/users")
class UserController {
private final UserService userService;
// 构造器注入,Spring自动搞定
public UserController(UserService userService) {
this.userService = userService;
}
// GET /api/users - 获取所有用户
@GetMapping
public Map<Long, User> getAllUsers() {
System.out.println("📋 查询所有用户");
return userService.getAllUsers();
}
// GET /api/users/{id} - 根据ID获取用户
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
System.out.println("🔍 查找用户ID:" + id);
return userService.getUser(id);
}
// POST /api/users - 创建新用户
// @RequestBody 从请求体解析JSON,很方便
@PostMapping
public User createUser(@RequestBody Map<String, String> request) {
String name = request.get("name");
String email = request.get("email");
return userService.createUser(name, email);
}
}
|
43.1.3 Web后端架构图
┌─────────────────────────────────────────────────────────────┐
│ 用户浏览器 │
└─────────────────────────┬───────────────────────────────────┘
│ HTTP/HTTPS请求
▼
┌─────────────────────────────────────────────────────────────┐
│ Nginx反向代理 │
│ (负载均衡、SSL终结、静态资源服务) │
└─────────────────────────┬───────────────────────────────────┘
│
┌────────────────┼────────────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Spring Boot │ │ Spring Boot │ │ Spring Boot │
│ 实例 1 │ │ 实例 2 │ │ 实例 3 │
│ :8080 │ │ :8081 │ │ :8082 │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
└─────────────────┼─────────────────┘
▼
┌─────────────────────┐
│ Redis 缓存 │
│ (Session共享/热点缓存) │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ MySQL 主库 │
│ (用户数据持久化) │
└─────────────────────┘
43.1.4 主流Java Web框架对比
| 框架 | 特点 | 适用场景 |
|---|
| Spring MVC | 传统Servlet-based,配置繁琐 | 老项目维护 |
| Spring Boot | 自动配置,快速启动 | 新项目首选 |
| Spring Cloud | 分布式微服务全套方案 | 微服务架构 |
| Struts 2 | 老的Action-based框架 | 遗留系统(不建议新用) |
| Play Framework | Scala/Kotlin友好,响应式 | 高并发APIs |
小贴士:如果你要新开Web项目,无脑选Spring Boot就对了。社区强大,文档完善,遇到问题随便搜都能找到答案。
43.2 微服务架构
微服务架构(Microservices)是什么?想象一下,一个大超市 vs 无数个便利店。大超市什么都有,但你要是只想买瓶水,还得整个超市逛一遍;而便利店虽然小,但满街都是,走两步就到。
微服务就是把一个大应用拆成N个小服务,每个服务负责一块功能,可以独立开发、独立部署、独立扩展。
43.2.1 Java微服务技术栈
Java在微服务领域几乎是标配,技术栈非常完整:
- 服务框架:Spring Boot(基础)、Spring Cloud(生态)、Dubbo(阿里系)
- 服务注册与发现:Eureka、Nacos、Consul
- API网关:Spring Cloud Gateway、Zuul
- 配置中心:Spring Cloud Config、Nacos
- 熔断器:Hystrix(已停止维护)、Resilience4j
43.2.2 用Spring Cloud写一个微服务示例
先解释几个概念:
- 服务注册中心:所有微服务的"通讯录",服务启动时把自己的地址登记上去,想调别的服务就去这儿查。
- Feign客户端:声明式的HTTP客户端,写起来像调本地方法一样简单。
- Ribbon:客户端负载均衡器,决定调用哪个具体实例。
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
| // ========== 服务提供方:用户服务 ==========
package com.example.userservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
import org.springframework.web.bind.annotation.*;
@SpringBootApplication
// @EnableEurekaServer 开启Eureka注册中心
// 访问 http://localhost:8761 查看注册的服务列表
@EnableEurekaServer
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
System.out.println("📝 用户服务启动完成");
}
}
// 用户实体
class User {
private Long id;
private String username;
private String phone;
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPhone() { return phone; }
public void setPhone(String phone) { this.phone = phone; }
}
// 用户Controller
@RestController
@RequestMapping("/users")
class UserController {
// 模拟数据库
private static final java.util.Map<Long, User> DB = new java.util.HashMap<>();
static {
User u1 = new User();
u1.setId(1L);
u1.setUsername("张三");
u1.setPhone("13800138000");
DB.put(1L, u1);
User u2 = new User();
u2.setId(2L);
u2.setUsername("李四");
u2.setPhone("13900139000");
DB.put(2L, u2);
}
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
System.out.println("查询用户ID: " + id);
return DB.get(id);
}
@GetMapping("/list")
public java.util.List<User> listUsers() {
return new java.util.ArrayList<>(DB.values());
}
}
|
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
| // ========== 服务消费方:订单服务 ==========
package com.example.orderservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
//@EnableEurekaClient 表明这是一个Eureka客户端,会自动注册到Eureka服务器
@EnableEurekaClient
@SpringBootApplication
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
System.out.println("📦 订单服务启动完成");
}
// @LoadBalanced 让RestTemplate支持负载均衡
// 不用自己写负载均衡算法,Ribbon帮你搞定
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
// 订单实体
class Order {
private Long orderId;
private Long userId;
private String productName;
private Double amount;
public Long getOrderId() { return orderId; }
public void setOrderId(Long orderId) { this.orderId = orderId; }
public Long getUserId() { return userId; }
public void setUserId(Long userId) { this.userId = userId; }
public String getProductName() { return productName; }
public void setProductName(String productName) { this.productName = productName; }
public Double getAmount() { return amount; }
public void setAmount(Double amount) { this.amount = amount; }
}
// 订单Controller
@RestController
@RequestMapping("/orders")
class OrderController {
private final RestTemplate restTemplate;
public OrderController(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@PostMapping("/create")
public String createOrder(@RequestBody Order order) {
// 通过服务名调用用户服务,不用关心IP和端口
// 服务名 "user-service" 会在Eureka中解析成具体地址
String userServiceUrl = "http://user-service/users/" + order.getUserId();
// 调用远程用户服务获取用户信息
User user = restTemplate.getForObject(userServiceUrl, User.class);
// 组装订单信息
String result = String.format(
"✅ 订单创建成功!\n" +
"订单号:%d\n" +
"商品:%s\n" +
"金额:%.2f元\n" +
"用户:%s (手机号: %s)",
order.getOrderId(),
order.getProductName(),
order.getAmount(),
user != null ? user.getUsername() : "未知",
user != null ? user.getPhone() : "未知"
);
System.out.println(result);
return result;
}
}
|
43.2.3 微服务架构图
┌─────────────────────────────────────────────────────────────────┐
│ API Gateway │
│ (Spring Cloud Gateway / Zuul) │
│ 统一入口,路由转发、鉴权、限流、日志 │
└─────────────────────────────┬───────────────────────────────────┘
│
┌────────────────────┼────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 用户服务 │ │ 订单服务 │ │ 商品服务 │
│ :8001 │ │ :8002 │ │ :8003 │
│ │ │ │ │ │
│ /users │◄────►│ /orders │◄────►│ /products │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
└────────────────────┼────────────────────┘
│
┌──────────────────┼──────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ MySQL │ │ MySQL │ │ MySQL │
│ (用户库) │ │ (订单库) │ │ (商品库) │
└─────────────┘ └─────────────┘ └─────────────┘
│
┌──────────────────┴──────────────────┐
│ Eureka 注册中心 │
│ (心跳检测、服务发现、故障转移) │
│ :8761 │
└────────────────────────────────────┘
43.2.4 微服务的"坑"与应对
| 问题 | 说明 | 解决方案 |
|---|
| 服务治理复杂 | 拆多了运维成本飙升 | Kubernetes容器编排 |
| 调用链路长 | 一个请求涉及多个服务,排查困难 | 链路追踪(Zipkin/SkyWalking) |
| 分布式事务 | 跨服务的数据一致性难保证 | Seata、TCC模式 |
| 服务雪崩 | 一个服务挂了,拖垮一堆 | 熔断器(Hystrix/Resilience4j) |
| 配置分散 | 几十个服务配置难管理 | 配置中心(Nacos/Apollo) |
过来人忠告:微服务虽好,但不要为了微服务而微服务。项目小的时候,单体应用反而更简单高效。等团队壮大了、业务复杂了,再考虑拆分也不迟。
43.3 大数据技术栈
大数据(Big Data)简单说就是:数据量大到Excel打不开、MySQL存不下、处理起来普通电脑要跑好几天的数据。常见的大数据场景有:用户行为分析、日志处理、实时推荐、风控模型等。
Java在大数据领域的地位,相当于"武林盟主"——Hadoop、Spark、Flink这些主流大数据框架,核心都是Java(或JVM语言Scala/Kotlin)写的。
43.3.1 Java大数据的核心玩家
- Hadoop:大哥级框架,HDFS分布式文件系统 + MapReduce分布式计算模型
- Spark:比MapReduce快100倍的内存计算框架,支持SQL、流处理、机器学习
- Flink:流处理领域的当红炸子鸡,实时性极强
- Hive:把SQL翻译成MapReduce,让分析师也能玩大数据
- Kafka:消息队列,大数据系统的"水管",扛住百万级TPS
43.3.2 用Spark做一个词频统计
词频统计(Word Count)是大数据的"Hello World"。需求很简单:统计一篇文章里每个词出现了多少次。
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
| // Spark Word Count示例
// 依赖:spark-core_2.12, scala-library
// Maven: https://mvnrepository.com/artifact/org.apache.spark
package com.example.spark;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import java.util.Arrays;
import java.util.Map;
public class WordCountJob {
public static void main(String[] args) {
// ========== 第一步:创建Spark配置 ==========
// SparkConf 设置Spark应用的基本信息
// setAppName 给你的任务起个名字,方便在Web UI里查看
SparkConf conf = new SparkConf()
.setAppName("词频统计任务")
.setMaster("local[*]"); // local[*] 表示用本地所有CPU核心运行,测试用
// ========== 第二步:创建Spark上下文 ==========
// JavaSparkContext是Spark的入口,类似Spring的ApplicationContext
// 所有Spark操作都通过它发起
try (JavaSparkContext sc = new JavaSparkContext(conf)) {
System.out.println("✅ Spark任务初始化完成");
System.out.println("📍 访问 http://localhost:4040 查看Spark Web UI");
// ========== 第三步:准备数据 ==========
// 模拟一些文本数据,真实场景会从HDFS/S3读取
String text = "Java is great Java is powerful " +
"Big Data is interesting Spark makes data processing easy " +
"Java runs everywhere Scala is concise " +
"Python is popular Java is enterprise ready";
// parallelize: 将本地集合转成RDD(弹性分布式数据集)
// RDD是Spark的核心抽象,代表不可变的、分区的数据集合
JavaRDD<String> lines = sc.parallelize(Arrays.asList(text));
// ========== 第四步:转换操作(Transformation) ==========
// flatMap: 一行变多词(拆开)
// map: 词 -> (词, 1) 元组
// reduceByKey: 按词聚合统计次数
Map<String, Long> wordCounts = lines
.flatMap(line -> Arrays.asList(line.split("\\s+")).iterator())
// \\s+ 表示一个或多个空白字符(空格、Tab、换行)
.filter(word -> !word.isEmpty()) // 过滤空字符串
.mapToPair(word -> new org.apache.spark.api.java.JavaPairRDD<>(word, 1))
.reduceByKey((a, b) -> a + b) // 相同词的计数相加
.collectAsMap(); // 转成Java Map方便打印
// ========== 第五步:输出结果 ==========
System.out.println("\n📊 词频统计结果:");
System.out.println("━━━━━━━━━━━━━━━━━");
wordCounts.entrySet().stream()
.sorted((e1, e2) -> Long.compare(e2.getValue(), e1.getValue()))
// 按出现次数降序排列
.forEach(entry ->
System.out.printf(" %-15s : %d 次%n",
entry.getKey(), entry.getValue())
);
System.out.println("━━━━━━━━━━━━━━━━━");
System.out.println("共发现 " + wordCounts.size() + " 个不同的词");
} catch (Exception e) {
System.err.println("❌ Spark任务执行失败:" + e.getMessage());
e.printStackTrace();
}
}
}
|
43.3.3 大数据架构图
┌─────────────────────────────────────────────────────────────────────┐
│ 数据源层 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │用户行为 │ │ 订单 │ │ 日志 │ │ 爬虫 │ │ IoT │ │
│ │ 埋点 │ │ 数据 │ │ 数据 │ │ 数据 │ │ 传感器 │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
└───────┼────────────┼────────────┼────────────┼────────────┼────────┘
│ │ │ │ │
└────────────┴────────────┴─────┬──────┴────────────┘
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 消息队列层 │
│ Kafka (日均万亿级消息,持久化、高吞吐) │
└─────────────────────────────────┬───────────────────────────────────┘
│
┌─────────────────────────┼─────────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ 实时计算 │ │ 批处理计算 │ │ 数据仓库 │
│ Flink/Spark │ │ Spark Core │ │ Hive/Spark │
│ Streaming │ │ MapReduce │ │ SQL │
│ :8080 │ │ │ │ │
└───────┬───────┘ └───────┬───────┘ └───────┬───────┘
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ Redis │ │ HDFS │ │ MySQL/ES │
│ (实时指标) │ │ (原始数据) │ │ (查询结果) │
└───────────────┘ └───────────────┘ └───────────────┘
│ │ │
└────────────────────────┴────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 应用层 │
│ 数据可视化 (Grafana/Superset) | 数据API服务 (Spring Boot) │
└─────────────────────────────────────────────────────────────────────┘
43.3.4 Java大数据工具链
| 工具 | 作用 | 一句话说明 |
|---|
| HDFS | 分布式文件系统 | 存得下地球级别的文件 |
| MapReduce | 分布式计算 | 搬砖的分布式版本 |
| Spark | 内存计算引擎 | 比MR快100倍,兼容MR生态 |
| Flink | 流处理引擎 | 真正的实时,延迟毫秒级 |
| Kafka | 消息队列 | 大数据系统的中枢神经 |
| Hive | 数据仓库 | SQL写得好就能玩大数据 |
| HBase | NoSQL数据库 | 实时读写HDFS上的数据 |
| Zookeeper | 分布式协调 | 大数据集群的"交通警察" |
冷知识:Hadoop的名字来源于一只毛绒玩具象(Fadoop项目创始人的儿子喜欢的玩具)。所以Hadoop的Logo就是一头象,这也是为什么大数据相关项目很多都用动物命名——Spark是火花,Flink是箭矢,Zookeeper是动物园管理员……
43.4 安卓开发
安卓开发(Android Development)就是开发运行在安卓手机、平板、手表、汽车上的应用。曾几何时,Java是安卓开发的绝对主角,Android SDK就是用Java写的,安卓应用也基本是Java天下。
虽然现在Google强推Kotlin,但Java在安卓领域依然有大量存量代码和开发者。而且,正是因为Java在安卓的地位,才让Java稳坐TIOBE排行榜前列这么多年。
43.4.1 Java vs Kotlin 安卓开发
- Java:成熟稳重,存量代码多,招聘容易
- Kotlin:语法简洁,null安全,Google亲儿子
- 现状:新项目Kotlin居多,但Java代码依然大量存在
43.4.2 用Java写一个简单的安卓Activity
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
| // MainActivity.java
// 这是一个完整的安卓Activity示例
package com.example.myapp;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
/**
* MainActivity - 主界面Activity
*
* Activity是安卓四大组件之一,代表一个单独的屏幕
* 类似于Web里的页面,或桌面应用里的窗口
*/
public class MainActivity extends Activity {
// UI组件声明
private TextView tvTitle; // 文本显示组件
private Button btnClick; // 点击按钮
private int clickCount = 0; // 点击计数器
/**
* onCreate - Activity创建时调用
* 类似于Spring的@PostConstruct或init方法
*
* @param savedInstanceState 之前保存的状态,用于恢复数据
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView设置这个Activity显示的布局
// R.layout.activity_main指向res/layout/activity_main.xml
setContentView(R.layout.activity_main);
// 初始化UI组件
initViews();
// 设置点击事件
setupListeners();
System.out.println("📱 MainActivity 创建完成");
}
/**
* initViews - 初始化视图组件
* findViewById通过ID找到布局文件中的组件
*/
private void initViews() {
tvTitle = findViewById(R.id.tv_title);
btnClick = findViewById(R.id.btn_click);
// 设置初始文本
tvTitle.setText("欢迎使用Java安卓应用!");
}
/**
* setupListeners - 设置事件监听器
*/
private void setupListeners() {
// 设置按钮点击监听器
btnClick.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 每点击一次,计数器加1
clickCount++;
// 更新文本显示
String message = String.format("按钮被点击了 %d 次!", clickCount);
tvTitle.setText(message);
// Toast是安卓的短提示,类似于Snackbar
Toast.makeText(
MainActivity.this, // Context上下文
"👍 点击成功!", // 显示的文本
Toast.LENGTH_SHORT // 显示时长
).show();
System.out.println("👆 按钮点击: " + clickCount);
}
});
}
/**
* onPause - Activity暂停时调用
* 适合保存一些临时数据
*/
@Override
protected void onPause() {
super.onPause();
System.out.println("⏸ Activity暂停");
}
/**
* onResume - Activity恢复时调用
*/
@Override
protected void onResume() {
super.onResume();
System.out.println("▶ Activity恢复");
}
/**
* onDestroy - Activity销毁时调用
* 适合做一些清理工作
*/
@Override
protected void onDestroy() {
super.onDestroy();
System.out.println("🔚 Activity销毁");
}
}
|
对应的布局文件 res/layout/activity_main.xml:
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
| <?xml version="1.0" encoding="utf-8"?>
<!-- android:layout_width/height: 宽度高度,match_parent填充父容器,wrap_content自适应 -->
<!-- android:padding: 内边距 -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="24dp">
<!-- TextView,文本显示组件 -->
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello Java Android!"
android:textSize="24sp"
android:textColor="#333333"
android:layout_marginBottom="32dp"/>
<!-- Button,点击按钮 -->
<Button
android:id="@+id/btn_click"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="点我呀!"
android:textSize="18sp"
android:paddingHorizontal="32dp"
android:paddingVertical="12dp"/>
</LinearLayout>
|
43.4.3 安卓架构图
┌─────────────────────────────────────────────────────────────────┐
│ 用户界面层 (UI Layer) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Activity / Fragment │ │
│ │ (处理用户交互,管理生命周期) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ ViewModel │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ ViewModel │ │
│ │ (存储UI数据,处理业务逻辑,配置变更 surviving) │ │
│ └─────────────────────────────────────────────────────────┘ │
└──────────────────────────────┬──────────────────────────────────┘
│ LiveData / StateFlow
▼
┌──────────────────────────────────────────────────────────────────┐
│ 数据层 (Data Layer) │
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │
│ │ Repository │ │ Room │ │ Retrofit │ │
│ │ (数据仓库) │ │ (本地数据库) │ │ (网络请求) │ │
│ └───────┬────────┘ └────────────────┘ └────────────────┘ │
│ │ │
└───────────┼────────────────────────────────────────────────────────┘
▼
┌──────────────────────────────────────────────────────────────────┐
│ 系统服务层 (Android Framework) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │
│ │ Activity │ │ Package │ │ Window │ │ Content │ │
│ │ Manager │ │ Manager │ │ Manager │ │ Provider │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │
│ │Notification│ │ Sensor │ │ GPS │ │ Alarm │ │
│ │ Manager │ │ Manager │ │ Manager │ │ Manager │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────┐
│ Linux Kernel │
│ (Binder驱动、内存管理、进程调度、网络堆栈) │
└──────────────────────────────────────────────────────────────────┘
43.4.4 Java在安卓生态中的地位
2017年Google I/O大会:Google宣布Kotlin成为安卓官方一级开发语言。
但是!Java开发者不用慌:
- 安卓Framework依然是Java API
- 大量存量代码是Java写的
- Java 8+的特性(Lambda、Stream)安卓都支持
- Kotlin和Java可以混编,互相调用无压力
| 对比项 | Java | Kotlin |
|---|
| 语法简洁度 | 较啰嗦 | 简洁 |
| Null安全 | NPE常客 | nullable type |
| 协程支持 | 无 | 原生支持 |
| 生态 | AndroidX完全兼容 | AndroidX完全兼容 |
| 学习曲线 | 平缓 | 稍有坡度 |
| 招聘需求 | 依然很多 | 越来越多 |
43.5 金融系统
金融系统是Java的"舒适区"。为什么这么说?因为金融系统讲究的是:
- 稳定性:7x24小时不能宕机,宕机就是钱
- 安全性:黑客天天盯着,漏洞就是灾难
- 一致性:钱不能算错,差一分钱都是大事
- 可追溯:每一笔交易都要能查到来源
Java恰好在这些方面非常契合,再加上强类型检查、异常机制、成熟的事务支持,让Java成为金融系统的不二之选。
43.5.1 金融系统的核心需求
- 事务控制:ACID(原子性、一致性、隔离性、持久性)是基本要求
- 分布式事务:跨系统的钱款转移不能出错
- 高可用:多机房部署,故障自动切换
- 风控:实时拦截异常交易
- 审计:所有操作都要记录日志
43.5.2 用Java写一个转账业务示例
转账(Transfer)是金融系统最经典也最考验技术的场景。看似简单的一句话"从A账户扣钱,加到B账户",背后藏着无数坑:并发、超时、数据不一致……
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
| package com.example.finance;
import java.math.BigDecimal; // 金额计算必须用BigDecimal,double会有精度问题!
import java.time.LocalDateTime;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;
/**
* 银行核心转账系统
*
* 金融系统铁律:
* 1. 金额用BigDecimal,绝不用double
* 2. 所有操作必须可审计
* 3. 并发控制要严谨
*/
public class TransferService {
// ========== 账户实体 ==========
static class Account {
private final String accountId; // 账户ID
private String ownerName; // 持卡人姓名
private BigDecimal balance; // 余额(必须是BigDecimal!)
private final ReentrantLock lock; // 账户级锁,保证并发安全
public Account(String accountId, String ownerName, BigDecimal initialBalance) {
this.accountId = accountId;
this.ownerName = ownerName;
this.balance = initialBalance;
this.lock = new ReentrantLock();
}
// getter和业务方法
public String getAccountId() { return accountId; }
public BigDecimal getBalance() { return balance; }
// 存款
public void deposit(BigDecimal amount) {
if (amount.compareTo(BigDecimal.ZERO) <= 0) {
throw new IllegalArgumentException("存款金额必须大于0");
}
balance = balance.add(amount);
}
// 取款(带余额检查)
public boolean withdraw(BigDecimal amount) {
if (amount.compareTo(BigDecimal.ZERO) <= 0) {
throw new IllegalArgumentException("取款金额必须大于0");
}
if (balance.compareTo(amount) < 0) {
return false; // 余额不足
}
balance = balance.subtract(amount);
return true;
}
}
// ========== 交易记录 ==========
static class Transaction {
private final String txId;
private final String fromAccount;
private final String toAccount;
private final BigDecimal amount;
private final LocalDateTime timestamp;
private final String status;
private final String remark;
public Transaction(String txId, String fromAccount, String toAccount,
BigDecimal amount, String status, String remark) {
this.txId = txId;
this.fromAccount = fromAccount;
this.toAccount = toAccount;
this.amount = amount;
this.timestamp = LocalDateTime.now();
this.status = status;
this.remark = remark;
}
@Override
public String toString() {
return String.format(
"交易流水号: %s\n" +
"转出账户: %s\n" +
"转入账户: %s\n" +
"金额: ¥%s\n" +
"时间: %s\n" +
"状态: %s\n" +
"备注: %s",
txId, fromAccount, toAccount, amount, timestamp, status, remark
);
}
}
// ========== 转账服务核心 ==========
private final ConcurrentHashMap<String, Account> accounts;
private final AtomicLong txSequence;
public TransferService() {
this.accounts = new ConcurrentHashMap<>();
this.txSequence = new AtomicLong(1);
// 初始化两个测试账户
Account acc1 = new Account("ACC001", "张三", new BigDecimal("10000.00"));
Account acc2 = new Account("ACC002", "李四", new BigDecimal("5000.00"));
accounts.put(acc1.getAccountId(), acc1);
accounts.put(acc2.getAccountId(), acc2);
}
/**
* 转账核心方法
*
* 金融系统转账必须保证:
* 1. 原子性:要么成功,要么失败,不能出现扣了钱但没到账的情况
* 2. 一致性:转出钱数 = 转入钱数,余额不能凭空消失
* 3. 隔离性:并发转账不能互相干扰
* 4. 持久性:交易记录必须落盘
*
* 这里用了"账户顺序加锁"来避免死锁
*/
public Transaction transfer(String fromAccountId, String toAccountId,
BigDecimal amount, String remark) {
// ========== 前置校验 ==========
if (amount.compareTo(BigDecimal.ZERO) <= 0) {
throw new IllegalArgumentException("转账金额必须大于0");
}
Account fromAccount = accounts.get(fromAccountId);
Account toAccount = accounts.get(toAccountId);
if (fromAccount == null) {
throw new IllegalArgumentException("转出账户不存在: " + fromAccountId);
}
if (toAccount == null) {
throw new IllegalArgumentException("转入账户不存在: " + toAccountId);
}
if (fromAccountId.equals(toAccountId)) {
throw new IllegalArgumentException("不能给自己转账");
}
// ========== 加锁(避免死锁:按账户ID顺序加锁) ==========
Account first = fromAccountId.compareTo(toAccountId) < 0 ? fromAccount : toAccount;
Account second = fromAccountId.compareTo(toAccountId) < 0 ? toAccount : fromAccount;
first.lock.lock();
second.lock.lock();
try {
// ========== 业务逻辑 ==========
// 检查余额
if (fromAccount.getBalance().compareTo(amount) < 0) {
return new Transaction(
generateTxId(), fromAccountId, toAccountId, amount,
"FAIL", "余额不足"
);
}
// 执行转账:扣款 + 入账
fromAccount.withdraw(amount);
toAccount.deposit(amount);
// 生成交易流水
Transaction tx = new Transaction(
generateTxId(), fromAccountId, toAccountId, amount,
"SUCCESS", remark
);
// ========== 审计日志(真实系统会写数据库或Kafka)==========
System.out.println("💰 转账成功!");
System.out.println(tx);
return tx;
} finally {
// ========== 释放锁(finally中释放,保证一定执行)==========
second.lock.unlock();
first.lock.unlock();
}
}
/**
* 查询账户余额
*/
public BigDecimal getBalance(String accountId) {
Account account = accounts.get(accountId);
if (account == null) {
throw new IllegalArgumentException("账户不存在: " + accountId);
}
return account.getBalance();
}
private String generateTxId() {
return String.format("TX%s%06d", System.currentTimeMillis(), txSequence.getAndIncrement());
}
// ========== 测试入口 ==========
public static void main(String[] args) {
TransferService service = new TransferService();
System.out.println("=== 转账系统测试 ===\n");
// 查看初始余额
System.out.println("📊 初始余额:");
System.out.println(" 张三: ¥" + service.getBalance("ACC001"));
System.out.println(" 李四: ¥" + service.getBalance("ACC002"));
System.out.println("\n" + "═".repeat(50));
// 执行转账
System.out.println("💸 执行转账:张三转给李四 ¥3000");
service.transfer("ACC001", "ACC002", new BigDecimal("3000"), "测试转账");
System.out.println("\n" + "═".repeat(50));
// 查看转账后余额
System.out.println("📊 转账后余额:");
System.out.println(" 张三: ¥" + service.getBalance("ACC001"));
System.out.println(" 李四: ¥" + service.getBalance("ACC002"));
System.out.println("\n" + "═".repeat(50));
// 测试余额不足
System.out.println("💸 执行转账:张三转给李四 ¥999999");
Transaction result = service.transfer("ACC001", "ACC002",
new BigDecimal("999999"), "余额不足测试");
System.out.println("结果: " + result.status);
}
}
|
43.5.3 金融系统架构图
┌──────────────────────────────────────────────────────────────────────┐
│ 负载均衡层 │
│ F5 / Nginx (SSL卸载、限流) │
└────────────────────────────┬─────────────────────────────────────────┘
│
┌────────────────────────────▼─────────────────────────────────────────┐
│ API网关层 │
│ (Spring Cloud Gateway / Kong) │
│ 统一鉴权、参数校验、请求路由、限流熔断 │
└────────────────────────────┬─────────────────────────────────────────┘
│
┌────────────────────────┼────────────────────────┐
│ │ │
▼ ▼ ▼
┌───────────┐ ┌───────────┐ ┌───────────┐
│ 账户服务 │ │ 交易服务 │ │ 支付服务 │
│ :8081 │ │ :8082 │ │ :8083 │
└─────┬─────┘ └─────┬─────┘ └─────┬─────┘
│ │ │
└─────────────────────┼──────────────────────┘
│
┌───────────────────────┼───────────────────────┐
│ │ │
▼ ▼ ▼
┌───────────┐ ┌───────────┐ ┌───────────┐
│ Oracle/ │ │ 分布式 │ │ 消息队列 │
│ PostgreSQL│ │ 事务 │ │ Kafka │
│ (主库) │ │ Seata │ │ (异步解耦) │
└───────────┘ └───────────┘ └───────────┘
│
▼
┌───────────────┐
│ 分布式缓存 │
│ Redis Cluster │
│ (Session/热点) │
└───────────────┘
│
▼
┌───────────────┐
│ 文件存储 │
│ MinIO/OSS │
│ (合同/凭证) │
└───────────────┘
43.5.4 金融系统的Java技术栈
| 场景 | 技术选型 | 说明 |
|---|
| 核心账户 | Oracle/DB2 + Spring Transaction | 强一致性,XA两阶段提交 |
| 交易处理 | Seata / TCC | 分布式事务解决方案 |
| 实时风控 | Flink + Redis | 毫秒级风控拦截 |
| 异步通知 | Kafka / RocketMQ | 交易结果异步推送 |
| 文件存储 | MinIO / 阿里OSS | 合同、凭证存储 |
| 日志审计 | ELK (Elasticsearch) | 全量日志查询分析 |
| 监控告警 | Prometheus + Grafana | 业务指标监控 |
金融系统忠告:在金融系统里,代码写错一行可能就是几百万的损失。所以金融系统的代码审查(Code Review)特别严格,测试覆盖率要求99%以上。而且,金融系统宁可慢一点,也要稳一点——“宁可少赚,不能出错"是金融系统的第一原则。
43.6 游戏服务器
游戏服务器(Game Server)是Java的又一个重要战场。虽然很多人觉得C++才是游戏开发的主流(确实客户端/引擎层面C++是王者),但在服务器端,Java凭借高并发、易开发、跨平台等优势,占据了相当大的市场份额。
尤其是MMORPG(大型多人在线角色扮演游戏)、手游服务端、休闲游戏等领域,Java的身影随处可见。
43.6.1 Java做游戏服务器的优势
- Netty框架:高性能NIO网络框架,Java游戏服务器的标配
- Goroutine类似物:虽然Java没有原生协程,但线程池+异步可以应对大部分场景
- 跨平台:安卓、iOS、PC端的游戏服务器可以用同一套代码
- 丰富的中间件:Redis做缓存、Kafka做消息、MySQL做存储,一条龙服务
- 成熟稳定:经过无数大型在线游戏验证
43.6.2 用Netty写一个简单的游戏聊天服务器
游戏服务器最核心的功能之一就是即时通讯。想象一下你在游戏里喊一声"副本来人来人来人”,几十个人同时收到,这就是聊天服务器干的事。
Netty是JBoss开源的高性能网络框架,基于NIO(Non-blocking I/O,非阻塞IO),是Java领域处理高并发网络连接的首选。
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
| // Netty聊天服务器示例
// 依赖:io.netty:netty-all:4.1.100.Final
package com.example.game.chat;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
import java.util.Set;
/**
* Netty游戏聊天服务器
*
* 核心概念:
* - Boss Group:接收连接请求的线程池
* - Worker Group:处理IO读写的线程池
* - Channel:网络连接的抽象
* - Handler:处理具体业务逻辑的处理器
*/
public class ChatServer {
private final int port;
// 在线玩家列表:playerId -> Channel
private final Map<String, Channel> onlinePlayers = new ConcurrentHashMap<>();
public ChatServer(int port) {
this.port = port;
}
public void start() throws InterruptedException {
// Boss线程组:处理连接请求,通常1-2个线程就够了
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
// Worker线程组:处理读写和业务逻辑,根据负载调整
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
// ServerBootstrap:Netty服务启动辅助类,链式配置
ServerBootstrap bootstrap = new ServerBootstrap()
.group(bossGroup, workerGroup) // 绑定线程组
.channel(NioServerSocketChannel.class) // NIO类型
.option(ChannelOption.SO_BACKLOG, 128) // 连接队列长度
.childOption(ChannelOption.SO_KEEPALIVE, true) // TCP保活
.childOption(ChannelOption.TCP_NODELAY, true) // 禁用Nagle算法,低延迟
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ChannelPipeline pipeline = ch.pipeline();
// 编解码器:将ByteBuf <-> String互相转换
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
// 业务处理器
pipeline.addLast(new ChatHandler(onlinePlayers));
}
});
// 绑定端口并启动
ChannelFuture future = bootstrap.bind(port).sync();
System.out.println("🎮 游戏聊天服务器已启动,端口:" + port);
System.out.println("📡 在线玩家数:" + onlinePlayers.size());
// 等待服务器关闭(优雅退出)
future.channel().closeFuture().sync();
} finally {
// 释放线程组资源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws InterruptedException {
new ChatServer(8888).start();
}
}
/**
* 聊天业务处理器
*
* @Sharable:表示这个Handler可以在多个Channel间共享
*/
@ChannelHandler.Sharable
class ChatHandler extends ChannelInboundHandlerAdapter {
private final Map<String, Channel> onlinePlayers;
public ChatHandler(Map<String, Channel> onlinePlayers) {
this.onlinePlayers = onlinePlayers;
}
/**
* channelActive:客户端连接建立时触发
*/
@Override
public void channelActive(ChannelHandlerContext ctx) {
String playerId = "玩家" + ctx.channel().remoteAddress();
onlinePlayers.put(playerId, ctx.channel());
System.out.println("✅ " + playerId + " 上线了!当前在线:" + onlinePlayers.size());
// 广播欢迎消息
broadcast("【系统】" + playerId + " 进入了聊天室", null);
}
/**
* channelRead:收到消息时触发
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
String message = (String) msg;
String playerId = getPlayerId(ctx.channel());
System.out.println("📨 " + playerId + " 说:" + message);
// 解析消息格式:@玩家名:内容 表示私聊,否则是公聊
if (message.startsWith("@")) {
int colonIdx = message.indexOf(':');
if (colonIdx > 0) {
String targetName = message.substring(1, colonIdx);
String privateMsg = message.substring(colonIdx + 1);
sendPrivateMessage(playerId, targetName, privateMsg);
}
} else {
// 公聊,广播给所有人
broadcast("【公聊】" + playerId + ":" + message, ctx.channel());
}
}
/**
* channelInactive:客户端断开连接时触发
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) {
String playerId = getPlayerId(ctx.channel());
onlinePlayers.remove(playerId);
System.out.println("❌ " + playerId + " 下线了!当前在线:" + onlinePlayers.size());
broadcast("【系统】" + playerId + " 离开了聊天室", null);
}
/**
* exceptionCaught:发生异常时触发
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
System.err.println("⚠️ 连接异常:" + cause.getMessage());
ctx.close();
}
// ========== 私有辅助方法 ==========
private String getPlayerId(Channel channel) {
// 简化:直接用远程地址作为ID
return "玩家" + channel.remoteAddress();
}
/**
* 广播消息给所有在线玩家
*/
private void broadcast(String message, Channel exclude) {
String data = message + "\n";
for (Channel ch : onlinePlayers.values()) {
if (ch != exclude && ch.isActive()) {
ch.writeAndFlush(data);
}
}
}
/**
* 发送私信
*/
private void sendPrivateMessage(String from, String toName, String message) {
Channel target = onlinePlayers.get(toName);
if (target != null && target.isActive()) {
String data = "【私聊】" + from + " 对你说:" + message + "\n";
target.writeAndFlush(data);
// 同时告诉自己发送成功了
Channel sender = onlinePlayers.get(from);
if (sender != null) {
sender.writeAndFlush("【私聊】你对 " + toName + " 说:" + message + "\n");
}
} else {
// 目标不在线,告知发送者
Channel sender = onlinePlayers.get(from);
if (sender != null) {
sender.writeAndFlush("【系统】玩家 " + toName + " 不在线或不存在\n");
}
}
}
}
|
43.6.3 游戏服务器架构图
┌──────────────────────────────────────────────────────────────────────┐
│ 负载均衡层 │
│ LBS (负载均衡器) + GSLB (全局负载均衡) │
│ 玩家就近接入、异地容灾、流量调度 │
└─────────────────────────────┬────────────────────────────────────────┘
│
┌─────────────────────────────▼────────────────────────────────────────┐
│ 网关节点层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Gateway 1 │ │ Gateway 2 │ │ Gateway 3 │ │
│ │ Netty │ │ Netty │ │ Netty │ │
│ │ :7001 │ │ :7002 │ │ :7003 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │ │ │
└───────────┼────────────────┼────────────────┼────────────────────────┘
│ │ │
└────────────────┼────────────────┘
│
┌────────────────────┼────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ 战斗服务 │ │ 聊天服务 │ │ 物品服务 │
│ (实时副本) │ │ (私聊/公会) │ │ (交易/背包) │
└───────┬───────┘ └───────┬───────┘ └───────┬───────┘
│ │ │
└──────────────────────┼──────────────────────┘
│
┌─────────────────────┼─────────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ Redis │ │ MySQL │ │ MongoDB │
│ (实时数据/ │ │ (永久存档/ │ │ (日志/聊天 │
│ 排行榜/缓存) │ │ 账户/装备) │ │ 记录) │
└───────────────┘ └───────────────┘ └───────────────┘
│ │ │
└─────────────────────┴─────────────────────┘
│
▼
┌─────────────────────┐
│ Kafka │
│ (消息总线/事件驱动) │
└─────────────────────┘
43.6.4 游戏服务器技术选型
| 场景 | 推荐技术 | 说明 |
|---|
| 网络通信 | Netty / Mina | 高性能NIO框架 |
| 游戏逻辑 | Java Thread + Actor模型 | 轻量级并发 |
| 实时战斗 | Jetty / Netty WebSocket | 保持连接,实时推送 |
| 数据缓存 | Redis Cluster | 热点数据、排行榜、会话 |
| 持久存储 | MySQL + Sharding | 水平分库分表 |
| 日志存储 | MongoDB / ELK | 玩家行为日志 |
| 消息队列 | Kafka / Disruptor | 高效事件分发 |
| 定时任务 | Quartz / Saturn | 每日奖励、排行榜刷新 |
游戏老兵经验谈:游戏服务器最怕两件事——卡顿和回档。卡顿影响体验,回档要命。所以游戏服务器的核心设计原则是:宁可请求失败重试,也不要数据错乱。另外,游戏服务器的性能调优是个技术活,JVM参数、Netty线程模型、GC策略都要精心调配。
本章小结
本章我们详细探讨了Java在各个领域的应用场景:
主要内容回顾
Web后端开发
- Java是Web后端的老牌劲旅,Spring Boot让开发效率飞起
- 经典组合:Spring Boot + MySQL + Redis
- 生态完善,文档丰富,招人容易
微服务架构
- Spring Cloud提供了一整套微服务解决方案
- 服务注册发现、负载均衡、熔断器、配置中心一应俱全
- 拆分虽好,但要根据团队规模和业务复杂度谨慎决策
大数据技术栈
- Hadoop、Spark、Flink三分天下
- Java/JVM系占据大数据领域半壁江山
- 词频统计只是开始,数据湖、实时分析才是星辰大海
安卓开发
- Java曾是安卓开发的绝对主角,Kotlin是后起之秀
- Android Framework依然基于Java API
- 两者可以混编,选择哪个取决于项目和团队
金融系统
- Java是金融系统的首选语言之一
- BigDecimal、事务控制、分布式事务是核心技能
- 稳定性 > 性能,安全第一
游戏服务器
- Netty是Java游戏服务器的标配网络框架
- 高并发、低延迟是核心诉求
- 玩家数据不能丢、不能错,这是铁律
关键知识点
| 概念 | 解释 |
|---|
| Spring Boot | Java Web开发神器,自动配置,开箱即用 |
| 微服务 | 大拆小、独立部署、独立扩展的架构模式 |
| Netty | 高性能NIO网络框架,游戏服务器标配 |
| Hadoop/Spark/Flink | 大数据处理三剑客 |
| BigDecimal | 金融计算必须用,double有精度陷阱 |
| ACID | 事务的四大特性:原子性、一致性、隔离性、持久性 |
写在最后
Java之所以能在一个又一个领域长盛不衰,靠的不是运气,而是稳定性、生态和人才。无论你是想写Web、搞大数据、做安卓还是进金融,Java都是一个不会错的选择。
记住:语言只是工具,思路才是核心。学会了一门语言的核心思想,换语言不过是语法糖的变化。祝你学有所成,早日成为某个领域的Java大牛!🦄