引言

Spring框架是Java企业级开发的事实标准,它通过依赖注入(DI)和面向切面编程(AOP)等核心思想,极大地简化了企业应用的开发。本指南将从基础概念出发,逐步深入到高级特性,并结合实战案例,帮助你全面掌握Spring框架的核心原理与应用技巧。

第一部分:Spring基础入门

1.1 Spring框架概述

Spring是一个轻量级的开源框架,最初由Rod Johnson在2003年发布。它的核心特性包括:

  • 依赖注入(DI):通过控制反转(IoC)容器管理对象之间的依赖关系
  • 面向切面编程(AOP):将横切关注点(如日志、事务)从业务逻辑中分离
  • 声明式事务管理:通过注解或配置实现事务管理
  • 集成支持:与各种持久层框架(如MyBatis、Hibernate)无缝集成

1.2 环境搭建

1.2.1 开发工具准备

  • JDK 8或更高版本
  • Maven或Gradle构建工具
  • IDE(推荐IntelliJ IDEA或Eclipse)

1.2.2 创建第一个Spring项目

使用Maven创建一个简单的Spring项目:

<!-- 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>spring-demo</artifactId>
    <version>1.0.0</version>
    
    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring.version>5.3.20</spring.version>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
    </dependencies>
</project>

1.2.3 创建简单的Bean和配置类

// 1. 创建一个简单的Bean
public class HelloWorldService {
    private String message;
    
    public HelloWorldService(String message) {
        this.message = message;
    }
    
    public void sayHello() {
        System.out.println("Hello, " + message);
    }
    
    public void setMessage(String message) {
        this.message = message;
    }
}

// 2. 创建配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {
    
    @Bean
    public HelloWorldService helloWorldService() {
        return new HelloWorldService("Spring Framework");
    }
}

// 3. 主程序
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        // 创建Spring容器
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        
        // 获取Bean
        HelloWorldService service = context.getBean(HelloWorldService.class);
        
        // 使用Bean
        service.sayHello();
    }
}

1.3 依赖注入详解

1.3.1 构造器注入

public class OrderService {
    private final UserService userService;
    private final PaymentService paymentService;
    
    // 构造器注入
    public OrderService(UserService userService, PaymentService paymentService) {
        this.userService = userService;
        this.paymentService = paymentService;
    }
    
    public void createOrder() {
        // 业务逻辑
    }
}

// 配置类
@Configuration
public class ServiceConfig {
    
    @Bean
    public UserService userService() {
        return new UserService();
    }
    
    @Bean
    public PaymentService paymentService() {
        return new PaymentService();
    }
    
    @Bean
    public OrderService orderService(UserService userService, PaymentService paymentService) {
        return new OrderService(userService, paymentService);
    }
}

1.3.2 Setter注入

public class OrderService {
    private UserService userService;
    private PaymentService paymentService;
    
    // Setter方法注入
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
    
    public void setPaymentService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }
}

1.3.3 字段注入(不推荐在生产环境使用)

public class OrderService {
    @Autowired
    private UserService userService;
    
    @Autowired
    private PaymentService paymentService;
}

1.4 Bean的作用域

Spring支持以下Bean作用域:

  • singleton(默认):每个Spring容器中一个Bean实例
  • prototype:每次请求都创建新实例
  • request:每个HTTP请求一个实例(Web环境)
  • session:每个HTTP会话一个实例(Web环境)
  • global-session:全局HTTP会话(Portlet环境)
@Configuration
public class ScopeConfig {
    
    @Bean
    @Scope("singleton")  // 默认作用域
    public SingletonBean singletonBean() {
        return new SingletonBean();
    }
    
    @Bean
    @Scope("prototype")
    public PrototypeBean prototypeBean() {
        return new PrototypeBean();
    }
}

第二部分:Spring核心原理深入

2.1 IoC容器工作原理

2.1.1 Bean的生命周期

Spring Bean的完整生命周期包括以下阶段:

  1. 实例化:通过构造器或工厂方法创建Bean实例
  2. 属性赋值:通过setter或构造器注入依赖
  3. 初始化前:调用BeanPostProcessor.postProcessBeforeInitialization()
  4. 初始化:调用InitializingBean.afterPropertiesSet()@PostConstruct方法
  5. 初始化后:调用BeanPostProcessor.postProcessAfterInitialization()
  6. 使用:Bean被应用程序使用
  7. 销毁:调用DisposableBean.destroy()@PreDestroy方法
@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("6. @PreDestroy方法调用");
    }
    
    @Override
    public void destroy() throws Exception {
        System.out.println("7. DisposableBean.destroy()调用");
    }
}

2.1.2 BeanPostProcessor详解

BeanPostProcessor是Spring提供的扩展点,允许在Bean初始化前后进行自定义处理。

