引言:为什么选择Spring框架?

Spring框架是Java企业级开发中最流行、最强大的开源框架之一。自2003年首次发布以来,Spring已经发展成为Java生态系统中不可或缺的基础设施。它不仅仅是一个框架,更是一个完整的编程模型和生态系统。

Spring的核心价值在于其依赖注入(DI)面向切面编程(AOP)理念,这些概念彻底改变了Java开发的方式。通过Spring,开发者可以编写更松耦合、更易测试、更易维护的代码。无论你是构建简单的Web应用,还是复杂的企业级系统,Spring都能提供相应的解决方案。

本文将带你从Spring的基础概念开始,逐步深入到高级特性和实际应用,最终达到精通水平。我们将涵盖Spring Framework的核心模块、Spring Boot的快速开发、Spring MVC的Web开发、数据访问、安全性以及微服务架构等关键主题。

第一部分:Spring基础概念与核心原理

1.1 什么是控制反转(IoC)和依赖注入(DI)

控制反转(Inversion of Control, IoC)是Spring框架最核心的设计理念。传统的编程方式中,对象自己负责创建和管理它所依赖的对象;而在IoC模式下,这个责任被反转给了外部容器(Spring IoC容器)。

依赖注入(Dependency Injection, DI)是实现IoC的具体方式。Spring容器通过三种主要方式将依赖关系注入到对象中:

  1. 构造器注入(Constructor Injection)
  2. Setter方法注入(Setter Injection)
  3. 字段注入(Field Injection)

让我们通过一个完整的例子来理解这些概念:

// 传统方式:紧密耦合
public class UserService {
    private UserRepository userRepository;
    
    public UserService() {
        // 直接创建依赖对象
        this.userRepository = new UserRepository();
    }
    
    public User getUserById(Long id) {
        return userRepository.findUser(id);
    }
}

// 使用Spring DI的方式
public class UserService {
    private final UserRepository userRepository;
    
    // 构造器注入 - 推荐方式
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
    
    public User getUserById(Long id) {
        return userRepository.findUser(id);
    }
}

// Repository接口
public interface UserRepository {
    User findUser(Long id);
}

// 实现类
@Repository
public class UserRepositoryImpl implements UserRepository {
    @Override
    public User findUser(Long id) {
        // 数据库查询逻辑
        return new User(id, "John Doe");
    }
}

1.2 Spring IoC容器详解

Spring IoC容器是Spring框架的核心,它负责实例化、配置和管理Bean的整个生命周期。主要的容器接口有两个:

  • BeanFactory:基础容器接口,提供基本的IoC功能
  • ApplicationContext:BeanFactory的子接口,提供了更多企业级功能

配置Bean的三种方式

1. 基于XML配置(传统方式)

<!-- applicationContext.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 构造器注入 -->
    <bean id="userRepository" class="com.example.UserRepositoryImpl"/>
    
    <bean id="userService" class="com.example.UserService">
        <constructor-arg ref="userRepository"/>
    </bean>
    
    <!-- Setter注入 -->
    <bean id="orderService" class="com.example.OrderService">
        <property name="orderRepository" ref="orderRepository"/>
    </bean>
</beans>

2. 基于注解配置(推荐方式)

// 主配置类
@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
    // 可以在这里定义额外的Bean
    @Bean
    public DataSource dataSource() {
        HikariDataSource ds = new HikariDataSource();
        ds.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
        ds.setUsername("root");
        ds.setPassword("password");
        return ds;
    }
}

// 使用注解标记组件
@Repository
public class UserRepositoryImpl implements UserRepository {
    // 实现细节
}

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;
    // 业务逻辑
}

@RestController
public class UserController {
    @Autowired
    private UserService userService;
    // 控制器逻辑
}

3. 基于Java配置(最灵活的方式)

@Configuration
public class AppConfig {
    
    @Bean
    public UserRepository userRepository() {
        return new UserRepositoryImpl();
    }
    
    @Bean
    public UserService userService() {
        return new UserService(userRepository());
    }
    
    // 使用@Import导入其他配置类
    @Import({DatabaseConfig.class, SecurityConfig.class})
    public static class CombinedConfig {
    }
}

1.3 Bean的作用域(Scope)

Spring Bean支持多种作用域,理解这些作用域对于正确设计应用至关重要:

@Component
@Scope("singleton")  // 默认作用域,每个容器中一个实例
public class SingletonBean {
    // ...
}

@Component
@Scope("prototype")  // 每次请求都创建新实例
public class PrototypeBean {
    // ...
}

@Component
@Scope("request")  // 每个HTTP请求一个实例(Web环境)
public class RequestScopedBean {
    // ...
}

@Component
@Scope("session")  // 每个HTTP会话一个实例(Web环境)
public class SessionScopedBean {
    // ...
}

@Component
@Scope("application")  // 每个ServletContext一个实例(Web环境)
public class ApplicationScopedBean {
    // ...
}

1.4 Bean的生命周期管理

Spring Bean的生命周期包含多个阶段,我们可以通过各种回调方法来控制:

@Component
public class LifecycleBean implements InitializingBean, DisposableBean {
    
    public LifecycleBean() {
        System.out.println("1. 构造函数调用");
    }
    
    @PostConstruct
    public void postConstruct() {
        System.out.println("3. @PostConstruct注解方法调用");
    }
    
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("4. InitializingBean.afterPropertiesSet()调用");
    }
    
    @PreDestroy
    public void preDestroy() {
        System.out.println("7. @PreDestroy注解方法调用");
    }
    
    @Override
    public void destroy() throws Exception {
        System.out.println("8. DisposableBean.destroy()调用");
    }
    
    // 自定义初始化方法
    @Bean(initMethod = "customInit", destroyMethod = "customDestroy")
    public AnotherBean anotherBean() {
        return new AnotherBean();
    }
}

class AnotherBean {
    public void customInit() {
        System.out.println("5. 自定义初始化方法");
    }
    
    public void customDestroy() {
        System.out.println("9. 自定义销毁方法");
    }
}

第二部分:Spring AOP面向切面编程

2.1 AOP核心概念

面向切面编程(Aspect-Oriented Programming, AOP)是Spring框架的另一个核心特性,它允许我们分离横切关注点(cross-cutting concerns),如日志、事务、安全性等。

