引言:Spring框架在企业级Java开发中的核心地位
Spring框架是Java企业级应用开发的事实标准,它通过依赖注入(DI)和面向切面编程(AOP)解决了企业开发中的核心痛点。根据2023年JetBrains开发者生态系统调查,Spring Boot在Java框架使用率中以67%的占比稳居第一,这充分证明了其在行业中的主导地位。
Spring框架的核心价值在于:
- 解耦:通过IoC容器管理对象依赖关系,降低代码耦合度
- 简化:提供大量样板代码的自动化处理,如事务管理、数据访问
- 集成:无缝整合各种主流技术栈(MyBatis、Hibernate、Redis等)
- 测试:提供强大的测试支持,包括Mock对象和测试切面
本文将从基础概念讲起,逐步深入到高级特性,最后通过实战案例展示如何解决企业级开发中的实际问题。
第一部分:Spring框架基础概念与核心原理
1.1 IoC容器与依赖注入原理
核心概念:IoC(Inversion of Control)控制反转,将对象的创建和管理权从程序员交给Spring容器。
依赖注入的三种方式:
- 构造器注入(推荐):通过构造函数传递依赖
- Setter注入:通过setter方法注入依赖
- 字段注入:使用
@Autowired直接注解字段(不推荐,不利于测试)
代码示例:三种依赖注入方式
// 1. 构造器注入(推荐)
@Service
public class OrderService {
private final UserService userService;
private final PaymentService paymentService;
// 使用构造器注入,明确依赖关系
public OrderService(UserService userService, PaymentService paymentService) {
this.userService = userService;
this.paymentService = paymentService;
}
}
// 2. Setter注入
@Service
public class OrderService {
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
}
// 3. 字段注入(不推荐)
@Service
public class OrderService {
@Autowired
private UserService userService;
}
Bean的作用域(Scope)详解
Spring Bean支持多种作用域,每种都有特定的使用场景:
| 作用域 | 描述 | 使用场景 |
|---|---|---|
| singleton | 默认,每个容器中一个Bean实例 | 无状态服务类、工具类 |
| prototype | 每次请求创建新实例 | 有状态的Bean,避免线程安全问题 |
| request | 每个HTTP请求一个实例 | Web应用中的请求级数据 |
| session | 每个HTTP会话一个实例 | 用户登录信息存储 |
| global-session | Portlet应用的全局会话 | 集群环境下的会话共享 |
Bean生命周期完整流程
Spring Bean的生命周期包含12个关键步骤,理解这些步骤对排查问题至关重要:
@Component
public class ComplexBean implements InitializingBean, DisposableBean {
private String name;
// 1. 构造器执行
public ComplexBean() {
System.out.println("1. 构造器执行");
}
// 2. 属性填充
@Value("ComplexBean")
public void setName(String name) {
this.name = name;
System.out.println("2. 属性填充");
}
// 3. BeanPostProcessor前置处理
// 4. @PostConstruct注解方法执行
@PostConstruct
public void postConstruct() {
System.out.println("4. @PostConstruct执行");
}
// 5. InitializingBean.afterPropertiesSet()
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("5. InitializingBean执行");
}
// 6. init-method指定的方法
@PreDestroy
public void preDestroy() {
System.out.println("11. @PreDestroy执行");
}
// 7. BeanPostProcessor后置处理
// 8. Bean就绪可用
// 9. 使用中...
// 10. 容器关闭
// 11. DisposableBean.destroy()
@Override
public void destroy() throws Exception {
System.out.println("12. DisposableBean执行");
}
}
1.2 AOP面向切面编程深度解析
AOP是Spring框架的另一大核心,它解决了横切关注点(如日志、事务、安全)的代码重复问题。
AOP核心术语
- Joinpoint:程序执行过程中的某个位置(如方法调用、异常抛出)
- Pointcut:匹配Joinpoint的表达式
- Advice:在Pointcut指定位置执行的具体逻辑
- Aspect:切面 = Pointcut + Advice
- Weaving:将切面应用到目标对象的过程
完整AOP示例:实现方法执行时间监控
// 1. 定义切面
@Aspect
@Component
public class PerformanceMonitorAspect {
// 定义切点:所有Service层的方法
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceMethods() {}
// 环绕通知:最强大的通知类型
@Around("serviceMethods()")
public Object monitorPerformance(ProceedingJoinPoint joinPoint) throws Throwable {
// 获取方法签名
String methodName = joinPoint.getSignature().getName();
String className = joinPoint.getTarget().getClass().getSimpleName();
// 开始时间
long start = System.currentTimeMillis();
try {
// 执行目标方法
Object result = joinPoint.proceed();
return result;
} finally {
// 计算执行时间
long duration = System.currentTimeMillis() - start;
// 记录日志
if (duration > 1000) { // 超过1秒警告
System.err.printf("[性能警告] %s.%s 执行耗时:%dms%n",
className, methodName, duration);
} else {
System.out.printf("[性能信息] %s.%s 执行耗时:%dms%n",
className, methodName, duration);
}
}
}
// 异常通知:记录异常信息
@AfterThrowing(pointcut = "serviceMethods()", throwing = "ex")
public void logException(JoinPoint joinPoint, Exception ex) {
String methodName = joinPoint.getSignature().getName();
System.err.printf("[异常记录] %s 方法抛出异常:%s%n",
methodName, ex.getMessage());
}
}
// 2. 业务服务类(无需修改任何代码)
@Service
public class UserService {
public void createUser() throws InterruptedException {
Thread.sleep(500); // 模拟耗时操作
System.out.println("用户创建成功");
}
}
// 3. 测试类
@SpringBootApplication
public class AopDemoApplication implements CommandLineRunner {
@Autowired
private UserService userService;
public static void main(String[] args) {
SpringApplication.run(AopDemoApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
userService.createUser();
}
}
AOP实现原理:动态代理
Spring AOP默认使用JDK动态代理(基于接口)或CGLIB(基于类继承):
// JDK动态代理示例
public class JdkDynamicProxyDemo {
interface UserService {
void save();
}
static class UserServiceImpl implements UserService {
@Override
public void save() {
System.out.println("保存用户");
}
}
static class PerformanceHandler implements InvocationHandler {
private final Object target;
public PerformanceHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long start = System.currentTimeMillis();
Object result = method.invoke(target, args);
System.out.println("耗时:" + (System.currentTimeMillis() - start) + "ms");
return result;
}
}
public static void main(String[] args) {
UserService target = new UserServiceImpl();
UserService proxy = (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
new Class[]{UserService.class},
new PerformanceHandler(target)
);
proxy.save(); // 输出:保存用户 + 耗时
}
}
第二部分:Spring Boot企业级开发实战
2.1 自动配置原理深度剖析
Spring Boot的”约定大于配置”理念通过自动配置实现,理解其原理是高级开发的必备技能。
自动配置工作流程
- @SpringBootApplication注解包含@EnableAutoConfiguration
- SpringFactoriesLoader加载META-INF/spring.factories
- 根据Conditional注解条件判断是否生效
自定义Starter实现
创建自定义Starter是封装通用功能的最佳实践:
// 1. 自定义配置属性
@ConfigurationProperties(prefix = "custom.email")
public class EmailProperties {
private String host = "localhost";
private int port = 25;
private String username;
private String password;
private boolean enabled = true;
// getters and setters
}
// 2. 自动配置类
@Configuration
@ConditionalOnClass(EmailService.class)
@ConditionalOnProperty(prefix = "custom.email", name = "enabled", havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(EmailProperties.class)
public class EmailAutoConfiguration {
@Bean
@ConditionalOnMissingBean // 当容器中没有该Bean时才创建
public EmailService emailService(EmailProperties properties) {
return new EmailService(properties);
}
}
// 3. 业务服务类
public class EmailService {
private final EmailProperties properties;
public EmailService(EmailProperties properties) {
this.properties = properties;
}
public void send(String to, String subject, String content) {
System.out.printf("发送邮件到:%s, 主题:%s, 内容:%s%n", to, subject, content);
// 实际实现会使用JavaMailSender
}
}
// 4. resources/META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.email.EmailAutoConfiguration
// 5. 使用方只需引入依赖即可自动配置
// application.yml
custom:
email:
host: smtp.example.com
username: user
password: pass
2.2 Spring Data JPA最佳实践
实体类设计规范
@Entity
@Table(name = "users", indexes = {
@Index(name = "idx_email", columnList = "email", unique = true),
@Index(name = "idx_status", columnList = "status")
})
@DynamicUpdate // 只更新修改的字段
@Where(clause = "deleted = false") // 逻辑删除过滤
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 100)
private String username;
@Column(nullable = false, length = 200, unique = true)
private String email;
@Column(nullable = false, length = 20)
@Enumerated(EnumType.STRING)
private UserStatus status = UserStatus.ACTIVE;
@Column(nullable = false)
private boolean deleted = false;
@CreationTimestamp
private LocalDateTime createdAt;
@UpdateTimestamp
private LocalDateTime updatedAt;
// 关联关系
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Order> orders;
// 枚举定义
public enum UserStatus {
ACTIVE, INACTIVE, BANNED
}
}
Repository层最佳实践
@Repository
public interface UserRepository extends JpaRepository<User, Long>,
JpaSpecificationExecutor<User> {
// 1. 方法名查询:Spring Data JPA会自动解析
Optional<User> findByEmail(String email);
// 2. 使用@Query自定义JPQL
@Query("SELECT u FROM User u WHERE u.email = :email AND u.status = :status")
Optional<User> findByEmailAndStatus(@Param("email") String email,
@Param("status") User.UserStatus status);
// 3. 原生SQL查询
@Query(value = "SELECT * FROM users WHERE email = ?1", nativeQuery = true)
Optional<User> findByEmailNative(String email);
// 4. 分页查询
@Query("SELECT u FROM User u WHERE u.username LIKE %:keyword%")
Page<User> findByUsernameContaining(@Param("keyword") String keyword, Pageable pageable);
// 5. 自定义查询返回DTO(避免返回实体类)
@Query("SELECT new com.example.dto.UserSummary(u.id, u.username, u.email) " +
"FROM User u WHERE u.status = :status")
List<UserSummary> findUserSummariesByStatus(@Param("status") User.UserStatus status);
// 6. 批量操作
@Modifying
@Query("UPDATE User u SET u.status = :status WHERE u.id IN :ids")
int updateStatusByIds(@Param("ids") List<Long> ids, @Param("status") User.UserStatus status);
// 7. 自定义方法名查询
List<User> findByStatusAndCreatedAtBetween(User.UserStatus status,
LocalDateTime start,
LocalDateTime end);
// 8. 使用EntityGraph解决N+1查询问题
@EntityGraph(attributePaths = {"orders"})
Optional<User> findUserWithOrdersById(Long id);
}
Service层实现与事务管理
@Service
@Transactional // 类级别事务管理
public class UserService {
private final UserRepository userRepository;
private final OrderRepository orderRepository;
public UserService(UserRepository userRepository, OrderRepository orderRepository) {
this.userRepository = userRepository;
this.orderRepository = orderRepository;
}
// 事务传播行为:REQUIRED(默认)- 如果存在事务则加入,否则新建
@Transactional(propagation = Propagation.REQUIRED,
rollbackFor = Exception.class,
timeout = 30)
public User createUserWithOrder(User user, Order order) {
// 1. 保存用户
User savedUser = userRepository.save(user);
// 2. 设置关联
order.setUser(savedUser);
orderRepository.save(order);
// 3. 发送事件(异步处理)
// 事件会在事务提交后才发布,避免事务未提交就读取数据
// applicationEventPublisher.publishEvent(new UserCreatedEvent(savedUser));
return savedUser;
}
// 只读事务,提升性能
@Transactional(readOnly = true)
public Optional<User> findUserById(Long id) {
return userRepository.findById(id);
}
// 事务传播:REQUIRES_NEW - 挂起当前事务,新建一个
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void logAudit(Long userId, String action) {
// 审计日志独立事务,即使主事务回滚,审计日志也会保存
// auditLogRepository.save(new AuditLog(userId, action));
}
// 异常回滚示例
@Transactional(rollbackFor = BusinessException.class)
public void complexBusinessOperation() throws BusinessException {
try {
// 业务操作
someBusinessLogic();
} catch (BusinessException e) {
// 记录日志但不回滚
log.error("业务异常", e);
throw e; // 重新抛出触发回滚
} catch (Exception e) {
// 其他异常不回滚
log.error("系统异常", e);
// 不抛出,事务正常提交
}
}
}
2.3 REST API设计与实现
Controller层规范
@RestController
@RequestMapping("/api/v1/users")
@Validated // 启用方法级别参数校验
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
// 1. 创建用户 - POST 201 Created
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public ApiResult<UserDTO> createUser(@Valid @RequestBody CreateUserRequest request) {
User user = convertToEntity(request);
User savedUser = userService.createUser(user);
return ApiResult.success(convertToDTO(savedUser));
}
// 2. 获取用户 - GET 200 OK
@GetMapping("/{id}")
public ApiResult<UserDTO> getUser(@PathVariable @Min(1) Long id) {
return userService.findUserById(id)
.map(user -> ApiResult.success(convertToDTO(user)))
.orElseThrow(() -> new UserNotFoundException(id));
}
// 3. 分页查询 - GET 200 OK
@GetMapping
public ApiResult<PageResult<UserDTO>> listUsers(
@RequestParam(defaultValue = "1") @Min(1) int page,
@RequestParam(defaultValue = "10") @Min(1) @Max(100) int size,
@RequestParam(required = false) String keyword) {
Pageable pageable = PageRequest.of(page - 1, size, Sort.by("createdAt").descending());
Page<User> userPage = userService.searchUsers(keyword, pageable);
PageResult<UserDTO> result = PageResult.of(
userPage.map(this::convertToDTO)
);
return ApiResult.success(result);
}
// 4. 更新用户 - PUT 200 OK
@PutMapping("/{id}")
public ApiResult<UserDTO> updateUser(@PathVariable Long id,
@Valid @RequestBody UpdateUserRequest request) {
User updatedUser = userService.updateUser(id, request);
return ApiResult.success(convertToDTO(updatedUser));
}
// 5. 删除用户 - DELETE 204 No Content
@DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
}
// 6. 批量操作 - POST 200 OK
@PostMapping("/batch")
public ApiResult<Void> batchCreate(@Valid @RequestBody List<CreateUserRequest> requests) {
List<User> users = requests.stream()
.map(this::convertToEntity)
.collect(Collectors.toList());
userService.batchCreate(users);
return ApiResult.success();
}
// DTO转换方法
private UserDTO convertToDTO(User user) {
UserDTO dto = new UserDTO();
dto.setId(user.getId());
dto.setUsername(user.getUsername());
dto.setEmail(user.getEmail());
dto.setStatus(user.getStatus().name());
dto.setCreatedAt(user.getCreatedAt());
return dto;
}
private User convertToEntity(CreateUserRequest request) {
User user = new User();
user.setUsername(request.getUsername());
user.setEmail(request.getEmail());
return user;
}
}
统一响应格式与异常处理
// 统一响应格式
public class ApiResult<T> {
private boolean success;
private String message;
private T data;
private long timestamp;
private ApiResult(boolean success, String message, T data) {
this.success = success;
this.message = message;
this.data =data;
this.timestamp = System.currentTimeMillis();
}
public static <T> ApiResult<T> success(T data) {
return new ApiResult<>(true, "操作成功", data);
}
public static <T> ApiResult<T> success() {
return new ApiResult<>(true, "操作成功", null);
}
public static <T> ApiResult<T> error(String message) {
return new ApiResult<>(false, message, null);
}
// getters
}
// 全局异常处理器
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiResult<Map<String, String>> handleValidationException(MethodArgumentNotValidException ex) {
Map<String, String> errors = ex.getBindingResult().getFieldErrors().stream()
.collect(Collectors.toMap(
FieldError::getField,
FieldError::getDefaultMessage
));
return ApiResult.error("参数校验失败:" + errors);
}
@ExceptionHandler(UserNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ApiResult<Void> handleUserNotFound(UserNotFoundException ex) {
return ApiResult.error(ex.getMessage());
}
@ExceptionHandler(BusinessException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiResult<Void> handleBusinessException(BusinessException ex) {
return ApiResult.error(ex.getMessage());
}
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ApiResult<Void> handleException(Exception ex) {
log.error("系统异常", ex);
return ApiResult.error("系统内部错误,请联系管理员");
}
}
第三部分:企业级高级特性与性能优化
3.1 缓存抽象与Redis集成
Spring Cache基础使用
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
// 缓存用户信息,key为方法参数id
@Cacheable(value = "users", key = "#id")
public User getUserById(Long id) {
log.info("从数据库查询用户:{}", id);
return userRepository.findById(id).orElse(null);
}
// 更新缓存
@CachePut(value = "users", key = "#user.id")
public User updateUser(User user) {
return userRepository.save(user);
}
// 删除缓存
@CacheEvict(value = "users", key = "#id")
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
// 复杂缓存:条件缓存
@Cacheable(value = "users",
key = "#id",
unless = "#result == null") // 结果为null不缓存
public User getUserByIdWithCondition(Long id) {
return userRepository.findById(id).orElse(null);
}
// 批量操作
@Cacheable(value = "users", key = "#ids")
public List<User> getUsersByIds(List<Long> ids) {
return userRepository.findAllById(ids);
}
}
Redis集成与配置
// 1. Redis配置类
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 使用Jackson序列化
Jackson2JsonRedisSerializer<Object> serializer =
new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(om);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(serializer);
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(serializer);
template.afterPropertiesSet();
return template;
}
// 自定义缓存管理器
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(10)) // 默认10分钟
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(
new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(
new GenericJackson2JsonRedisSerializer()));
return RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
}
}
// 2. 使用RedisTemplate直接操作
@Service
public class CacheService {
private final RedisTemplate<String, Object> redisTemplate;
public CacheService(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
// 设置值
public void set(String key, Object value, long timeout, TimeUnit unit) {
redisTemplate.opsForValue().set(key, value, timeout, unit);
}
// 获取值
public Object get(String key) {
return redisTemplate.opsForValue().get(key);
}
// Hash操作
public void putHash(String key, String hashKey, Object value) {
redisTemplate.opsForHash().put(key, hashKey, value);
}
public Object getHash(String key, String hashKey) {
return redisTemplate.opsForHash().get(key, hashKey);
}
// 分布式锁实现
public boolean tryLock(String key, long timeout, TimeUnit unit) {
return redisTemplate.opsForValue()
.setIfAbsent(key, "LOCK", timeout, unit);
}
public void unlock(String key) {
redisTemplate.delete(key);
}
}
3.2 异步处理与消息队列
@Async异步处理
@Service
public class AsyncService {
private static final Logger log = LoggerFactory.getLogger(AsyncService.class);
// 自定义线程池配置
@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.initialize();
return executor;
}
// 异步方法
@Async("taskExecutor")
public void sendEmail(String to, String subject, String content) {
log.info("开始发送邮件到:{}", to);
try {
// 模拟耗时操作
Thread.sleep(2000);
log.info("邮件发送成功:{}", to);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("邮件发送失败", e);
}
}
// 带返回值的异步方法
@Async("taskExecutor")
public CompletableFuture<String> processOrderAsync(Long orderId) {
log.info("异步处理订单:{}", orderId);
try {
Thread.sleep(1000);
return CompletableFuture.completedFuture("订单" + orderId + "处理完成");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return CompletableFuture.completedFuture("订单" + orderId + "处理失败");
}
}
}
Spring事件驱动架构
// 1. 自定义事件
public class UserCreatedEvent extends ApplicationEvent {
private final User user;
public UserCreatedEvent(Object source, User user) {
super(source);
this.user = user;
}
public User getUser() {
return user;
}
}
// 2. 事件发布者
@Service
public class UserService {
private final ApplicationEventPublisher eventPublisher;
private final UserRepository userRepository;
public UserService(ApplicationEventPublisher eventPublisher,
UserRepository userRepository) {
this.eventPublisher = eventPublisher;
this.userRepository = userRepository;
}
@Transactional
public void createUser(User user) {
userRepository.save(user);
// 发布事件(事务提交后才执行监听器)
eventPublisher.publishEvent(new UserCreatedEvent(this, user));
}
}
// 3. 事件监听器
@Component
public class UserEventListener {
private static final Logger log = LoggerFactory.getLogger(UserEventListener.class);
// 同步监听(默认)
@EventListener
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void handleUserCreated(UserCreatedEvent event) {
log.info("处理用户创建事件:{}", event.getUser().getId());
// 发送欢迎邮件、记录审计日志等
}
// 异步监听
@Async
@EventListener
public void handleUserCreatedAsync(UserCreatedEvent event) {
log.info("异步处理用户创建事件:{}", event.getUser().getId());
// 调用第三方API、发送通知等
}
// 条件监听
@EventListener(condition = "#event.user.status == T(com.example.UserStatus).ACTIVE")
public void handleActiveUserCreated(UserCreatedEvent event) {
log.info("活跃用户创建事件:{}", event.getUser().getId());
}
}
3.3 安全框架Spring Security集成
基础配置
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) // 启用方法级安全
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// 禁用CSRF(JWT场景下)
.csrf().disable()
// 认证配置
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll() // 公开接口
.requestMatchers("/api/admin/**").hasRole("ADMIN") // 管理员接口
.anyRequest().authenticated() // 其他需要认证
)
// JWT过滤器
.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
// 异常处理
.exceptionHandling(ex -> ex
.authenticationEntryPoint(new RestAuthenticationEntryPoint())
.accessDeniedHandler(new RestAccessDeniedHandler())
)
// 会话管理(无状态)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
);
return http.build();
}
@Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter();
}
// 密码编码器
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// 认证管理器
@Bean
public AuthenticationManager authenticationManager(
UserDetailsService userDetailsService,
PasswordEncoder passwordEncoder) {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setPasswordEncoder(passwordEncoder);
return new ProviderManager(provider);
}
}
// JWT认证过滤器
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
String jwt = getJwtFromRequest(request);
if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) {
Authentication authentication = tokenProvider.getAuthentication(jwt);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
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;
}
}
方法级安全控制
@Service
public class AdminService {
// 只有ADMIN角色可以访问
@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(Long id) {
// 删除用户逻辑
}
// 拥有USER_DELETE权限或ADMIN角色
@PreAuthorize("hasAuthority('USER_DELETE') or hasRole('ADMIN')")
public void deleteUserWithPermission(Long id) {
// 删除用户逻辑
}
// 参数级权限控制
@PreAuthorize("@securityService.isOwner(#id)")
public void updateProfile(Long id, UserProfile profile) {
// 只能修改自己的资料
}
// 表达式返回值控制
@PostAuthorize("returnObject.username == authentication.name or hasRole('ADMIN')")
public User getUser(Long id) {
// 返回用户信息
return userRepository.findById(id).orElse(null);
}
// 过滤返回集合
@PostFilter("filterObject.username == authentication.name or hasRole('ADMIN')")
public List<User> listUsers() {
return userRepository.findAll();
}
// 输入参数过滤
@PreFilter("filterObject.username == authentication.name or hasRole('ADMIN')")
public void updateUsers(List<User> users) {
// 批量更新
}
}
3.4 测试策略与最佳实践
单元测试
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserRepository userRepository;
@Mock
private OrderRepository orderRepository;
@InjectMocks
private UserService userService;
@Test
@DisplayName("创建用户成功")
void createUserSuccess() {
// Given
User user = new User();
user.setUsername("testuser");
user.setEmail("test@example.com");
when(userRepository.save(any(User.class))).thenReturn(user);
// When
User result = userService.createUser(user);
// Then
assertNotNull(result);
assertEquals("testuser", result.getUsername());
verify(userRepository, times(1)).save(user);
}
@Test
@DisplayName("创建用户失败 - 邮箱重复")
void createUserFailEmailExists() {
// Given
User user = new User();
user.setEmail("existing@example.com");
when(userRepository.findByEmail("existing@example.com"))
.thenReturn(Optional.of(new User()));
// When & Then
assertThrows(BusinessException.class, () -> {
userService.createUser(user);
});
verify(userRepository, never()).save(any());
}
}
集成测试
@SpringBootTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Transactional // 测试后回滚
class UserServiceIntegrationTest {
@Autowired
private UserService userService;
@Autowired
private UserRepository userRepository;
@Test
@DisplayName("完整用户创建流程")
void completeUserCreationFlow() {
// Given
User user = new User();
user.setUsername("integration");
user.setEmail("integration@test.com");
// When
User savedUser = userService.createUser(user);
// Then
assertNotNull(savedUser.getId());
// 验证数据库
User found = userRepository.findById(savedUser.getId()).orElse(null);
assertNotNull(found);
assertEquals("integration", found.getUsername());
}
}
MockMvc Web层测试
@WebMvcTest(UserController.class)
class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
@Test
@DisplayName("GET /api/v1/users/1 - 成功")
void getUserSuccess() throws Exception {
// Given
UserDTO userDTO = new UserDTO();
userDTO.setId(1L);
userDTO.setUsername("test");
when(userService.findUserById(1L)).thenReturn(Optional.of(new User()));
// When & Then
mockMvc.perform(get("/api/v1/users/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.data.username").value("test"));
}
@Test
@DisplayName("POST /api/v1/users - 参数错误")
void createUserInvalidParams() throws Exception {
// Given
CreateUserRequest request = new CreateUserRequest();
request.setEmail("invalid-email");
// When & Then
mockMvc.perform(post("/api/v1/users")
.contentType(MediaType.APPLICATION_JSON)
.content(new ObjectMapper().writeValueAsString(request)))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.success").value(false));
}
}
第四部分:企业级应用架构模式
4.1 分层架构设计
标准的企业级应用分层:
┌─────────────────────────────────────┐
│ Controller层(API接口层) │
│ - 参数校验 │
│ - 响应格式化 │
│ - 简单的业务逻辑 │
├─────────────────────────────────────┤
│ Service层(业务逻辑层) │
│ - 核心业务逻辑 │
│ - 事务管理 │
│ - 权限控制 │
├─────────────────────────────────────┤
│ Repository层(数据访问层) │
│ - 数据库操作 │
│ - ORM映射 │
│ - 基础CRUD │
├─────────────────────────────────────┤
│ Domain层(领域模型层) │
│ - 实体类定义 │
│ - 业务规则 │
│ - 领域服务 │
└─────────────────────────────────────┘
4.2 领域驱动设计(DDD)在Spring中的实践
实体与值对象
// 领域实体(有唯一标识)
@Entity
public class Order {
@Id
private OrderId id;
private CustomerId customerId;
private OrderStatus status;
private Money totalAmount;
private LocalDateTime createdAt;
// 聚合根方法
public void addItem(Product product, int quantity) {
if (status != OrderStatus.PENDING) {
throw new IllegalStateException("只能修改待处理订单");
}
items.add(new OrderItem(product, quantity));
recalculateTotal();
}
private void recalculateTotal() {
this.totalAmount = items.stream()
.map(OrderItem::getSubtotal)
.reduce(Money.ZERO, Money::add);
}
}
// 值对象(无标识,不可变)
public class Money {
private final BigDecimal amount;
private final Currency currency;
public Money add(Money other) {
if (!this.currency.equals(other.currency)) {
throw new IllegalArgumentException("货币类型不匹配");
}
return new Money(this.amount.add(other.amount), currency);
}
// equals, hashCode, toString
}
// 聚合根
@Entity
public class Order extends AggregateRoot<OrderId> {
// ... 聚合逻辑
}
防腐层(Anti-Corruption Layer)
// 外部系统接口适配器
@Component
public class PaymentGatewayAdapter {
private final PaymentGatewayClient client;
public PaymentResult processPayment(PaymentCommand command) {
try {
// 转换为外部系统格式
ExternalPaymentRequest externalRequest = toExternalRequest(command);
// 调用外部系统
ExternalPaymentResponse externalResponse = client.pay(externalRequest);
// 转换回领域模型
return toDomainResult(externalResponse);
} catch (ExternalSystemException e) {
throw new PaymentException("支付失败", e);
}
}
private ExternalPaymentRequest toExternalRequest(PaymentCommand command) {
// 转换逻辑
return new ExternalPaymentRequest();
}
private PaymentResult toDomainResult(ExternalPaymentResponse response) {
// 转换逻辑
return new PaymentResult();
}
}
4.3 微服务架构集成
服务注册与发现(Eureka)
// 1. Eureka Server
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
// 2. Eureka Client配置
spring:
application:
name: user-service
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
// 3. 服务调用(RestTemplate + 负载均衡)
@Service
public class OrderServiceClient {
private final RestTemplate restTemplate;
public OrderServiceClient(RestTemplateBuilder builder) {
this.restTemplate = builder.build();
}
public OrderDTO getOrder(Long orderId) {
// user-service是服务名,由Eureka解析
String url = "http://user-service/api/orders/{orderId}";
return restTemplate.getForObject(url, OrderDTO.class, orderId);
}
}
// 4. 负载均衡配置
@Bean
@LoadBalanced // 重要:启用负载均衡
public RestTemplate restTemplate() {
return new RestTemplate();
}
API网关(Spring Cloud Gateway)
// Gateway配置
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- StripPrefix=1
- name: Retry
args:
retries: 3
backoff:
firstBackoff: 50ms
maxBackoff: 500ms
- name: RateLimit
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
第五部分:企业级开发难题解决方案
5.1 数据库事务并发控制
乐观锁实现
@Entity
public class Product {
@Id
private Long id;
private String name;
private BigDecimal price;
@Version // 乐观锁版本号
private Integer version;
// 库存扣减(乐观锁)
public void deductStock(int quantity) {
if (this.stock < quantity) {
throw new InsufficientStockException("库存不足");
}
this.stock -= quantity;
}
}
// Service层
@Service
public class ProductService {
@Transactional
public void deductStock(Long productId, int quantity) {
Product product = productRepository.findById(productId)
.orElseThrow(() -> new ProductNotFoundException(productId));
product.deductStock(quantity);
// 保存时会自动检查版本号
// 如果版本号不匹配,会抛出OptimisticLockException
productRepository.save(product);
}
}
悲观锁实现
// Repository层
public interface ProductRepository extends JpaRepository<Product, Long> {
// 使用SELECT FOR UPDATE进行悲观锁
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT p FROM Product p WHERE p.id = :id")
Optional<Product> findByIdForUpdate(@Param("id") Long id);
}
// Service层
@Service
public class ProductService {
@Transactional
public void deductStock(Long productId, int quantity) {
// 加悲观锁,其他事务必须等待
Product product = productRepository.findByIdForUpdate(productId)
.orElseThrow(() -> new ProductNotFoundException(productId));
product.deductStock(quantity);
productRepository.save(product);
}
}
5.2 分布式锁实现
Redis分布式锁(Redisson)
@Component
public class DistributedLockService {
@Autowired
private RedissonClient redissonClient;
/**
* 执行带分布式锁的业务逻辑
* @param lockKey 锁的key
* @param waitTime 等待锁时间(毫秒)
* @param leaseTime 锁持有时间(毫秒)
* @param business 业务逻辑
*/
public <T> T executeWithLock(String lockKey, long waitTime, long leaseTime,
Supplier<T> business) {
RLock lock = redissonClient.getLock(lockKey);
try {
// 尝试加锁,最多等待waitTime,锁定leaseTime后自动释放
if (lock.tryLock(waitTime, leaseTime, TimeUnit.MILLISECONDS)) {
return business.get();
} else {
throw new LockAcquireException("获取分布式锁失败");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new LockAcquireException("获取锁被中断", e);
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
// 使用示例
@Service
public class OrderService {
@Autowired
private DistributedLockService lockService;
public void processOrder(Long orderId) {
String lockKey = "order:process:" + orderId;
lockService.executeWithLock(lockKey, 5000, 30000, () -> {
// 只有获取锁的线程才能执行
Order order = orderRepository.findById(orderId);
if (order.getStatus() == OrderStatus.PENDING) {
// 处理订单逻辑
order.setStatus(OrderStatus.PROCESSING);
orderRepository.save(order);
}
return null;
});
}
}
}
5.3 大数据量分库分表
ShardingSphere集成
// 1. Maven依赖
// sharding-jdbc-spring-boot-starter
// 2. 配置
spring:
shardingsphere:
datasource:
names: ds0, ds1
ds0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/db0
username: root
password: root
ds1:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/db1
username: root
password: root
rules:
sharding:
tables:
orders:
actual-data-nodes: ds${0..1}.orders_${0..7} # 2库8表
table-strategy:
standard:
sharding-column: user_id
sharding-algorithm-name: orders-inline
database-strategy:
standard:
sharding-column: user_id
sharding-algorithm-name: database-inline
sharding-algorithms:
database-inline:
type: INLINE
props:
algorithm-expression: ds${user_id % 2}
orders-inline:
type: INLINE
props:
algorithm-expression: orders_${user_id % 8}
// 3. 使用(透明分片)
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
public void createOrder(Order order) {
// ShardingSphere会自动根据user_id路由到正确的库表
orderRepository.save(order);
}
public List<Order> getUserOrders(Long userId) {
// 自动路由到对应库表查询
return orderRepository.findByUserId(userId);
}
}
5.4 接口幂等性保障
幂等性实现方案
// 1. 幂等表设计
@Entity
@Table(indexes = @Index(name = "idx_business_key", columnList = "businessKey", unique = true))
public class IdempotentRecord {
@Id
private String id;
private String businessKey; // 业务唯一标识
private String status; // SUCCESS, FAILED
private LocalDateTime createdAt;
}
// 2. 幂等性Service
@Service
public class IdempotentService {
@Autowired
private IdempotentRepository idempotentRepository;
@Autowired
private RedisTemplate<String, String> redisTemplate;
/**
* 执行幂等性业务
* @param businessKey 业务唯一标识
* @param business 业务逻辑
*/
public <T> T executeIdempotent(String businessKey, Supplier<T> business) {
// 方案1:Redis分布式锁 + 数据库幂等表(推荐)
String lockKey = "idempotent:" + businessKey;
// 先检查是否已执行
Optional<IdempotentRecord> record = idempotentRepository.findByBusinessKey(businessKey);
if (record.isPresent()) {
if ("SUCCESS".equals(record.get().getStatus())) {
// 已成功执行,直接返回结果(需要业务层支持返回结果)
throw new IdempotentException("重复请求,已处理");
} else {
// 上次失败,可以重试
return business.get();
}
}
// 获取分布式锁
RLock lock = redissonClient.getLock(lockKey);
try {
if (lock.tryLock(1000, 5000, TimeUnit.MILLISECONDS)) {
// 双重检查
record = idempotentRepository.findByBusinessKey(businessKey);
if (record.isPresent()) {
throw new IdempotentException("重复请求");
}
// 创建幂等记录
IdempotentRecord newRecord = new IdempotentRecord();
newRecord.setBusinessKey(businessKey);
newRecord.setStatus("PROCESSING");
newRecord.setCreatedAt(LocalDateTime.now());
idempotentRepository.save(newRecord);
try {
// 执行业务
T result = business.get();
// 更新为成功
newRecord.setStatus("SUCCESS");
idempotentRepository.save(newRecord);
return result;
} catch (Exception e) {
// 更新为失败(可选)
newRecord.setStatus("FAILED");
idempotentRepository.save(newRecord);
throw e;
}
}
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
throw new IdempotentException("获取幂等锁失败");
}
}
// 3. 使用示例
@Service
public class PaymentService {
@Autowired
private IdempotentService idempotentService;
public PaymentResult processPayment(PaymentRequest request) {
// 业务唯一标识:支付单号
String businessKey = request.getPaymentNo();
return idempotentService.executeIdempotent(businessKey, () -> {
// 实际支付逻辑
return doProcessPayment(request);
});
}
}
5.5 系统监控与诊断
Spring Boot Actuator + Prometheus + Grafana
// 1. Maven依赖
// spring-boot-starter-actuator
// micrometer-registry-prometheus
// 2. 配置
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: always
metrics:
export:
prometheus:
enabled: true
tags:
application: ${spring.application.name}
// 3. 自定义健康检查
@Component
public class DatabaseHealthIndicator implements HealthIndicator {
@Autowired
private DataSource dataSource;
@Override
public Health health() {
try (Connection conn = dataSource.getConnection()) {
conn.createStatement().execute("SELECT 1");
return Health.up()
.withDetail("database", "MySQL")
.withDetail("version", conn.getMetaData().getDatabaseProductVersion())
.build();
} catch (Exception e) {
return Health.down()
.withDetail("error", e.getMessage())
.build();
}
}
}
// 4. 自定义指标
@Service
public class BusinessMetricsService {
private final MeterRegistry meterRegistry;
public BusinessMetricsService(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}
public void recordOrderCreated(double amount) {
// 计数器
meterRegistry.counter("orders.created",
"type", "online",
"currency", "CNY").increment();
// 计时器
Timer timer = meterRegistry.timer("order.processing.time");
timer.record(() -> {
// 处理订单
});
// 仪表(Gauge)
Gauge.builder("order.amount", () -> amount)
.description("订单金额")
.register(meterRegistry);
}
}
应用性能监控(APM)
// 使用SkyWalking自动追踪(无需代码)
// 只需在JVM参数添加:
// -javaagent:/path/to/skywalking-agent.jar
// -Dskywalking.agent.service_name=user-service
// 或者使用Spring Cloud Sleuth + Zipkin
// 1. Maven依赖
// spring-cloud-starter-sleuth
// spring-cloud-starter-zipkin
// 2. 配置
spring:
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
probability: 1.0 # 采样率100%
// 3. 日志自动注入TraceId
// 在日志中自动添加[TraceId,SpanId]前缀
第六部分:Spring框架高级特性
6.1 动态数据源切换
// 1. 动态数据源配置
@Configuration
public class DynamicDataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.master")
public DataSource masterDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.slave")
public DataSource slaveDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
public DataSource dynamicDataSource(DataSource masterDataSource,
DataSource slaveDataSource) {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put("master", masterDataSource);
targetDataSources.put("slave", slaveDataSource);
DynamicDataSource dynamicDataSource = new DynamicDataSource();
dynamicDataSource.setTargetDataSources(targetDataSources);
dynamicDataSource.setDefaultTargetDataSource(masterDataSource);
return dynamicDataSource;
}
}
// 2. 数据源上下文
public class DataSourceContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
public static void setDataSource(String dataSource) {
contextHolder.set(dataSource);
}
public static String getDataSource() {
return contextHolder.get();
}
public static void clear() {
contextHolder.remove();
}
}
// 3. 动态数据源类
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSource();
}
}
// 4. AOP切换数据源
@Aspect
@Component
public class DataSourceAspect {
@Before("@annotation(master)")
public void beforeMaster(JoinPoint joinPoint, Master master) {
DataSourceContextHolder.setDataSource("master");
}
@Before("@annotation(slave)")
public void beforeSlave(JoinPoint joinPoint, Slave slave) {
DataSourceContextHolder.setDataSource("slave");
}
@After("@annotation(master) || @annotation(slave)")
public void after(JoinPoint joinPoint) {
DataSourceContextHolder.clear();
}
}
// 5. 自定义注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Master {}
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Slave {}
// 6. 使用示例
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Master
public void createUser(User user) {
userRepository.save(user);
}
@Slave
public User getUser(Long id) {
return userRepository.findById(id).orElse(null);
}
}
6.2 动态路由与规则引擎
// 1. 规则定义
public interface RoutingRule {
boolean matches(RoutingContext context);
String getTarget();
}
// 2. 上下文
public class RoutingContext {
private String userId;
private String region;
private String deviceType;
private Map<String, Object> attributes;
// getters
}
// 3. 规则引擎
@Component
public class RoutingEngine {
private final List<RoutingRule> rules;
public RoutingEngine(List<RoutingRule> rules) {
this.rules = rules;
}
public String route(RoutingContext context) {
return rules.stream()
.filter(rule -> rule.matches(context))
.map(RoutingRule::getTarget)
.findFirst()
.orElse("default");
}
}
// 4. 具体规则实现
@Component
@Order(1)
public class RegionRoutingRule implements RoutingRule {
@Override
public boolean matches(RoutingContext context) {
return "CN".equals(context.getRegion());
}
@Override
public String getTarget() {
return "cn-datasource";
}
}
@Component
@Order(2)
public class DefaultRoutingRule implements RoutingRule {
@Override
public boolean matches(RoutingContext context) {
return true; // 总是匹配
}
@Override
public String getTarget() {
return "default-datasource";
}
}
6.3 柔性事务与最终一致性
本地消息表实现最终一致性
// 1. 消息表实体
@Entity
@Table(name = "local_message")
public class LocalMessage {
@Id
private String id;
private String businessKey;
private String topic;
private String payload;
private String status; // PENDING, SENT, FAILED
private int retryCount;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
// 2. 消息服务
@Service
public class LocalMessageService {
@Autowired
private LocalMessageRepository messageRepository;
@Autowired
private RabbitTemplate rabbitTemplate;
@Transactional
public void sendMessage(String businessKey, String topic, Object payload) {
// 1. 保存消息到本地表(与业务在同一事务)
LocalMessage message = new LocalMessage();
message.setId(UUID.randomUUID().toString());
message.setBusinessKey(businessKey);
message.setTopic(topic);
message.setPayload(toJson(payload));
message.setStatus("PENDING");
message.setRetryCount(0);
messageRepository.save(message);
// 2. 业务操作...
}
// 定时任务重试发送
@Scheduled(fixedDelay = 30000)
@Transactional
public void retrySendFailedMessages() {
List<LocalMessage> messages = messageRepository
.findByStatusAndRetryCountLessThan("FAILED", 3, PageRequest.of(0, 100));
for (LocalMessage message : messages) {
try {
rabbitTemplate.convertAndSend(message.getTopic(), message.getPayload());
message.setStatus("SENT");
messageRepository.save(message);
} catch (Exception e) {
message.setRetryCount(message.getRetryCount() + 1);
if (message.getRetryCount() >= 3) {
message.setStatus("FAILED");
// 发送告警
}
messageRepository.save(message);
}
}
}
}
第七部分:企业级开发最佳实践
7.1 代码规范与设计原则
SOLID原则在Spring中的应用
// S - 单一职责原则
// 坏例子:一个类做太多事
@Service
public class OrderService {
public void createOrder() { /*...*/ }
public void sendEmail() { /*...*/ } // ❌ 职责不单一
public void calculateTax() { /*...*/ }
}
// 好例子:职责分离
@Service
public class OrderService {
private final EmailService emailService;
private final TaxCalculator taxCalculator;
public void createOrder() {
// 只负责订单创建
}
}
// O - 开闭原则
// 使用抽象和扩展
public interface PaymentStrategy {
void pay(Money amount);
}
@Service
public class AlipayStrategy implements PaymentStrategy {
public void pay(Money amount) { /*...*/ }
}
@Service
public class WechatPayStrategy implements PaymentStrategy {
public void pay(Money amount) { /*...*/ }
}
// L - 里氏替换原则
// 子类必须能替换父类
public abstract class Animal {
public abstract void makeSound();
}
public class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("汪汪");
}
}
// I - 接口隔离原则
// 接口要精简
public interface ReadableRepository<T> {
T findById(Long id);
List<T> findAll();
}
public interface WritableRepository<T> {
T save(T entity);
void delete(Long id);
}
// D - 依赖倒置原则
// 依赖抽象,不依赖具体实现
@Service
public class OrderService {
private final PaymentStrategy paymentStrategy; // 抽象
public OrderService(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
}
7.2 异常处理最佳实践
// 1. 异常分层
// 业务异常(可恢复)
public class BusinessException extends RuntimeException {
private String errorCode;
public BusinessException(String errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
}
// 系统异常(不可恢复)
public class SystemException extends RuntimeException {
public SystemException(String message, Throwable cause) {
super(message, cause);
}
}
// 2. 异常处理原则
@Service
public class UserService {
// ✅ 好:具体异常,明确意图
public void createUser(User user) {
if (userRepository.existsByEmail(user.getEmail())) {
throw new BusinessException("USER_EMAIL_EXISTS", "邮箱已存在");
}
userRepository.save(user);
}
// ❌ 坏:过于宽泛的异常捕获
public void badExample() {
try {
// 业务逻辑
} catch (Exception e) {
// 吞掉异常或打印日志后继续
log.error("出错了", e);
// 不推荐:隐藏了问题
}
}
// ✅ 好:异常转换
public User getUser(Long id) {
try {
return userRepository.findById(id).orElseThrow();
} catch (Exception e) {
throw new SystemException("查询用户失败", e);
}
}
}
7.3 日志规范
// 1. 日志级别使用
@Service
public class OrderService {
private static final Logger log = LoggerFactory.getLogger(OrderService.class);
public void processOrder(Order order) {
// TRACE: 极其详细的调试信息(通常不开启)
log.trace("进入processOrder方法,order={}", order);
// DEBUG: 开发调试信息
log.debug("订单{}状态:{}", order.getId(), order.getStatus());
// INFO: 重要业务节点(生产环境开启)
log.info("开始处理订单:{}", order.getId());
// WARN: 潜在问题警告
if (order.getAmount().compareTo(BigDecimal.ZERO) < 0) {
log.warn("订单金额异常:{}", order.getAmount());
}
// ERROR: 错误信息
try {
// 业务逻辑
} catch (Exception e) {
log.error("订单{}处理失败", order.getId(), e);
throw e;
}
}
}
// 2. 日志格式规范
// 正确:使用参数化日志
log.info("用户{}创建订单{},金额:{}", userId, orderId, amount);
// 错误:字符串拼接
log.info("用户" + userId + "创建订单" + orderId); // ❌ 性能差
7.4 配置管理最佳实践
# 1. 配置文件组织
# application.yml (基础配置)
spring:
application:
name: user-service
profiles:
active: dev
# application-dev.yml (开发环境)
spring:
datasource:
url: jdbc:mysql://localhost:3306/dev_db
username: dev_user
password: dev_pass
# application-prod.yml (生产环境)
spring:
datasource:
url: jdbc:mysql://db.prod.com:3306/prod_db
username: ${DB_USER}
password: ${DB_PASSWORD}
# 2. 配置属性类
@ConfigurationProperties(prefix = "app")
public class AppProperties {
private final Cache cache = new Cache();
private final Email email = new Email();
public static class Cache {
private boolean enabled = true;
private Duration ttl = Duration.ofMinutes(10);
// getters/setters
}
public static class Email {
private String host;
private int port;
// getters/setters
}
}
// 3. 敏感信息加密
// 使用Jasypt加密
// 1. Maven依赖:jasypt-spring-boot-starter
// 2. 配置加密密钥
jasypt:
encryptor:
password: ${JASYPT_PASSWORD}
// 3. 加密密码
// ENC(加密后的字符串)
spring:
datasource:
password: ENC(xxxxxxxx)
第八部分:实战案例 - 电商系统开发
8.1 需求分析与架构设计
需求:实现一个支持高并发的电商订单系统
核心功能:
- 商品管理
- 购物车
- 订单创建
- 库存扣减
- 支付处理
- 分布式锁防止超卖
8.2 完整代码实现
// 1. 领域模型
@Entity
public class Product {
@Id
private Long id;
private String name;
private BigDecimal price;
private Integer stock;
@Version
private Integer version;
public void deductStock(int quantity) {
if (stock < quantity) {
throw new InsufficientStockException("库存不足");
}
stock -= quantity;
}
}
@Entity
public class Order {
@Id
private Long id;
private String orderNo;
private Long userId;
private BigDecimal amount;
private OrderStatus status;
@OneToMany(cascade = CascadeType.ALL)
private List<OrderItem> items;
}
// 2. Repository层
public interface ProductRepository extends JpaRepository<Product, Long> {
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT p FROM Product p WHERE p.id = :id")
Optional<Product> findByIdForUpdate(@Param("id") Long id);
}
public interface OrderRepository extends JpaRepository<Order, Long> {
Optional<Order> findByOrderNo(String orderNo);
}
// 3. Service层
@Service
@Transactional
public class OrderService {
private final ProductRepository productRepository;
private final OrderRepository orderRepository;
private final RedisTemplate<String, Object> redisTemplate;
private final ApplicationEventPublisher eventPublisher;
public OrderService(ProductRepository productRepository,
OrderRepository orderRepository,
RedisTemplate<String, Object> redisTemplate,
ApplicationEventPublisher eventPublisher) {
this.productRepository = productRepository;
this.orderRepository = orderRepository;
this.redisTemplate = redisTemplate;
this.eventPublisher = eventPublisher;
}
public Order createOrder(Long userId, List<OrderItemRequest> items) {
// 1. 生成订单号(分布式ID)
String orderNo = generateOrderNo();
// 2. 计算总金额并扣减库存(使用悲观锁)
BigDecimal totalAmount = BigDecimal.ZERO;
List<OrderItem> orderItems = new ArrayList<>();
for (OrderItemRequest itemRequest : items) {
// 获取分布式锁防止超卖
String lockKey = "product:stock:" + itemRequest.getProductId();
RLock lock = redissonClient.getLock(lockKey);
try {
if (!lock.tryLock(3000, 10000, TimeUnit.MILLISECONDS)) {
throw new LockAcquireException("商品抢购太频繁,请稍后重试");
}
// 悲观锁查询并扣减库存
Product product = productRepository.findByIdForUpdate(itemRequest.getProductId())
.orElseThrow(() -> new ProductNotFoundException(itemRequest.getProductId()));
product.deductStock(itemRequest.getQuantity());
productRepository.save(product);
// 累加金额
BigDecimal itemTotal = product.getPrice().multiply(
new BigDecimal(itemRequest.getQuantity()));
totalAmount = totalAmount.add(itemTotal);
// 创建订单项
OrderItem orderItem = new OrderItem();
orderItem.setProductId(product.getId());
orderItem.setProductName(product.getName());
orderItem.setQuantity(itemRequest.getQuantity());
orderItem.setUnitPrice(product.getPrice());
orderItems.add(orderItem);
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
// 3. 创建订单
Order order = new Order();
order.setOrderNo(orderNo);
order.setUserId(userId);
order.setAmount(totalAmount);
order.setStatus(OrderStatus.PENDING);
order.setItems(orderItems);
Order savedOrder = orderRepository.save(order);
// 4. 发布订单创建事件(异步处理支付、通知等)
eventPublisher.publishEvent(new OrderCreatedEvent(this, savedOrder));
return savedOrder;
}
private String generateOrderNo() {
// 基于Redis的分布式ID生成器
String key = "order:no:seq";
Long seq = redisTemplate.opsForValue().increment(key);
return "ORD" + System.currentTimeMillis() + String.format("%06d", seq);
}
}
// 4. 事件监听器
@Component
public class OrderEventListener {
@Async
@EventListener
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void handleOrderCreated(OrderCreatedEvent event) {
Order order = event.getOrder();
// 1. 发送支付请求(异步)
// paymentService.requestPayment(order);
// 2. 发送通知(异步)
// notificationService.sendOrderCreatedNotification(order);
// 3. 记录审计日志
log.info("订单创建事件处理完成:{}", order.getOrderNo());
}
}
// 5. Controller层
@RestController
@RequestMapping("/api/orders")
public class OrderController {
private final OrderService orderService;
public OrderController(OrderService orderService) {
this.orderService = orderService;
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public ApiResult<OrderDTO> createOrder(@Valid @RequestBody CreateOrderRequest request,
@AuthenticationPrincipal UserDetails userDetails) {
Long userId = Long.parseLong(userDetails.getUsername());
Order order = orderService.createOrder(userId, request.getItems());
return ApiResult.success(convertToDTO(order));
}
}
8.3 性能优化点
- 库存扣减:使用Redis分布式锁 + 悲观锁,防止超卖
- 订单号生成:基于Redis原子递增,避免数据库压力
- 异步处理:订单创建后异步处理支付和通知,提升响应速度
- 缓存:商品信息缓存到Redis,减少数据库查询
8.4 测试验证
@SpringBootTest
@Transactional
class OrderServiceIntegrationTest {
@Autowired
private OrderService orderService;
@Autowired
private ProductRepository productRepository;
@Test
@DisplayName("并发下单测试 - 防止超卖")
void concurrentOrderTest() throws InterruptedException {
// 准备商品:库存10
Product product = new Product();
product.setId(1L);
product.setName("iPhone 15");
product.setPrice(new BigDecimal("5999"));
product.setStock(10);
productRepository.save(product);
// 模拟100个线程同时下单,每个线程购买1个
int threadCount = 100;
CountDownLatch startLatch = new CountDownLatch(1);
CountDownLatch endLatch = new CountDownLatch(threadCount);
AtomicInteger successCount = new AtomicInteger(0);
AtomicInteger failCount = new AtomicInteger(0);
for (int i = 0; i < threadCount; i++) {
new Thread(() -> {
try {
startLatch.await(); // 等待开始信号
orderService.createOrder(1L, Arrays.asList(
new OrderItemRequest(1L, 1)
));
successCount.incrementAndGet();
} catch (Exception e) {
failCount.incrementAndGet();
} finally {
endLatch.countDown();
}
}).start();
}
// 统一启动
startLatch.countDown();
endLatch.await();
// 验证:只有10个成功,90个失败
assertEquals(10, successCount.get());
assertEquals(90, failCount.get());
// 验证库存:0
Product finalProduct = productRepository.findById(1L).orElse(null);
assertEquals(0, finalProduct.getStock());
}
}
第九部分:持续学习与进阶路线
9.1 Spring生态体系
Spring Framework Core
├── IoC容器
├── AOP
├── 数据访问
└── 事务管理
Spring Boot
├── 自动配置
├── 嵌入式服务器
├── Actuator
└── Starter
Spring Cloud
├── Eureka(服务发现)
├── Ribbon(负载均衡)
├── Hystrix(熔断器)
├── Gateway(网关)
└── Config(配置中心)
Spring Data
├── JPA
├── MongoDB
├── Redis
└── Elasticsearch
Spring Security
├── 认证
├── 授权
├── OAuth2
└── JWT
Spring Batch(批处理)
Spring Integration(集成)
Spring WebSocket(实时通信)
9.2 推荐学习路径
基础阶段(1-2个月)
- 掌握Spring Core和IoC/AOP原理
- 熟练使用Spring Boot开发Web应用
- 理解Spring Data JPA
进阶阶段(2-3个月)
- 深入Spring Security
- 掌握Spring Cloud微服务
- 学习缓存、消息队列集成
高级阶段(持续)
- 阅读Spring源码
- 理解设计模式在Spring中的应用
- 掌握性能调优和故障排查
9.3 推荐资源
- 官方文档:spring.io/projects/spring-framework
- 书籍:《Spring实战》、《Spring Boot编程思想》
- 源码:GitHub spring-projects/spring-framework
- 社区:Spring官方论坛、Stack Overflow
总结
Spring框架作为Java企业级开发的基石,其价值不仅在于提供强大的功能,更在于其优秀的架构设计和扩展性。通过本文的学习,你应该能够:
- 理解核心原理:IoC、AOP、自动配置等底层机制
- 掌握实战技巧:数据访问、事务管理、安全控制等
- 解决企业难题:并发控制、分布式锁、性能优化等
- 遵循最佳实践:代码规范、异常处理、日志规范等
记住,Spring框架的学习是一个持续的过程。建议在实际项目中不断实践,遇到问题时查阅官方文档和源码,逐步形成自己的技术体系。同时,关注Spring生态的最新发展,如Spring Native、Spring GraphQL等新技术,保持技术的先进性。
最后,技术只是工具,真正的价值在于解决业务问题。在使用Spring框架时,始终要思考如何更好地支撑业务发展,如何提升系统质量,如何为用户创造价值。这才是成为一名优秀Java开发者的根本。