@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
    
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof UserService) {
            System.out.println("在UserService初始化前进行处理");
            // 可以在这里修改Bean的属性或行为
        }
        return bean;
    }
    
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof UserService) {
            System.out.println("在UserService初始化后进行处理");
            // 可以在这里创建代理对象
        }
        return bean;
    }
}

2.2 AOP原理与应用

2.2.1 AOP核心概念

  • 切面(Aspect):横切关注点的模块化
  • 连接点(Join Point):程序执行过程中的某个位置
  • 切点(Pointcut):匹配连接点的表达式
  • 通知(Advice):在切点执行的具体操作
  • 目标对象(Target):被代理的对象
  • 代理(Proxy):Spring创建的代理对象

2.2.2 基于注解的AOP实现

// 1. 定义切面
@Aspect
@Component
public class LoggingAspect {
    
    // 定义切点:所有public方法
    @Pointcut("execution(public * com.example.service.*.*(..))")
    public void serviceMethods() {}
    
    // 前置通知
    @Before("serviceMethods()")
    public void beforeMethod(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("开始执行方法: " + methodName);
    }
    
    // 后置通知
    @After("serviceMethods()")
    public void afterMethod(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("方法执行完成: " + methodName);
    }
    
    // 返回通知
    @AfterReturning(pointcut = "serviceMethods()", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        System.out.println("方法返回值: " + result);
    }
    
    // 异常通知
    @AfterThrowing(pointcut = "serviceMethods()", throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint, Exception ex) {
        System.out.println("方法执行异常: " + ex.getMessage());
    }
    
    // 环绕通知
    @Around("serviceMethods()")
    public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        System.out.println("环绕通知 - 方法开始");
        
        try {
            Object result = joinPoint.proceed();  // 执行目标方法
            long end = System.currentTimeMillis();
            System.out.println("环绕通知 - 方法执行完成,耗时: " + (end - start) + "ms");
            return result;
        } catch (Exception e) {
            System.out.println("环绕通知 - 方法执行异常: " + e.getMessage());
            throw e;
        }
    }
}

// 2. 启用AOP
@Configuration
@EnableAspectJAutoProxy
public class AopConfig {
    // 配置类
}

// 3. 目标类
@Service
public class UserService {
    
    public String getUserById(Long id) {
        System.out.println("执行getUserById方法");
        return "User-" + id;
    }
    
    public void deleteUser(Long id) {
        System.out.println("执行deleteUser方法");
        if (id == null) {
            throw new IllegalArgumentException("ID不能为空");
        }
    }
}

2.2.3 AOP实现原理

Spring AOP默认使用JDK动态代理(针对接口)或CGLIB代理(针对类)。代理对象的创建过程:

  1. 代理创建时机:当Bean被注入到其他Bean时,Spring容器会检查是否需要创建代理
  2. 代理创建过程
    • 获取Bean的Class对象
    • 检查是否需要代理(通过@Aspect注解或XML配置)
    • 创建代理对象(JDK或CGLIB)
    • 将代理对象放入容器
// 深入理解代理创建
public class ProxyCreator {
    
    // JDK动态代理示例
    public static Object createJdkProxy(Object target, Class<?>[] interfaces) {
        return Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            interfaces,
            new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("JDK代理 - 方法调用前");
                    Object result = method.invoke(target, args);
                    System.out.println("JDK代理 - 方法调用后");
                    return result;
                }
            }
        );
    }
    
    // CGLIB代理示例(需要添加cglib依赖)
    public static Object createCglibProxy(Object target) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                System.out.println("CGLIB代理 - 方法调用前");
                Object result = proxy.invokeSuper(obj, args);
                System.out.println("CGLIB代理 - 方法调用后");
                return result;
            }
        });
        return enhancer.create();
    }
}

2.3 事务管理

2.3.1 事务传播行为

Spring定义了7种事务传播行为:

  • REQUIRED(默认):如果当前存在事务,则加入;否则新建事务
  • REQUIRES_NEW:总是新建事务,如果当前存在事务,则挂起当前事务
  • SUPPORTS:如果当前存在事务,则加入;否则以非事务方式执行
  • MANDATORY:如果当前存在事务,则加入;否则抛出异常
  • NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,则挂起
  • NEVER:以非事务方式执行,如果当前存在事务,则抛出异常
  • NESTED:如果当前存在事务,则在嵌套事务中执行;否则新建事务
@Service
public class OrderService {
    
    @Autowired
    private UserService userService;
    
    @Autowired
    private PaymentService paymentService;
    