AOP的核心术语:

  • 切面(Aspect):封装了横切关注点的模块
  • 连接点(Join Point):程序执行过程中的某个点(如方法执行)
  • 通知(Advice):切面在特定连接点执行的动作
  • 切入点(Pointcut):匹配连接点的表达式
  • 目标对象(Target):被代理的对象
  • 代理(Proxy):Spring创建的对象,包含目标对象和通知

2.2 Spring AOP实现示例

让我们创建一个完整的日志切面示例:

// 1. 定义切面
@Aspect
@Component
public class LoggingAspect {
    
    private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
    
    // 2. 定义切入点表达式
    // 匹配com.example.service包下所有类的所有方法
    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceMethods() {}
    
    // 3. 前置通知
    @Before("serviceMethods()")
    public void logBefore(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        logger.info("执行方法: {},参数: {}", methodName, Arrays.toString(args));
    }
    
    // 4. 返回后通知
    @AfterReturning(pointcut = "serviceMethods()", returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        String methodName = joinPoint.getSignature().getName();
        logger.info("方法 {} 执行完成,返回值: {}", methodName, result);
    }
    
    // 5. 异常通知
    @AfterThrowing(pointcut = "serviceMethods()", throwing = "ex")
    public void logAfterThrowing(JoinPoint joinPoint, Exception ex) {
        String methodName = joinPoint.getSignature().getName();
        logger.error("方法 {} 执行异常: {}", methodName, ex.getMessage(), ex);
    }
    
    // 6. 最终通知
    @After("serviceMethods()")
    public void logAfter(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        logger.info("方法 {} 执行结束", methodName);
    }
    
    // 7. 环绕通知(最强大的通知类型)
    @Around("serviceMethods()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        try {
            Object result = joinPoint.proceed();  // 执行目标方法
            long duration = System.currentTimeMillis() - start;
            logger.info("方法执行耗时: {} ms", duration);
            return result;
        } catch (Exception e) {
            long duration = System.currentTimeMillis() - start;
            logger.error("方法执行失败,耗时: {} ms", duration);
            throw e;
        }
    }
}

更复杂的切入点表达式

@Aspect
@Component
public class AdvancedAspect {
    
    // 匹配所有public方法
    @Pointcut("execution(public * *(..))")
    public void publicMethods() {}
    
    // 匹配指定包下所有方法
    @Pointcut("within(com.example.service..*)")
    public void inServicePackage() {}
    
    // 匹配实现了特定接口的类
    @Pointcut("this(com.example.service.UserService)")
    public void userServiceImplementation() {}
    
    // 匹配带有特定注解的方法
    @Pointcut("@annotation(com.example.annotation.Loggable)")
    public void annotatedMethods() {}
    
    // 组合切入点
    @Pointcut("publicMethods() && inServicePackage()")
    public void publicServiceMethods() {}
    
    // 带参数的切入点
    @Pointcut("execution(* com.example.service.*.*(Long, ..))")
    public void methodsWithLongParam() {}
}

2.3 使用AOP实现事务管理

// 自定义事务切面
@Aspect
@Component
@Transactional
public class TransactionAspect {
    
    @Around("@annotation(transactional)")
    public Object manageTransaction(ProceedingJoinPoint joinPoint, 
                                   Transactional transactional) throws Throwable {
        TransactionStatus status = null;
        try {
            // 开启事务
            status = beginTransaction(transactional);
            Object result = joinPoint.proceed();
            // 提交事务
            commitTransaction(status);
            return result;
        } catch (Exception e) {
            // 回滚事务
            rollbackTransaction(status);
            throw e;
        }
    }
    
    private TransactionStatus beginTransaction(Transactional tx) {
        // 事务实现细节
        return null; // 简化示例
    }
    
    private void commitTransaction(TransactionStatus status) {
        // 提交逻辑
    }
    
    private void rollbackTransaction(TransactionStatus status) {
        // 回滚逻辑
    }
}

第三部分:Spring Boot快速开发

3.1 Spring Boot简介

Spring Boot是Spring框架的”约定优于配置”理念的完美体现。它通过自动配置和起步依赖,极大地简化了Spring应用的开发过程。

Spring Boot的核心特性:

  • 自动配置:根据classpath中的jar包自动配置Bean
  • 起步依赖:简化Maven/Gradle配置
  • 嵌入式服务器:无需单独部署Servlet容器
  • 生产级监控:提供健康检查、指标等
  • 外部化配置:灵活的配置管理

3.2 创建第一个Spring Boot应用

方式一:使用Spring Initializr(推荐)

访问 start.spring.io 或使用IDE创建项目。

方式二:手动创建

项目结构:

my-spring-boot-app/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/
│   │   │       └── example/
│   │   │           └── demo/
│   │   │               ├── DemoApplication.java
│   │   │               ├── controller/
│   │   │               ├── service/
│   │   │               └── model/
│   │   └── resources/
│   │       ├── application.properties
│   │       └── static/
│   └── test/
├── pom.xml

pom.xml配置:

<?xml version="1.0" encoding="UTF-8"?>
<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>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.0</version>
        <relativePath/>
    </parent>
    
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>1.0.0</version>
    
    <properties>
        <java.version>17</java.version>
    </properties>
    
    <dependencies>
        <!-- Web开发起步依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <!-- 数据访问 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        
        <!-- 数据库驱动 -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        
        <!-- 测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

主应用类:

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

3.3 Spring Boot自动配置原理

Spring Boot的自动配置基于条件化配置,通过@Conditional系列注解实现:

// 自动配置类示例
@Configuration
@ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class})  // 当类路径存在指定类时
@ConditionalOnMissingBean(DataSource.class)  // 当容器中不存在DataSource Bean时
@EnableConfigurationProperties(DataSourceProperties.class)  // 启用配置属性
public class DataSourceAutoConfiguration {
    
    @Configuration
    @ConditionalOnEmbeddedDatabase  // 嵌入式数据库条件
    static class EmbeddedDataSourceConfiguration {
        @Bean
        @ConfigurationProperties(prefix = "spring.datasource")
        public EmbeddedDataSource dataSource() {
            // 创建嵌入式数据源
            return new EmbeddedDatabaseBuilder()
                .setType(EmbeddedDatabaseType.H2)
                .build();
        }
    }
}

3.4 外部化配置

Spring Boot支持多种配置源,按优先级排序:

// 1. 命令行参数
// java -jar app.jar --server.port=8081 --spring.datasource.url=jdbc:mysql://...

