引言

Spring框架是Java企业级开发的事实标准,它提供了全面的基础设施支持,让开发者能够专注于业务逻辑而非底层技术细节。本指南将从基础概念讲起,逐步深入到高级特性,并通过实战案例展示Spring在实际项目中的应用,最后解析常见问题及解决方案。

第一部分:Spring基础概念

1.1 Spring框架概述

Spring是一个开源的Java平台,最初由Rod Johnson在2002年提出。它的核心理念是控制反转(IoC)面向切面编程(AOP)。Spring框架的主要模块包括:

  • Spring Core:提供IoC容器和依赖注入功能
  • Spring AOP:提供面向切面编程支持
  • Spring MVC:Web框架
  • Spring Data:数据访问抽象
  • Spring Security:安全框架
  • Spring Boot:快速开发工具

1.2 控制反转(IoC)与依赖注入(DI)

控制反转是一种设计原则,它将对象的创建和管理权从应用程序代码转移到容器中。依赖注入是实现IoC的具体方式。

示例:传统方式 vs Spring方式

传统方式:

// 传统方式:手动创建和管理对象
public class UserService {
    private UserRepository userRepository;
    
    public UserService() {
        this.userRepository = new UserRepositoryImpl(); // 紧耦合
    }
    
    public User getUser(Long id) {
        return userRepository.findById(id);
    }
}

Spring方式:

// Spring方式:通过容器管理依赖
@Component
public class UserService {
    private final UserRepository userRepository;
    
    // 构造器注入(推荐方式)
    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
    
    public User getUser(Long id) {
        return userRepository.findById(id);
    }
}

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

配置类示例:

@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
    // Spring Boot会自动配置,这里展示传统配置方式
}

1.3 Spring Bean的作用域

Spring Bean有以下作用域:

  • singleton(默认):每个容器中一个Bean实例
  • prototype:每次请求都创建新实例
  • request:每个HTTP请求一个实例(Web环境)
  • session:每个HTTP会话一个实例(Web环境)
  • global-session:全局HTTP会话(Portlet环境)

示例:

@Component
@Scope("prototype") // 每次获取都创建新实例
public class PrototypeBean {
    private final String id = UUID.randomUUID().toString();
    
    public String getId() {
        return id;
    }
}

第二部分:Spring Boot快速入门

2.1 Spring Boot简介

Spring Boot是Spring框架的扩展,它:

  • 简化了Spring应用的配置
  • 提供了嵌入式Web服务器
  • 提供了生产级监控和管理功能
  • 遵循”约定优于配置”原则

2.2 创建第一个Spring Boot应用

使用Spring Initializr创建项目

  1. 访问 start.spring.io
  2. 选择:
    • Project: Maven
    • Language: Java
    • Spring Boot: 3.x
    • Group: com.example
    • Artifact: demo
    • Dependencies: Spring Web
  3. 下载项目并导入IDE

主应用类:

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);
    }
}

创建第一个REST控制器:

package com.example.demo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
    
    @GetMapping("/hello")
    public String hello() {
        return "Hello, Spring Boot!";
    }
    
    @GetMapping("/hello/{name}")
    public String helloWithName(@PathVariable String name) {
        return "Hello, " + name + "!";
    }
}

运行应用:

mvn spring-boot:run
# 或者
java -jar target/demo-0.0.1-SNAPSHOT.jar

2.3 Spring Boot配置

application.properties vs application.yml

application.properties:

server.port=8080
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=secret
spring.jpa.hibernate.ddl-auto=update

application.yml (推荐):

server:
  port: 8080

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb
    username: root
    password: secret
  jpa:
    hibernate:
      ddl-auto: update

多环境配置:

# application-dev.yml
spring:
  profiles: dev
  datasource:
    url: jdbc:mysql://localhost:3306/mydb_dev

# application-prod.yml
spring:
  profiles: prod
  datasource:
    url: jdbc:mysql://prod-db:3306/mydb_prod

第三部分:Spring核心特性深入

3.1 依赖注入详解

三种注入方式对比:

1. 构造器注入(推荐):

@Service
public class OrderService {
    private final PaymentService paymentService;
    private final NotificationService notificationService;
    
