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

Spring框架是Java企业级应用开发的事实标准,它解决了企业级开发中的诸多难题。作为一款轻量级的开源框架,Spring的核心优势在于其控制反转(IoC)和面向切面编程(AOP)的设计理念。这些设计不仅降低了代码的耦合度,还提高了代码的可测试性和可维护性。在现代企业级开发中,Spring不仅仅是一个框架,更是一套完整的生态体系,涵盖了数据访问、Web开发、安全控制、微服务架构等多个领域。对于Java开发者而言,掌握Spring意味着掌握了构建现代化、高性能、可扩展企业级应用的关键技术。

第一部分:Spring框架基础入门

1.1 Spring框架概述

Spring框架是一个分层架构,它允许开发者选择性地使用其各个模块。核心模块是整个框架的基础,提供了IoC容器和依赖注入功能。除此之外,Spring还提供了Spring MVC用于Web开发,Spring Data用于数据访问,Spring Security用于安全控制等。Spring框架的设计哲学是“非侵入式”,这意味着开发者可以在不修改现有代码的情况下引入Spring功能。

1.2 环境搭建与第一个Spring应用

在开始Spring开发之前,我们需要配置开发环境。推荐使用IntelliJ IDEA作为开发工具,Maven或Gradle作为构建工具。以下是使用Maven创建Spring项目的步骤:

  1. 在pom.xml中添加Spring核心依赖:
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.20</version>
    </dependency>
</dependencies>
  1. 创建一个简单的Java类:
public class HelloWorld {
    private String message;

    public void setMessage(String message) {
        this.message = message;
    }

    public void getMessage() {
        System.out.println("Message: " + message);
    }
}
  1. 创建Spring配置文件(beans.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="helloWorld" class="com.example.HelloWorld">
        <property name="message" value="Hello Spring!" />
    </bean>
</beans>
  1. 编写主程序测试:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld");
        helloWorld.getMessage();
    }
}

1.3 依赖注入(DI)详解

依赖注入是Spring框架的核心功能之一,它实现了对象之间的解耦。Spring提供了两种主要的依赖注入方式:构造器注入和Setter方法注入。

构造器注入示例:

public class OrderService {
    private final UserService userService;
    
    // 构造器注入
    public OrderService(UserService userService) {
        this.userService = userService;
    }
}

Setter方法注入示例:

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

在XML配置中,我们可以这样定义:

<!-- 构造器注入 -->
<bean id="orderService" class="com.example.OrderService">
    <constructor-arg ref="userService" />
</bean>

<!-- Setter方法注入 -->
<bean id="orderService" class="com.example.OrderService">
    <property name="userService" ref="userService" />
</bean>

1.4 Spring IoC容器详解

Spring IoC容器是Spring框架的核心,它负责创建、配置和管理Bean的生命周期。Spring提供了两种主要的IoC容器:BeanFactory和ApplicationContext。ApplicationContext是BeanFactory的子接口,提供了更多企业级功能,如事件发布、国际化支持等。

BeanFactory示例:

BeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
HelloWorld hello = (HelloWorld) factory.getBean("helloWorld");

ApplicationContext示例:

ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
HelloWorld hello = context.getBean(HelloWorld.class);

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

2.1 面向切面编程(AOP)原理与应用

AOP是Spring框架的另一个核心特性,它允许开发者在不修改源代码的情况下为程序添加额外功能。Spring AOP基于代理模式实现,主要概念包括切面(Aspect)、连接点(Join Point)、通知(Advice)和切入点(Pointcut)。

AOP术语解释:

  • 切面(Aspect):横切关注点的模块化,如日志、事务管理等
  • 连接点(Join Point):程序执行过程中的某个特定点,如方法调用
  • 通知(Advice):切面在连接点执行的具体操作
  • 切入点(Pointcut):匹配连接点的规则

使用注解方式实现AOP:

  1. 添加AOP依赖:
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.3.20</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.7</version>
</dependency>
  1. 定义切面类:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;

@Aspect
@Component
public class LoggingAspect {
    
    // 前置通知:在目标方法执行前执行
    @Before("execution(* com.example.service.*.*(..))")
    public void logBefore() {
        System.out.println("方法执行前:记录日志");
    }
    
    // 后置通知:在目标方法执行后执行
    @After("execution(* com.example.service.*.*(..))")
    public void logAfter() {
        System.out.println("方法执行后:记录日志");
    }
    
    // 环绕通知:包围目标方法
    @Around("execution(* com.example.service.*.*(..))")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕通知:方法执行前");
        Object result = joinPoint.proceed(); // 执行目标方法
        System.out.println("环绕通知:方法执行后");
        return result;
    }
}
  1. 启用AOP注解支持:
@Configuration
@ComponentScan("com.example")
@EnableAspectJAutoProxy
public class AppConfig {
}

2.2 Bean的生命周期管理

Spring管理的Bean具有完整的生命周期,从实例化、初始化到销毁。理解Bean的生命周期对于开发复杂应用至关重要。

Bean生命周期的完整流程:

  1. 实例化Bean对象
  2. 设置Bean属性
  3. 调用BeanNameAware.setBeanName()
  4. 调用BeanFactoryAware.setBeanFactory()
  5. 调用ApplicationContextAware.setApplicationContext()
  6. 调用BeanPostProcessor.postProcessBeforeInitialization()
  7. 调用InitializingBean.afterPropertiesSet()
  8. 调用自定义的init方法
  9. 调用BeanPostProcessor.postProcessAfterInitialization()
  10. Bean就绪,可以使用
  11. 调用DisposableBean.destroy()
  12. 调用自定义的destroy方法