// 2. JVM系统属性
// java -Dserver.port=8081 -jar app.jar

// 3. 环境变量
// export SERVER_PORT=8081

// 4. application.properties/yml
// server.port=8080

// 5. @ConfigurationProperties绑定
@Component
@ConfigurationProperties(prefix = "app")
public class AppProperties {
    private String name;
    private String version;
    private Database database = new Database();
    
    public static class Database {
        private String url;
        private String username;
        private String password;
        // getters and setters
    }
    // getters and setters
}

application.yml示例:

server:
  port: 8080
  servlet:
    context-path: /api

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb
    username: root
    password: password
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL8Dialect

app:
  name: My Application
  version: 1.0.0
  database:
    url: jdbc:mysql://localhost:3306/mydb
    username: root
    password: password

第四部分:Spring MVC Web开发

4.1 Spring MVC架构概述

Spring MVC是基于Servlet API的Web框架,采用经典的MVC(Model-View-Controller)设计模式:

  • DispatcherServlet:前端控制器,所有请求的入口点
  • HandlerMapping:将请求映射到处理器
  • HandlerAdapter:执行处理器方法
  • ViewResolver:解析视图名称到具体视图
  • HandlerInterceptor:请求处理拦截器

4.2 创建RESTful API

@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    // GET /api/users - 获取所有用户
    @GetMapping
    public ResponseEntity<List<User>> getAllUsers() {
        List<User> users = userService.findAll();
        return ResponseEntity.ok(users);
    }
    
    // GET /api/users/{id} - 获取单个用户
    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable Long id) {
        return userService.findById(id)
            .map(ResponseEntity::ok)
            .orElse(ResponseEntity.notFound().build());
    }
    
    // POST /api/users - 创建用户
    @PostMapping
    public ResponseEntity<User> createUser(@Valid @RequestBody User user, 
                                          BindingResult result) {
        if (result.hasErrors()) {
            return ResponseEntity.badRequest().build();
        }
        User savedUser = userService.save(user);
        return ResponseEntity.status(HttpStatus.CREATED).body(savedUser);
    }
    
    // PUT /api/users/{id} - 更新用户
    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(@PathVariable Long id, 
                                          @Valid @RequestBody User user) {
        return userService.findById(id)
            .map(existing -> {
                user.setId(id);
                return ResponseEntity.ok(userService.save(user));
            })
            .orElse(ResponseEntity.notFound().build());
    }
    
    // DELETE /api/users/{id} - 删除用户
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        if (userService.findById(id).isPresent()) {
            userService.delete(id);
            return ResponseEntity.noContent().build();
        }
        return ResponseEntity.notFound().build();
    }
    
    // GET /api/users/search?name=John - 条件查询
    @GetMapping("/search")
    public ResponseEntity<List<User>> searchUsers(
            @RequestParam(required = false) String name,
            @RequestParam(required = false) String email) {
        List<User> users = userService.search(name, email);
        return ResponseEntity.ok(users);
    }
}

4.3 请求参数验证

// 实体类验证注解
public class User {
    
    @NotNull(message = "ID不能为空")
    private Long id;
    
    @NotBlank(message = "用户名不能为空")
    @Size(min = 3, max = 20, message = "用户名长度必须在3-20个字符之间")
    private String username;
    
    @Email(message = "邮箱格式不正确")
    @NotBlank(message = "邮箱不能为空")
    private String email;
    
    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
    private String phone;
    
    @Min(value = 18, message = "年龄必须大于18岁")
    @Max(value = 120, message = "年龄不能超过120岁")
    private Integer age;
    
    // getters and setters
}

// 自定义验证注解
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UniqueUsernameValidator.class)
public @interface UniqueUsername {
    String message() default "用户名已存在";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

// 验证器实现
public class UniqueUsernameValidator implements ConstraintValidator<UniqueUsername, String> {
    
    @Autowired
    private UserRepository userRepository;
    
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        return !userRepository.existsByUsername(value);
    }
}

4.4 全局异常处理

// 全局异常处理器
@RestControllerAdvice
public class GlobalExceptionHandler {
    
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    
    // 处理验证异常
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ErrorResponse> handleValidationExceptions(
            MethodArgumentNotValidException ex) {
        List<String> errors = ex.getBindingResult()
            .getFieldErrors()
            .stream()
            .map(error -> error.getField() + ": " + error.getDefaultMessage())
            .collect(Collectors.toList());
        
        return ResponseEntity.badRequest()
            .body(new ErrorResponse("VALIDATION_ERROR", errors.toString()));
    }
    
    // 处理资源未找到异常
    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleResourceNotFound(
            ResourceNotFoundException ex) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND)
            .body(new ErrorResponse("NOT_FOUND", ex.getMessage()));
    }
    
    // 处理业务异常
    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<ErrorResponse> handleBusinessException(
            BusinessException ex) {
        return ResponseEntity.badRequest()
            .body(new ErrorResponse("BUSINESS_ERROR", ex.getMessage()));
    }
    
    // 处理所有未预期的异常
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex) {
        logger.error("Unexpected error occurred", ex);
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
            .body(new ErrorResponse("INTERNAL_ERROR", "系统内部错误"));
    }
}

// 错误响应DTO
public class ErrorResponse {
    private String code;
    private String message;
    private LocalDateTime timestamp;
    
    public ErrorResponse(String code, String message) {
        this.code = code;
        this.message = message;
        this.timestamp = LocalDateTime.now();
    }
    // getters and setters
}

4.5 拦截器和过滤器

// 自定义拦截器
@Component
public class AuthInterceptor implements HandlerInterceptor {
    
    @Override
    public boolean preHandle(HttpServletRequest request, 
                           HttpServletResponse response, 
                           Object handler) throws Exception {
        // 在控制器方法执行前调用
        String token = request.getHeader("Authorization");
        if (!isValidToken(token)) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }
        return true;
    }
    
    @Override
    public void postHandle(HttpServletRequest request, 
                          HttpServletResponse response, 
                          Object handler, 
                          ModelAndView modelAndView) throws Exception {
        // 在控制器方法执行后调用
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, 
                               HttpServletResponse response, 
                               Object handler, 
                               Exception ex) throws Exception {
        // 在请求完成后调用
    }
    
    private boolean isValidToken(String token) {
        // Token验证逻辑
        return token != null && token.startsWith("Bearer ");
    }
}