    // 默认传播行为:REQUIRED
    @Transactional
    public void createOrder(Order order) {
        // 1. 创建订单
        orderRepository.save(order);
        
        // 2. 扣减库存
        inventoryService.deductStock(order.getProductId(), order.getQuantity());
        
        // 3. 支付处理
        paymentService.processPayment(order);
        
        // 4. 发送通知
        notificationService.sendOrderNotification(order);
    }
    
    // REQUIRES_NEW传播行为
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void logOrderCreation(Order order) {
        // 独立事务,即使外层事务回滚,这个日志也会保存
        auditLogRepository.save(new AuditLog("ORDER_CREATED", order.getId()));
    }
    
    // NESTED传播行为
    @Transactional(propagation = Propagation.NESTED)
    public void processSubOrder(Order order) {
        // 嵌套事务,如果外层事务回滚,嵌套事务也会回滚
        // 但嵌套事务可以独立提交
        subOrderRepository.save(order.getSubOrder());
    }
}

2.3.2 事务隔离级别

Spring支持以下事务隔离级别:

  • DEFAULT:使用数据库默认隔离级别
  • READ_UNCOMMITTED:读未提交
  • READ_COMMITTED:读已提交(Oracle默认)
  • REPEATABLE_READ:可重复读(MySQL默认)
  • SERIALIZABLE:串行化
@Service
public class AccountService {
    
    // 使用READ_COMMITTED隔离级别
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public void transferMoney(Long fromAccountId, Long toAccountId, BigDecimal amount) {
        Account fromAccount = accountRepository.findById(fromAccountId);
        Account toAccount = accountRepository.findById(toAccountId);
        
        // 检查余额
        if (fromAccount.getBalance().compareTo(amount) < 0) {
            throw new InsufficientBalanceException("余额不足");
        }
        
        // 扣款
        fromAccount.setBalance(fromAccount.getBalance().subtract(amount));
        accountRepository.save(fromAccount);
        
        // 存款
        toAccount.setBalance(toAccount.getBalance().add(amount));
        accountRepository.save(toAccount);
    }
}

第三部分:Spring Boot实战

3.1 Spring Boot快速入门

3.1.1 创建Spring Boot项目

使用Spring Initializr创建项目:

<!-- pom.xml -->
<project>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.0</version>
    </parent>
    
    <dependencies>
        <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>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

3.1.2 创建RESTful API

// 1. 实体类
@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(nullable = false)
    private String username;
    
    @Column(nullable = false)
    private String email;
    
    // 构造器、getter、setter省略
}

// 2. Repository接口
public interface UserRepository extends JpaRepository<User, Long> {
    User findByUsername(String username);
    List<User> findByEmailContaining(String email);
}

// 3. Service层
@Service
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    public User createUser(User user) {
        // 业务逻辑验证
        if (userRepository.findByUsername(user.getUsername()) != null) {
            throw new RuntimeException("用户名已存在");
        }
        return userRepository.save(user);
    }
    
    public List<User> getAllUsers() {
        return userRepository.findAll();
    }
    
    public User getUserById(Long id) {
        return userRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("用户不存在"));
    }
}

// 4. Controller层
@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        User createdUser = userService.createUser(user);
        return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);
    }
    
    @GetMapping
    public ResponseEntity<List<User>> getAllUsers() {
        return ResponseEntity.ok(userService.getAllUsers());
    }
    
    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable Long id) {
        return ResponseEntity.ok(userService.getUserById(id));
    }
    
    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User user) {
        User existingUser = userService.getUserById(id);
        existingUser.setUsername(user.getUsername());
        existingUser.setEmail(user.getEmail());
        User updatedUser = userService.createUser(existingUser);
        return ResponseEntity.ok(updatedUser);
    }
    
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
        return ResponseEntity.noContent().build();
    }
}

// 5. 主应用类
@SpringBootApplication
public class UserApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserApplication.class, args);
    }
}

3.2 Spring Boot配置管理

3.2.1 配置文件

Spring Boot支持多种配置文件格式:

  • application.properties:键值对格式
  • application.yml:YAML格式(推荐)
# 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
  profiles:
    active: dev

logging:
  level:
    com.example: DEBUG
    org.springframework.web: INFO

3.2.2 配置类

@Configuration
@ConfigurationProperties(prefix = "app")
public class AppConfig {
    
    private String name;
    private String version;
    private Database database = new Database();
    
    // 构造器、getter、setter省略
    
    @Data
    public static class Database {
        private String url;
        private String username;
        private String password;
    }
}

// 使用配置
@Service
public class ConfigService {
    
    @Autowired
    private AppConfig appConfig;
    
    public void printConfig() {
        System.out.println("应用名称: " + appConfig.getName());
        System.out.println("数据库URL: " + appConfig.getDatabase().getUrl());
    }
}

3.3 Spring Boot高级特性

3.3.1 自动配置原理