    @Autowired
    public OrderService(PaymentService paymentService, 
                       NotificationService notificationService) {
        this.paymentService = paymentService;
        this.notificationService = notificationService;
    }
}

2. Setter注入:

@Service
public class OrderService {
    private PaymentService paymentService;
    
    @Autowired
    public void setPaymentService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }
}

3. 字段注入(不推荐):

@Service
public class OrderService {
    @Autowired
    private PaymentService paymentService;
}

条件装配:

@Configuration
public class AppConfig {
    
    @Bean
    @ConditionalOnProperty(name = "app.feature.enabled", havingValue = "true")
    public FeatureService featureService() {
        return new FeatureService();
    }
    
    @Bean
    @ConditionalOnMissingBean(DataSource.class)
    public DataSource defaultDataSource() {
        return new HikariDataSource();
    }
}

3.2 AOP(面向切面编程)

AOP核心概念:

  • 切面(Aspect):横切关注点的模块化
  • 连接点(Join Point):程序执行过程中的某个点
  • 通知(Advice):切面在特定连接点执行的动作
  • 切点(Pointcut):匹配连接点的表达式

示例:日志切面

@Aspect
@Component
public class LoggingAspect {
    
    private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
    
    // 切点:所有Service方法
    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceMethods() {}
    
    // 前置通知
    @Before("serviceMethods()")
    public void logBefore(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        logger.info("Executing method: {}", methodName);
    }
    
    // 后置通知
    @After("serviceMethods()")
    public void logAfter(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        logger.info("Finished executing method: {}", methodName);
    }
    
    // 环绕通知
    @Around("serviceMethods()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        try {
            Object result = joinPoint.proceed();
            long endTime = System.currentTimeMillis();
            logger.info("Method {} executed in {} ms", 
                       joinPoint.getSignature().getName(), 
                       endTime - startTime);
            return result;
        } catch (Exception e) {
            logger.error("Exception in method {}: {}", 
                        joinPoint.getSignature().getName(), 
                        e.getMessage());
            throw e;
        }
    }
}

自定义注解实现AOP:

// 自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecutionTime {
}

// 切面
@Aspect
@Component
public class ExecutionTimeAspect {
    
    @Around("@annotation(logExecutionTime)")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint, 
                                  LogExecutionTime logExecutionTime) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long endTime = System.currentTimeMillis();
        System.out.println("Method " + joinPoint.getSignature().getName() + 
                          " took " + (endTime - startTime) + " ms");
        return result;
    }
}

3.3 Spring事务管理

编程式事务:

@Service
public class TransactionalService {
    
    @Autowired
    private PlatformTransactionManager transactionManager;
    
    public void performTransaction() {
        TransactionStatus status = transactionManager.getTransaction(
            new DefaultTransactionDefinition());
        
        try {
            // 业务逻辑
            transactionManager.commit(status);
        } catch (Exception e) {
            transactionManager.rollback(status);
            throw e;
        }
    }
}

声明式事务(推荐):

@Service
public class OrderService {
    
    @Autowired
    private OrderRepository orderRepository;
    
    @Autowired
    private PaymentService paymentService;
    
    @Transactional
    public Order createOrder(Order order) {
        // 保存订单
        orderRepository.save(order);
        
        // 处理支付
        paymentService.processPayment(order);
        
        return order;
    }
    
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void logOrderCreation(Order order) {
        // 独立事务,即使主事务回滚,日志也会保存
        orderRepository.saveLog(order);
    }
}

事务传播行为:

// REQUIRED - 如果当前存在事务,则加入;否则新建(默认)
@Transactional(propagation = Propagation.REQUIRED)

// REQUIRES_NEW - 总是新建事务,挂起当前事务
@Transactional(propagation = Propagation.REQUIRES_NEW)

// NESTED - 如果当前存在事务,则在嵌套事务中执行
@Transactional(propagation = Propagation.NESTED)

// SUPPORTS - 如果当前存在事务,则加入;否则以非事务方式执行
@Transactional(propagation = Propagation.SUPPORTS)