// 注册拦截器
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    
    @Autowired
    private AuthInterceptor authInterceptor;
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor)
            .addPathPatterns("/api/**")  // 拦截所有/api开头的请求
            .excludePathPatterns("/api/public/**");  // 排除公共接口
    }
    
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
            .allowedOrigins("http://localhost:3000")
            .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
            .allowedHeaders("*")
            .allowCredentials(true)
            .maxAge(3600);
    }
}

第五部分:Spring Data访问技术

5.1 Spring Data JPA

Spring Data JPA是Spring Data项目的一部分,它简化了JPA(Java Persistence API)的使用。

实体类定义

@Entity
@Table(name = "users")
public class User {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(nullable = false, unique = true, length = 50)
    private String username;
    
    @Column(nullable = false, length = 100)
    private String email;
    
    @Column(length = 20)
    private String phone;
    
    @Column
    private Integer age;
    
    @CreationTimestamp
    @Column(updatable = false)
    private LocalDateTime createdAt;
    
    @UpdateTimestamp
    private LocalDateTime updatedAt;
    
    @Version
    private Long version;  // 乐观锁
    
    // JPA关系映射
    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    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 username, String email) {
        this.username = username;
        this.email = email;
    }
    
    // getters and setters
    // equals, hashCode, toString
}

Repository接口

// 基础Repository接口
public interface UserRepository extends JpaRepository<User, Long>, 
                                        JpaSpecificationExecutor<User> {
    
    // 方法名查询
    Optional<User> findByUsername(String username);
    Optional<User> findByEmail(String email);
    List<User> findByAgeGreaterThan(Integer age);
    List<User> findByUsernameContaining(String keyword);
    
    // 使用@Query注解
    @Query("SELECT u FROM User u WHERE u.email = :email")
    Optional<User> findByEmailQuery(@Param("email") String email);
    
    // 原生SQL查询
    @Query(value = "SELECT * FROM users WHERE age >= :minAge", nativeQuery = true)
    List<User> findUsersByMinAge(@Param("minAge") Integer minAge);
    
    // 动态查询
    @Query("SELECT u FROM User u WHERE " +
           "(:username IS NULL OR u.username LIKE %:username%) AND " +
           "(:email IS NULL OR u.email LIKE %:email%)")
    List<User> searchUsers(@Param("username") String username, 
                          @Param("email") String email);
    
    // 自定义更新操作
    @Modifying
    @Query("UPDATE User u SET u.email = :email WHERE u.id = :id")
    int updateEmail(@Param("id") Long id, @Param("email") String email);
    
    // 分页查询
    Page<User> findByAgeGreaterThan(Integer age, Pageable pageable);
    
    // 排序查询
    List<User> findByAgeGreaterThan(Integer age, Sort sort);
    
    // 统计查询
    long countByAgeGreaterThan(Integer age);
    
    // 存在性查询
    boolean existsByUsername(String username);
    
    // 删除查询
    @Modifying
    @Query("DELETE FROM User u WHERE u.age < :age")
    void deleteByAgeLessThan(@Param("age") Integer age);
}

自定义Repository实现

// 自定义Repository接口
public interface UserRepositoryCustom {
    List<User> findComplexUsers(String keyword, Integer minAge, Integer maxAge);
}

// 实现类
@Repository
public class UserRepositoryImpl implements UserRepositoryCustom {
    
    @PersistenceContext
    private EntityManager entityManager;
    
    @Override
    public List<User> findComplexUsers(String keyword, Integer minAge, Integer maxAge) {
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<User> query = cb.createQuery(User.class);
        Root<User> root = query.from(User.class);
        
        List<Predicate> predicates = new ArrayList<>();
        
        if (keyword != null && !keyword.isEmpty()) {
            predicates.add(cb.or(
                cb.like(root.get("username"), "%" + keyword + "%"),
                cb.like(root.get("email"), "%" + keyword + "%")
            ));
        }
        
        if (minAge != null) {
            predicates.add(cb.greaterThanOrEqualTo(root.get("age"), minAge));
        }
        
        if (maxAge != null) {
            predicates.add(cb.lessThanOrEqualTo(root.get("age"), maxAge));
        }
        
        query.where(predicates.toArray(new Predicate[0]));
        query.orderBy(cb.desc(root.get("createdAt")));
        
        return entityManager.createQuery(query).getResultList();
    }
}

5.2 事务管理

@Service
@Transactional
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    @Autowired
    private OrderRepository orderRepository;
    
    // 事务传播行为
    @Transactional(propagation = Propagation.REQUIRED)
    public void createUserWithOrders(User user, List<Order> orders) {
        userRepository.save(user);
        // 如果save失败,整个事务回滚
        for (Order order : orders) {
            order.setUser(user);
            orderRepository.save(order);
            // 如果某个订单保存失败,前面的操作也会回滚
        }
    }
    
    // 只读事务
    @Transactional(readOnly = true)
    public User findUserWithOrders(Long id) {
        return userRepository.findById(id).orElse(null);
    }
    
    // 不同的隔离级别
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public void updateUser(Long id, String email) {
        userRepository.updateEmail(id, email);
    }
    
    // 自定义事务回滚
    @Transactional(rollbackFor = BusinessException.class)
    public void complexOperation() throws BusinessException {
        try {
            // 业务逻辑
        } catch (Exception e) {
            // 只回滚指定异常
            throw new BusinessException("操作失败", e);
        }
    }
    
    // 事务传播:REQUIRES_NEW
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void auditLog(String message) {
        // 独立事务,即使外层事务回滚,审计日志也会保存
        // saveAuditLog(message);
    }
}

5.3 多数据源配置

// 主数据源配置
@Configuration
@MapperScan(basePackages = "com.example.mapper.master", sqlSessionFactoryRef = "masterSqlSessionFactory")
public class MasterDataSourceConfig {
    
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.master")
    public DataSource masterDataSource() {
        return DataSourceBuilder.create().build();
    }
    