Spring Boot自动配置的核心是@EnableAutoConfiguration注解,它通过spring.factories文件加载自动配置类。

// 自定义自动配置
@Configuration
@ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class})
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "hikari", matchIfMissing = true)
@EnableConfigurationProperties(DataSourceProperties.class)
public class HikariDataSourceAutoConfiguration {
    
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.hikari")
    public HikariDataSource dataSource(DataSourceProperties properties) {
        HikariDataSource dataSource = properties.initializeDataSourceBuilder()
                .type(HikariDataSource.class)
                .build();
        dataSource.setPoolName("HikariCP-Pool");
        return dataSource;
    }
}

3.3.2 多环境配置

# application-dev.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb_dev
    username: dev_user
    password: dev_password

# application-prod.yml
spring:
  datasource:
    url: jdbc:mysql://prod-server:3306/mydb_prod
    username: prod_user
    password: prod_password
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5
// 环境特定配置
@Configuration
@Profile("dev")
public class DevConfig {
    
    @Bean
    public DataSource devDataSource() {
        // 开发环境数据源配置
        return new EmbeddedDatabaseBuilder()
                .setType(EmbeddedDatabaseType.H2)
                .addScript("classpath:schema-dev.sql")
                .build();
    }
}

@Configuration
@Profile("prod")
public class ProdConfig {
    
    @Bean
    public DataSource prodDataSource() {
        // 生产环境数据源配置
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setJdbcUrl("jdbc:mysql://prod-server:3306/mydb_prod");
        dataSource.setUsername("prod_user");
        dataSource.setPassword("prod_password");
        dataSource.setMaximumPoolSize(20);
        return dataSource;
    }
}

第四部分:Spring高级实战

4.1 Spring Security安全框架

4.1.1 基础配置

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Autowired
    private UserDetailsService userDetailsService;
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()  // 禁用CSRF(REST API通常禁用)
            .authorizeRequests()
                .antMatchers("/api/public/**").permitAll()  // 公开接口
                .antMatchers("/api/admin/**").hasRole("ADMIN")  // 管理员接口
                .anyRequest().authenticated()  // 其他接口需要认证
            .and()
            .httpBasic()  // 使用HTTP Basic认证
            .and()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);  // 无状态会话
    }
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
            .passwordEncoder(passwordEncoder());
    }
    
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

// 用户详情服务
@Service
public class CustomUserDetailsService implements UserDetailsService {
    
    @Autowired
    private UserRepository userRepository;
    
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("用户不存在");
        }
        
        return org.springframework.security.core.userdetails.User
                .withUsername(user.getUsername())
                .password(user.getPassword())
                .roles(user.getRoles().toArray(new String[0]))
                .build();
    }
}

4.1.2 JWT认证

// JWT工具类
@Component
public class JwtUtil {
    
    private static final String SECRET_KEY = "your-secret-key";
    private static final long EXPIRATION_TIME = 86400000; // 24小时
    
    public String generateToken(UserDetails userDetails) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("roles", userDetails.getAuthorities());
        
        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 Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token)
                .getBody()
                .getSubject();
    }
    
    public boolean validateToken(String token, UserDetails userDetails) {
        final String username = extractUsername(token);
        return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
    }
    
    private boolean isTokenExpired(String token) {
        return extractExpiration(token).before(new Date());
    }
    
    private Date extractExpiration(String token) {
        return Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token)
                .getBody()
                .getExpiration();
    }
}

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

4.2 Spring Data JPA高级用法

4.2.1 自定义查询方法

public interface UserRepository extends JpaRepository<User, Long> {
    
    // 方法名约定查询
    List<User> findByUsername(String username);
    List<User> findByEmailContaining(String email);
    List<User> findByAgeGreaterThanAndStatus(Integer age, String status);
    
    // @Query注解
    @Query("SELECT u FROM User u WHERE u.username = :username")
    User findByUsernameWithQuery(@Param("username") String username);
    
    // 原生SQL查询
    @Query(value = "SELECT * FROM users WHERE age > :age", nativeQuery = true)
    List<User> findUsersByAgeGreaterThan(@Param("age") Integer age);
    
    // 分页查询
    @Query("SELECT u FROM User u WHERE u.status = :status")
    Page<User> findByStatus(@Param("status") String status, Pageable pageable);
    
    // 动态查询
    @Query("SELECT u FROM User u WHERE " +
           "(:username IS NULL OR u.username = :username) AND " +
           "(:email IS NULL OR u.email = :email)")
    List<User> findUsersByDynamicCriteria(@Param("username") String username, 
                                         @Param("email") String email);
    
    // 自定义更新
    @Modifying
    @Query("UPDATE User u SET u.status = :status WHERE u.id = :id")
    int updateUserStatus(@Param("id") Long id, @Param("status") String status);
    