实现Bean生命周期管理的示例:

import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class LifeCycleBean implements BeanNameAware, InitializingBean, DisposableBean, ApplicationContextAware {
    
    private String name;
    private ApplicationContext context;
    
    public LifeCycleBean() {
        System.out.println("1. 构造函数被调用");
    }
    
    @Override
    public void setBeanName(String name) {
        this.name = name;
        System.out.println("2. setBeanName被调用,Bean名称:" + name);
    }
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.context = applicationContext;
        System.out.println("3. setApplicationContext被调用");
    }
    
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("5. afterPropertiesSet被调用");
    }
    
    public void customInit() {
        System.out.println("6. 自定义init方法被调用");
    }
    
    @Override
    public void destroy() throws Exception {
        System.out.println("7. destroy被调用");
    }
    
    public void customDestroy() {
        System.out.println("8. 自定义destroy方法被调用");
    }
}

XML配置:

<bean id="lifeCycleBean" class="com.example.LifeCycleBean"
      init-method="customInit" destroy-method="customDestroy" />

2.3 Spring事件驱动模型

Spring提供了强大的事件驱动模型,允许组件之间通过事件进行通信。Spring事件基于观察者模式实现。

自定义事件类:

import org.springframework.context.ApplicationEvent;

public class CustomEvent extends ApplicationEvent {
    private String message;
    
    public CustomEvent(Object source, String message) {
        super(source);
        this.message = message;
    }
    
    public String getMessage() {
        return message;
    }
}

事件监听器:

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class CustomEventListener implements ApplicationListener<CustomEvent> {
    @Override
    public void onApplicationEvent(CustomEvent event) {
        System.out.println("收到事件:" + event.getMessage());
    }
}

事件发布者:

import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

@Component
public class CustomEventPublisher {
    private final ApplicationEventPublisher publisher;
    
    public CustomEventPublisher(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }
    
    public void publishEvent(String message) {
        publisher.publishEvent(new CustomEvent(this, message));
    }
}

第三部分:Spring Data访问技术

3.1 Spring JDBC模板

Spring JDBC抽象层消除了传统JDBC编程的样板代码,提供了更简洁的数据库访问方式。

配置数据源:

@Configuration
public class DataSourceConfig {
    
    @Bean
    public DataSource dataSource() {
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setUsername("root");
        dataSource.setPassword("password");
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        return dataSource;
    }
    
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

使用JdbcTemplate进行CRUD操作:

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

@Component
public class UserRepository {
    
    private final JdbcTemplate jdbcTemplate;
    
    public UserRepository(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    
    // 查询单个对象
    public User findById(Long id) {
        String sql = "SELECT * FROM users WHERE id = ?";
        return jdbcTemplate.queryForObject(sql, new UserRowMapper(), id);
    }
    
    // 查询列表
    public List<User> findAll() {
        String sql = "SELECT * FROM users";
        return jdbcTemplate.query(sql, new UserRowMapper());
    }
    
    // 插入数据
    public void insert(User user) {
        String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
        jdbcTemplate.update(sql, user.getName(), user.getEmail());
    }
    
    // 更新数据
    public void update(User user) {
        String sql = "UPDATE users SET name = ?, email = ? WHERE id = ?";
        jdbcTemplate.update(sql, user.getName(), user.getEmail(), user.getId());
    }
    
    // 删除数据
    public void delete(Long id) {
        String sql = "DELETE FROM users WHERE id = ?";
        jdbcTemplate.update(sql, id);
    }
    
    // RowMapper用于映射结果集到对象
    private static class UserRowMapper implements RowMapper<User> {
        @Override
        public User mapRow(ResultSet rs, int rowNum) throws SQLException {
            User user = new User();
            user.setId(rs.getLong("id"));
            user.setName(rs.getString("name"));
            user.setEmail(rs.getString("email"));
            return user;
        }
    }
}

3.2 Spring Data JPA

Spring Data JPA是Spring Data项目的一部分,它基于JPA规范,进一步简化了数据访问层的开发。

配置Spring Data JPA:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.example.repository")
public class JpaConfig {
    
    @Bean
    public DataSource dataSource() {
        // 数据源配置...
    }
    
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource());
        em.setPackagesToScan("com.example.entity");
        
        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        
        return em;
    }
    
    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(emf);
        return transactionManager;
    }
}

定义实体类:

import javax.persistence.*;

@Entity
@Table(name = "users")
public class User {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(nullable = false, length = 100)
    private String name;
    
    @Column(nullable = false, unique = true, length = 150)
    private String email;
    
    // 构造函数、getter和setter...
}

定义Repository接口:

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;

public interface UserRepository extends JpaRepository<User, Long> {
    
    // 方法名查询:自动实现
    List<User> findByName(String name);
    
    // 使用JPQL查询
    @Query("SELECT u FROM User u WHERE u.email = :email")
    User findByEmail(@Param("email") String email);
    
    // 复杂查询
    @Query("SELECT u FROM User u WHERE u.name LIKE %:keyword% OR u.email LIKE %:keyword%")
    List<User> searchUsers(@Param("keyword") String keyword);
}

使用Repository:

@Service
public class UserService {
    
    private final UserRepository userRepository;
    
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
    
    public User createUser(User user) {
        return userRepository.save(user);
    }
    
    public List<User> getAllUsers() {
        return userRepository.findAll();
    }
    
    public Optional<User> getUserById(Long id) {
        return userRepository.findById(id);
    }
    
    public void deleteUser(Long id) {
        userRepository.deleteById(id);
    }
}

3.3 声明式事务管理

Spring提供了声明式事务管理,通过AOP实现,无需在代码中手动管理事务。