    @Bean
    public SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver()
            .getResources("classpath:mapper/master/*.xml"));
        return bean.getObject();
    }
    
    @Bean
    public DataSourceTransactionManager masterTransactionManager(@Qualifier("masterDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

// 从数据源配置
@Configuration
@MapperScan(basePackages = "com.example.mapper.slave", sqlSessionFactoryRef = "slaveSqlSessionFactory")
public class SlaveDataSourceConfig {
    
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.slave")
    public DataSource slaveDataSource() {
        return DataSourceBuilder.create().build();
    }
    
    @Bean
    public SqlSessionFactory slaveSqlSessionFactory(@Qualifier("slaveDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver()
            .getResources("classpath:mapper/slave/*.xml"));
        return bean.getObject();
    }
    
    @Bean
    public DataSourceTransactionManager slaveTransactionManager(@Qualifier("slaveDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

第六部分:Spring Security安全框架

6.1 Spring Security基础

Spring Security是Spring生态系统中的安全框架,提供认证和授权功能。

基本配置

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf().disable()  // 禁用CSRF(用于REST API)
            .authorizeHttpRequests(authz -> authz
                .requestMatchers("/api/public/**").permitAll()  // 公共接口
                .requestMatchers("/api/admin/**").hasRole("ADMIN")  // 管理员接口
                .requestMatchers("/api/user/**").hasAnyRole("USER", "ADMIN")  // 用户接口
                .anyRequest().authenticated()  // 其他需要认证
            )
            .sessionManagement(session -> session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)  // 无状态
            )
            .httpBasic();  // 使用HTTP Basic认证
        
        return http.build();
    }
    
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    
    @Bean
    public AuthenticationManager authenticationManager(
            UserDetailsService userDetailsService,
            PasswordEncoder passwordEncoder) {
        
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(userDetailsService);
        provider.setPasswordEncoder(passwordEncoder);
        
        return new ProviderManager(provider);
    }
}

自定义UserDetailsService

@Service
public class CustomUserDetailsService implements UserDetailsService {
    
    @Autowired
    private UserRepository userRepository;
    
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username)
            .orElseThrow(() -> new UsernameNotFoundException("用户不存在: " + username));
        
        return org.springframework.security.core.userdetails.User
            .withUsername(user.getUsername())
            .password(user.getPassword())
            .authorities(user.getRoles().stream()
                .map(role -> new SimpleGrantedAuthority("ROLE_" + role.getName()))
                .collect(Collectors.toList()))
            .accountExpired(false)
            .accountLocked(false)
            .credentialsExpired(false)
            .disabled(false)
            .build();
    }
}

6.2 JWT认证实现

// JWT工具类
@Component
public class JwtTokenUtil {
    
    private static final String SECRET_KEY = "your-secret-key-min-256-bits";
    private static final long EXPIRATION_TIME = 86400000; // 24小时
    
    public String generateToken(UserDetails userDetails) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("roles", userDetails.getAuthorities().stream()
            .map(GrantedAuthority::getAuthority)
            .collect(Collectors.toList()));
        
        return Jwts.builder()
            .setClaims(claims)
            .setSubject(userDetails.getUsername())
            .setIssuedAt(new Date())
            .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
            .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
            .compact();
    }
    
    public String extractUsername(String token) {
        return extractClaim(token, Claims::getSubject);
    }
    
    public Date extractExpiration(String token) {
        return extractClaim(token, Claims::getExpiration);
    }
    
    public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = extractAllClaims(token);
        return claimsResolver.apply(claims);
    }
    
    private Claims extractAllClaims(String token) {
        return Jwts.parser()
            .setSigningKey(SECRET_KEY)
            .parseClaimsJws(token)
            .getBody();
    }
    
    private Boolean isTokenExpired(String token) {
        return extractExpiration(token).before(new Date());
    }
    
    public Boolean validateToken(String token, UserDetails userDetails) {
        final String username = extractUsername(token);
        return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
    }
}

// JWT认证过滤器
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    
    @Autowired
    private UserDetailsService userDetailsService;
    
    @Override
    protected void doFilterInternal(HttpServletRequest request, 
                                  HttpServletResponse response, 
                                  FilterChain filterChain) throws ServletException, IOException {
        
        final String authHeader = request.getHeader("Authorization");
        
        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            filterChain.doFilter(request, response);
            return;
        }
        
        final String jwt = authHeader.substring(7);
        final String username = jwtTokenUtil.extractUsername(jwt);
        
        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = userDetailsService.loadUserByUsername(username);
            
            if (jwtTokenUtil.validateToken(jwt, userDetails)) {
                UsernamePasswordAuthenticationToken authentication = 
                    new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        }
        
        filterChain.doFilter(request, response);
    }
}

// 更新Security配置以支持JWT
@Configuration
@EnableWebSecurity
public class SecurityConfig {
    
    @Autowired
    private JwtAuthenticationFilter jwtAuthenticationFilter;
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .authorizeHttpRequests(authz -> authz
                .requestMatchers("/api/auth/**").permitAll()
                .anyRequest().authenticated()
            )
            .sessionManagement(session -> session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            )
            .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
        
        return http.build();
    }
}

6.3 方法级安全

@Configuration
@EnableMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig {
}

@Service
public class SecureService {
    
    // 只有ADMIN角色可以访问
    @PreAuthorize("hasRole('ADMIN')")
    public void adminOnlyMethod() {
        // 管理员操作
    }
    
    // 只有USER角色可以访问
    @PreAuthorize("hasRole('USER')")
    public void userOnlyMethod() {
        // 用户操作
    }
    
    // 方法参数级权限控制
    @PreAuthorize("hasRole('ADMIN') or #userId == authentication.principal.id")
    public void updateUser(Long userId, String newEmail) {
        // 只能更新自己的信息,或管理员可以更新所有
    }
    
    // 返回值过滤
    @PostFilter("filterObject.owner == authentication.principal.username")
    public List<Order> getOrders() {
        // 返回的订单列表会被过滤,只保留当前用户的订单
        return orderRepository.findAll();
    }
    
    // 角色层次结构
    @PreAuthorize("hasAuthority('ROLE_ADMIN') or hasAuthority('ROLE_MANAGER')")
    public void managerMethod() {
        // 管理员和经理都可以访问
    }
}

第七部分:Spring测试

7.1 单元测试

@SpringBootTest
class UserServiceTest {
    
    @Autowired
    private UserService userService;
    
    @MockBean
    private UserRepository userRepository;
    
    @Test
    void shouldReturnUserWhenUserExists() {
        // Given
        User mockUser = new User(1L, "john", "john@example.com");
        when(userRepository.findById(1L)).thenReturn(Optional.of(mockUser));
        
        // When
        Optional<User> result = userService.findById(1L);
        
        // Then
        assertThat(result).isPresent();
        assertThat(result.get().getUsername()).isEqualTo("john");
        verify(userRepository, times(1)).findById(1L);
    }
    
