
文章目录
-
- 第一部分:转型背景与核心差异分析
-
- [1.1 为什么需要从 .NET 转型到 Java](#1.1 为什么需要从 .NET 转型到 Java)
- [1.2 .NET 与 Java 核心架构差异](#1.2 .NET 与 Java 核心架构差异)
-
- [1.2.1 运行时环境对比](#1.2.1 运行时环境对比)
- [1.2.2 内存管理机制](#1.2.2 内存管理机制)
- [1.3 心态调整与学习策略](#1.3 心态调整与学习策略)
-
- [1.3.1 相似性利用](#1.3.1 相似性利用)
- [1.3.2 差异性重视](#1.3.2 差异性重视)
- [第二部分:Java 语言基础深入学习](#第二部分:Java 语言基础深入学习)
-
- [2.1 Java 语法核心概念](#2.1 Java 语法核心概念)
-
- [2.1.1 基本数据类型与包装类](#2.1.1 基本数据类型与包装类)
- [2.1.2 字符串处理](#2.1.2 字符串处理)
- [2.2 面向对象编程深入](#2.2 面向对象编程深入)
-
- [2.2.1 类与继承](#2.2.1 类与继承)
- [2.2.2 访问控制与封装](#2.2.2 访问控制与封装)
- [2.3 异常处理机制](#2.3 异常处理机制)
- [2.4 集合框架](#2.4 集合框架)
- [第三部分:Java 生态系统与工具链](#第三部分:Java 生态系统与工具链)
-
- [3.1 构建工具:Maven 与 Gradle](#3.1 构建工具:Maven 与 Gradle)
-
- [3.1.1 Maven 详细配置](#3.1.1 Maven 详细配置)
- [3.1.2 Gradle 构建脚本](#3.1.2 Gradle 构建脚本)
- [3.2 开发工具与环境配置](#3.2 开发工具与环境配置)
-
- [3.2.1 IDE 选择与配置](#3.2.1 IDE 选择与配置)
- [3.2.2 版本控制集成](#3.2.2 版本控制集成)
- [3.3 测试框架](#3.3 测试框架)
-
- [3.3.1 JUnit 测试](#3.3.1 JUnit 测试)
- [3.3.2 Mockito 模拟测试](#3.3.2 Mockito 模拟测试)
- [第四部分:Spring 框架深入学习](#第四部分:Spring 框架深入学习)
-
- [4.1 Spring Core 核心概念](#4.1 Spring Core 核心概念)
-
- [4.1.1 依赖注入与控制反转](#4.1.1 依赖注入与控制反转)
- [4.1.2 AOP 面向切面编程](#4.1.2 AOP 面向切面编程)
- [4.2 Spring Boot 自动化配置](#4.2 Spring Boot 自动化配置)
-
- [4.2.1 Spring Boot 应用启动](#4.2.1 Spring Boot 应用启动)
- [4.2.2 应用配置文件](#4.2.2 应用配置文件)
- [4.3 Spring MVC Web 开发](#4.3 Spring MVC Web 开发)
-
- [4.3.1 RESTful API 开发](#4.3.1 RESTful API 开发)
- 第五部分:数据库与持久层技术
-
- [5.1 JPA 与 Hibernate](#5.1 JPA 与 Hibernate)
-
- [5.1.1 实体类映射](#5.1.1 实体类映射)
- [5.1.2 Repository 数据访问层](#5.1.2 Repository 数据访问层)
- [5.2 数据库迁移与版本控制](#5.2 数据库迁移与版本控制)
-
- [5.2.1 Flyway 数据库迁移](#5.2.1 Flyway 数据库迁移)
- [5.2.2 Flyway 配置](#5.2.2 Flyway 配置)
- 第六部分:高级主题与最佳实践
-
- [6.1 性能优化与缓存](#6.1 性能优化与缓存)
-
- [6.1.1 Redis 缓存集成](#6.1.1 Redis 缓存集成)
- [6.2 安全与认证授权](#6.2 安全与认证授权)
-
- [6.2.1 Spring Security 配置](#6.2.1 Spring Security 配置)
- [6.3 微服务与分布式系统](#6.3 微服务与分布式系统)
-
- [6.3.1 Spring Cloud 微服务配置](#6.3.1 Spring Cloud 微服务配置)
- 第七部分:部署与运维
-
- [7.1 Docker 容器化部署](#7.1 Docker 容器化部署)
-
- [7.1.1 Dockerfile 配置](#7.1.1 Dockerfile 配置)
- [7.1.2 Docker Compose 配置](#7.1.2 Docker Compose 配置)
- [7.2 监控与日志](#7.2 监控与日志)
-
- [7.2.1 Spring Boot Actuator 配置](#7.2.1 Spring Boot Actuator 配置)
- [7.2.2 自定义健康检查](#7.2.2 自定义健康检查)
- 第八部分:学习路线与持续提升
-
- [8.1 分阶段学习计划](#8.1 分阶段学习计划)
-
- 阶段一:基础入门(1-2个月)
- [阶段二:Spring 框架(2-3个月)](#阶段二:Spring 框架(2-3个月))
- 阶段三:高级特性(2-3个月)
- 阶段四:生产实践(持续)
- [8.2 持续学习资源](#8.2 持续学习资源)
- [8.3 社区参与](#8.3 社区参与)
- 总结

第一部分:转型背景与核心差异分析
1.1 为什么需要从 .NET 转型到 Java
在当前的技术环境中,从 .NET 转型到 Java 通常基于以下考虑:
- 跨平台需求增加:Java 的"一次编写,到处运行"特性在云原生和容器化环境中具有优势
- 生态系统丰富性:Java 拥有庞大的开源生态系统和社区支持
- 成本考量:Java 开源技术栈可以降低许可成本
- 人才市场因素:Java 开发者在全球范围内更为普及
- 企业级应用成熟度:Java 在企业级应用和大规模系统中有着深厚的积累
1.2 .NET 与 Java 核心架构差异
1.2.1 运行时环境对比
.NET CLR vs JVM:
csharp
// .NET 中的类型系统示例
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public virtual void Display()
{
Console.WriteLine($"Name: {Name}, Age: {Age}");
}
}
java
// Java 中的对应实现
public class Person {
private String name;
private int age;
public Person() {}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public void display() {
System.out.println("Name: " + name + ", Age: " + age);
}
}
主要差异:
- Java 中没有属性语法,使用 getter/setter 方法
- Java 方法默认是虚方法(virtual),而 C# 需要显式声明
- Java 包机制与 .NET 命名空间有相似性但实现不同
1.2.2 内存管理机制
.NET GC vs Java GC:
csharp
// .NET 中的资源管理
public class ResourceHandler : IDisposable
{
private bool disposed = false;
public void ProcessData()
{
if (disposed)
throw new ObjectDisposedException(nameof(ResourceHandler));
// 处理逻辑
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// 释放托管资源
}
// 释放非托管资源
disposed = true;
}
}
~ResourceHandler()
{
Dispose(false);
}
}
java
// Java 中的资源管理
public class ResourceHandler implements AutoCloseable {
private boolean closed = false;
public void processData() {
if (closed) {
throw new IllegalStateException("ResourceHandler is closed");
}
// 处理逻辑
}
@Override
public void close() {
if (!closed) {
// 释放资源
closed = true;
}
}
// Java 7+ 的 try-with-resources
public static void main(String[] args) {
try (ResourceHandler handler = new ResourceHandler()) {
handler.processData();
} catch (Exception e) {
e.printStackTrace();
}
}
}
1.3 心态调整与学习策略
1.3.1 相似性利用
- 面向对象编程概念相通
- 设计模式应用基本一致
- 软件开发原则通用
1.3.2 差异性重视
- 平台特性差异
- 生态系统工具链
- 部署和运维方式
第二部分:Java 语言基础深入学习
2.1 Java 语法核心概念
2.1.1 基本数据类型与包装类
java
// Java 基本数据类型与包装类
public class DataTypesExample {
public static void main(String[] args) {
// 基本数据类型
byte byteValue = 127;
short shortValue = 32767;
int intValue = 2147483647;
long longValue = 9223372036854775807L; // 注意 L 后缀
float floatValue = 3.14f; // 注意 f 后缀
double doubleValue = 3.141592653589793;
char charValue = 'A';
boolean booleanValue = true;
// 对应的包装类
Byte byteObj = byteValue;
Short shortObj = shortValue;
Integer intObj = intValue;
Long longObj = longValue;
Float floatObj = floatValue;
Double doubleObj = doubleValue;
Character charObj = charValue;
Boolean booleanObj = booleanValue;
// 自动装箱和拆箱
Integer autoBoxed = 100; // 自动装箱
int autoUnboxed = autoBoxed; // 自动拆箱
// 与 .NET 对比:Java 有明确的原始类型和包装类型区分
}
}
2.1.2 字符串处理
java
public class StringHandling {
public static void main(String[] args) {
// 字符串创建
String str1 = "Hello";
String str2 = new String("World");
// 字符串不可变性
String original = "Java";
String modified = original.concat(" Programming");
System.out.println(original); // 输出: Java
System.out.println(modified); // 输出: Java Programming
// StringBuilder 用于可变字符串操作
StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(" ");
sb.append("World");
String result = sb.toString();
System.out.println(result); // 输出: Hello World
// StringBuffer 线程安全版本
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("Thread");
stringBuffer.append("Safe");
// 与 C# 对比:Java 字符串也是不可变的,但 Java 有 StringBuilder/StringBuffer
}
}
2.2 面向对象编程深入
2.2.1 类与继承
java
// 基类
public abstract class Animal {
protected String name;
protected int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
// 抽象方法
public abstract void makeSound();
// 具体方法
public void sleep() {
System.out.println(name + " is sleeping");
}
// final 方法,不能被子类重写
public final void breathe() {
System.out.println(name + " is breathing");
}
}
// 接口
public interface Pet {
void play();
String getOwner();
}
// 继承与实现
public class Dog extends Animal implements Pet {
private String owner;
public Dog(String name, int age, String owner) {
super(name, age); // 调用父类构造函数
this.owner = owner;
}
@Override
public void makeSound() {
System.out.println("Woof! Woof!");
}
@Override
public void play() {
System.out.println(name + " is playing with " + owner);
}
@Override
public String getOwner() {
return owner;
}
// 静态方法
public static void describe() {
System.out.println("Dogs are loyal animals");
}
}
2.2.2 访问控制与封装
java
public class AccessModifiersExample {
// private - 仅当前类可见
private String privateField = "private";
// default (package-private) - 同包可见
String defaultField = "default";
// protected - 同包和子类可见
protected String protectedField = "protected";
// public - 所有类可见
public String publicField = "public";
// getter 和 setter 方法
public String getPrivateField() {
return privateField;
}
public void setPrivateField(String value) {
this.privateField = value;
}
}
2.3 异常处理机制
java
public class ExceptionHandling {
// 检查型异常
public void readFile(String filename) throws IOException {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(filename));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (FileNotFoundException e) {
System.err.println("File not found: " + filename);
throw e; // 重新抛出异常
} catch (IOException e) {
System.err.println("Error reading file: " + e.getMessage());
throw e;
} finally {
// 确保资源被释放
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
System.err.println("Error closing reader: " + e.getMessage());
}
}
}
}
// 使用 try-with-resources (Java 7+)
public void readFileModern(String filename) throws IOException {
try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} // 自动调用 reader.close()
}
// 非检查型异常
public void divideNumbers(int a, int b) {
if (b == 0) {
throw new IllegalArgumentException("Divisor cannot be zero");
}
int result = a / b;
System.out.println("Result: " + result);
}
// 自定义异常
public static class CustomException extends Exception {
public CustomException(String message) {
super(message);
}
public CustomException(String message, Throwable cause) {
super(message, cause);
}
}
}
2.4 集合框架
java
import java.util.*;
import java.util.stream.Collectors;
public class CollectionExamples {
public void listExamples() {
// ArrayList - 类似 C# List<T>
List<String> arrayList = new ArrayList<>();
arrayList.add("Apple");
arrayList.add("Banana");
arrayList.add("Orange");
// LinkedList
List<String> linkedList = new LinkedList<>();
linkedList.add("First");
linkedList.add("Second");
// 遍历方式
for (String fruit : arrayList) {
System.out.println(fruit);
}
// 使用迭代器
Iterator<String> iterator = arrayList.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
// Java 8+ Stream API
arrayList.stream()
.filter(f -> f.startsWith("A"))
.forEach(System.out::println);
}
public void setExamples() {
// HashSet - 无序,不允许重复
Set<String> hashSet = new HashSet<>();
hashSet.add("Apple");
hashSet.add("Banana");
hashSet.add("Apple"); // 不会被添加
// TreeSet - 有序
Set<String> treeSet = new TreeSet<>();
treeSet.add("Orange");
treeSet.add("Apple");
treeSet.add("Banana");
// 输出顺序: Apple, Banana, Orange
}
public void mapExamples() {
// HashMap - 类似 C# Dictionary<TKey, TValue>
Map<String, Integer> hashMap = new HashMap<>();
hashMap.put("John", 25);
hashMap.put("Jane", 30);
hashMap.put("Bob", 35);
// 获取值
Integer age = hashMap.get("John");
// 遍历
for (Map.Entry<String, Integer> entry : hashMap.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// Java 8+ 方式
hashMap.forEach((key, value) -> System.out.println(key + ": " + value));
// TreeMap - 按键排序
Map<String, Integer> treeMap = new TreeMap<>();
treeMap.put("Orange", 5);
treeMap.put("Apple", 3);
treeMap.put("Banana", 7);
// 按键顺序: Apple, Banana, Orange
}
public void streamExamples() {
List<String> names = Arrays.asList("John", "Jane", "Bob", "Alice", "Charlie");
// Stream 操作
List<String> result = names.stream()
.filter(name -> name.length() > 4)
.map(String::toUpperCase)
.sorted()
.collect(Collectors.toList());
System.out.println(result); // [ALICE, CHARLIE]
// 分组
Map<Integer, List<String>> groupedByLength = names.stream()
.collect(Collectors.groupingBy(String::length));
System.out.println(groupedByLength);
}
}
第三部分:Java 生态系统与工具链
3.1 构建工具:Maven 与 Gradle
3.1.1 Maven 详细配置
xml
<!-- pom.xml 示例 -->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 项目坐标 -->
<groupId>com.example</groupId>
<artifactId>my-java-app</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>5.3.9</spring.version>
</properties>
<dependencies>
<!-- Spring Framework -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- 日志 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.32</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 编译器插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
<!-- 打包插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<archive>
<manifest>
<mainClass>com.example.MainApplication</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
3.1.2 Gradle 构建脚本
groovy
// build.gradle 示例
plugins {
id 'java'
id 'application'
}
group = 'com.example'
version = '1.0.0'
sourceCompatibility = '11'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework:spring-context:5.3.9'
implementation 'org.slf4j:slf4j-api:1.7.32'
testImplementation 'junit:junit:4.13.2'
}
application {
mainClassName = 'com.example.MainApplication'
}
// 自定义任务
task createStartScripts(type: CreateStartScripts) {
mainClass = 'com.example.MainApplication'
applicationName = 'myapp'
outputDir = new File(project.buildDir, 'scripts')
classpath = jar.outputs.files + project.configurations.runtimeClasspath
}
// 测试配置
test {
useJUnit()
testLogging {
events "passed", "skipped", "failed"
exceptionFormat "full"
}
}
3.2 开发工具与环境配置
3.2.1 IDE 选择与配置
IntelliJ IDEA 推荐配置:
- 安装 Lombok 插件
- 配置 Code Style 符合团队规范
- 启用 Annotation Processors
- 配置 Debug 和 Hot Swap
Eclipse 配置:
- 安装 Spring Tools Suite
- 配置 Build Path
- 设置 Formatter 和 Clean Up
3.2.2 版本控制集成
java
// Git 版本控制最佳实践示例
public class VersionControlExample {
/**
* 功能:用户注册
* 作者:张三
* 日期:2023-10-01
* 版本:1.0
*/
public void registerUser(String username, String password) {
// 参数验证
if (username == null || username.trim().isEmpty()) {
throw new IllegalArgumentException("用户名不能为空");
}
if (password == null || password.length() < 6) {
throw new IllegalArgumentException("密码长度至少6位");
}
// 业务逻辑
// ...
}
/**
* 功能:用户登录
* 修改:李四 - 2023-10-02 - 添加记住登录状态功能
*/
public boolean loginUser(String username, String password, boolean rememberMe) {
// 登录逻辑
return true;
}
}
3.3 测试框架
3.3.1 JUnit 测试
java
import org.junit.*;
import static org.junit.Assert.*;
public class CalculatorTest {
private Calculator calculator;
@BeforeClass
public static void setUpClass() {
// 在所有测试方法之前执行一次
System.out.println("测试类初始化");
}
@AfterClass
public static void tearDownClass() {
// 在所有测试方法之后执行一次
System.out.println("测试类清理");
}
@Before
public void setUp() {
// 在每个测试方法之前执行
calculator = new Calculator();
}
@After
public void tearDown() {
// 在每个测试方法之后执行
calculator = null;
}
@Test
public void testAdd() {
// 准备
int a = 5;
int b = 3;
int expected = 8;
// 执行
int actual = calculator.add(a, b);
// 验证
assertEquals("加法计算错误", expected, actual);
}
@Test
public void testDivide() {
// 测试正常除法
assertEquals(2, calculator.divide(6, 3));
}
@Test(expected = IllegalArgumentException.class)
public void testDivideByZero() {
// 测试除零异常
calculator.divide(5, 0);
}
@Test
@Ignore("尚未实现")
public void testAdvancedFeature() {
// 被忽略的测试
}
// 参数化测试
@RunWith(Parameterized.class)
public static class ParameterizedTest {
private int input;
private int expected;
private Calculator calculator = new Calculator();
public ParameterizedTest(int input, int expected) {
this.input = input;
this.expected = expected;
}
@Parameterized.Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][] {
{0, 0}, {1, 1}, {2, 4}, {3, 9}
});
}
@Test
public void testSquare() {
assertEquals(expected, calculator.square(input));
}
}
}
// 被测试的类
class Calculator {
public int add(int a, int b) {
return a + b;
}
public int divide(int a, int b) {
if (b == 0) {
throw new IllegalArgumentException("除数不能为零");
}
return a / b;
}
public int square(int x) {
return x * x;
}
}
3.3.2 Mockito 模拟测试
java
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.*;
import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest {
@Mock
private UserRepository userRepository;
@Mock
private EmailService emailService;
@InjectMocks
private UserService userService;
@Test
public void testRegisterUser() {
// 准备模拟数据
User user = new User("john@example.com", "John Doe");
when(userRepository.save(any(User.class))).thenReturn(user);
doNothing().when(emailService).sendWelcomeEmail(anyString());
// 执行测试
User registeredUser = userService.registerUser("john@example.com", "John Doe");
// 验证行为
verify(userRepository, times(1)).save(any(User.class));
verify(emailService, times(1)).sendWelcomeEmail("john@example.com");
// 验证结果
assertNotNull(registeredUser);
assertEquals("john@example.com", registeredUser.getEmail());
}
@Test
public void testRegisterUserWithExistingEmail() {
// 模拟已存在的用户
when(userRepository.findByEmail("existing@example.com"))
.thenReturn(new User("existing@example.com", "Existing User"));
// 验证异常
try {
userService.registerUser("existing@example.com", "New User");
fail("应该抛出异常");
} catch (IllegalArgumentException e) {
assertEquals("邮箱已存在", e.getMessage());
}
// 验证保存方法没有被调用
verify(userRepository, never()).save(any(User.class));
}
@Captor
private ArgumentCaptor<User> userCaptor;
@Test
public void testUserRegistrationDetails() {
// 执行测试
userService.registerUser("test@example.com", "Test User");
// 捕获参数并验证
verify(userRepository).save(userCaptor.capture());
User capturedUser = userCaptor.getValue();
assertEquals("test@example.com", capturedUser.getEmail());
assertEquals("Test User", capturedUser.getName());
assertNotNull(capturedUser.getRegistrationDate());
}
}
// 相关类定义
class User {
private String email;
private String name;
private Date registrationDate;
public User(String email, String name) {
this.email = email;
this.name = name;
this.registrationDate = new Date();
}
// getters and setters
}
interface UserRepository {
User save(User user);
User findByEmail(String email);
}
interface EmailService {
void sendWelcomeEmail(String email);
}
class UserService {
private UserRepository userRepository;
private EmailService emailService;
public User registerUser(String email, String name) {
// 检查邮箱是否已存在
User existing = userRepository.findByEmail(email);
if (existing != null) {
throw new IllegalArgumentException("邮箱已存在");
}
// 创建新用户
User newUser = new User(email, name);
User savedUser = userRepository.save(newUser);
// 发送欢迎邮件
emailService.sendWelcomeEmail(email);
return savedUser;
}
}
第四部分:Spring 框架深入学习
4.1 Spring Core 核心概念
4.1.1 依赖注入与控制反转
java
// 配置类方式
@Configuration
@ComponentScan("com.example")
@PropertySource("classpath:application.properties")
public class AppConfig {
@Bean
@Profile("dev")
public DataSource devDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("classpath:schema.sql")
.addScript("classpath:data.sql")
.build();
}
@Bean
@Profile("prod")
public DataSource prodDataSource() {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
dataSource.setUsername("user");
dataSource.setPassword("password");
return dataSource;
}
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
// 服务类
@Service
@Transactional
public class UserService {
private final UserRepository userRepository;
private final EmailService emailService;
// 构造器注入(推荐)
@Autowired
public UserService(UserRepository userRepository, EmailService emailService) {
this.userRepository = userRepository;
this.emailService = emailService;
}
public User registerUser(UserRegistrationDto dto) {
// 业务逻辑
User user = new User();
user.setEmail(dto.getEmail());
user.setName(dto.getName());
user.setPassword(encodePassword(dto.getPassword()));
User savedUser = userRepository.save(user);
emailService.sendWelcomeEmail(savedUser.getEmail());
return savedUser;
}
private String encodePassword(String password) {
// 密码加密逻辑
return password; // 实际应该使用 BCrypt 等
}
}
// 数据访问层
@Repository
public class JpaUserRepository implements UserRepository {
@PersistenceContext
private EntityManager entityManager;
@Override
public User save(User user) {
if (user.getId() == null) {
entityManager.persist(user);
return user;
} else {
return entityManager.merge(user);
}
}
@Override
public Optional<User> findByEmail(String email) {
TypedQuery<User> query = entityManager.createQuery(
"SELECT u FROM User u WHERE u.email = :email", User.class);
query.setParameter("email", email);
try {
return Optional.of(query.getSingleResult());
} catch (NoResultException e) {
return Optional.empty();
}
}
}
// 邮件服务
@Service
public class EmailService {
private final JavaMailSender mailSender;
private final TemplateEngine templateEngine;
@Autowired
public EmailService(JavaMailSender mailSender, TemplateEngine templateEngine) {
this.mailSender = mailSender;
this.templateEngine = templateEngine;
}
@Async
public void sendWelcomeEmail(String email) {
try {
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setTo(email);
helper.setSubject("欢迎注册");
Context context = new Context();
context.setVariable("email", email);
String htmlContent = templateEngine.process("welcome-email", context);
helper.setText(htmlContent, true);
mailSender.send(message);
} catch (Exception e) {
throw new RuntimeException("发送邮件失败", e);
}
}
}
4.1.2 AOP 面向切面编程
java
// 自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecutionTime {
}
// 切面类
@Aspect
@Component
public class LoggingAspect {
private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
@Around("@annotation(LogExecutionTime)")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object proceed = joinPoint.proceed();
long executionTime = System.currentTimeMillis() - start;
logger.info("{} executed in {} ms",
joinPoint.getSignature(), executionTime);
return proceed;
}
// 异常处理切面
@AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))",
throwing = "ex")
public void logServiceException(Exception ex) {
logger.error("Service layer exception: {}", ex.getMessage(), ex);
}
// 方法调用前后通知
@Before("execution(* com.example.service.UserService.*(..))")
public void logMethodCall(JoinPoint joinPoint) {
logger.debug("调用方法: {} with args: {}",
joinPoint.getSignature().getName(),
Arrays.toString(joinPoint.getArgs()));
}
}
// 使用切面的服务
@Service
public class OrderService {
@LogExecutionTime
public Order createOrder(OrderRequest request) {
// 业务逻辑
try {
Thread.sleep(100); // 模拟处理时间
return new Order();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
}
}
4.2 Spring Boot 自动化配置
4.2.1 Spring Boot 应用启动
java
// 主应用类
@SpringBootApplication
@EnableAsync
@EnableScheduling
@EnableCaching
@EnableTransactionManagement
public class Application {
private static final Logger logger = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
// 自定义启动配置
app.setBannerMode(Banner.Mode.CONSOLE);
app.setLogStartupInfo(true);
ConfigurableApplicationContext context = app.run(args);
// 应用启动后执行
checkBeans(context);
}
private static void checkBeans(ConfigurableApplicationContext context) {
logger.info("检查Spring Bean配置...");
String[] beanNames = context.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
if (beanName.contains("service") || beanName.contains("controller")) {
logger.debug("加载的Bean: {}", beanName);
}
}
}
}
// 配置类
@Configuration
@EnableConfigurationProperties({AppProperties.class, SecurityProperties.class})
public class AppConfig {
@Bean
@ConditionalOnMissingBean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
return mapper;
}
@Bean
@ConditionalOnProperty(name = "app.cache.enabled", havingValue = "true")
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("users", "orders");
}
}
// 配置属性类
@ConfigurationProperties(prefix = "app")
@Component
@Validated
public class AppProperties {
@NotBlank
private String name;
@Min(1024)
@Max(65535)
private int port = 8080;
private Security security = new Security();
// getters and setters
public static class Security {
private boolean enabled = true;
private String secretKey;
// getters and setters
}
}
4.2.2 应用配置文件
yaml
# application.yml
spring:
application:
name: my-spring-app
profiles:
active: @activatedProperties@
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: ${DB_USERNAME:root}
password: ${DB_PASSWORD:password}
hikari:
maximum-pool-size: 20
minimum-idle: 5
jpa:
hibernate:
ddl-auto: validate
show-sql: true
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL8Dialect
format_sql: true
redis:
host: localhost
port: 6379
timeout: 2000ms
server:
port: 8080
servlet:
context-path: /api
compression:
enabled: true
app:
name: "My Application"
port: 8080
security:
enabled: true
secret-key: ${APP_SECRET:default-secret-key}
cache:
enabled: true
logging:
level:
com.example: DEBUG
org.springframework.security: INFO
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} - %logger{36} - %msg%n"
file:
name: logs/application.log
max-size: 10MB
4.3 Spring MVC Web 开发
4.3.1 RESTful API 开发
java
// 统一响应格式
public class ApiResponse<T> {
private boolean success;
private String message;
private T data;
private String timestamp;
public ApiResponse(boolean success, String message, T data) {
this.success = success;
this.message = message;
this.data = data;
this.timestamp = Instant.now().toString();
}
public static <T> ApiResponse<T> success(T data) {
return new ApiResponse<>(true, "成功", data);
}
public static <T> ApiResponse<T> success(String message, T data) {
return new ApiResponse<>(true, message, data);
}
public static <T> ApiResponse<T> error(String message) {
return new ApiResponse<>(false, message, null);
}
// getters and setters
}
// 统一异常处理
@ControllerAdvice
@RestController
public class GlobalExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(EntityNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ApiResponse<Void> handleEntityNotFound(EntityNotFoundException ex) {
logger.warn("实体未找到: {}", ex.getMessage());
return ApiResponse.error(ex.getMessage());
}
@ExceptionHandler(ValidationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiResponse<Void> handleValidationException(ValidationException ex) {
logger.warn("验证失败: {}", ex.getMessage());
return ApiResponse.error(ex.getMessage());
}
@ExceptionHandler(AccessDeniedException.class)
@ResponseStatus(HttpStatus.FORBIDDEN)
public ApiResponse<Void> handleAccessDenied(AccessDeniedException ex) {
logger.warn("访问被拒绝: {}", ex.getMessage());
return ApiResponse.error("没有访问权限");
}
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ApiResponse<Void> handleGenericException(Exception ex) {
logger.error("服务器内部错误", ex);
return ApiResponse.error("服务器内部错误,请稍后重试");
}
// 处理方法参数验证错误
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiResponse<Map<String, String>> handleValidationErrors(MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors()
.forEach(error -> errors.put(error.getField(), error.getDefaultMessage()));
return new ApiResponse<>(false, "参数验证失败", errors);
}
}
// REST 控制器
@RestController
@RequestMapping("/api/v1/users")
@Validated
@Slf4j
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping
@PreAuthorize("hasRole('ADMIN')")
public ApiResponse<Page<UserDto>> getUsers(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size,
@RequestParam(required = false) String search) {
Pageable pageable = PageRequest.of(page, size, Sort.by("createdAt").descending());
Page<UserDto> users = userService.getUsers(pageable, search);
return ApiResponse.success(users);
}
@GetMapping("/{id}")
public ApiResponse<UserDto> getUser(@PathVariable Long id) {
UserDto user = userService.getUserById(id);
return ApiResponse.success(user);
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public ApiResponse<UserDto> createUser(@Valid @RequestBody CreateUserRequest request) {
UserDto createdUser = userService.createUser(request);
return ApiResponse.success("用户创建成功", createdUser);
}
@PutMapping("/{id}")
public ApiResponse<UserDto> updateUser(
@PathVariable Long id,
@Valid @RequestBody UpdateUserRequest request) {
UserDto updatedUser = userService.updateUser(id, request);
return ApiResponse.success("用户更新成功", updatedUser);
}
@DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
}
@GetMapping("/{id}/orders")
public ApiResponse<List<OrderDto>> getUserOrders(@PathVariable Long id) {
List<OrderDto> orders = userService.getUserOrders(id);
return ApiResponse.success(orders);
}
}
// DTO 类
public class CreateUserRequest {
@NotBlank(message = "邮箱不能为空")
@Email(message = "邮箱格式不正确")
private String email;
@NotBlank(message = "姓名不能为空")
@Size(min = 2, max = 50, message = "姓名长度必须在2-50个字符之间")
private String name;
@NotBlank(message = "密码不能为空")
@Size(min = 6, message = "密码长度至少6位")
@Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).*$",
message = "密码必须包含大小写字母和数字")
private String password;
// getters and setters
}
// 服务层实现
@Service
@Transactional(readOnly = true)
@Slf4j
public class UserService {
private final UserRepository userRepository;
private final UserMapper userMapper;
private final PasswordEncoder passwordEncoder;
public UserService(UserRepository userRepository, UserMapper userMapper,
PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.userMapper = userMapper;
this.passwordEncoder = passwordEncoder;
}
public Page<UserDto> getUsers(Pageable pageable, String search) {
Specification<User> spec = buildSearchSpecification(search);
Page<User> users = userRepository.findAll(spec, pageable);
return users.map(userMapper::toDto);
}
public UserDto getUserById(Long id) {
User user = userRepository.findById(id)
.orElseThrow(() -> new EntityNotFoundException("用户不存在: " + id));
return userMapper.toDto(user);
}
@Transactional
public UserDto createUser(CreateUserRequest request) {
// 检查邮箱是否已存在
if (userRepository.existsByEmail(request.getEmail())) {
throw new ValidationException("邮箱已存在: " + request.getEmail());
}
User user = new User();
user.setEmail(request.getEmail());
user.setName(request.getName());
user.setPassword(passwordEncoder.encode(request.getPassword()));
user.setStatus(UserStatus.ACTIVE);
user.setCreatedAt(LocalDateTime.now());
User savedUser = userRepository.save(user);
log.info("创建用户成功: {}", savedUser.getEmail());
return userMapper.toDto(savedUser);
}
@Transactional
public UserDto updateUser(Long id, UpdateUserRequest request) {
User user = userRepository.findById(id)
.orElseThrow(() -> new EntityNotFoundException("用户不存在: " + id));
user.setName(request.getName());
user.setUpdatedAt(LocalDateTime.now());
User updatedUser = userRepository.save(user);
return userMapper.toDto(updatedUser);
}
@Transactional
public void deleteUser(Long id) {
User user = userRepository.findById(id)
.orElseThrow(() -> new EntityNotFoundException("用户不存在: " + id));
user.setStatus(UserStatus.DELETED);
userRepository.save(user);
log.info("删除用户: {}", id);
}
private Specification<User> buildSearchSpecification(String search) {
return (root, query, criteriaBuilder) -> {
if (StringUtils.isEmpty(search)) {
return criteriaBuilder.conjunction();
}
String likePattern = "%" + search.toLowerCase() + "%";
return criteriaBuilder.or(
criteriaBuilder.like(criteriaBuilder.lower(root.get("name")), likePattern),
criteriaBuilder.like(criteriaBuilder.lower(root.get("email")), likePattern)
);
};
}
}
第五部分:数据库与持久层技术
5.1 JPA 与 Hibernate
5.1.1 实体类映射
java
// 基类实体
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@CreatedDate
@Column(name = "created_at", updatable = false)
private LocalDateTime createdAt;
@LastModifiedDate
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@Version
private Long version;
// getters and setters
}
// 用户实体
@Entity
@Table(name = "users",
indexes = {
@Index(name = "idx_user_email", columnList = "email", unique = true),
@Index(name = "idx_user_status", columnList = "status")
})
@NamedQueries({
@NamedQuery(
name = "User.findByStatus",
query = "SELECT u FROM User u WHERE u.status = :status"
)
})
public class User extends BaseEntity {
@Column(name = "email", nullable = false, length = 100)
private String email;
@Column(name = "name", nullable = false, length = 50)
private String name;
@Column(name = "password_hash", nullable = false, length = 100)
private String password;
@Enumerated(EnumType.STRING)
@Column(name = "status", length = 20)
private UserStatus status = UserStatus.ACTIVE;
@Column(name = "last_login_at")
private LocalDateTime lastLoginAt;
// 一对一关系
@OneToOne(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private UserProfile profile;
// 一对多关系
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@OrderBy("createdAt DESC")
private List<Order> orders = new ArrayList<>();
// 多对多关系
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(
name = "user_roles",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id")
)
private Set<Role> roles = new HashSet<>();
// 构造函数
public User() {}
public User(String email, String name) {
this.email = email;
this.name = name;
}
// 业务方法
public void addOrder(Order order) {
orders.add(order);
order.setUser(this);
}
public void removeOrder(Order order) {
orders.remove(order);
order.setUser(null);
}
public void addRole(Role role) {
roles.add(role);
role.getUsers().add(this);
}
// getters and setters
}
// 枚举定义
public enum UserStatus {
ACTIVE, INACTIVE, SUSPENDED, DELETED
}
// 订单实体
@Entity
@Table(name = "orders")
public class Order extends BaseEntity {
@Column(name = "order_number", unique = true, length = 20)
private String orderNumber;
@Column(name = "total_amount", precision = 10, scale = 2)
private BigDecimal totalAmount;
@Enumerated(EnumType.STRING)
@Column(name = "status", length = 20)
private OrderStatus status = OrderStatus.PENDING;
// 多对一关系
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
// 一对多关系
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<OrderItem> items = new ArrayList<>();
// 嵌入式对象
@Embedded
private Address shippingAddress;
// 业务方法
public void addItem(OrderItem item) {
items.add(item);
item.setOrder(this);
}
public BigDecimal calculateTotal() {
return items.stream()
.map(OrderItem::getSubtotal)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
// getters and setters
}
// 嵌入式地址类
@Embeddable
public class Address {
@Column(name = "street", length = 100)
private String street;
@Column(name = "city", length = 50)
private String city;
@Column(name = "state", length = 50)
private String state;
@Column(name = "zip_code", length = 20)
private String zipCode;
@Column(name = "country", length = 50)
private String country = "China";
// getters and setters
}
5.1.2 Repository 数据访问层
java
// 基础 Repository 接口
@NoRepositoryBean
public interface BaseRepository<T, ID> extends JpaRepository<T, ID>, JpaSpecificationExecutor<T> {
default Optional<T> findByIdOptional(ID id) {
return findById(id);
}
List<T> findByCreatedAtBetween(LocalDateTime start, LocalDateTime end);
@Query("SELECT COUNT(e) FROM #{#entityName} e")
long countAll();
@Modifying
@Query("UPDATE #{#entityName} e SET e.status = :status WHERE e.id = :id")
int updateStatus(@Param("id") ID id, @Param("status") String status);
}
// 用户 Repository
@Repository
public interface UserRepository extends BaseRepository<User, Long> {
// 派生查询方法
Optional<User> findByEmail(String email);
boolean existsByEmail(String email);
List<User> findByStatusOrderByCreatedAtDesc(UserStatus status);
List<User> findByNameContainingIgnoreCase(String name);
// @Query 注解查询
@Query("SELECT u FROM User u WHERE u.email LIKE %:domain")
List<User> findByEmailDomain(@Param("domain") String domain);
@Query("SELECT u.name, COUNT(o) FROM User u LEFT JOIN u.orders o GROUP BY u.id")
List<Object[]> findUserOrderCount();
// 原生 SQL 查询
@Query(value = "SELECT * FROM users WHERE DATE(created_at) = :date", nativeQuery = true)
List<User> findByCreatedDate(@Param("date") LocalDate date);
// 分页查询
Page<User> findByStatus(UserStatus status, Pageable pageable);
// 使用 Specification 进行复杂查询
default Page<User> findActiveUsersWithOrders(Pageable pageable) {
return findAll((root, query, criteriaBuilder) -> {
List<Predicate> predicates = new ArrayList<>();
predicates.add(criteriaBuilder.equal(root.get("status"), UserStatus.ACTIVE));
predicates.add(criteriaBuilder.isNotEmpty(root.get("orders")));
return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
}, pageable);
}
}
// 自定义 Repository 实现
public interface UserRepositoryCustom {
List<User> findComplexUsers(UserSearchCriteria criteria);
Page<User> searchUsers(UserSearchCriteria criteria, Pageable pageable);
}
// 自定义 Repository 实现类
@Repository
@Transactional(readOnly = true)
public class UserRepositoryImpl implements UserRepositoryCustom {
@PersistenceContext
private EntityManager entityManager;
@Override
public List<User> findComplexUsers(UserSearchCriteria criteria) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<User> query = cb.createQuery(User.class);
Root<User> root = query.from(User.class);
List<Predicate> predicates = buildPredicates(criteria, cb, root);
query.where(predicates.toArray(new Predicate[0]));
TypedQuery<User> typedQuery = entityManager.createQuery(query);
return typedQuery.getResultList();
}
@Override
public Page<User> searchUsers(UserSearchCriteria criteria, Pageable pageable) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<User> query = cb.createQuery(User.class);
Root<User> root = query.from(User.class);
List<Predicate> predicates = buildPredicates(criteria, cb, root);
query.where(predicates.toArray(new Predicate[0]));
// 排序
List<Order> orders = new ArrayList<>();
for (Sort.Order sortOrder : pageable.getSort()) {
if (sortOrder.isAscending()) {
orders.add(cb.asc(root.get(sortOrder.getProperty())));
} else {
orders.add(cb.desc(root.get(sortOrder.getProperty())));
}
}
query.orderBy(orders);
TypedQuery<User> typedQuery = entityManager.createQuery(query);
typedQuery.setFirstResult((int) pageable.getOffset());
typedQuery.setMaxResults(pageable.getPageSize());
List<User> result = typedQuery.getResultList();
// 获取总数
Long total = getTotalCount(criteria);
return new PageImpl<>(result, pageable, total);
}
private List<Predicate> buildPredicates(UserSearchCriteria criteria,
CriteriaBuilder cb, Root<User> root) {
List<Predicate> predicates = new ArrayList<>();
if (StringUtils.hasText(criteria.getKeyword())) {
String likePattern = "%" + criteria.getKeyword().toLowerCase() + "%";
predicates.add(cb.or(
cb.like(cb.lower(root.get("name")), likePattern),
cb.like(cb.lower(root.get("email")), likePattern)
));
}
if (criteria.getStatus() != null) {
predicates.add(cb.equal(root.get("status"), criteria.getStatus()));
}
if (criteria.getStartDate() != null) {
predicates.add(cb.greaterThanOrEqualTo(root.get("createdAt"),
criteria.getStartDate()));
}
if (criteria.getEndDate() != null) {
predicates.add(cb.lessThanOrEqualTo(root.get("createdAt"),
criteria.getEndDate()));
}
return predicates;
}
private Long getTotalCount(UserSearchCriteria criteria) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
Root<User> root = countQuery.from(User.class);
List<Predicate> predicates = buildPredicates(criteria, cb, root);
countQuery.select(cb.count(root)).where(predicates.toArray(new Predicate[0]));
return entityManager.createQuery(countQuery).getSingleResult();
}
}
// 搜索条件类
@Data
public class UserSearchCriteria {
private String keyword;
private UserStatus status;
private LocalDateTime startDate;
private LocalDateTime endDate;
private Boolean hasOrders;
}
5.2 数据库迁移与版本控制
5.2.1 Flyway 数据库迁移
sql
-- V1__Create_users_table.sql
CREATE TABLE users (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(100) NOT NULL UNIQUE,
name VARCHAR(50) NOT NULL,
password_hash VARCHAR(100) NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
version BIGINT DEFAULT 0
);
CREATE INDEX idx_user_email ON users(email);
CREATE INDEX idx_user_status ON users(status);
-- V2__Create_orders_table.sql
CREATE TABLE orders (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
order_number VARCHAR(20) UNIQUE NOT NULL,
user_id BIGINT NOT NULL,
total_amount DECIMAL(10,2),
status VARCHAR(20) DEFAULT 'PENDING',
shipping_street VARCHAR(100),
shipping_city VARCHAR(50),
shipping_state VARCHAR(50),
shipping_zip_code VARCHAR(20),
shipping_country VARCHAR(50) DEFAULT 'China',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
version BIGINT DEFAULT 0,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
CREATE INDEX idx_order_user_id ON orders(user_id);
CREATE INDEX idx_order_number ON orders(order_number);
-- V3__Create_order_items_table.sql
CREATE TABLE order_items (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
order_id BIGINT NOT NULL,
product_name VARCHAR(100) NOT NULL,
quantity INT NOT NULL,
unit_price DECIMAL(10,2) NOT NULL,
subtotal DECIMAL(10,2) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE
);
-- V4__Add_last_login_to_users.sql
ALTER TABLE users ADD COLUMN last_login_at TIMESTAMP NULL;
-- V5__Create_user_roles.sql
CREATE TABLE roles (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL UNIQUE,
description VARCHAR(200),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE user_roles (
user_id BIGINT NOT NULL,
role_id BIGINT NOT NULL,
assigned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (user_id, role_id),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE
);
-- V6__Insert_initial_data.sql
INSERT INTO roles (name, description) VALUES
('ADMIN', '系统管理员'),
('USER', '普通用户'),
('MANAGER', '经理');
-- 回滚脚本 R__Drop_user_roles.sql
DROP TABLE IF EXISTS user_roles;
DROP TABLE IF EXISTS roles;
5.2.2 Flyway 配置
java
@Configuration
public class FlywayConfig {
@Bean
public FlywayMigrationStrategy flywayMigrationStrategy() {
return flyway -> {
// 在迁移前执行的操作
log.info("开始数据库迁移...");
flyway.migrate();
};
}
@Bean
@ConfigurationProperties(prefix = "spring.flyway")
public FlywayProperties flywayProperties() {
return new FlywayProperties();
}
}
yaml
# application.yml 中的 Flyway 配置
spring:
flyway:
enabled: true
locations: classpath:db/migration
baseline-on-migrate: true
baseline-version: 1
validate-on-migrate: true
out-of-order: false
clean-disabled: true
table: flyway_schema_history
placeholders:
table-prefix: ""
第六部分:高级主题与最佳实践
6.1 性能优化与缓存
6.1.1 Redis 缓存集成
java
// 缓存配置
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(30))
.disableCachingNullValues()
.serializeKeysWith(RedisSerializationContext.SerializationPair
.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer()));
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.withInitialCacheConfigurations(getCacheConfigurations())
.transactionAware()
.build();
}
private Map<String, RedisCacheConfiguration> getCacheConfigurations() {
Map<String, RedisCacheConfiguration> cacheConfigs = new HashMap<>();
cacheConfigs.put("users", RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofHours(1))
.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer())));
cacheConfigs.put("products", RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(15)));
return cacheConfigs;
}
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
// 使用 Jackson 序列化
Jackson2JsonRedisSerializer<Object> serializer =
new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.activateDefaultTyping(mapper.getPolymorphicTypeValidator(),
ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(mapper);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(serializer);
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(serializer);
template.afterPropertiesSet();
return template;
}
}
// 缓存服务
@Service
@Slf4j
public class CacheService {
private final RedisTemplate<String, Object> redisTemplate;
private final ObjectMapper objectMapper;
public CacheService(RedisTemplate<String, Object> redisTemplate,
ObjectMapper objectMapper) {
this.redisTemplate = redisTemplate;
this.objectMapper = objectMapper;
}
public <T> void set(String key, T value, Duration ttl) {
try {
redisTemplate.opsForValue().set(key, value, ttl);
} catch (Exception e) {
log.error("Redis 设置缓存失败 key: {}", key, e);
}
}
@SuppressWarnings("unchecked")
public <T> T get(String key, Class<T> type) {
try {
Object value = redisTemplate.opsForValue().get(key);
if (value == null) {
return null;
}
if (type.isInstance(value)) {
return (T) value;
}
// 类型转换
return objectMapper.convertValue(value, type);
} catch (Exception e) {
log.error("Redis 获取缓存失败 key: {}", key, e);
return null;
}
}
public boolean delete(String key) {
try {
return Boolean.TRUE.equals(redisTemplate.delete(key));
} catch (Exception e) {
log.error("Redis 删除缓存失败 key: {}", key, e);
return false;
}
}
public boolean exists(String key) {
try {
return Boolean.TRUE.equals(redisTemplate.hasKey(key));
} catch (Exception e) {
log.error("Redis 检查键存在失败 key: {}", key, e);
return false;
}
}
public void setHash(String key, String hashKey, Object value) {
try {
redisTemplate.opsForHash().put(key, hashKey, value);
} catch (Exception e) {
log.error("Redis 设置哈希缓存失败 key: {}, hashKey: {}", key, hashKey, e);
}
}
@SuppressWarnings("unchecked")
public <T> T getHash(String key, String hashKey, Class<T> type) {
try {
Object value = redisTemplate.opsForHash().get(key, hashKey);
if (value == null) {
return null;
}
if (type.isInstance(value)) {
return (T) value;
}
return objectMapper.convertValue(value, type);
} catch (Exception e) {
log.error("Redis 获取哈希缓存失败 key: {}, hashKey: {}", key, hashKey, e);
return null;
}
}
}
// 使用缓存的服务
@Service
@Slf4j
public class CachedUserService {
private final UserRepository userRepository;
private final CacheService cacheService;
private final UserMapper userMapper;
private static final String USER_CACHE_PREFIX = "user:";
private static final String USER_LIST_CACHE_KEY = "users:list";
private static final Duration USER_CACHE_TTL = Duration.ofHours(1);
public CachedUserService(UserRepository userRepository, CacheService cacheService,
UserMapper userMapper) {
this.userRepository = userRepository;
this.cacheService = cacheService;
this.userMapper = userMapper;
}
@Cacheable(value = "users", key = "#id", unless = "#result == null")
public UserDto getUserById(Long id) {
log.debug("从数据库获取用户: {}", id);
User user = userRepository.findById(id)
.orElseThrow(() -> new EntityNotFoundException("用户不存在: " + id));
return userMapper.toDto(user);
}
@Cacheable(value = "users", key = "#email", unless = "#result == null")
public UserDto getUserByEmail(String email) {
log.debug("从数据库获取用户: {}", email);
User user = userRepository.findByEmail(email)
.orElseThrow(() -> new EntityNotFoundException("用户不存在: " + email));
return userMapper.toDto(user);
}
@Caching(
put = {
@CachePut(value = "users", key = "#result.id"),
@CachePut(value = "users", key = "#result.email")
},
evict = {
@CacheEvict(value = "users", key = "'list'"),
@CacheEvict(value = "users", key = "'search:' + #result.status")
}
)
public UserDto updateUser(UserDto userDto) {
User user = userRepository.findById(userDto.getId())
.orElseThrow(() -> new EntityNotFoundException("用户不存在: " + userDto.getId()));
userMapper.updateUserFromDto(userDto, user);
User updatedUser = userRepository.save(user);
log.info("更新用户: {}", userDto.getId());
return userMapper.toDto(updatedUser);
}
@CacheEvict(value = "users", allEntries = true)
public void evictAllUserCaches() {
log.info("清除所有用户缓存");
}
// 手动缓存管理
public List<UserDto> getActiveUsers() {
String cacheKey = "users:active";
// 尝试从缓存获取
List<UserDto> cachedUsers = cacheService.get(cacheKey, List.class);
if (cachedUsers != null) {
log.debug("从缓存获取活跃用户列表");
return cachedUsers;
}
// 从数据库获取
log.debug("从数据库获取活跃用户列表");
List<User> users = userRepository.findByStatusOrderByCreatedAtDesc(UserStatus.ACTIVE);
List<UserDto> userDtos = users.stream()
.map(userMapper::toDto)
.collect(Collectors.toList());
// 设置缓存
cacheService.set(cacheKey, userDtos, Duration.ofMinutes(30));
return userDtos;
}
}
6.2 安全与认证授权
6.2.1 Spring Security 配置
java
// 安全配置
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class SecurityConfig {
private final UserDetailsService userDetailsService;
private final JwtTokenProvider jwtTokenProvider;
public SecurityConfig(UserDetailsService userDetailsService,
JwtTokenProvider jwtTokenProvider) {
this.userDetailsService = userDetailsService;
this.jwtTokenProvider = jwtTokenProvider;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.cors().and()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/public/**").permitAll()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.antMatchers("/api/user/**").hasAnyRole("USER", "ADMIN")
.antMatchers("/api/**").authenticated()
.anyRequest().permitAll()
.and()
.apply(new JwtConfigurer(jwtTokenProvider));
return http.build();
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOriginPattern("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
config.addExposedHeader("Authorization");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
// JWT 配置
public class JwtConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
private final JwtTokenProvider jwtTokenProvider;
public JwtConfigurer(JwtTokenProvider jwtTokenProvider) {
this.jwtTokenProvider = jwtTokenProvider;
}
@Override
public void configure(HttpSecurity http) {
JwtTokenFilter customFilter = new JwtTokenFilter(jwtTokenProvider);
http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
}
}
// JWT Token 过滤器
public class JwtTokenFilter extends OncePerRequestFilter {
private final JwtTokenProvider jwtTokenProvider;
public JwtTokenFilter(JwtTokenProvider jwtTokenProvider) {
this.jwtTokenProvider = jwtTokenProvider;
}
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
String token = resolveToken(request);
if (token != null && jwtTokenProvider.validateToken(token)) {
Authentication auth = jwtTokenProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(auth);
}
filterChain.doFilter(request, response);
}
private String resolveToken(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
return null;
}
}
// JWT Token 提供者
@Component
public class JwtTokenProvider {
@Value("${app.jwt.secret:defaultSecret}")
private String jwtSecret;
@Value("${app.jwt.expiration:86400000}")
private long jwtExpirationMs;
private static final Logger logger = LoggerFactory.getLogger(JwtTokenProvider.class);
public String generateToken(Authentication authentication) {
UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal();
Date now = new Date();
Date expiryDate = new Date(now.getTime() + jwtExpirationMs);
return Jwts.builder()
.setSubject(userPrincipal.getUsername())
.setIssuedAt(now)
.setExpiration(expiryDate)
.signWith(SignatureAlgorithm.HS512, jwtSecret)
.compact();
}
public String getUsernameFromToken(String token) {
Claims claims = Jwts.parser()
.setSigningKey(jwtSecret)
.parseClaimsJws(token)
.getBody();
return claims.getSubject();
}
public boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token);
return true;
} catch (SignatureException ex) {
logger.error("Invalid JWT signature");
} catch (MalformedJwtException ex) {
logger.error("Invalid JWT token");
} catch (ExpiredJwtException ex) {
logger.error("Expired JWT token");
} catch (UnsupportedJwtException ex) {
logger.error("Unsupported JWT token");
} catch (IllegalArgumentException ex) {
logger.error("JWT claims string is empty");
}
return false;
}
public Authentication getAuthentication(String token) {
String username = getUsernameFromToken(token);
UserDetails userDetails = loadUserByUsername(username);
return new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities());
}
private UserDetails loadUserByUsername(String username) {
// 实现用户加载逻辑
return null; // 实际应该从数据库加载
}
}
// 用户详情服务
@Service
@Transactional(readOnly = true)
public class CustomUserDetailsService implements UserDetailsService {
private final UserRepository userRepository;
public CustomUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User user = userRepository.findByEmail(email)
.orElseThrow(() -> new UsernameNotFoundException("用户不存在: " + email));
return UserPrincipal.create(user);
}
public UserDetails loadUserById(Long id) {
User user = userRepository.findById(id)
.orElseThrow(() -> new UsernameNotFoundException("用户不存在: " + id));
return UserPrincipal.create(user);
}
}
// 用户主体类
public class UserPrincipal implements UserDetails {
private Long id;
private String email;
private String password;
private Collection<? extends GrantedAuthority> authorities;
public UserPrincipal(Long id, String email, String password,
Collection<? extends GrantedAuthority> authorities) {
this.id = id;
this.email = email;
this.password = password;
this.authorities = authorities;
}
public static UserPrincipal create(User user) {
List<GrantedAuthority> authorities = user.getRoles().stream()
.map(role -> new SimpleGrantedAuthority("ROLE_" + role.getName()))
.collect(Collectors.toList());
return new UserPrincipal(
user.getId(),
user.getEmail(),
user.getPassword(),
authorities
);
}
// UserDetails 接口方法实现
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return email;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
// getters
public Long getId() {
return id;
}
}
6.3 微服务与分布式系统
6.3.1 Spring Cloud 微服务配置
java
// 服务注册与发现
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
// 配置类
@Configuration
public class FeignConfig {
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
@Bean
public ErrorDecoder errorDecoder() {
return new CustomErrorDecoder();
}
}
// Feign 客户端
@FeignClient(name = "order-service", path = "/api/orders")
public interface OrderServiceClient {
@GetMapping("/user/{userId}")
List<OrderDto> getUserOrders(@PathVariable("userId") Long userId);
@PostMapping
OrderDto createOrder(@RequestBody CreateOrderRequest request);
@PutMapping("/{orderId}/status")
OrderDto updateOrderStatus(@PathVariable("orderId") Long orderId,
@RequestBody UpdateOrderStatusRequest request);
}
// 服务调用示例
@Service
@Slf4j
public class UserOrderService {
private final OrderServiceClient orderServiceClient;
private final CircuitBreakerFactory circuitBreakerFactory;
public UserOrderService(OrderServiceClient orderServiceClient,
CircuitBreakerFactory circuitBreakerFactory) {
this.orderServiceClient = orderServiceClient;
this.circuitBreakerFactory = circuitBreakerFactory;
}
public List<OrderDto> getUserOrdersWithFallback(Long userId) {
CircuitBreaker circuitBreaker = circuitBreakerFactory.create("order-service");
return circuitBreaker.run(
() -> orderServiceClient.getUserOrders(userId),
throwable -> {
log.warn("订单服务调用失败,使用降级策略", throwable);
return Collections.emptyList();
}
);
}
@Retry(name = "order-service", fallbackMethod = "createOrderFallback")
public OrderDto createOrderWithRetry(CreateOrderRequest request) {
return orderServiceClient.createOrder(request);
}
public OrderDto createOrderFallback(CreateOrderRequest request, Exception ex) {
log.error("创建订单重试失败", ex);
// 返回默认值或抛出业务异常
throw new BusinessException("订单服务暂时不可用");
}
}
// 配置中心配置
@Configuration
@RefreshScope
public class AppConfig {
@Value("${app.feature.enabled:false}")
private boolean featureEnabled;
@Value("${app.cache.ttl:300}")
private long cacheTtl;
@Bean
@RefreshScope
public CacheManager cacheManager() {
// 动态配置的缓存管理器
return new ConcurrentMapCacheManager();
}
// getters
}
第七部分:部署与运维
7.1 Docker 容器化部署
7.1.1 Dockerfile 配置
dockerfile
# 多阶段构建 Dockerfile
FROM openjdk:11-jdk-slim as builder
# 安装 Maven
RUN apt-get update && apt-get install -y maven
WORKDIR /app
COPY pom.xml .
COPY src ./src
# 构建应用
RUN mvn clean package -DskipTests
# 运行时镜像
FROM openjdk:11-jre-slim
# 安装必要的工具
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
&& rm -rf /var/lib/apt/lists/*
# 创建应用用户
RUN groupadd -r appuser && useradd -r -g appuser appuser
# 创建应用目录
RUN mkdir -p /app/logs && chown -R appuser:appuser /app
USER appuser
WORKDIR /app
# 复制构建结果
COPY --from=builder /app/target/*.jar app.jar
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/actuator/health || exit 1
# 环境变量
ENV JAVA_OPTS="-Xms512m -Xmx1024m -XX:+UseG1GC -Djava.security.egd=file:/dev/./urandom"
ENV SPRING_PROFILES_ACTIVE="docker"
# 暴露端口
EXPOSE 8080
# 启动应用
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
7.1.2 Docker Compose 配置
yaml
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=docker
- DB_HOST=mysql
- REDIS_HOST=redis
depends_on:
- mysql
- redis
networks:
- app-network
deploy:
resources:
limits:
memory: 1G
reservations:
memory: 512M
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: myapp
MYSQL_USER: appuser
MYSQL_PASSWORD: apppassword
ports:
- "3306:3306"
volumes:
- mysql-data:/var/lib/mysql
- ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- app-network
command:
- --default-authentication-plugin=mysql_native_password
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
redis:
image: redis:6.2-alpine
ports:
- "6379:6379"
volumes:
- redis-data:/data
networks:
- app-network
command: redis-server --appendonly yes
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
- ./nginx/ssl:/etc/nginx/ssl
depends_on:
- app
networks:
- app-network
volumes:
mysql-data:
redis-data:
networks:
app-network:
driver: bridge
7.2 监控与日志
7.2.1 Spring Boot Actuator 配置
yaml
# 监控配置
management:
endpoints:
web:
exposure:
include: health,info,metrics,loggers,prometheus
base-path: /actuator
endpoint:
health:
show-details: always
show-components: always
metrics:
enabled: true
loggers:
enabled: true
metrics:
export:
prometheus:
enabled: true
distribution:
percentiles-histogram:
http.server.requests: true
info:
env:
enabled: true
7.2.2 自定义健康检查
java
@Component
public class DatabaseHealthIndicator implements HealthIndicator {
private final DataSource dataSource;
public DatabaseHealthIndicator(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public Health health() {
try (Connection connection = dataSource.getConnection()) {
// 执行简单的数据库检查
try (Statement statement = connection.createStatement()) {
statement.execute("SELECT 1");
}
return Health.up()
.withDetail("database", "MySQL")
.withDetail("validationQuery", "SELECT 1")
.build();
} catch (Exception e) {
return Health.down(e)
.withDetail("database", "MySQL")
.withDetail("error", e.getMessage())
.build();
}
}
}
@Component
public class RedisHealthIndicator implements HealthIndicator {
private final RedisTemplate<String, Object> redisTemplate;
public RedisHealthIndicator(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
@Override
public Health health() {
try {
// 执行简单的 Redis 操作
String testKey = "health:check";
redisTemplate.opsForValue().set(testKey, "test", Duration.ofSeconds(10));
String value = (String) redisTemplate.opsForValue().get(testKey);
if ("test".equals(value)) {
return Health.up()
.withDetail("redis", "connected")
.build();
} else {
return Health.down()
.withDetail("redis", "unexpected response")
.build();
}
} catch (Exception e) {
return Health.down(e)
.withDetail("redis", "connection failed")
.withDetail("error", e.getMessage())
.build();
}
}
}
第八部分:学习路线与持续提升
8.1 分阶段学习计划
阶段一:基础入门(1-2个月)
- Java 语言基础
- 语法、面向对象、集合框架
- 异常处理、IO 操作、多线程
- 开发工具掌握
- IntelliJ IDEA 使用
- Maven/Gradle 构建工具
- Git 版本控制
阶段二:Spring 框架(2-3个月)
- Spring Core
- IOC、DI、AOP 概念
- Bean 生命周期管理
- Spring Boot
- 自动配置原理
- Starter 使用
- 应用配置管理
- 数据访问
- JPA/Hibernate
- 事务管理
- 数据库迁移
阶段三:高级特性(2-3个月)
- 微服务架构
- Spring Cloud 组件
- 服务注册发现
- 配置中心
- 性能优化
- 缓存策略
- 数据库优化
- JVM 调优
- 安全防护
- Spring Security
- OAuth2/JWT
- 安全最佳实践
阶段四:生产实践(持续)
- 容器化部署
- Docker/Kubernetes
- CI/CD 流水线
- 监控运维
- 应用监控
- 日志分析
- 性能调优
- 架构设计
- 系统架构模式
- 领域驱动设计
- 代码重构
8.2 持续学习资源
官方文档
在线课程
- Spring 官方教程
- Baeldung Java/Spring 教程
- Java Brains YouTube 频道
实践项目
- 个人博客系统
- 电商平台
- 微服务示例项目
- 开源项目贡献
8.3 社区参与
技术社区
- Stack Overflow
- GitHub
- 掘金、CSDN
- 公司内部技术分享
持续提升建议
- 代码审查:参与团队代码审查,学习优秀代码风格
- 技术分享:定期进行技术分享,巩固知识
- 开源贡献:参与开源项目,了解最佳实践
- 技术博客:撰写技术博客,加深理解
- 参加技术会议:了解行业最新动态
总结
从 .NET 转型到 Java 是一个系统性的过程,需要从语言基础开始,逐步深入到框架使用、系统架构和运维部署。关键成功因素包括:
- 扎实的基础:深入理解 Java 语言特性和 JVM 原理
- 框架熟练度:掌握 Spring 生态系统的核心组件
- 工程化能力:熟悉构建工具、测试框架和 CI/CD
- 架构思维:理解微服务、分布式系统设计原则
- 持续学习:跟上技术发展趋势,不断更新知识体系
通过系统的学习和实践,.NET 开发者可以成功转型为 Java 开发者,并在新的技术栈中发挥更大的价值。记住,转型不仅是技术栈的切换,更是思维方式和开发理念的更新。保持开放的心态和持续学习的态度,是成功转型的关键。