    // 自定义删除
    @Modifying
    @Query("DELETE FROM User u WHERE u.status = :status")
    int deleteUsersByStatus(@Param("status") String status);
}

4.2.2 复杂查询与Specification

// 使用Specification进行动态查询
@Service
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    public List<User> searchUsers(String username, String email, Integer minAge, Integer maxAge) {
        Specification<User> spec = Specification.where(null);
        
        if (username != null && !username.isEmpty()) {
            spec = spec.and((root, query, cb) -> cb.equal(root.get("username"), username));
        }
        
        if (email != null && !email.isEmpty()) {
            spec = spec.and((root, query, cb) -> cb.like(root.get("email"), "%" + email + "%"));
        }
        
        if (minAge != null) {
            spec = spec.and((root, query, cb) -> cb.greaterThanOrEqualTo(root.get("age"), minAge));
        }
        
        if (maxAge != null) {
            spec = spec.and((root, query, cb) -> cb.lessThanOrEqualTo(root.get("age"), maxAge));
        }
        
        return userRepository.findAll(spec);
    }
    
    // 分页查询
    public Page<User> searchUsersWithPagination(String username, String email, 
                                               Integer minAge, Integer maxAge, 
                                               int page, int size) {
        Specification<User> spec = Specification.where(null);
        
        if (username != null && !username.isEmpty()) {
            spec = spec.and((root, query, cb) -> cb.equal(root.get("username"), username));
        }
        
        if (email != null && !email.isEmpty()) {
            spec = spec.and((root, query, cb) -> cb.like(root.get("email"), "%" + email + "%"));
        }
        
        if (minAge != null) {
            spec = spec.and((root, query, cb) -> cb.greaterThanOrEqualTo(root.get("age"), minAge));
        }
        
        if (maxAge != null) {
            spec = spec.and((root, query, cb) -> cb.lessThanOrEqualTo(root.get("age"), maxAge));
        }
        
        Pageable pageable = PageRequest.of(page, size, Sort.by("id").descending());
        return userRepository.findAll(spec, pageable);
    }
}

4.3 Spring Cloud微服务架构

4.3.1 服务注册与发现(Eureka)

# 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配置
server:
  port: 8081

spring:
  application:
    name: user-service

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true  # 使用IP地址注册
// Eureka Client启动类
@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}

// 服务调用
@Service
public class OrderService {
    
    @Autowired
    private RestTemplate restTemplate;
    
    @LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
    
    public User getUserById(Long userId) {
        // 通过服务名调用,Eureka会自动负载均衡
        return restTemplate.getForObject(
            "http://user-service/api/users/" + userId, 
            User.class
        );
    }
}

4.3.2 配置中心(Config Server)

# Config Server配置
server:
  port: 8888

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

// Config Client配置
spring:
  application:
    name: user-service
  cloud:
    config:
      uri: http://localhost:8888
      profile: dev
      label: main

4.4 Spring性能优化

4.4.1 连接池优化

# HikariCP配置
spring:
  datasource:
    hikari:
      # 连接池大小
      maximum-pool-size: 20
      minimum-idle: 5
      # 连接超时
      connection-timeout: 30000
      # 空闲连接超时
      idle-timeout: 600000
      # 连接最大生命周期
      max-lifetime: 1800000
      # 连接测试查询
      connection-test-query: SELECT 1
      # 连接预热
      initialization-fail-timeout: 1
      # 连接泄漏检测
      leak-detection-threshold: 60000

4.4.2 缓存优化

// 启用缓存
@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 {
    
    @Autowired
    private UserRepository userRepository;
    
    @Cacheable(value = "users", key = "#id")
    public User getUserById(Long id) {
        System.out.println("从数据库查询用户: " + id);
        return userRepository.findById(id).orElse(null);
    }
    
    @CacheEvict(value = "users", key = "#id")
    public void deleteUser(Long id) {
        userRepository.deleteById(id);
    }
    
    @CachePut(value = "users", key = "#user.id")
    public User updateUser(User user) {
        return userRepository.save(user);
    }
    
    @Cacheable(value = "users", key = "'all'")
    public List<User> getAllUsers() {
        System.out.println("从数据库查询所有用户");
        return userRepository.findAll();
    }
}

4.4.3 异步处理

// 启用异步支持
@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.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

// 异步服务
@Service
public class NotificationService {
    
    @Async
    public void sendEmailNotification(String email, String message) {
        System.out.println("开始发送邮件到: " + email);
        // 模拟耗时操作
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        System.out.println("邮件发送完成: " + email);
    }
    