// NOT_SUPPORTED - 以非事务方式执行,挂起当前事务
@Transactional(propagation = Propagation.NOT_SUPPORTED)

// MANDATORY - 必须在事务中执行,否则抛出异常
@Transactional(propagation = Propagation.MANDATORY)

// NEVER - 必须在非事务中执行,否则抛出异常
@Transactional(propagation = Propagation.NEVER)

第四部分:Spring Data JPA实战

4.1 JPA基础

实体类定义:

@Entity
@Table(name = "users")
public class User {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(name = "username", nullable = false, unique = true)
    private String username;
    
    @Column(name = "email")
    private String email;
    
    @Column(name = "created_at")
    private LocalDateTime createdAt;
    
    // 关联关系
    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
    private List<Order> orders = new ArrayList<>();
    
    // 构造函数、getter/setter...
}

Repository接口:

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    
    // 方法名查询
    User findByUsername(String username);
    
    // 使用@Query注解
    @Query("SELECT u FROM User u WHERE u.email = :email")
    User findByEmail(@Param("email") String email);
    
    // 原生SQL查询
    @Query(value = "SELECT * FROM users WHERE username = :username", 
           nativeQuery = true)
    User findByUsernameNative(@Param("username") String username);
    
    // 分页查询
    Page<User> findByUsernameContaining(String username, Pageable pageable);
    
    // 自定义查询
    @Query("SELECT new com.example.dto.UserDTO(u.id, u.username) " +
           "FROM User u WHERE u.createdAt > :date")
    List<UserDTO> findUsersCreatedAfter(@Param("date") LocalDateTime date);
}

4.2 高级查询技巧

动态查询(QueryDSL集成):

// 1. 添加依赖
// pom.xml
<dependency>
    <groupId>com.querydsl</groupId>
    <artifactId>querydsl-jpa</artifactId>
    <version>5.0.0</version>
</dependency>

// 2. 创建QueryDSL实体
@Entity
@QueryEntity
public class User {
    // ... 实体定义
}

// 3. 创建Repository
public interface UserRepository extends JpaRepository<User, Long>, 
                                         QuerydslPredicateExecutor<User> {
}

// 4. 使用示例
@Service
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    public List<User> searchUsers(String username, String email, 
                                 LocalDateTime startDate) {
        QUser user = QUser.user;
        
        BooleanExpression predicate = user.id.isNotNull();
        
        if (username != null && !username.isEmpty()) {
            predicate = predicate.and(user.username.contains(username));
        }
        
        if (email != null && !email.isEmpty()) {
            predicate = predicate.and(user.email.eq(email));
        }
        
        if (startDate != null) {
            predicate = predicate.and(user.createdAt.after(startDate));
        }
        
        return (List<User>) userRepository.findAll(predicate);
    }
}

多表关联查询:

// 1. 实体关联
@Entity
public class Order {
    @Id
    private Long id;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;
    
    @OneToMany(mappedBy = "order")
    private List<OrderItem> items = new ArrayList<>();
}

@Entity
public class OrderItem {
    @Id
    private Long id;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "order_id")
    private Order order;
    
    private String productName;
    private Integer quantity;
}

// 2. 自定义查询
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
    
    @Query("SELECT o FROM Order o " +
           "JOIN FETCH o.user u " +
           "JOIN FETCH o.items i " +
           "WHERE o.id = :id")
    Order findOrderWithDetails(@Param("id") Long id);
    
    // 使用DTO投影
    @Query("SELECT new com.example.dto.OrderSummaryDTO(" +
           "o.id, u.username, COUNT(i.id), SUM(i.quantity * i.price)) " +
           "FROM Order o " +
           "JOIN o.user u " +
           "JOIN o.items i " +
           "GROUP BY o.id, u.username")
    List<OrderSummaryDTO> getOrdersSummary();
}

4.3 Spring Data JPA性能优化

1. N+1查询问题及解决方案

问题代码:

// 会导致N+1查询问题
List<Order> orders = orderRepository.findAll();
for (Order order : orders) {
    // 每次访问都会触发新的查询
    System.out.println(order.getUser().getUsername());
}

解决方案1:使用JOIN FETCH

