引言
Spring框架是Java企业级开发中最流行、最强大的开源框架之一。自2003年发布以来,Spring已经发展成为一个庞大的生态系统,涵盖了从依赖注入、面向切面编程到微服务架构的全方位解决方案。本文将从基础概念讲起,逐步深入到高级特性和实战应用,帮助读者系统性地掌握Spring框架的核心原理与应用技巧。
第一部分:Spring框架基础
1.1 Spring框架概述
Spring是一个轻量级的控制反转(IoC)和面向切面编程(AOP)的容器框架。它的核心特性包括:
- 依赖注入(DI):通过IoC容器管理对象之间的依赖关系
- 面向切面编程(AOP):实现横切关注点的分离
- 声明式事务管理:简化数据库事务处理
- MVC框架:提供Web应用开发的完整解决方案
1.2 Spring核心模块
Spring框架由多个模块组成,主要模块包括:
- Spring Core:提供IoC容器和依赖注入功能
- Spring Context:提供配置和访问应用上下文的机制
- Spring AOP:实现面向切面编程
- Spring JDBC:简化JDBC操作
- Spring ORM:集成ORM框架(如Hibernate)
- Spring Web:提供Web应用支持
- Spring MVC:基于MVC模式的Web框架
1.3 Spring Boot简介
Spring Boot是Spring框架的扩展,旨在简化Spring应用的初始搭建和开发过程。它提供了:
- 自动配置:根据类路径自动配置Spring应用
- 嵌入式服务器:内置Tomcat、Jetty等服务器
- 生产就绪特性:提供健康检查、指标监控等
- 简化依赖管理:通过starter简化依赖配置
第二部分:Spring核心原理详解
2.1 依赖注入(DI)与控制反转(IoC)
2.1.1 基本概念
控制反转(Inversion of Control, IoC)是一种设计原则,将对象的创建和管理权从应用程序代码转移到容器中。依赖注入(Dependency Injection, DI)是实现IoC的一种方式。
2.1.2 Spring中的依赖注入方式
Spring支持三种主要的依赖注入方式:
- 构造器注入:通过构造函数传递依赖
- Setter注入:通过setter方法注入依赖
- 字段注入:直接在字段上使用注解
2.1.3 代码示例
// 1. 构造器注入示例
@Service
public class UserService {
private final UserRepository userRepository;
// 构造器注入
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User getUserById(Long id) {
return userRepository.findById(id).orElse(null);
}
}
// 2. Setter注入示例
@Service
public class OrderService {
private PaymentService paymentService;
// Setter注入
@Autowired
public void setPaymentService(PaymentService paymentService) {
this.paymentService = paymentService;
}
public void processOrder(Order order) {
paymentService.processPayment(order);
}
}
// 3. 字段注入示例(不推荐在生产代码中使用)
@Service
public class ProductService {
@Autowired
private InventoryService inventoryService;
public boolean checkStock(Long productId, int quantity) {
return inventoryService.checkStock(productId, quantity);
}
}
2.2 Spring Bean生命周期
Spring Bean的生命周期包括以下阶段:
- 实例化:通过构造函数或工厂方法创建Bean实例
- 属性填充:注入依赖和配置属性
- 初始化:调用初始化方法(如
@PostConstruct) - 使用:Bean被应用程序使用
- 销毁:调用销毁方法(如
@PreDestroy)
2.2.1 Bean生命周期示例
@Component
public class LifecycleBean {
public LifecycleBean() {
System.out.println("1. 构造器被调用");
}
@PostConstruct
public void init() {
System.out.println("2. 初始化方法被调用");
}
@PreDestroy
// 注意:在Spring Boot中,需要配置关闭钩子才能看到效果
public void destroy() {
System.out.println("5. 销毁方法被调用");
}
// 使用Bean
public void doSomething() {
System.out.println("3. Bean正在被使用");
}
}
2.3 Spring AOP(面向切面编程)
AOP允许将横切关注点(如日志、事务、安全)从业务逻辑中分离出来。
2.3.1 AOP核心概念
- 切面(Aspect):横切关注点的模块化
- 连接点(Join Point):程序执行过程中的某个点
- 通知(Advice):在特定连接点执行的动作
- 切入点(Pointcut):匹配连接点的表达式
2.3.2 AOP示例:日志切面
// 1. 定义切面
@Aspect
@Component
public class LoggingAspect {
// 定义切入点:所有Service层的方法
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceMethods() {}
// 前置通知:在方法执行前记录日志
@Before("serviceMethods()")
public void logBefore(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
String className = joinPoint.getTarget().getClass().getSimpleName();
System.out.println("[" + className + "] 开始执行方法: " + methodName);
}
// 后置通知:在方法执行后记录日志
@After("serviceMethods()")
public void logAfter(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("[" + joinPoint.getTarget().getClass().getSimpleName() + "] 方法执行完成: " + methodName);
}
// 环绕通知:记录方法执行时间
@Around("serviceMethods()")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = joinPoint.proceed(); // 执行目标方法
long endTime = System.currentTimeMillis();
System.out.println("方法执行耗时: " + (endTime - startTime) + "ms");
return result;
}
}
第三部分:Spring Boot实战开发
3.1 Spring Boot项目搭建
3.1.1 使用Spring Initializr创建项目
访问 https://start.spring.io 创建项目:
- 选择项目元数据(Group、Artifact、Name)
- 选择依赖:Spring Web、Spring Data JPA、MySQL Driver等
- 生成项目并下载
3.1.2 项目结构
src/main/java/com/example/demo/
├── DemoApplication.java # 启动类
├── controller/ # 控制器层
│ └── UserController.java
├── service/ # 服务层
│ └── UserService.java
├── repository/ # 数据访问层
│ └── UserRepository.java
├── entity/ # 实体类
│ └── User.java
└── config/ # 配置类
└── WebConfig.java
3.2 RESTful API开发
3.2.1 实体类定义
// User.java
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String username;
@Column(nullable = false)
private String email;
@Column(nullable = false)
private String password;
// 构造函数、getter、setter省略
}
3.2.2 数据访问层(Repository)
// UserRepository.java
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// Spring Data JPA会自动实现以下方法
Optional<User> findByUsername(String username);
List<User> findByEmailContaining(String email);
// 自定义查询
@Query("SELECT u FROM User u WHERE u.username = :username AND u.password = :password")
User findByUsernameAndPassword(@Param("username") String username,
@Param("password") String password);
}
3.2.3 服务层
// UserService.java
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public User createUser(User user) {
// 业务逻辑:检查用户名是否已存在
if (userRepository.findByUsername(user.getUsername()).isPresent()) {
throw new RuntimeException("用户名已存在");
}
return userRepository.save(user);
}
public User getUserById(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new RuntimeException("用户不存在"));
}
public List<User> getAllUsers() {
return userRepository.findAll();
}
public User updateUser(Long id, User userDetails) {
User user = getUserById(id);
user.setUsername(userDetails.getUsername());
user.setEmail(userDetails.getEmail());
user.setPassword(userDetails.getPassword());
return userRepository.save(user);
}
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
}
3.2.4 控制器层
// UserController.java
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@PostMapping
public ResponseEntity<User> createUser(@RequestBody User user) {
User createdUser = userService.createUser(user);
return new ResponseEntity<>(createdUser, HttpStatus.CREATED);
}
@GetMapping("/{id}")
public ResponseEntity<User> getUserById(@PathVariable Long id) {
User user = userService.getUserById(id);
return ResponseEntity.ok(user);
}
@GetMapping
public ResponseEntity<List<User>> getAllUsers() {
List<User> users = userService.getAllUsers();
return ResponseEntity.ok(users);
}
@PutMapping("/{id}")
public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User userDetails) {
User updatedUser = userService.updateUser(id, userDetails);
return ResponseEntity.ok(updatedUser);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return ResponseEntity.noContent().build();
}
}
3.3 数据库配置与连接
3.3.1 配置文件
# application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/spring_demo?useSSL=false&serverTimezone=UTC
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update # 自动创建/更新表结构
show-sql: true # 显示SQL语句
properties:
hibernate:
format_sql: true
dialect: org.hibernate.dialect.MySQL8Dialect
# 配置H2内存数据库用于测试(可选)
h2:
console:
enabled: true
path: /h2-console
# 服务器配置
server:
port: 8080
servlet:
context-path: /demo
3.3.2 数据库连接测试
// DatabaseTest.java
@Component
public class DatabaseTest {
@Autowired
private DataSource dataSource;
@PostConstruct
public void testConnection() {
try (Connection connection = dataSource.getConnection()) {
System.out.println("数据库连接成功!连接信息: " + connection.getMetaData().getURL());
} catch (SQLException e) {
System.err.println("数据库连接失败: " + e.getMessage());
}
}
}
第四部分:Spring高级特性
4.1 事务管理
4.1.1 声明式事务
Spring提供了声明式事务管理,通过@Transactional注解实现。
// BankService.java
@Service
public class BankService {
@Autowired
private AccountRepository accountRepository;
@Transactional
public void transferMoney(Long fromAccountId, Long toAccountId, BigDecimal amount) {
// 1. 扣款
Account fromAccount = accountRepository.findById(fromAccountId)
.orElseThrow(() -> new RuntimeException("转出账户不存在"));
fromAccount.setBalance(fromAccount.getBalance().subtract(amount));
accountRepository.save(fromAccount);
// 2. 模拟异常
if (amount.compareTo(new BigDecimal("10000")) > 0) {
throw new RuntimeException("转账金额过大,操作失败");
}
// 3. 收款
Account toAccount = accountRepository.findById(toAccountId)
.orElseThrow(() -> new RuntimeException("转入账户不存在"));
toAccount.setBalance(toAccount.getBalance().add(amount));
accountRepository.save(toAccount);
}
}
4.1.2 事务传播行为
Spring支持7种事务传播行为:
- REQUIRED(默认):如果当前存在事务,则加入;否则新建事务
- REQUIRES_NEW:总是新建事务,挂起当前事务
- SUPPORTS:如果当前存在事务,则加入;否则以非事务方式执行
- MANDATORY:如果当前不存在事务,则抛出异常
- NOT_SUPPORTED:以非事务方式执行,挂起当前事务
- NEVER:如果当前存在事务,则抛出异常
- NESTED:如果当前存在事务,则在嵌套事务中执行
@Service
public class TransactionPropagationService {
@Autowired
private TransactionPropagationService self;
// REQUIRED示例
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
System.out.println("方法A开始");
self.methodB(); // 调用methodB,methodB会加入methodA的事务
System.out.println("方法A结束");
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB() {
System.out.println("方法B开始(新事务)");
// 这里的操作会在独立的事务中执行
System.out.println("方法B结束");
}
}
4.2 Spring Security
4.2.1 基本配置
// SecurityConfig.java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable() // 禁用CSRF(对于REST API)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll() // 公开接口
.requestMatchers("/api/admin/**").hasRole("ADMIN") // 管理员接口
.anyRequest().authenticated() // 其他接口需要认证
)
.httpBasic(Customizer.withDefaults()) // 使用HTTP Basic认证
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 无状态会话
);
return http.build();
}
@Bean
public UserDetailsService userDetailsService() {
// 内存用户存储(生产环境应使用数据库)
UserDetails user = User.builder()
.username("user")
.password(passwordEncoder().encode("password"))
.roles("USER")
.build();
UserDetails admin = User.builder()
.username("admin")
.password(passwordEncoder().encode("admin"))
.roles("ADMIN", "USER")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
4.2.2 JWT认证示例
// JwtAuthenticationFilter.java
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JwtTokenProvider tokenProvider;
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
try {
String jwt = getJwtFromRequest(request);
if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) {
String username = tokenProvider.getUsernameFromToken(jwt);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (Exception ex) {
logger.error("无法设置用户认证", ex);
}
filterChain.doFilter(request, response);
}
private String getJwtFromRequest(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
return null;
}
}
4.3 异步处理与消息队列
4.3.1 Spring异步编程
// AsyncService.java
@Service
public class AsyncService {
@Async("taskExecutor")
public CompletableFuture<String> processAsync(String data) {
System.out.println("异步处理开始: " + Thread.currentThread().getName());
try {
Thread.sleep(2000); // 模拟耗时操作
return CompletableFuture.completedFuture("处理结果: " + data);
} catch (InterruptedException e) {
return CompletableFuture.failedFuture(e);
}
}
@Async
public void sendEmail(String email, String content) {
// 模拟发送邮件的耗时操作
System.out.println("发送邮件到: " + email);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("邮件发送完成");
}
}
// AsyncConfig.java
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(25);
executor.setThreadNamePrefix("Async-");
executor.initialize();
return executor;
}
}
4.3.2 Spring与消息队列(RabbitMQ示例)
// RabbitMQ配置
@Configuration
public class RabbitMQConfig {
@Bean
public Queue queue() {
return new Queue("emailQueue", true); // 持久化队列
}
@Bean
public TopicExchange exchange() {
return new TopicExchange("emailExchange");
}
@Bean
public Binding binding(Queue queue, TopicExchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with("email.#");
}
}
// 消息生产者
@Service
public class MessageProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
public void sendEmailMessage(String email, String content) {
EmailMessage message = new EmailMessage(email, content);
rabbitTemplate.convertAndSend("emailExchange", "email.send", message);
System.out.println("消息已发送: " + message);
}
}
// 消息消费者
@Component
public class MessageConsumer {
@RabbitListener(queues = "emailQueue")
public void receiveEmailMessage(EmailMessage message) {
System.out.println("接收到消息: " + message);
// 处理邮件发送逻辑
sendEmail(message.getEmail(), message.getContent());
}
private void sendEmail(String email, String content) {
// 实际发送邮件的逻辑
System.out.println("正在发送邮件到: " + email);
try {
Thread.sleep(2000); // 模拟发送耗时
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("邮件发送完成: " + email);
}
}
第五部分:Spring微服务架构
5.1 Spring Cloud基础
Spring Cloud是一套基于Spring Boot的微服务解决方案,提供了:
- 服务发现:Eureka、Consul、Zookeeper
- 配置管理:Spring Cloud Config
- API网关:Spring Cloud Gateway
- 断路器:Hystrix、Resilience4j
- 分布式追踪:Sleuth + Zipkin
5.2 服务注册与发现
5.2.1 Eureka Server配置
# application.yml (Eureka Server)
server:
port: 8761
eureka:
client:
register-with-eureka: false # 不向自己注册
fetch-registry: false # 不从自己获取注册表
server:
enable-self-preservation: false # 关闭自我保护模式(开发环境)
// EurekaServerApplication.java
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
5.2.2 Eureka Client配置
# application.yml (Eureka Client)
server:
port: 8081
spring:
application:
name: user-service
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true # 使用IP地址注册
// UserServiceApplication.java
@SpringBootApplication
@EnableEurekaClient
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
5.3 服务间调用
5.3.1 使用RestTemplate
// OrderService.java
@Service
public class OrderService {
@LoadBalanced // 负载均衡
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Autowired
private RestTemplate restTemplate;
public Order createOrder(Long userId, List<OrderItem> items) {
// 调用用户服务获取用户信息
User user = restTemplate.getForObject(
"http://user-service/api/users/" + userId,
User.class
);
// 创建订单逻辑
Order order = new Order();
order.setUserId(userId);
order.setUserName(user.getUsername());
order.setItems(items);
return orderRepository.save(order);
}
}
5.3.2 使用Feign客户端
// UserFeignClient.java
@FeignClient(name = "user-service", url = "http://localhost:8081")
public interface UserFeignClient {
@GetMapping("/api/users/{id}")
User getUserById(@PathVariable("id") Long id);
@PostMapping("/api/users")
User createUser(@RequestBody User user);
}
// OrderService.java
@Service
public class OrderService {
@Autowired
private UserFeignClient userFeignClient;
public Order createOrder(Long userId, List<OrderItem> items) {
// 使用Feign调用用户服务
User user = userFeignClient.getUserById(userId);
Order order = new Order();
order.setUserId(userId);
order.setUserName(user.getUsername());
order.setItems(items);
return orderRepository.save(order);
}
}
5.4 API网关(Spring Cloud Gateway)
5.4.1 Gateway配置
# application.yml
server:
port: 8080
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service # 负载均衡到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: CircuitBreaker
args:
name: orderServiceCircuitBreaker
fallbackUri: forward:/fallback/order
5.4.2 自定义过滤器
// LoggingFilter.java
@Component
public class LoggingFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 请求前处理
System.out.println("请求开始: " + exchange.getRequest().getPath());
long startTime = System.currentTimeMillis();
// 继续执行过滤器链
return chain.filter(exchange).doFinally(signalType -> {
long endTime = System.currentTimeMillis();
System.out.println("请求结束: " + exchange.getRequest().getPath() +
", 耗时: " + (endTime - startTime) + "ms");
});
}
@Override
public int getOrder() {
return -1; // 最高优先级
}
}
第六部分:Spring性能优化与最佳实践
6.1 性能优化技巧
6.1.1 数据库优化
// 1. 使用分页查询避免全表扫描
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// Spring Data JPA分页查询
Page<User> findByStatus(String status, Pageable pageable);
// 自定义分页查询
@Query(value = "SELECT * FROM users WHERE status = :status LIMIT :limit OFFSET :offset",
nativeQuery = true)
List<User> findUsersByStatus(@Param("status") String status,
@Param("limit") int limit,
@Param("offset") int offset);
}
// 2. 使用批量操作
@Service
public class BatchService {
@Autowired
private UserRepository userRepository;
@Transactional
public void batchInsert(List<User> users) {
// 使用JPA的批量插入
for (int i = 0; i < users.size(); i++) {
userRepository.save(users.get(i));
if (i % 50 == 0) {
// 每50条刷新一次
userRepository.flush();
}
}
}
// 使用原生SQL批量更新
@Modifying
@Query("UPDATE User u SET u.status = :status WHERE u.id IN :ids")
void batchUpdateStatus(@Param("status") String status, @Param("ids") List<Long> ids);
}
6.1.2 缓存优化
// CacheConfig.java
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
// 配置Redis缓存
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(10))
.disableCachingNullValues();
return RedisCacheManager.builder(RedisConnectionFactory)
.cacheDefaults(config)
.build();
}
}
// CacheService.java
@Service
public class CacheService {
@Autowired
private UserRepository userRepository;
// 使用@Cacheable注解
@Cacheable(value = "users", key = "#id")
public User getUserById(Long id) {
System.out.println("从数据库查询用户: " + id);
return userRepository.findById(id).orElse(null);
}
// 使用@CachePut注解
@CachePut(value = "users", key = "#user.id")
public User updateUser(User user) {
System.out.println("更新用户并更新缓存: " + user.getId());
return userRepository.save(user);
}
// 使用@CacheEvict注解
@CacheEvict(value = "users", key = "#id")
public void deleteUser(Long id) {
System.out.println("删除用户并清除缓存: " + id);
userRepository.deleteById(id);
}
// 组合缓存注解
@Caching(
cacheable = {@Cacheable(value = "users", key = "#id")},
put = {@CachePut(value = "users", key = "#user.id")},
evict = {@CacheEvict(value = "users", key = "#id")}
)
public User getUserOrUpdate(Long id, User user) {
// 复杂的缓存逻辑
return userRepository.findById(id).orElse(user);
}
}
6.2 代码质量与测试
6.2.1 单元测试
// UserServiceTest.java
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
void shouldCreateUserSuccessfully() {
// 准备测试数据
User user = new User();
user.setUsername("testuser");
user.setEmail("test@example.com");
// 模拟Repository行为
when(userRepository.findByUsername("testuser")).thenReturn(Optional.empty());
when(userRepository.save(any(User.class))).thenReturn(user);
// 执行测试
User result = userService.createUser(user);
// 验证结果
assertNotNull(result);
assertEquals("testuser", result.getUsername());
verify(userRepository).save(user);
}
@Test
void shouldThrowExceptionWhenUsernameExists() {
User existingUser = new User();
existingUser.setUsername("testuser");
when(userRepository.findByUsername("testuser"))
.thenReturn(Optional.of(existingUser));
// 验证异常
assertThrows(RuntimeException.class, () -> {
userService.createUser(new User("testuser", "test@example.com", "password"));
});
}
}
6.2.2 集成测试
// UserControllerIntegrationTest.java
@SpringBootTest
@AutoConfigureMockMvc
class UserControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private UserRepository userRepository;
@BeforeEach
void setup() {
userRepository.deleteAll();
}
@Test
void shouldCreateUser() throws Exception {
String userJson = "{\"username\":\"testuser\",\"email\":\"test@example.com\",\"password\":\"password\"}";
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content(userJson))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.username").value("testuser"));
}
@Test
void shouldGetUserById() throws Exception {
User user = new User("testuser", "test@example.com", "password");
userRepository.save(user);
mockMvc.perform(get("/api/users/" + user.getId()))
.andExpect(status().isOk())
.andExpect(jsonPath("$.username").value("testuser"));
}
}
第七部分:Spring生态系统与扩展
7.1 Spring Data JPA高级特性
7.1.1 自定义查询方法
// UserRepository.java
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// 1. 方法名查询
List<User> findByUsernameAndStatus(String username, String status);
// 2. @Query注解
@Query("SELECT u FROM User u WHERE u.email LIKE %:keyword%")
List<User> findByEmailContaining(@Param("keyword") String keyword);
// 3. 原生SQL查询
@Query(value = "SELECT * FROM users WHERE created_at > :date", nativeQuery = true)
List<User> findUsersCreatedAfter(@Param("date") Date date);
// 4. 分页查询
Page<User> findByStatus(String status, Pageable pageable);
// 5. 投影(只返回部分字段)
@Query("SELECT u.username, u.email FROM User u WHERE u.status = :status")
List<UserProjection> findUserProjections(@Param("status") String status);
// 6. 动态查询(使用Specification)
default List<User> findUsersByCriteria(UserCriteria criteria) {
Specification<User> spec = (root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
if (criteria.getUsername() != null) {
predicates.add(cb.equal(root.get("username"), criteria.getUsername()));
}
if (criteria.getStatus() != null) {
predicates.add(cb.equal(root.get("status"), criteria.getStatus()));
}
if (criteria.getStartDate() != null) {
predicates.add(cb.greaterThanOrEqualTo(root.get("createdAt"), criteria.getStartDate()));
}
return cb.and(predicates.toArray(new Predicate[0]));
};
return findAll(spec);
}
}
7.1.2 实体关系映射
// User.java (一对多关系)
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
private String username;
// 一对多:一个用户有多个订单
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Order> orders = new ArrayList<>();
// 省略其他字段和方法
}
// Order.java (多对一关系)
@Entity
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;
// 省略其他字段和方法
}
// Product.java (多对多关系)
@Entity
@Table(name = "products")
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToMany
@JoinTable(
name = "product_categories",
joinColumns = @JoinColumn(name = "product_id"),
inverseJoinColumns = @JoinColumn(name = "category_id")
)
private Set<Category> categories = new HashSet<>();
// 省略其他字段和方法
}
7.2 Spring Reactive编程
7.2.1 WebFlux基础
// WebFluxController.java
@RestController
@RequestMapping("/api/reactive")
public class WebFluxController {
@Autowired
private ReactiveUserService reactiveUserService;
// 返回Mono(单个值)
@GetMapping("/user/{id}")
public Mono<User> getUserById(@PathVariable Long id) {
return reactiveUserService.getUserById(id);
}
// 返回Flux(多个值)
@GetMapping("/users")
public Flux<User> getAllUsers() {
return reactiveUserService.getAllUsers();
}
// 流式响应
@GetMapping("/stream")
public Flux<String> streamData() {
return Flux.interval(Duration.ofSeconds(1))
.map(seq -> "数据流: " + seq)
.take(10); // 只返回前10个
}
}
7.2.2 响应式数据库访问
// ReactiveUserRepository.java
@Repository
public interface ReactiveUserRepository extends ReactiveMongoRepository<User, Long> {
// 响应式查询
Flux<User> findByStatus(String status);
// 自定义响应式查询
@Query("{ 'username': ?0 }")
Mono<User> findByUsername(String username);
// 分页查询
Flux<User> findByStatus(String status, Pageable pageable);
}
第八部分:Spring学习资源与进阶路径
8.1 学习资源推荐
8.1.1 官方文档
- Spring Framework官方文档:https://spring.io/projects/spring-framework
- Spring Boot官方文档:https://spring.io/projects/spring-boot
- Spring Cloud官方文档:https://spring.io/projects/spring-cloud
8.1.2 优秀书籍
- 《Spring实战》(Craig Walls著):Spring经典入门书籍
- 《Spring Boot实战》(Craig Walls著):Spring Boot权威指南
- 《Spring微服务实战》(John Carnell著):Spring Cloud微服务开发
- 《Spring 5响应式编程》(Iuliana Cosmina著):Spring Reactive编程
8.1.3 在线课程
- Spring官方教程:https://spring.io/guides
- Baeldung Spring教程:https://www.baeldung.com/spring
- Spring Boot视频教程:B站、YouTube上的优质Spring Boot教程
8.2 进阶学习路径
8.2.1 阶段一:基础巩固(1-2个月)
- 深入理解IoC容器和依赖注入
- 掌握Spring AOP原理和应用
- 熟练使用Spring Boot开发Web应用
- 掌握Spring Data JPA进行数据库操作
8.2.2 阶段二:高级特性(2-3个月)
- 学习Spring事务管理
- 掌握Spring Security安全框架
- 学习Spring异步编程和消息队列
- 掌握Spring测试框架(JUnit、Mockito)
8.2.3 阶段三:微服务架构(2-3个月)
- 学习Spring Cloud核心组件
- 掌握服务注册与发现(Eureka)
- 学习API网关(Spring Cloud Gateway)
- 掌握配置中心(Spring Cloud Config)
- 学习分布式追踪(Sleuth + Zipkin)
8.2.4 阶段四:高级主题(持续学习)
- Spring Reactive编程(WebFlux)
- Spring性能优化
- Spring源码分析
- 云原生Spring(Kubernetes、Docker集成)
8.3 实战项目建议
8.3.1 初级项目
- 博客系统:用户管理、文章发布、评论功能
- 电商后台:商品管理、订单处理、用户管理
- 任务管理系统:任务创建、分配、进度跟踪
8.3.2 中级项目
- 微服务电商系统:用户服务、商品服务、订单服务、支付服务
- 社交平台:用户关系、动态发布、消息通知
- 在线教育平台:课程管理、学习进度、考试系统
8.3.3 高级项目
- 分布式系统:结合Spring Cloud和消息队列
- 实时数据处理:结合Spring WebFlux和响应式编程
- 云原生应用:部署到Kubernetes,使用Spring Cloud Kubernetes
结语
Spring框架作为Java企业级开发的基石,其生态系统庞大且不断演进。通过本文的学习,您应该已经掌握了从基础概念到高级特性的完整知识体系。记住,理论学习与实践相结合是掌握Spring的关键。建议您:
- 动手实践:每个概念都通过代码示例亲自实现
- 阅读源码:理解Spring框架的内部工作原理
- 参与社区:关注Spring官方博客、GitHub仓库和社区讨论
- 持续学习:Spring框架不断更新,保持学习的热情
Spring的学习是一个持续的过程,随着您经验的积累,您会发现更多Spring框架的精妙之处。祝您在Spring的学习和应用道路上取得成功!