    @Async
    public CompletableFuture<String> processOrderAsync(Long orderId) {
        System.out.println("开始异步处理订单: " + orderId);
        // 模拟业务处理
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return CompletableFuture.completedFuture("订单处理完成: " + orderId);
    }
}

第五部分:Spring测试与调试

5.1 单元测试

5.1.1 JUnit 5 + Mockito

// 被测试的Service
@Service
public class OrderService {
    
    @Autowired
    private PaymentService paymentService;
    
    @Autowired
    private InventoryService inventoryService;
    
    @Transactional
    public Order createOrder(Order order) {
        // 验证库存
        if (!inventoryService.checkStock(order.getProductId(), order.getQuantity())) {
            throw new InsufficientStockException("库存不足");
        }
        
        // 扣减库存
        inventoryService.deductStock(order.getProductId(), order.getQuantity());
        
        // 支付处理
        PaymentResult paymentResult = paymentService.processPayment(order);
        
        if (!paymentResult.isSuccess()) {
            throw new PaymentException("支付失败");
        }
        
        // 保存订单
        return orderRepository.save(order);
    }
}

// 单元测试
@ExtendWith(MockitoExtension.class)
class OrderServiceTest {
    
    @Mock
    private PaymentService paymentService;
    
    @Mock
    private InventoryService inventoryService;
    
    @Mock
    private OrderRepository orderRepository;
    
    @InjectMocks
    private OrderService orderService;
    
    @Test
    void shouldCreateOrderSuccessfully() {
        // 准备测试数据
        Order order = new Order();
        order.setProductId(1L);
        order.setQuantity(2);
        order.setAmount(new BigDecimal("99.99"));
        
        // Mock行为
        when(inventoryService.checkStock(1L, 2)).thenReturn(true);
        when(inventoryService.deductStock(1L, 2)).thenReturn(true);
        
        PaymentResult paymentResult = new PaymentResult();
        paymentResult.setSuccess(true);
        paymentResult.setTransactionId("TXN-12345");
        when(paymentService.processPayment(order)).thenReturn(paymentResult);
        
        when(orderRepository.save(any(Order.class))).thenReturn(order);
        
        // 执行测试
        Order result = orderService.createOrder(order);
        
        // 验证结果
        assertNotNull(result);
        assertEquals(order.getProductId(), result.getProductId());
        
        // 验证方法调用
        verify(inventoryService).checkStock(1L, 2);
        verify(inventoryService).deductStock(1L, 2);
        verify(paymentService).processPayment(order);
        verify(orderRepository).save(order);
    }
    
    @Test
    void shouldThrowExceptionWhenInsufficientStock() {
        // 准备测试数据
        Order order = new Order();
        order.setProductId(1L);
        order.setQuantity(100);
        
        // Mock行为
        when(inventoryService.checkStock(1L, 100)).thenReturn(false);
        
        // 执行测试并验证异常
        assertThrows(InsufficientStockException.class, () -> {
            orderService.createOrder(order);
        });
        
        // 验证方法调用
        verify(inventoryService).checkStock(1L, 100);
        verifyNoInteractions(paymentService);
        verifyNoInteractions(orderRepository);
    }
}

5.1.2 Spring Boot Test

// 集成测试
@SpringBootTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Rollback
class OrderServiceIntegrationTest {
    
    @Autowired
    private OrderService orderService;
    
    @Autowired
    private OrderRepository orderRepository;
    
    @Autowired
    private TestEntityManager entityManager;
    
    @Test
    @Transactional
    void shouldCreateOrderInDatabase() {
        // 准备测试数据
        Product product = new Product();
        product.setName("Test Product");
        product.setStock(10);
        entityManager.persist(product);
        
        Order order = new Order();
        order.setProductId(product.getId());
        order.setQuantity(2);
        order.setAmount(new BigDecimal("99.99"));
        
        // 执行测试
        Order savedOrder = orderService.createOrder(order);
        
        // 验证结果
        assertNotNull(savedOrder.getId());
        
        // 验证数据库状态
        Order foundOrder = orderRepository.findById(savedOrder.getId()).orElse(null);
        assertNotNull(foundOrder);
        assertEquals(2, foundOrder.getQuantity());
        
        // 验证库存扣减
        Product updatedProduct = entityManager.find(Product.class, product.getId());
        assertEquals(8, updatedProduct.getStock());
    }
}

5.2 测试配置

# application-test.yml
spring:
  datasource:
    url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
    driver-class-name: org.h2.Driver
    username: sa
    password: 
  jpa:
    hibernate:
      ddl-auto: create-drop
    show-sql: true
    properties:
      hibernate:
        format_sql: true
  flyway:
    enabled: false
// 测试配置类
@TestConfiguration
public class TestConfig {
    