    @Test
    void shouldThrowExceptionWhenUserNotFound() {
        // Given
        when(userRepository.findById(999L)).thenReturn(Optional.empty());
        
        // When & Then
        assertThrows(ResourceNotFoundException.class, () -> {
            userService.getUser(999L);
        });
    }
}

7.2 Web层测试

@WebMvcTest(UserController.class)
class UserControllerTest {
    
    @Autowired
    private MockMvc mockMvc;
    
    @MockBean
    private UserService userService;
    
    @Test
    void shouldReturnUserWhenExists() throws Exception {
        User user = new User(1L, "john", "john@example.com");
        when(userService.findById(1L)).thenReturn(Optional.of(user));
        
        mockMvc.perform(get("/api/users/1"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.id").value(1))
            .andExpect(jsonPath("$.username").value("john"));
    }
    
    @Test
    void shouldReturn404WhenUserNotFound() throws Exception {
        when(userService.findById(999L)).thenReturn(Optional.empty());
        
        mockMvc.perform(get("/api/users/999"))
            .andExpect(status().isNotFound());
    }
    
    @Test
    void shouldCreateUser() throws Exception {
        User newUser = new User(null, "john", "john@example.com");
        User savedUser = new User(1L, "john", "john@example.com");
        
        when(userService.save(any(User.class))).thenReturn(savedUser);
        
        mockMvc.perform(post("/api/users")
                .contentType(MediaType.APPLICATION_JSON)
                .content("{\"username\":\"john\",\"email\":\"john@example.com\"}"))
            .andExpect(status().isCreated())
            .andExpect(jsonPath("$.id").value(1));
    }
}

7.3 集成测试

@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class UserRepositoryIntegrationTest {
    
    @Autowired
    private TestEntityManager entityManager;
    
    @Autowired
    private UserRepository userRepository;
    
    @Test
    void shouldFindUserByUsername() {
        User user = new User("john", "john@example.com");
        entityManager.persist(user);
        entityManager.flush();
        
        Optional<User> found = userRepository.findByUsername("john");
        
        assertThat(found).isPresent();
        assertThat(found.get().getEmail()).isEqualTo("john@example.com");
    }
    
    @Test
    void shouldReturnEmptyWhenUserNotFound() {
        Optional<User> found = userRepository.findByUsername("nonexistent");
        assertThat(found).isEmpty();
    }
}

第八部分:Spring高级特性

8.1 Spring事件驱动编程

// 自定义事件
public class UserCreatedEvent extends ApplicationEvent {
    private final User user;
    
    public UserCreatedEvent(Object source, User user) {
        super(source);
        this.user = user;
    }
    
    public User getUser() {
        return user;
    }
}

// 事件发布者
@Service
public class UserService {
    
    @Autowired
    private ApplicationEventPublisher eventPublisher;
    
    public void createUser(User user) {
        // 保存用户
        userRepository.save(user);
        // 发布事件
        eventPublisher.publishEvent(new UserCreatedEvent(this, user));
    }
}

// 事件监听器
@Component
public class UserEventListener {
    
    @EventListener
    public void handleUserCreated(UserCreatedEvent event) {
        // 异步处理
        sendWelcomeEmail(event.getUser());
        logUserCreation(event.getUser());
    }
    
    @Async  // 异步执行
    public void sendWelcomeEmail(User user) {
        // 发送欢迎邮件逻辑
    }
    
    @Async
    public void logUserCreation(User user) {
        // 记录日志
    }
}

// 异步配置
@Configuration
@EnableAsync
public class AsyncConfig {
    
    @Bean
    public TaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(25);
        executor.setThreadNamePrefix("Async-");
        executor.initialize();
        return executor;
    }
}

8.2 Spring缓存

@Configuration
@EnableCaching
public class CacheConfig {
    
    @Bean
    public CacheManager cacheManager() {
        // 使用Caffeine作为缓存实现
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        cacheManager.setCaffeine(Caffeine.newBuilder()
            .expireAfterWrite(10, TimeUnit.MINUTES)
            .maximumSize(1000)
            .recordStats());
        return cacheManager;
    }
}

@Service
public class UserService {
    
    @Cacheable(value = "users", key = "#id")
    public User getUser(Long id) {
        // 只有在缓存中不存在时才会执行此方法
        return userRepository.findById(id).orElse(null);
    }
    
    @CachePut(value = "users", key = "#user.id")
    public User updateUser(User user) {
        // 更新缓存
        return userRepository.save(user);
    }
    
    @CacheEvict(value = "users", key = "#id")
    public void deleteUser(Long id) {
        // 清除缓存
        userRepository.deleteById(id);
    }
    
    @Caching(
        put = {
            @CachePut(value = "users", key = "#user.id"),
            @CachePut(value = "usernames", key = "#user.username")
        },
        evict = {
            @CacheEvict(value = "allUsers", allEntries = true)
        }
    )
    public User createUser(User user) {
        return userRepository.save(user);
    }
}

8.3 Spring批处理

@Configuration
@EnableBatchProcessing
public class BatchConfig {
    
    @Autowired
    private JobBuilderFactory jobBuilderFactory;
    
    @Autowired
    private StepBuilderFactory stepBuilderFactory;
    
    @Bean
    public Job importUserJob(Step step1) {
        return jobBuilderFactory.get("importUserJob")
            .incrementer(new RunIdIncrementer())
            .flow(step1)
            .end()
            .listener(jobCompletionListener())
            .build();
    }
    
    @Bean
    public Step step1(ItemReader<User> reader, 
                     ItemWriter<User> writer,
                     ItemProcessor<User, User> processor) {
        return stepBuilderFactory.get("step1")
            .<User, User>chunk(10)
            .reader(reader)
            .processor(processor)
            .writer(writer)
            .build();
    }
    
    @Bean
    public ItemReader<User> reader() {
        // 从CSV文件读取
        FlatFileItemReader<User> reader = new FlatFileItemReader<>();
        reader.setResource(new ClassPathResource("users.csv"));
        reader.setLineMapper(new DefaultLineMapper<User>() {{
            setLineTokenizer(new DelimitedLineTokenizer() {{
                setNames("username", "email", "age");
            }});
            setFieldSetMapper(new BeanWrapperFieldSetMapper<User>() {{
                setTargetType(User.class);
            }});
        }});
        return reader;
    }
    