@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
    
    @Query("SELECT o FROM Order o JOIN FETCH o.user WHERE o.status = :status")
    List<Order> findOrdersWithUserByStatus(@Param("status") String status);
}

解决方案2:使用EntityGraph

@EntityGraph(attributePaths = {"user", "items"})
List<Order> findByStatus(String status);

2. 批量操作优化

@Service
public class BatchService {
    
    @Autowired
    private UserRepository userRepository;
    
    @Transactional
    public void batchInsert(List<User> users) {
        // Spring Data JPA默认会批量插入
        userRepository.saveAll(users);
    }
    
    @Transactional
    public void batchUpdate(List<User> users) {
        // 批量更新需要特殊处理
        int batchSize = 50;
        for (int i = 0; i < users.size(); i += batchSize) {
            int end = Math.min(i + batchSize, users.size());
            List<User> batch = users.subList(i, end);
            userRepository.saveAll(batch);
        }
    }
}

第五部分:Spring Security实战

5.1 基础配置

1. 添加依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

2. 基础配置类:

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf().disable() // 根据需要启用或禁用
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/public/**").permitAll()
                .requestMatchers("/admin/**").hasRole("ADMIN")
                .requestMatchers("/api/**").authenticated()
                .anyRequest().authenticated()
            )
            .formLogin(form -> form
                .loginPage("/login")
                .defaultSuccessUrl("/dashboard")
                .permitAll()
            )
            .logout(logout -> logout
                .logoutUrl("/logout")
                .logoutSuccessUrl("/login?logout")
                .permitAll()
            );
        
        return http.build();
    }
    
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

5.2 自定义用户认证

1. 用户实体:

@Entity
@Table(name = "users")
public class User implements UserDetails {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(unique = true, nullable = false)
    private String username;
    
    @Column(nullable = false)
    private String password;
    
    @Column
    private String email;
    
    @ElementCollection(fetch = FetchType.EAGER)
    @CollectionTable(name = "user_roles", joinColumns = @JoinColumn(name = "user_id"))
    @Column(name = "role")
    private Set<String> roles = new HashSet<>();
    
    // UserDetails方法
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return roles.stream()
            .map(role -> new SimpleGrantedAuthority("ROLE_" + role))
            .collect(Collectors.toList());
    }
    
    @Override
    public boolean isAccountNonExpired() { return true; }
    
    @Override
    public boolean isAccountNonLocked() { return true; }
    
    @Override
    public boolean isCredentialsNonExpired() { return true; }
    
    @Override
    public boolean isEnabled() { return true; }
}

2. 自定义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("User not found: " + username));
        
        return user;
    }
}

5.3 JWT认证实现

1. JWT工具类:

@Component
public class JwtUtil {
    
    @Value("${jwt.secret}")
    private String secret;
    
    @Value("${jwt.expiration}")
    private Long expiration;
    
    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))
            .signWith(SignatureAlgorithm.HS256, secret)
            .compact();
    }
    
    public Boolean validateToken(String token, UserDetails userDetails) {
        final String username = extractUsername(token);
        return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
    }
    
    public String extractUsername(String token) {
        return getClaims(token).getSubject();
    }
    
    private Claims getClaims(String token) {
        return Jwts.parser()
            .setSigningKey(secret)
            .parseClaimsJws(token)
            .getBody();
    }
    
    private Boolean isTokenExpired(String token) {
        return getClaims(token).getExpiration().before(new Date());
    }
}

2. JWT认证过滤器:

@Component
public class JwtRequestFilter extends OncePerRequestFilter {
    
    @Autowired
    private JwtUtil jwtUtil;
    
    @Autowired
    private CustomUserDetailsService 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 authentication = 
                    new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        }
        
        filterChain.doFilter(request, response);
    }
}

3. 配置JWT过滤器:

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    
    @Autowired
    private JwtRequestFilter jwtRequestFilter;
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/auth/**").permitAll()
                .anyRequest().authenticated()
            )
            .sessionManagement(session -> session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            );
        
        http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
        
        return http.build();
    }
}

第六部分:Spring Boot高级特性

6.1 Spring Boot Actuator

1. 添加依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

2. 配置application.yml:

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus
  endpoint:
    health:
      show-details: always
    metrics:
      export:
        prometheus:
          enabled: true

3. 自定义健康检查:

@Component
public class CustomHealthIndicator implements HealthIndicator {
    
    @Autowired
    private DataSource dataSource;
    
    @Override
    public Health health() {
        try (Connection connection = dataSource.getConnection()) {
            if (connection.isValid(2)) {
                return Health.up()
                    .withDetail("database", "connected")
                    .withDetail("timestamp", System.currentTimeMillis())
                    .build();
            }
        } catch (Exception e) {
            return Health.down()
                .withDetail("error", e.getMessage())
                .build();
        }
        return Health.down().build();
    }
}

6.2 Spring Boot缓存

1. 添加依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2. 启用缓存:

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

3. 缓存配置:

@Configuration
public class CacheConfig {
    
    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(Duration.ofMinutes(10))
            .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
        
        return RedisCacheManager.builder(connectionFactory)
            .cacheDefaults(config)
            .build();
    }
}

4. 使用缓存:

@Service
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    @Cacheable(value = "users", key = "#id")
    public User getUserById(Long id) {
        // 这个方法只有在缓存中没有对应key时才会执行
        System.out.println("Fetching user from database...");
        return userRepository.findById(id).orElse(null);
    }
    
    @CacheEvict(value = "users", key = "#id")
    public void updateUser(Long id, User user) {
        // 更新用户,同时清除缓存
        userRepository.save(user);
    }
    
    @CachePut(value = "users", key = "#user.id")
    public User updateUserAndCache(User user) {
        // 更新用户,同时更新缓存
        return userRepository.save(user);
    }
    
    @Cacheable(value = "users", key = "#username", unless = "#result == null")
    public User getUserByUsername(String username) {
        return userRepository.findByUsername(username).orElse(null);
    }
}

6.3 Spring Boot异步处理

1. 启用异步支持:

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

2. 配置线程池:

@Configuration
public class AsyncConfig {
    
    @Bean(name = "taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(100);
        executor.setThreadNamePrefix("Async-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(60);
        executor.initialize();
        return executor;
    }
}

3. 异步方法:

@Service
public class EmailService {
    
    @Async("taskExecutor")
    public CompletableFuture<Void> sendEmail(String to, String subject, String content) {
        try {
            // 模拟发送邮件耗时操作
            Thread.sleep(2000);
            System.out.println("Email sent to: " + to);
            return CompletableFuture.completedFuture(null);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return CompletableFuture.failedFuture(e);
        }
    }
    
    @Async
    public CompletableFuture<List<String>> processBatch(List<String> items) {
        // 并行处理
        return CompletableFuture.supplyAsync(() -> {
            return items.parallelStream()
                .map(item -> processItem(item))
                .collect(Collectors.toList());
        });
    }
    
    private String processItem(String item) {
        // 处理逻辑
        return "Processed: " + item;
    }
}

4. 异步调用示例:

@RestController
public class EmailController {
    
    @Autowired
    private EmailService emailService;
    
    @PostMapping("/send-email")
    public ResponseEntity<String> sendEmail(@RequestBody EmailRequest request) {
        // 异步发送邮件,立即返回
        CompletableFuture<Void> future = emailService.sendEmail(
            request.getTo(), 
            request.getSubject(), 
            request.getContent()
        );
        
        // 可以添加回调
        future.thenRun(() -> {
            System.out.println("Email sent successfully");
        }).exceptionally(ex -> {
            System.err.println("Failed to send email: " + ex.getMessage());
            return null;
        });
        
        return ResponseEntity.accepted().body("Email will be sent asynchronously");
    }
}

第七部分:Spring Cloud微服务实战

7.1 Spring Cloud基础

1. 服务注册与发现(Eureka)

Eureka Server:

// 1. 添加依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

// 2. 启动类
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

// 3. 配置
server:
  port: 8761

eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
  server:
    enable-self-preservation: false

Eureka Client:

// 1. 添加依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

// 2. 启动类
@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}

// 3. 配置
server:
  port: 8081

spring:
  application:
    name: user-service

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

2. 服务调用(Feign)

// 1. 添加依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

// 2. 启用Feign
@SpringBootApplication
@EnableFeignClients
public class OrderServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }
}

// 3. Feign客户端接口
@FeignClient(name = "user-service", fallback = UserFeignClientFallback.class)
public interface UserFeignClient {
    
    @GetMapping("/users/{id}")
    User getUserById(@PathVariable("id") Long id);
    
    @PostMapping("/users")
    User createUser(@RequestBody User user);
}

// 4. 降级处理
@Component
public class UserFeignClientFallback implements UserFeignClient {
    
    @Override
    public User getUserById(Long id) {
        // 返回默认用户或缓存数据
        return new User(id, "Default User");
    }
    
    @Override
    public User createUser(User user) {
        throw new RuntimeException("User service is unavailable");
    }
}

7.2 Spring Cloud Gateway

1. 添加依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

2. 配置路由:

spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/api/users/**
          filters:
            - StripPrefix=1
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 20
                key-resolver: "#{@userKeyResolver}"
        
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/api/orders/**
          filters:
            - StripPrefix=1
            - name: Hystrix
              args:
                name: fallbackcmd
                fallbackUri: forward:/fallback
        
        - id: auth-service
          uri: lb://auth-service
          predicates:
            - Path=/api/auth/**
          filters:
            - StripPrefix=1
            - JwtAuthenticationFilter

3. 自定义过滤器:

@Component
public class JwtAuthenticationFilter implements GlobalFilter, Ordered {
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getHeaders().getFirst("Authorization");
        
        if (token == null || !token.startsWith("Bearer ")) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        
        // 验证JWT逻辑
        String jwt = token.substring(7);
        if (!validateToken(jwt)) {
            exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
            return exchange.getResponse().setComplete();
        }
        
        return chain.filter(exchange);
    }
    
    @Override
    public int getOrder() {
        return -1; // 在其他过滤器之前执行
    }
}

第八部分:常见问题解析

8.1 依赖注入相关问题

问题1:循环依赖

现象: Bean A依赖Bean B,Bean B又依赖Bean A

解决方案:

  1. 重构代码:引入第三方组件或使用事件驱动
  2. 使用@Lazy延迟注入
@Service
public class ServiceA {
    @Autowired
    @Lazy
    private ServiceB serviceB;
}

@Service
public class ServiceB {
    @Autowired
    private ServiceA serviceA;
}
  1. 使用Setter注入代替构造器注入

问题2:Bean创建失败

常见原因:

  1. 缺少依赖:检查pom.xml中是否包含所需依赖
  2. 配置错误:检查application.yml中的配置项
  3. Bean名称冲突:使用@Qualifier指定Bean名称

示例:

@Configuration
public class AppConfig {
    
    @Bean
    public DataSource dataSource1() {
        return new HikariDataSource();
    }
    
    @Bean
    public DataSource dataSource2() {
        return new HikariDataSource();
    }
}

@Service
public class UserService {
    
    @Autowired
    @Qualifier("dataSource1")
    private DataSource dataSource;
}

8.2 事务管理问题

问题1:事务不生效

常见原因:

  1. 方法不是public
  2. 自调用问题:在同一个类中调用另一个事务方法
  3. 异常类型不匹配:默认只回滚RuntimeException

解决方案:

@Service
public class OrderService {
    
    @Transactional(rollbackFor = Exception.class)
    public void processOrder() {
        // 业务逻辑
    }
    
    // 自调用问题解决方案
    @Autowired
    private OrderService self; // 注入自己
    
    public void methodA() {
        self.methodB(); // 通过代理调用
    }
    
    @Transactional
    public void methodB() {
        // 事务方法
    }
}

问题2:事务传播行为错误

示例:

@Service
public class OrderService {
    
    @Transactional
    public void outerMethod() {
        // 外层事务
        innerMethod(); // 调用内部方法
    }
    
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void innerMethod() {
        // 独立事务
    }
}

8.3 性能问题

问题1:N+1查询问题

解决方案:

  1. 使用JOIN FETCH
  2. 使用@EntityGraph
  3. 使用DTO投影
  4. 批量查询
// 批量查询示例
@Service
public class BatchService {
    
    @Autowired
    private UserRepository userRepository;
    
    public List<User> getUsersByIds(List<Long> ids) {
        // 分批查询,避免一次查询过多数据
        List<User> result = new ArrayList<>();
        int batchSize = 100;
        
        for (int i = 0; i < ids.size(); i += batchSize) {
            int end = Math.min(i + batchSize, ids.size());
            List<Long> batchIds = ids.subList(i, end);
            result.addAll(userRepository.findAllById(batchIds));
        }
        
        return result;
    }
}

问题2:内存泄漏

常见原因:

  1. 缓存未清理
  2. 静态集合未清理
  3. 数据库连接未关闭

解决方案:

// 使用WeakHashMap避免内存泄漏
@Component
public class CacheManager {
    
    private Map<String, Object> cache = new WeakHashMap<>();
    
    public void put(String key, Object value) {
        cache.put(key, value);
    }
    
    public Object get(String key) {
        return cache.get(key);
    }
}

8.4 配置相关问题

问题1:配置不生效

排查步骤:

  1. 检查配置文件名称是否正确(application.yml或application.properties)
  2. 检查配置文件位置是否正确(src/main/resources)
  3. 检查配置项是否正确(注意大小写和缩进)
  4. 检查是否有多环境配置覆盖

示例:

# application.yml
spring:
  profiles:
    active: dev

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

问题2:配置注入失败

解决方案:

@Component
public class ConfigProperties {
    
    @Value("${app.name}")
    private String appName;
    
    @Value("${app.version}")
    private String appVersion;
    
    // 使用@ConfigurationProperties
    @ConfigurationProperties(prefix = "app")
    @Component
    public static class AppProperties {
        private String name;
        private String version;
        private List<String> features = new ArrayList<>();
        
        // getter/setter
    }
}

8.5 Spring Boot启动问题

问题1:启动失败

常见错误:

  1. 端口冲突
server:
  port: 8080 # 修改为其他端口
  1. 依赖冲突
# 查看依赖树
mvn dependency:tree
  1. 数据库连接失败
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb
    username: root
    password: secret
    hikari:
      connection-timeout: 30000
      maximum-pool-size: 10

问题2:启动速度慢

优化方案:

  1. 排除不必要的自动配置
@SpringBootApplication(exclude = {
    DataSourceAutoConfiguration.class,
    SecurityAutoConfiguration.class
})
  1. 使用懒加载
spring:
  main:
    lazy-initialization: true
  1. 减少类路径扫描
@SpringBootApplication
@ComponentScan(excludeFilters = {
    @ComponentScan.Filter(type = FilterType.REGEX, pattern = "com\\.example\\.test.*")
})

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

9.1 代码组织最佳实践

1. 分层架构:

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

2. 命名规范:

  • 实体类:使用名词,如User, Order
  • Repository:使用名词+Repository,如UserRepository
  • Service:使用名词+Service,如UserService
  • Controller:使用名词+Controller,如UserController
  • DTO:使用名词+DTO,如UserDTO

9.2 性能优化技巧

1. 数据库优化:

// 1. 使用索引
@Entity
@Table(indexes = {
    @Index(name = "idx_username", columnList = "username"),
    @Index(name = "idx_email", columnList = "email")
})
public class User {
    // ...
}

// 2. 使用批量操作
@Service
public class BatchService {
    
    @Transactional
    public void batchInsert(List<User> users) {
        int batchSize = 50;
        for (int i = 0; i < users.size(); i += batchSize) {
            int end = Math.min(i + batchSize, users.size());
            List<User> batch = users.subList(i, end);
            userRepository.saveAll(batch);
        }
    }
}

2. 缓存策略:

@Service
public class CacheService {
    
    @Cacheable(value = "users", key = "#id", 
               unless = "#result == null", 
               cacheManager = "redisCacheManager")
    public User getUser(Long id) {
        // 数据库查询
        return userRepository.findById(id).orElse(null);
    }
    
    @CacheEvict(value = "users", key = "#id", 
                cacheManager = "redisCacheManager")
    public void deleteUser(Long id) {
        userRepository.deleteById(id);
    }
}

3. 异步处理:

@Service
public class AsyncService {
    
    @Async
    public CompletableFuture<Void> processAsync(Runnable task) {
        return CompletableFuture.runAsync(task);
    }
    
    @Async
    public <T> CompletableFuture<List<T>> processBatchAsync(List<T> items, 
                                                           Function<T, T> processor) {
        return CompletableFuture.supplyAsync(() -> {
            return items.parallelStream()
                .map(processor)
                .collect(Collectors.toList());
        });
    }
}

9.3 测试策略

1. 单元测试:

@ExtendWith(MockitoExtension.class)
class UserServiceTest {
    
    @Mock
    private UserRepository userRepository;
    
    @InjectMocks
    private UserService userService;
    
    @Test
    void shouldReturnUserWhenExists() {
        // Given
        User user = new User(1L, "john");
        when(userRepository.findById(1L)).thenReturn(Optional.of(user));
        
        // When
        User result = userService.getUserById(1L);
        
        // Then
        assertThat(result).isNotNull();
        assertThat(result.getUsername()).isEqualTo("john");
        verify(userRepository, times(1)).findById(1L);
    }
}

2. 集成测试:

@SpringBootTest
@AutoConfigureMockMvc
class UserControllerIntegrationTest {
    
    @Autowired
    private MockMvc mockMvc;
    
    @Test
    void shouldGetUserById() throws Exception {
        mockMvc.perform(get("/users/1"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.id").value(1))
            .andExpect(jsonPath("$.username").value("john"));
    }
}

3. 测试配置:

@TestConfiguration
public class TestConfig {
    
    @Bean
    public DataSource testDataSource() {
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.H2)
            .addScript("classpath:schema.sql")
            .addScript("classpath:test-data.sql")
            .build();
    }
}

第十部分:Spring 6和Spring Boot 3新特性

10.1 Java 17+要求

Spring Boot 3要求:

  • Java 17+(最低要求)
  • Jakarta EE 9+(包名从javax.改为jakarta.

迁移示例:

// Spring Boot 2.x (javax.*)
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.servlet.http.HttpServletRequest;

// Spring Boot 3.x (jakarta.*)
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.servlet.http.HttpServletRequest;

10.2 新特性

1. 虚拟线程(Project Loom)支持:

// 启用虚拟线程
spring:
  threads:
    virtual:
      enabled: true

// 自定义线程池使用虚拟线程
@Bean
public ExecutorService virtualThreadExecutor() {
    return Executors.newVirtualThreadPerTaskExecutor();
}

2. 响应式编程增强:

@RestController
public class ReactiveController {
    
    @GetMapping("/flux")
    public Flux<String> getFlux() {
        return Flux.just("A", "B", "C")
            .delayElements(Duration.ofMillis(100));
    }
    
    @GetMapping("/mono")
    public Mono<String> getMono() {
        return Mono.just("Hello")
            .delayElement(Duration.ofMillis(100));
    }
}

3. GraalVM原生镜像支持:

<!-- 添加原生镜像支持 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-graalvm-native</artifactId>
</dependency>

4. 改进的AOT处理:

// 使用AOT处理优化启动时间
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

结语

Spring框架是一个功能强大且不断发展的生态系统。从基础的IoC容器到复杂的微服务架构,Spring提供了全面的解决方案。通过本指南的学习,你应该能够:

  1. 理解Spring核心概念:IoC、DI、AOP
  2. 掌握Spring Boot快速开发:配置、自动配置、启动器
  3. 深入Spring Data JPA:实体映射、查询优化、性能调优
  4. 实现Spring Security:认证、授权、JWT
  5. 构建微服务架构:服务注册、发现、网关
  6. 解决常见问题:依赖注入、事务、性能问题
  7. 遵循最佳实践:代码组织、性能优化、测试策略

记住,Spring的学习是一个持续的过程。建议:

  • 定期阅读官方文档
  • 参与开源项目
  • 关注Spring社区动态
  • 在实际项目中不断实践

祝你在Spring开发之旅中取得成功!