使用@Transactional注解:

import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Service;

@Service
public class BankService {
    
    private final AccountRepository accountRepository;
    
    public BankService(AccountRepository accountRepository) {
        this.accountRepository = accountRepository;
    }
    
    @Transactional
    public void transferMoney(Long fromAccountId, Long toAccountId, BigDecimal amount) {
        Account fromAccount = accountRepository.findById(fromAccountId)
            .orElseThrow(() -> new RuntimeException("账户不存在"));
        Account toAccount = accountRepository.findById(toAccountId)
            .orElseThrow(() -> new RuntimeException("账户不存在"));
        
        if (fromAccount.getBalance().compareTo(amount) < 0) {
            throw new RuntimeException("余额不足");
        }
        
        fromAccount.setBalance(fromAccount.getBalance().subtract(amount));
        toAccount.setBalance(toAccount.getBalance().add(amount));
        
        accountRepository.save(fromAccount);
        accountRepository.save(toAccount);
    }
}

配置事务管理器:

@Configuration
@EnableTransactionManagement
public class TransactionConfig {
    
    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(emf);
        return transactionManager;
    }
}

第四部分:Spring Web开发

4.1 Spring MVC框架

Spring MVC是Spring框架的Web模块,遵循MVC设计模式,提供了灵活的Web开发能力。

配置DispatcherServlet:

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }
    
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[] { WebConfig.class };
    }
    
    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
}

Web配置类:

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.example.controller")
public class WebConfig implements WebMvcConfigurer {
    
    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        return resolver;
    }
    
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.jsp("/WEB-INF/views/", ".jsp");
    }
}

控制器示例:

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.ui.Model;

@Controller
@RequestMapping("/users")
public class UserController {
    
    @GetMapping
    public String listUsers(Model model) {
        // 获取用户列表并添加到model
        model.addAttribute("users", userService.getAllUsers());
        return "users/list"; // 返回视图名称
    }
    
    @GetMapping("/{id}")
    public String getUser(@PathVariable Long id, Model model) {
        User user = userService.getUserById(id);
        model.addAttribute("user", user);
        return "users/detail";
    }
    
    @PostMapping
    public String createUser(@ModelAttribute User user) {
        userService.createUser(user);
        return "redirect:/users";
    }
    
    @PutMapping("/{id}")
    public String updateUser(@PathVariable Long id, @ModelAttribute User user) {
        user.setId(id);
        userService.updateUser(user);
        return "redirect:/users";
    }
    
    @DeleteMapping("/{id}")
    public String deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
        return "redirect:/users";
    }
}

RESTful API控制器:

import org.springframework.web.bind.annotation.*;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpStatus;

@RestController
@RequestMapping("/api/users")
public class UserApiController {
    
    private final UserService userService;
    
    public UserApiController(UserService userService) {
        this.userService = userService;
    }
    
    @GetMapping
    public List<User> getAllUsers() {
        return userService.getAllUsers();
    }
    
    @GetMapping("/{id}")
    public ResponseEntity<User> getUser(@PathVariable Long id) {
        return userService.getUserById(id)
            .map(ResponseEntity::ok)
            .orElse(ResponseEntity.notFound().build());
    }
    
    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public User createUser(@RequestBody User user) {
        return userService.createUser(user);
    }
    
    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User user) {
        try {
            user.setId(id);
            User updatedUser = userService.updateUser(user);
            return ResponseEntity.ok(updatedUser);
        } catch (Exception e) {
            return ResponseEntity.notFound().build();
        }
    }
    
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
        Spring Boot是Spring框架的扩展,它简化了Spring应用的配置和部署。Spring Boot遵循“约定优于配置”的原则,提供了自动配置功能,大大减少了开发者的配置工作量。

### 5.1 Spring Boot快速入门