    @Bean
    public ItemProcessor<User, User> processor() {
        return user -> {
            user.setEmail(user.getEmail().toLowerCase());
            return user;
        };
    }
    
    @Bean
    public ItemWriter<User> writer() {
        return users -> {
            // 批量写入数据库
            users.forEach(user -> userRepository.save(user));
        };
    }
    
    @Bean
    public JobExecutionListener jobCompletionListener() {
        return new JobExecutionListenerSupport() {
            @Override
            public void afterJob(JobExecution jobExecution) {
                System.out.println("Job completed: " + jobExecution.getStatus());
            }
        };
    }
}

8.4 Spring WebSocket

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
    
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(new ChatWebSocketHandler(), "/chat")
            .setAllowedOrigins("*");
    }
}

@Component
public class ChatWebSocketHandler extends TextWebSocketHandler {
    
    private final List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();
    
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        sessions.add(session);
        session.sendMessage(new TextMessage("Connected to chat server"));
    }
    
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        // 广播消息到所有会话
        for (WebSocketSession s : sessions) {
            if (s.isOpen()) {
                s.sendMessage(message);
            }
        }
    }
    
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        sessions.remove(session);
    }
}

第九部分:Spring微服务架构

9.1 Spring Cloud基础

Spring Cloud为分布式系统开发提供了一整套工具。

服务注册与发现(Eureka)

# application.yml for Eureka Server
server:
  port: 8761

eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://localhost:8761/eureka/
  server:
    enable-self-preservation: false
// Eureka Server
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

// Eureka Client
@SpringBootApplication
@EnableEurekaClient
public class UserServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}

// 配置
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

服务调用(Feign)

// Feign客户端
@FeignClient(name = "order-service", fallback = OrderServiceFallback.class)
public interface OrderServiceClient {
    
    @GetMapping("/api/orders/user/{userId}")
    List<Order> getOrdersByUserId(@PathVariable("userId") Long userId);
    
    @PostMapping("/api/orders")
    Order createOrder(@RequestBody Order order);
}

// 熔断器
@Component
public class OrderServiceFallback implements OrderServiceClient {
    
    @Override
    public List<Order> getOrdersByUserId(Long userId) {
        return Collections.emptyList(); // 返回空列表
    }
    
    @Override
    public Order createOrder(Order order) {
        throw new RuntimeException("Order service unavailable");
    }
}

// 使用Feign
@Service
public class UserService {
    
    @Autowired
    private OrderServiceClient orderServiceClient;
    
    public UserWithOrders getUserWithOrders(Long userId) {
        User user = userRepository.findById(userId).orElse(null);
        if (user == null) return null;
        
        List<Order> orders = orderServiceClient.getOrdersByUserId(userId);
        return new UserWithOrders(user, orders);
    }
}

配置中心(Config Server)

# Config Server application.yml
server:
  port: 8888

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/your-repo/config-repo
          search-paths: '{application}'
          username: your-username
          password: your-password
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}

# Config Client bootstrap.yml
spring:
  application:
    name: user-service
  cloud:
    config:
      uri: http://localhost:8888
      profile: dev

熔断器(Hystrix)

@Service
public class ProductService {
    
    @Autowired
    private ProductRepository productRepository;
    
    @HystrixCommand(
        fallbackMethod = "getProductFallback",
        commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")
        },
        threadPoolProperties = {
            @HystrixProperty(name = "coreSize", value = "10"),
            @HystrixProperty(name = "maxQueueSize", value = "100")
        }
    )
    public Product getProduct(Long id) {
        // 模拟慢查询
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return productRepository.findById(id).orElse(null);
    }
    
    public Product getProductFallback(Long id) {
        // 降级返回
        return new Product(id, "Fallback Product", 0.0);
    }
}

9.2 API网关(Spring Cloud Gateway)

# application.yml
server:
  port: 8080

spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/api/users/**
          filters:
            - StripPrefix=1
            - name: Retry
              args:
                retries: 3
                backoff:
                  firstBackoff: 50ms
                  maxBackoff: 500ms
                  factor: 2
                  basedOnPreviousValue: false
        
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/api/orders/**
          filters:
            - StripPrefix=1
            - RateLimit=10, 20s  # 20秒内最多10个请求
        
        - id: auth-service
          uri: lb://auth-service
          predicates:
            - Path=/api/auth/**
          filters:
            - StripPrefix=1
// 自定义过滤器
@Component
public class LoggingFilter implements GlobalFilter, Ordered {
    
    private static final Logger logger = LoggerFactory.getLogger(LoggingFilter.class);
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        logger.info("Request: {} {}", 
            exchange.getRequest().getMethod(), 
            exchange.getRequest().getURI());
        
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            logger.info("Response: {}", exchange.getResponse().getStatusCode());
        }));
    }
    
    @Override
    public int getOrder() {
        return -1; // 优先级最高
    }
}

9.3 分布式追踪(Sleuth + Zipkin)

# application.yml
spring:
  zipkin:
    base-url: http://localhost:9411
  sleuth:
    sampler:
      probability: 1.0  # 100%采样
// 自定义追踪
@Service
public class TracedService {
    
    @Autowired
    private Tracer tracer;
    
    public void processWithTracing() {
        Span span = tracer.nextSpan().name("process").start();
        try (Tracer.SpanInScope ws = tracer.withSpanInScope(span)) {
            // 业务逻辑
            logger.info("Processing in span: {}", span.context().traceIdString());
        } finally {
            span.end();
        }
    }
}

第十部分:Spring性能优化与最佳实践

10.1 性能优化技巧

1. 连接池优化

# HikariCP配置
spring:
  datasource:
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5
      connection-timeout: 30000
      idle-timeout: 600000
      max-lifetime: 1800000
      leak-detection-threshold: 60000
      pool-name: MyHikariCP

2. JPA优化

// 使用DTO避免N+1查询
public interface UserSummary {
    Long getId();
    String getUsername();
    String getEmail();
}

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    
    // 只查询需要的字段
    @Query("SELECT u.id as id, u.username as username, u.email as email FROM User u")
    List<UserSummary> findAllSummaries();
    
    // 使用JOIN FETCH避免N+1
    @Query("SELECT u FROM User u JOIN FETCH u.orders WHERE u.id = :id")
    Optional<User> findByIdWithOrders(@Param("id") Long id);
    
    // 批量查询
    @Query("SELECT u FROM User u WHERE u.id IN :ids")
    List<User> findByIds(@Param("ids") List<Long> ids);
}

3. 缓存优化

@CacheConfig(cacheNames = "users")
@Service
public class CachedUserService {
    
    @Cacheable(key = "#id")
    public User getUser(Long id) {
        return userRepository.findById(id).orElse(null);
    }
    
    @CacheEvict(allEntries = true)
    public void clearCache() {
        // 清空整个缓存
    }
    
    @Caching(
        evict = {
            @CacheEvict(key = "#user.id"),
            @CacheEvict(value = "usernames", key = "#user.username")
        }
    )
    public void updateUser(User user) {
        userRepository.save(user);
    }
}

10.2 监控与健康检查

// 自定义健康检查
@Component
public class DatabaseHealthIndicator implements HealthIndicator {
    
    @Autowired
    private DataSource dataSource;
    
    @Override
    public Health health() {
        try (Connection conn = dataSource.getConnection()) {
            conn.createStatement().execute("SELECT 1");
            return Health.up()
                .withDetail("database", "MySQL")
                .withDetail("connections", getActiveConnections())
                .build();
        } catch (Exception e) {
            return Health.down()
                .withDetail("error", e.getMessage())
                .build();
        }
    }
    
    private int getActiveConnections() {
        // 获取活跃连接数
        return 0; // 简化示例
    }
}

// 自定义指标
@Component
public class CustomMetrics {
    
    private final Counter requestCounter = Counter.build()
        .name("http_requests_total")
        .help("Total HTTP requests")
        .labelNames("method", "path", "status")
        .register();
    
    private final Histogram requestDuration = Histogram.build()
        .name("http_request_duration_seconds")
        .help("HTTP request duration in seconds")
        .buckets(0.1, 0.5, 1, 2, 5)
        .register();
    
    public void recordRequest(String method, String path, String status, double duration) {
        requestCounter.labels(method, path, status).inc();
        requestDuration.observe(duration);
    }
}

10.3 日志配置

<!-- logback-spring.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
    
    <springProperty scope="context" name="APP_NAME" source="spring.application.name"/>
    
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
        </encoder>
    </appender>
    
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/${APP_NAME}.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>logs/${APP_NAME}.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
            <totalSizeCap>1GB</totalSizeCap>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    
    <appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="FILE"/>
        <queueSize>10000</queueSize>
        <discardingThreshold>0</discardingThreshold>
    </appender>
    
    <!-- 不同环境不同日志级别 -->
    <springProfile name="dev">
        <root level="DEBUG">
            <appender-ref ref="CONSOLE"/>
        </root>
    </springProfile>
    
    <springProfile name="prod">
        <root level="INFO">
            <appender-ref ref="ASYNC_FILE"/>
        </root>
        
        <!-- 特定包的日志级别 -->
        <logger name="com.example" level="DEBUG"/>
        <logger name="org.springframework" level="WARN"/>
        <logger name="org.hibernate" level="WARN"/>
    </springProfile>
</configuration>

第十一部分:Spring学习路径与资源

11.1 学习路线建议

阶段一:基础入门(1-2周)

  • 掌握Java基础(集合、多线程、反射、注解)
  • 理解IoC和DI概念
  • 学习Spring基础配置(XML和注解)
  • 完成简单的控制台应用

阶段二:Web开发(2-3周)

  • 学习Spring MVC
  • 掌握RESTful API设计
  • 理解HTTP协议和状态码
  • 实现完整的CRUD应用

阶段三:数据访问(2-3周)

  • 学习JPA和Hibernate
  • 掌握Spring Data JPA
  • 理解事务管理
  • 实现复杂的数据查询

阶段四:Spring Boot(2周)

  • 理解自动配置原理
  • 掌握起步依赖
  • 学习外部化配置
  • 构建生产级应用

阶段五:安全性(1-2周)

  • 学习Spring Security基础
  • 掌握认证和授权
  • 实现JWT认证
  • 理解OAuth2

阶段六:高级特性(2-3周)

  • AOP深入
  • 缓存和异步处理
  • 事件驱动编程
  • 批处理

阶段七:微服务(3-4周)

  • Spring Cloud基础
  • 服务注册与发现
  • API网关和熔断器
  • 分布式追踪

阶段八:性能优化与最佳实践(持续学习)

  • 性能调优
  • 监控和日志
  • 测试策略
  • 代码规范

11.2 推荐学习资源

官方文档:

书籍推荐:

  • 《Spring实战》(Spring in Action)
  • 《Spring Boot编程思想》
  • 《Spring Cloud微服务实战》
  • 《Spring 5核心原理》

在线课程:

社区和论坛:

  • Spring官方论坛
  • Stack Overflow
  • GitHub Spring项目
  • 国内技术社区(如掘金、思否)

11.3 实践项目建议

初级项目:

  1. 用户管理系统(CRUD)
  2. 博客系统
  3. 待办事项应用

中级项目:

  1. 电商后台系统
  2. 在线考试系统
  3. 即时通讯应用

高级项目:

  1. 微服务架构的电商平台
  2. 大数据处理平台
  3. 高并发秒杀系统

总结

Spring框架是一个功能强大、生态丰富的Java开发框架。通过本文的学习,你应该已经掌握了从基础概念到高级特性的完整知识体系。记住,理论学习只是第一步,真正的精通来自于不断的实践和项目经验。

关键要点回顾:

  1. IoC和DI是Spring的核心,理解它们对于掌握Spring至关重要
  2. AOP帮助我们分离横切关注点,提高代码的可维护性
  3. Spring Boot通过自动配置大大简化了开发过程
  4. Spring MVC提供了强大的Web开发能力
  5. Spring Data简化了数据访问层的开发
  6. Spring Security提供了全面的安全解决方案
  7. Spring Cloud为微服务架构提供了完整的工具链

持续学习的建议:

  • 阅读Spring源码,理解内部实现机制
  • 关注Spring新版本的特性更新
  • 参与开源项目,贡献代码
  • 在实际项目中应用所学知识
  • 与社区保持交流,学习最佳实践

Spring生态系统在不断演进,保持学习的热情和实践的习惯,你将能够掌握这个强大的框架,并在Java开发领域取得更大的成就。祝你学习顺利!