    @Bean
    public DataSource testDataSource() {
        return new EmbeddedDatabaseBuilder()
                .setType(EmbeddedDatabaseType.H2)
                .addScript("classpath:test-schema.sql")
                .addScript("classpath:test-data.sql")
                .build();
    }
    
    @Bean
    public CacheManager testCacheManager() {
        return new ConcurrentMapCacheManager();
    }
}

第六部分:Spring最佳实践

6.1 项目结构

src/main/java/com/example/
├── config/              # 配置类
├── controller/          # 控制器层
├── service/             # 服务层
├── repository/          # 数据访问层
├── entity/              # 实体类
├── dto/                 # 数据传输对象
├── exception/           # 自定义异常
├── util/                # 工具类
└── aspect/              # 切面类

6.2 命名规范

  • 包名:小写,使用点分隔,如 com.example.project.module
  • 类名:大驼峰,如 UserService, OrderController
  • 方法名:小驼峰,如 getUserById, createOrder
  • 常量:全大写,下划线分隔,如 MAX_RETRY_COUNT
  • 变量名:小驼峰,如 userName, orderList

6.3 异常处理

// 全局异常处理器
@RestControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(ResourceNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ErrorResponse handleResourceNotFoundException(ResourceNotFoundException ex) {
        return new ErrorResponse("RESOURCE_NOT_FOUND", ex.getMessage());
    }
    
    @ExceptionHandler(ValidationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ErrorResponse handleValidationException(ValidationException ex) {
        return new ErrorResponse("VALIDATION_ERROR", ex.getMessage());
    }
    
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ErrorResponse handleException(Exception ex) {
        // 记录日志
        log.error("系统异常", ex);
        return new ErrorResponse("INTERNAL_ERROR", "系统内部错误");
    }
}

// 自定义异常
public class ResourceNotFoundException extends RuntimeException {
    public ResourceNotFoundException(String message) {
        super(message);
    }
}

// 错误响应DTO
@Data
public class ErrorResponse {
    private String code;
    private String message;
    private long timestamp;
    
    public ErrorResponse(String code, String message) {
        this.code = code;
        this.message = message;
        this.timestamp = System.currentTimeMillis();
    }
}

6.4 日志配置

# application.yml
logging:
  level:
    root: INFO
    com.example: DEBUG
    org.springframework.web: INFO
    org.hibernate.SQL: DEBUG
    org.hibernate.type.descriptor.sql.BasicBinder: TRACE
  pattern:
    console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
    file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
  file:
    name: logs/application.log
    max-size: 10MB
    max-history: 30
// 日志使用示例
@Service
public class OrderService {
    
    private static final Logger logger = LoggerFactory.getLogger(OrderService.class);
    
    public Order createOrder(Order order) {
        logger.debug("开始创建订单: {}", order);
        
        try {
            // 业务逻辑
            Order savedOrder = orderRepository.save(order);
            logger.info("订单创建成功,订单ID: {}", savedOrder.getId());
            return savedOrder;
        } catch (Exception e) {
            logger.error("创建订单失败,订单信息: {}", order, e);
            throw new OrderCreationException("创建订单失败", e);
        }
    }
}

第七部分:Spring高级主题

7.1 Spring响应式编程(Reactive)

// 响应式Web应用
@SpringBootApplication
public class ReactiveApplication {
    public static void main(String[] args) {
        SpringApplication.run(ReactiveApplication.class, args);
    }
}

// 响应式Controller
@RestController
@RequestMapping("/api/reactive")
public class ReactiveController {
    
    @Autowired
    private ReactiveUserService reactiveUserService;
    
    @GetMapping("/users/{id}")
    public Mono<User> getUserById(@PathVariable Long id) {
        return reactiveUserService.getUserById(id);
    }
    
    @GetMapping("/users")
    public Flux<User> getAllUsers() {
        return reactiveUserService.getAllUsers();
    }
    
    @PostMapping("/users")
    public Mono<User> createUser(@RequestBody User user) {
        return reactiveUserService.createUser(user);
    }
}

// 响应式Service
@Service
public class ReactiveUserService {
    
    @Autowired
    private ReactiveUserRepository reactiveUserRepository;
    
    public Mono<User> getUserById(Long id) {
        return reactiveUserRepository.findById(id)
                .switchIfEmpty(Mono.error(new ResourceNotFoundException("用户不存在")));
    }
    
    public Flux<User> getAllUsers() {
        return reactiveUserRepository.findAll();
    }
    
    public Mono<User> createUser(User user) {
        return reactiveUserRepository.save(user);
    }
}

// 响应式Repository
public interface ReactiveUserRepository extends ReactiveMongoRepository<User, Long> {
    Flux<User> findByUsername(String username);
    Mono<User> findByEmail(String email);
}

7.2 Spring WebSocket

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

// WebSocket处理器
@Component
public class ChatWebSocketHandler extends TextWebSocketHandler {
    
    private static final List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();
    
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        sessions.add(session);
        session.sendMessage(new TextMessage("欢迎加入聊天室"));
    }
    
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String payload = message.getPayload();
        System.out.println("收到消息: " + payload);
        
        // 广播消息给所有客户端
        for (WebSocketSession s : sessions) {
            if (s.isOpen()) {
                s.sendMessage(new TextMessage("用户" + session.getId() + ": " + payload));
            }
        }
    }
    
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        sessions.remove(session);
    }
}