**创建Spring Boot项目:**
可以使用Spring Initializr(https://start.spring.io)快速生成项目,或者使用Spring Boot CLI。

**使用Spring Initializr创建项目:**
1. 访问https://start.spring.io
2. 选择项目配置:
   - Project: Maven Project
   - Language: Java
   - Spring Boot: 2.7.x
   - Group: com.example
   - Artifact: demo
   - Dependencies: Spring Web, Spring Data JPA, H2 Database
3. 点击Generate下载项目

**Spring Boot主类:**
```java
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);
    }
}

5.2 Spring Boot自动配置原理

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

自动配置示例:

@Configuration
@ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class})
@ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory")
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {
    
    @Bean
    @ConditionalOnMissingBean
    public DataSource dataSource(DataSourceProperties properties) {
        return properties.initializeDataSourceBuilder().build();
    }
}

自定义自动配置:

@Configuration
@ConditionalOnClass(MyService.class)
@ConditionalOnProperty(name = "myapp.enabled", havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(MyAppProperties.class)
public class MyAppAutoConfiguration {
    
    @Bean
    @ConditionalOnMissingBean
    public MyService myService(MyAppProperties properties) {
        return new MyService(properties.getMessage());
    }
}

5.3 Spring Boot配置文件

application.properties示例:

# 服务器配置
server.port=8080
server.servlet.context-path=/api

# 数据源配置
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# JPA配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

# 日志配置
logging.level.com.example=DEBUG
logging.level.org.springframework.web=INFO

application.yml示例:

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

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

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

多环境配置:

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

# application-prod.yml
spring:
  profiles: prod
  datasource:
    url: jdbc:mysql://prod-server:3306/test_prod

5.4 Spring Boot Starter原理

Spring Boot Starter是一组依赖描述符的集合,它简化了依赖管理。

自定义Starter步骤:

  1. 创建自动配置类:
@Configuration
@ConditionalOnClass(MyService.class)
@ConditionalOnProperty(name = "myapp.enabled", havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(MyAppProperties.class)
public class MyAppAutoConfiguration {
    
    @Bean
    @ConditionalOnMissingBean
    public MyService myService(MyAppProperties properties) {
        return new MyService(properties.getMessage());
    }
}
  1. 创建属性类:
@ConfigurationProperties(prefix = "myapp")
public class MyAppProperties {
    private boolean enabled = true;
    private String message = "Hello Starter";
    
    // getter和setter...
}
  1. 创建spring.factories文件:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.MyAppAutoConfiguration
  1. 打包为jar并发布

第六部分:Spring Security安全框架

6.1 Spring Security基础

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

基本配置:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/api/public/**").permitAll()
                .antMatchers("/api/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            .and()
            .httpBasic()
            .and()
            .csrf().disable();
    }
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("user")
                .password("{noop}password")
                .roles("USER")
            .and()
            .withUser("admin")
                .password("{noop}admin")
                .roles("USER", "ADMIN");
    }
}

6.2 自定义用户认证

基于数据库的认证:

@Service
public class CustomUserDetailsService implements UserDetailsService {
    
    private final UserRepository userRepository;
    
    public CustomUserDetailsService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
    
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username)
            .orElseThrow(() -> new UsernameNotFoundException("用户不存在"));
        
        return org.springframework.security.core.userdetails.User
            .withUsername(user.getUsername())
            .password(user.getPassword())
            .roles(user.getRoles().toArray(new String[0]))
            .build();
    }
}

配置自定义UserDetailsService:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    private final CustomUserDetailsService userDetailsService;
    
    public SecurityConfig(CustomUserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }
    
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

6.3 JWT认证

JWT工具类:

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

@Component
public class JwtTokenUtil {
    
    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<>();
        return createToken(claims, userDetails.getUsername());
    }
    
    private String createToken(Map<String, Object> claims, String subject) {
        return Jwts.builder()
            .setClaims(claims)
            .setSubject(subject)
            .setIssuedAt(new Date(System.currentTimeMillis()))
            .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
            .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
            .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 extractClaim(token, Claims::getSubject);
    }
    
    public Date extractExpiration(String token) {
        return extractClaim(token, Claims::getExpiration);
    }
    
    private <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());
    }
}

JWT认证过滤器:

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class JwtRequestFilter extends OncePerRequestFilter {
    
    private final UserDetailsService userDetailsService;
    private final JwtTokenUtil jwtTokenUtil;
    
    public JwtRequestFilter(UserDetailsService userDetailsService, JwtTokenUtil jwtTokenUtil) {
        this.userDetailsService = userDetailsService;
        this.jwtTokenUtil = jwtTokenUtil;
    }
    
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            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 = jwtTokenUtil.extractUsername(jwt);
        }
        
        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
            
            if (jwtTokenUtil.validateToken(jwt, userDetails)) {
                UsernamePasswordAuthenticationToken authenticationToken = 
                    new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            }
        }
        chain.doFilter(request, response);
    }
}

配置JWT安全:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    private final CustomUserDetailsService userDetailsService;
    private final JwtTokenUtil jwtTokenUtil;
    
    public SecurityConfig(CustomUserDetailsService userDetailsService, JwtTokenUtil jwtTokenUtil) {
        this.userDetailsService = userDetailsService;
        this.jwtTokenUtil = jwtTokenUtil;
    }
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .authorizeRequests()
                .antMatchers("/api/auth/**").permitAll()
                .anyRequest().authenticated()
            .and()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        
        http.addFilterBefore(jwtRequestFilter(), UsernamePasswordAuthenticationFilter.class);
    }
    
    @Bean
    public JwtRequestFilter jwtRequestFilter() {
        return new JwtRequestFilter(userDetailsService, jwtTokenUtil);
    }
    
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
    
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

第七部分:Spring微服务架构

7.1 Spring Cloud基础

Spring Cloud是基于Spring Boot的微服务框架,提供了分布式系统开发的常见模式。

服务注册与发现(Eureka):

  1. Eureka Server:
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

Eureka Server配置:

server:
  port: 8761

eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://localhost:8761/eureka/
  1. Eureka Client:
@SpringBootApplication
@EnableEurekaClient
public class UserServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}

Eureka Client配置:

server:
  port: 8081

spring:
  application:
    name: user-service

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

7.2 服务调用(Feign)

Feign客户端:

@FeignClient(name = "user-service")
public interface UserServiceClient {
    
    @GetMapping("/users/{id}")
    User getUserById(@PathVariable("id") Long id);
    
    @PostMapping("/users")
    User createUser(@RequestBody User user);
}

启用Feign:

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

7.3 熔断器(Hystrix)

Feign集成Hystrix:

@FeignClient(name = "user-service", fallback = UserServiceFallback.class)
public interface UserServiceClient {
    // ...
}

@Component
public class UserServiceFallback implements UserServiceClient {
    
    @Override
    public User getUserById(Long id) {
        // 返回降级数据
        User fallbackUser = new User();
        fallbackUser.setId(id);
        fallbackUser.setName("默认用户");
        return fallbackUser;
    }
    
    @Override
    public User createUser(User user) {
        return null;
    }
}

配置Hystrix:

feign:
  hystrix:
    enabled: true

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 5000

7.4 配置中心(Config)

Config Server:

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

Config Server配置:

server:
  port: 8888

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/your-repo/config-repo
          search-paths: config
          username: your-username
          password: your-password

Config Client配置:

spring:
  application:
    name: user-service
  cloud:
    config:
      uri: http://localhost:8888
      profile: dev

第八部分:Spring高级特性与最佳实践

8.1 Spring测试框架

单元测试示例:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;

@ExtendWith(MockitoExtension.class)
public class UserServiceTest {
    
    @Mock
    private UserRepository userRepository;
    
    @InjectMocks
    private UserService userService;
    
    @Test
    public void testCreateUser() {
        User user = new User();
        user.setName("John");
        user.setEmail("john@example.com");
        
        when(userRepository.save(any(User.class))).thenReturn(user);
        
        User savedUser = userService.createUser(user);
        
        assertNotNull(savedUser);
        assertEquals("John", savedUser.getName());
        verify(userRepository, times(1)).save(user);
    }
}

集成测试示例:

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.http.ResponseEntity;
import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class UserControllerIntegrationTest {
    
    @LocalServerPort
    private int port;
    
    @Autowired
    private TestRestTemplate restTemplate;
    
    @Test
    public void testGetUser() {
        String url = "http://localhost:" + port + "/api/users/1";
        ResponseEntity<User> response = restTemplate.getForEntity(url, User.class);
        
        assertEquals(200, response.getStatusCodeValue());
        assertNotNull(response.getBody());
    }
}

8.2 Spring AOP高级应用

自定义注解实现日志:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecution {
}

切面实现:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Aspect
@Component
public class LoggingAspect {
    
    private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
    
    @Around("@annotation(logExecution)")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint, LogExecution logExecution) throws Throwable {
        long start = System.currentTimeMillis();
        
        Object result = joinPoint.proceed();
        
        long executionTime = System.currentTimeMillis() - start;
        
        logger.info(joinPoint.getSignature() + " executed in " + executionTime + "ms");
        
        return result;
    }
}

使用自定义注解:

@Service
public class SomeService {
    
    @LogExecution
    public void someMethod() {
        // 业务逻辑
    }
}

8.3 Spring性能优化

连接池优化(HikariCP):

spring:
  datasource:
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5
      connection-timeout: 30000
      idle-timeout: 600000
      max-lifetime: 1800000
      leak-detection-threshold: 60000

缓存配置:

@Configuration
@EnableCaching
public class CacheConfig {
    
    @Bean
    public CacheManager cacheManager() {
        RedisCacheManager cacheManager = RedisCacheManager.create(redisConnectionFactory());
        return cacheManager;
    }
    
    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        return new JedisConnectionFactory();
    }
}

使用缓存:

@Service
public class UserService {
    
    @Cacheable(value = "users", key = "#id")
    public User getUserById(Long id) {
        // 数据库查询
        return userRepository.findById(id).orElse(null);
    }
    
    @CacheEvict(value = "users", key = "#user.id")
    public void updateUser(User user) {
        userRepository.save(user);
    }
}

8.4 Spring最佳实践

1. 分层架构设计:

controller → service → repository → database

2. 异常处理:

@ControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(UserNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleUserNotFound(UserNotFoundException ex) {
        ErrorResponse error = new ErrorResponse("USER_NOT_FOUND", ex.getMessage());
        return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
    }
    
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleGenericException(Exception ex) {
        ErrorResponse error = new ErrorResponse("INTERNAL_ERROR", "系统内部错误");
        return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

3. DTO模式:

// DTO类
public class UserDTO {
    private String name;
    private String email;
    // getter和setter...
}

// 转换器
public class UserConverter {
    public static UserDTO toDTO(User user) {
        UserDTO dto = new UserDTO();
        dto.setName(user.getName());
        dto.setEmail(user.getEmail());
        return dto;
    }
    
    public static User toEntity(UserDTO dto) {
        User user = new User();
        user.setName(dto.getName());
        user.setEmail(dto.getEmail());
        return user;
    }
}

4. 配置管理:

  • 使用环境变量管理敏感信息
  • 使用Spring Cloud Config集中管理配置
  • 使用Profile区分不同环境配置

5. 日志规范:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Service
public class OrderService {
    
    private static final Logger logger = LoggerFactory.getLogger(OrderService.class);
    
    public void processOrder(Order order) {
        logger.info("开始处理订单: {}", order.getId());
        try {
            // 业务逻辑
            logger.debug("订单详情: {}", order);
        } catch (Exception e) {
            logger.error("处理订单失败: {}", order.getId(), e);
            throw new OrderProcessingException("订单处理失败", e);
        }
    }
}

第九部分:Spring生态与未来趋势

9.1 Spring Boot Actuator

启用Actuator:

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

配置Actuator端点:

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,env
  endpoint:
    health:
      show-details: always

自定义健康检查:

import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;

@Component
public class DatabaseHealthIndicator implements HealthIndicator {
    
    @Override
    public Health health() {
        // 检查数据库连接
        boolean isConnected = checkDatabaseConnection();
        
        if (isConnected) {
            return Health.up()
                .withDetail("database", "MySQL")
                .withDetail("status", "connected")
                .build();
        } else {
            return Health.down()
                .withDetail("database", "MySQL")
                .withDetail("status", "disconnected")
                .build();
        }
    }
    
    private boolean checkDatabaseConnection() {
        // 实际的数据库连接检查逻辑
        return true;
    }
}

9.2 Spring WebFlux响应式编程

WebFlux控制器:

import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@RestController
@RequestMapping("/api/reactive")
public class ReactiveUserController {
    
    private final ReactiveUserRepository userRepository;
    
    public ReactiveUserController(ReactiveUserRepository userRepository) {
        this.userRepository = userRepository;
    }
    
    @GetMapping("/users")
    public Flux<User> getAllUsers() {
        return userRepository.findAll();
    }
    
    @GetMapping("/users/{id}")
    public Mono<User> getUser(@PathVariable Long id) {
        return userRepository.findById(id)
            .switchIfEmpty(Mono.error(new UserNotFoundException(id)));
    }
    
    @PostMapping("/users")
    public Mono<User> createUser(@RequestBody User user) {
        return userRepository.save(user);
    }
}

WebFlux配置:

@Configuration
@EnableWebFlux
public class WebFluxConfig implements WebFluxConfigurer {
    
    @Bean
    public RouterFunction<ServerResponse> routerFunction() {
        return RouterFunctions.route()
            .GET("/api/reactive/users", request -> 
                ServerResponse.ok().body(userRepository.findAll(), User.class))
            .build();
    }
}

9.3 Spring Native与GraalVM

Spring Native简介: Spring Native是Spring Boot的实验性特性,可以将Spring应用编译为原生镜像,显著提升启动速度和内存使用效率。

使用Spring Native:

<dependency>
    <groupId>org.springframework.experimental</groupId>
    <artifactId>spring-native</artifactId>
    <version>0.11.4</version>
</dependency>

构建原生镜像:

# 使用Pack构建
pack build myapp --builder paketobuildpacks/builder:base --env BP_NATIVE_IMAGE=true

# 使用GraalVM native-image
native-image -H:+ReportExceptionStackTraces -H:+StaticExecutableWithDynamicLibC \
    -H:Name=myapp -H:Class=com.example.MyApplication

9.4 Spring与云原生

Spring Cloud Kubernetes:

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

Kubernetes配置:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service
spec:
  replicas: 3
  selector:
    matchLabels:
      app: user-service
  template:
    metadata:
      labels:
        app: user-service
    spec:
      containers:
      - name: user-service
        image: user-service:1.0
        ports:
        - containerPort: 8080
        env:
        - name: SPRING_PROFILES_ACTIVE
          value: "prod"
        - name: SPRING_CLOUD_KUBERNETES_CONFIG_ENABLED
          value: "true"

第十部分:企业级Spring应用实战案例

10.1 电商系统架构设计

整体架构:

API Gateway → Service Registry → Microservices
                ↓
          Config Center → 各个微服务
                ↓
          Monitoring → 各个微服务

用户服务实现:

// 实体类
@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(unique = true, nullable = false)
    private String username;
    
    private String password;
    private String email;
    private String phone;
    
    @Enumerated(EnumType.STRING)
    private UserRole role;
    
    // 构造函数、getter和setter...
}

// Repository
public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByUsername(String username);
    Optional<User> findByEmail(String email);
}

// Service
@Service
@Transactional
public class UserService {
    
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
    private final JwtTokenUtil jwtTokenUtil;
    
    public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder, JwtTokenUtil jwtTokenUtil) {
        this.userRepository = userRepository;
        this.passwordEncoder = passwordEncoder;
        this.jwtTokenUtil = jwtTokenUtil;
    }
    
    public String register(UserRegistrationDTO dto) {
        if (userRepository.findByUsername(dto.getUsername()).isPresent()) {
            throw new RuntimeException("用户名已存在");
        }
        
        User user = new User();
        user.setUsername(dto.getUsername());
        user.setPassword(passwordEncoder.encode(dto.getPassword()));
        user.setEmail(dto.getEmail());
        user.setPhone(dto.getPhone());
        user.setRole(UserRole.CUSTOMER);
        
        userRepository.save(user);
        return "注册成功";
    }
    
    public String login(UserLoginDTO dto) {
        User user = userRepository.findByUsername(dto.getUsername())
            .orElseThrow(() -> new RuntimeException("用户不存在"));
        
        if (!passwordEncoder.matches(dto.getPassword(), user.getPassword())) {
            throw new RuntimeException("密码错误");
        }
        
        return jwtTokenUtil.generateToken(
            org.springframework.security.core.userdetails.User
                .withUsername(user.getUsername())
                .password(user.getPassword())
                .roles(user.getRole().name())
                .build()
        );
    }
}

// Controller
@RestController
@RequestMapping("/api/users")
public class UserController {
    
    private final UserService userService;
    
    public UserController(UserService userService) {
        this.userService = userService;
    }
    
    @PostMapping("/register")
    public ResponseEntity<String> register(@RequestBody UserRegistrationDTO dto) {
        return ResponseEntity.ok(userService.register(dto));
    }
    
    @PostMapping("/login")
    public ResponseEntity<String> login(@RequestBody UserLoginDTO dto) {
        return ResponseEntity.ok(userService.login(dto));
    }
}

商品服务实现:

// 实体类
@Entity
@Table(name = "products")
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    private String description;
    private BigDecimal price;
    private Integer stock;
    
    @Enumerated(EnumType.STRING)
    private ProductStatus status;
    
    // 构造函数、getter和setter...
}

// Service
@Service
public class ProductService {
    
    private final ProductRepository productRepository;
    private final RedisTemplate<String, Object> redisTemplate;
    
    public ProductService(ProductRepository productRepository, RedisTemplate<String, Object> redisTemplate) {
        this.productRepository = productRepository;
        this.redisTemplate = redisTemplate;
    }
    
    @Cacheable(value = "products", key = "#id")
    public Product getProductById(Long id) {
        return productRepository.findById(id)
            .orElseThrow(() -> new RuntimeException("商品不存在"));
    }
    
    @CacheEvict(value = "products", key = "#product.id")
    public void updateProduct(Product product) {
        productRepository.save(product);
    }
    
    // 扣减库存
    @Transactional
    public boolean decreaseStock(Long productId, Integer quantity) {
        String lockKey = "product_stock_" + productId;
        
        try {
            // 获取分布式锁
            Boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS);
            if (Boolean.FALSE.equals(locked)) {
                return false;
            }
            
            Product product = productRepository.findById(productId)
                .orElseThrow(() -> new RuntimeException("商品不存在"));
            
            if (product.getStock() < quantity) {
                return false;
            }
            
            product.setStock(product.getStock() - quantity);
            productRepository.save(product);
            
            return true;
        } finally {
            redisTemplate.delete(lockKey);
        }
    }
}

订单服务实现:

// 实体类
@Entity
@Table(name = "orders")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private Long userId;
    private BigDecimal totalAmount;
    
    @Enumerated(EnumType.STRING)
    private OrderStatus status;
    
    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
    private List<OrderItem> items;
    
    // 构造函数、getter和setter...
}

@Entity
@Table(name = "order_items")
public class OrderItem {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @ManyToOne
    @JoinColumn(name = "order_id")
    private Order order;
    
    private Long productId;
    private String productName;
    private Integer quantity;
    private BigDecimal price;
    
    // 构造函数、getter和setter...
}

// Service
@Service
public class OrderService {
    
    private final OrderRepository orderRepository;
    private final ProductFeignClient productFeignClient;
    private final PaymentFeignClient paymentFeignClient;
    
    public OrderService(OrderRepository orderRepository, ProductFeignClient productFeignClient, PaymentFeignClient paymentFeignClient) {
        this.orderRepository = orderRepository;
        this.productFeignClient = productFeignClient;
        this.paymentFeignClient = paymentFeignClient;
    }
    
    @Transactional
    public Order createOrder(OrderDTO orderDTO) {
        // 1. 验证商品
        BigDecimal totalAmount = BigDecimal.ZERO;
        List<OrderItem> items = new ArrayList<>();
        
        for (OrderItemDTO itemDTO : orderDTO.getItems()) {
            Product product = productFeignClient.getProductById(itemDTO.getProductId());
            if (product == null) {
                throw new RuntimeException("商品不存在: " + itemDTO.getProductId());
            }
            
            // 2. 扣减库存
            boolean success = productFeignClient.decreaseStock(itemDTO.getProductId(), itemDTO.getQuantity());
            if (!success) {
                throw new RuntimeException("库存不足: " + product.getName());
            }
            
            // 3. 计算金额
            BigDecimal itemAmount = product.getPrice().multiply(new BigDecimal(itemDTO.getQuantity()));
            totalAmount = totalAmount.add(itemAmount);
            
            OrderItem item = new OrderItem();
            item.setProductId(product.getId());
            item.setProductName(product.getName());
            item.setQuantity(itemDTO.getQuantity());
            item.setPrice(product.getPrice());
            items.add(item);
        }
        
        // 4. 创建订单
        Order order = new Order();
        order.setUserId(orderDTO.getUserId());
        order.setTotalAmount(totalAmount);
        order.setStatus(OrderStatus.PENDING);
        order.setItems(items);
        
        items.forEach(item -> item.setOrder(order));
        
        orderRepository.save(order);
        
        // 5. 发送订单创建事件
        // eventPublisher.publishEvent(new OrderCreatedEvent(this, order));
        
        return order;
    }
    
    @Transactional
    public void processPayment(Long orderId) {
        Order order = orderRepository.findById(orderId)
            .orElseThrow(() -> new RuntimeException("订单不存在"));
        
        if (order.getStatus() != OrderStatus.PENDING) {
            throw new RuntimeException("订单状态不正确");
        }
        
        // 调用支付服务
        boolean paymentSuccess = paymentFeignClient.processPayment(orderId, order.getTotalAmount());
        
        if (paymentSuccess) {
            order.setStatus(OrderStatus.PAID);
            orderRepository.save(order);
        } else {
            // 支付失败,恢复库存
            for (OrderItem item : order.getItems()) {
                productFeignClient.increaseStock(item.getProductId(), item.getQuantity());
            }
            throw new RuntimeException("支付失败");
        }
    }
}

10.2 微服务通信模式

同步通信(Feign):

@FeignClient(name = "inventory-service")
public interface InventoryFeignClient {
    
    @GetMapping("/api/inventory/{productId}")
    Inventory getInventory(@PathVariable("productId") Long productId);
    
    @PostMapping("/api/inventory/decrease")
    boolean decreaseStock(@RequestParam("productId") Long productId, @RequestParam("quantity") Integer quantity);
}

异步通信(消息队列):

import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;

@Service
public class OrderEventService {
    
    private final KafkaTemplate<String, Object> kafkaTemplate;
    
    public OrderEventService(KafkaTemplate<String, Object> kafkaTemplate) {
        this.kafkaTemplate = kafkaTemplate;
    }
    
    public void publishOrderCreatedEvent(Order order) {
        kafkaTemplate.send("order-created", order);
    }
    
    @KafkaListener(topics = "order-created", groupId = "inventory-group")
    public void handleOrderCreated(Order order) {
        // 处理订单创建事件,如更新库存、发送通知等
        System.out.println("收到订单创建事件: " + order.getId());
    }
}

10.3 分布式事务处理

Saga模式实现:

// Saga协调器
@Service
public class OrderSagaCoordinator {
    
    private final OrderService orderService;
    private final InventoryService inventoryService;
    private final PaymentService paymentService;
    
    public void createOrderSaga(OrderDTO orderDTO) {
        try {
            // 1. 创建订单(临时状态)
            Order order = orderService.createOrder(orderDTO);
            
            // 2. 扣减库存
            boolean inventorySuccess = inventoryService.decreaseStock(orderDTO);
            if (!inventorySuccess) {
                // 补偿:取消订单
                orderService.cancelOrder(order.getId());
                throw new RuntimeException("库存扣减失败");
            }
            
            // 3. 处理支付
            boolean paymentSuccess = paymentService.processPayment(order.getId(), order.getTotalAmount());
            if (!paymentSuccess) {
                // 补偿:恢复库存,取消订单
                inventoryService.increaseStock(orderDTO);
                orderService.cancelOrder(order.getId());
                throw new RuntimeException("支付失败");
            }
            
            // 4. 确认订单
            orderService.confirmOrder(order.getId());
            
        } catch (Exception e) {
            // 记录Saga失败
            log.error("Saga执行失败: {}", e.getMessage());
            throw e;
        }
    }
}

10.4 监控与日志

Micrometer集成:

import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Counter;
import org.springframework.stereotype.Component;

@Component
public class MetricsCollector {
    
    private final Counter orderCounter;
    
    public MetricsCollector(MeterRegistry registry) {
        this.orderCounter = Counter.builder("orders.total")
            .description("Total number of orders")
            .register(registry);
    }
    
    public void incrementOrderCount() {
        orderCounter.increment();
    }
}

分布式追踪(Sleuth + Zipkin):

spring:
  zipkin:
    base-url: http://localhost:9411
  sleuth:
    sampler:
      probability: 1.0

第十一部分:Spring面试题与高级知识点

11.1 核心原理面试题

1. Spring Bean的作用域有哪些?

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

2. Spring如何解决循环依赖? Spring通过三级缓存解决循环依赖:

// 一级缓存:存放完全初始化好的Bean
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

// 二级缓存:存放早期暴露的Bean(未完全初始化)
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

// 三级缓存:存放Bean工厂,用于创建Bean
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

3. Spring AOP代理方式选择

  • JDK动态代理:目标类实现了接口
  • CGLIB代理:目标类没有实现接口
// 强制使用CGLIB
@EnableAspectJAutoProxy(proxyTargetClass = true)

11.2 性能调优面试题

1. 如何优化Spring Boot启动速度?

  • 延迟初始化:spring.main.lazy-initialization=true
  • 减少类路径扫描:@ComponentScan指定具体包
  • 使用Spring Boot 2.3+的分层JAR
  • 使用GraalVM编译为原生镜像

2. 如何优化数据库连接池?

spring:
  datasource:
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5
      connection-timeout: 30000
      idle-timeout: 600000
      max-lifetime: 1800000
      leak-detection-threshold: 60000

11.3 架构设计面试题

1. 如何设计一个高并发的Spring系统?

  • 使用缓存(Redis)减少数据库压力
  • 使用消息队列(Kafka/RabbitMQ)削峰填谷
  • 数据库读写分离
  • 使用分布式锁
  • 服务降级和熔断

2. Spring Cloud与Dubbo对比

  • Spring Cloud:基于HTTP/REST,生态完善,配置简单
  • Dubbo:基于RPC,性能更好,服务治理功能强大

第十二部分:Spring学习路线与资源推荐

12.1 学习路线图

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

  • 掌握IoC和DI
  • 理解Bean生命周期
  • 学习AOP基础
  • 完成第一个Spring应用

阶段二:核心进阶(2-3周)

  • 深入理解AOP原理
  • 掌握Spring Data访问
  • 学习Spring MVC
  • 理解事务管理

阶段三:Spring Boot(2周)

  • 自动配置原理
  • Starter机制
  • 配置文件管理
  • Actuator监控

阶段四:Spring Security(1-2周)

  • 认证与授权
  • JWT实现
  • OAuth2.0
  • 方法级安全

阶段五:微服务架构(3-4周)

  • Spring Cloud基础
  • 服务注册与发现
  • 配置中心
  • 熔断器
  • 网关

阶段六:高级特性与实战(持续学习)

  • 响应式编程
  • 性能优化
  • 分布式事务
  • 容器化部署

12.2 推荐学习资源

官方文档:

书籍推荐:

  • 《Spring实战》(Craig Walls著)
  • 《Spring Boot编程思想》(小马哥著)
  • 《Spring Cloud微服务实战》(翟永超著)
  • 《Spring 5核心原理》(Tom著)

在线课程:

社区与论坛:

12.3 实战项目建议

初级项目:

  • 个人博客系统
  • 简单的电商后台
  • 任务管理系统

中级项目:

  • 微服务架构的电商系统
  • 在线教育平台
  • 社交媒体应用

高级项目:

  • 高并发秒杀系统
  • 大数据处理平台
  • 金融交易系统

总结

Spring框架作为Java企业级开发的基石,其重要性不言而喻。从基础的IoC容器到复杂的微服务架构,Spring提供了一套完整的解决方案。掌握Spring不仅需要理解其核心原理,更需要在实际项目中不断实践和总结。

学习Spring的关键在于:

  1. 理解核心概念:IoC、AOP、DI是Spring的基石,必须深入理解
  2. 实践驱动:通过实际项目来巩固知识,不要只停留在理论层面
  3. 循序渐进:按照学习路线逐步深入,不要急于求成
  4. 关注生态:Spring不仅仅是一个框架,而是一个完整的生态体系
  5. 持续学习:技术在不断发展,保持学习的热情和习惯

希望这份指南能够帮助你从Spring入门到精通,在企业级开发的道路上越走越远。记住,最好的学习方式就是动手实践,遇到问题时多查阅官方文档,多参与社区讨论,相信你一定能成为Spring技术专家!