7.3 Spring批处理

// 批处理配置
@Configuration
@EnableBatchProcessing
public class BatchConfig {
    
    @Autowired
    private JobBuilderFactory jobBuilderFactory;
    
    @Autowired
    private StepBuilderFactory stepBuilderFactory;
    
    @Bean
    public Job importUserJob() {
        return jobBuilderFactory.get("importUserJob")
                .start(importUserStep())
                .next(verifyUserStep())
                .build();
    }
    
    @Bean
    public Step importUserStep() {
        return stepBuilderFactory.get("importUserStep")
                .<User, User>chunk(10)
                .reader(userItemReader())
                .processor(userItemProcessor())
                .writer(userItemWriter())
                .build();
    }
    
    @Bean
    public Step verifyUserStep() {
        return stepBuilderFactory.get("verifyUserStep")
                .tasklet((contribution, chunkContext) -> {
                    // 验证逻辑
                    System.out.println("验证用户数据完成");
                    return RepeatStatus.FINISHED;
                })
                .build();
    }
    
    @Bean
    public ItemReader<User> userItemReader() {
        // 从文件读取用户数据
        FlatFileItemReader<User> reader = new FlatFileItemReader<>();
        reader.setResource(new ClassPathResource("users.csv"));
        reader.setLineMapper(new DefaultLineMapper<User>() {{
            setLineTokenizer(new DelimitedLineTokenizer() {{
                setNames("id", "username", "email", "age");
            }});
            setFieldSetMapper(new BeanWrapperFieldSetMapper<User>() {{
                setTargetType(User.class);
            }});
        }});
        return reader;
    }
    
    @Bean
    public ItemProcessor<User, User> userItemProcessor() {
        return user -> {
            // 数据处理逻辑
            user.setUsername(user.getUsername().toUpperCase());
            return user;
        };
    }
    
    @Bean
    public ItemWriter<User> userItemWriter() {
        return users -> {
            // 批量写入数据库
            System.out.println("写入 " + users.size() + " 条用户记录");
        };
    }
}

第八部分:Spring监控与运维

8.1 Spring Boot Actuator

# application.yml
management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus,loggers
      base-path: /actuator
  endpoint:
    health:
      show-details: always
    metrics:
      export:
        prometheus:
          enabled: true
  metrics:
    export:
      prometheus:
        enabled: true
    distribution:
      percentiles-histogram:
        http.server.requests: true
// 自定义健康检查
@Component
public class CustomHealthIndicator implements HealthIndicator {
    
    @Autowired
    private DataSource dataSource;
    
    @Override
    public Health health() {
        try (Connection connection = dataSource.getConnection()) {
            return Health.up()
                    .withDetail("database", "connected")
                    .withDetail("version", connection.getMetaData().getDatabaseProductVersion())
                    .build();
        } catch (Exception e) {
            return Health.down()
                    .withDetail("error", e.getMessage())
                    .build();
        }
    }
}

8.2 分布式追踪

// 集成Sleuth + Zipkin
@Configuration
public class TracingConfig {
    
    @Bean
    public Sampler defaultSampler() {
        return Sampler.ALWAYS_SAMPLE;  // 采样率100%(生产环境应调整)
    }
}

// 使用追踪
@Service
public class OrderService {
    
    @Autowired
    private RestTemplate restTemplate;
    
    public Order createOrder(Order order) {
        // Sleuth会自动添加追踪信息
        User user = restTemplate.getForObject(
            "http://user-service/api/users/" + order.getUserId(), 
            User.class
        );
        
        // 业务逻辑
        return orderRepository.save(order);
    }
}

总结

通过本指南的学习,你应该已经掌握了Spring框架从基础到高级的完整知识体系。Spring框架的核心在于其灵活的架构设计和强大的扩展能力。在实际开发中,建议:

  1. 理解原理:深入理解IoC、AOP、事务等核心原理
  2. 实践驱动:通过实际项目巩固知识
  3. 持续学习:关注Spring生态的最新发展
  4. 最佳实践:遵循社区公认的最佳实践

Spring框架的学习是一个持续的过程,建议在实际项目中不断探索和应用,逐步提升自己的技术水平。