引言:为什么选择Spring框架?
Spring框架是Java企业级开发中最流行、最强大的开源框架之一。自2003年首次发布以来,Spring已经发展成为Java生态系统中不可或缺的基础设施。它不仅仅是一个框架,更是一个完整的编程模型和生态系统。
Spring的核心价值在于其依赖注入(DI)和面向切面编程(AOP)理念,这些概念彻底改变了Java开发的方式。通过Spring,开发者可以编写更松耦合、更易测试、更易维护的代码。无论你是构建简单的Web应用,还是复杂的企业级系统,Spring都能提供相应的解决方案。
本文将带你从Spring的基础概念开始,逐步深入到高级特性和实际应用,最终达到精通水平。我们将涵盖Spring Framework的核心模块、Spring Boot的快速开发、Spring MVC的Web开发、数据访问、安全性以及微服务架构等关键主题。
第一部分:Spring基础概念与核心原理
1.1 什么是控制反转(IoC)和依赖注入(DI)
控制反转(Inversion of Control, IoC)是Spring框架最核心的设计理念。传统的编程方式中,对象自己负责创建和管理它所依赖的对象;而在IoC模式下,这个责任被反转给了外部容器(Spring IoC容器)。
依赖注入(Dependency Injection, DI)是实现IoC的具体方式。Spring容器通过三种主要方式将依赖关系注入到对象中:
- 构造器注入(Constructor Injection)
- Setter方法注入(Setter Injection)
- 字段注入(Field Injection)
让我们通过一个完整的例子来理解这些概念:
// 传统方式:紧密耦合
public class UserService {
private UserRepository userRepository;
public UserService() {
// 直接创建依赖对象
this.userRepository = new UserRepository();
}
public User getUserById(Long id) {
return userRepository.findUser(id);
}
}
// 使用Spring DI的方式
public class UserService {
private final UserRepository userRepository;
// 构造器注入 - 推荐方式
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User getUserById(Long id) {
return userRepository.findUser(id);
}
}
// Repository接口
public interface UserRepository {
User findUser(Long id);
}
// 实现类
@Repository
public class UserRepositoryImpl implements UserRepository {
@Override
public User findUser(Long id) {
// 数据库查询逻辑
return new User(id, "John Doe");
}
}
1.2 Spring IoC容器详解
Spring IoC容器是Spring框架的核心,它负责实例化、配置和管理Bean的整个生命周期。主要的容器接口有两个:
- BeanFactory:基础容器接口,提供基本的IoC功能
- ApplicationContext:BeanFactory的子接口,提供了更多企业级功能
配置Bean的三种方式
1. 基于XML配置(传统方式)
<!-- applicationContext.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="userRepository" class="com.example.UserRepositoryImpl"/>
<bean id="userService" class="com.example.UserService">
<constructor-arg ref="userRepository"/>
</bean>
<!-- Setter注入 -->
<bean id="orderService" class="com.example.OrderService">
<property name="orderRepository" ref="orderRepository"/>
</bean>
</beans>
2. 基于注解配置(推荐方式)
// 主配置类
@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
// 可以在这里定义额外的Bean
@Bean
public DataSource dataSource() {
HikariDataSource ds = new HikariDataSource();
ds.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
ds.setUsername("root");
ds.setPassword("password");
return ds;
}
}
// 使用注解标记组件
@Repository
public class UserRepositoryImpl implements UserRepository {
// 实现细节
}
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
// 业务逻辑
}
@RestController
public class UserController {
@Autowired
private UserService userService;
// 控制器逻辑
}
3. 基于Java配置(最灵活的方式)
@Configuration
public class AppConfig {
@Bean
public UserRepository userRepository() {
return new UserRepositoryImpl();
}
@Bean
public UserService userService() {
return new UserService(userRepository());
}
// 使用@Import导入其他配置类
@Import({DatabaseConfig.class, SecurityConfig.class})
public static class CombinedConfig {
}
}
1.3 Bean的作用域(Scope)
Spring Bean支持多种作用域,理解这些作用域对于正确设计应用至关重要:
@Component
@Scope("singleton") // 默认作用域,每个容器中一个实例
public class SingletonBean {
// ...
}
@Component
@Scope("prototype") // 每次请求都创建新实例
public class PrototypeBean {
// ...
}
@Component
@Scope("request") // 每个HTTP请求一个实例(Web环境)
public class RequestScopedBean {
// ...
}
@Component
@Scope("session") // 每个HTTP会话一个实例(Web环境)
public class SessionScopedBean {
// ...
}
@Component
@Scope("application") // 每个ServletContext一个实例(Web环境)
public class ApplicationScopedBean {
// ...
}
1.4 Bean的生命周期管理
Spring Bean的生命周期包含多个阶段,我们可以通过各种回调方法来控制:
@Component
public class LifecycleBean implements InitializingBean, DisposableBean {
public LifecycleBean() {
System.out.println("1. 构造函数调用");
}
@PostConstruct
public void postConstruct() {
System.out.println("3. @PostConstruct注解方法调用");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("4. InitializingBean.afterPropertiesSet()调用");
}
@PreDestroy
public void preDestroy() {
System.out.println("7. @PreDestroy注解方法调用");
}
@Override
public void destroy() throws Exception {
System.out.println("8. DisposableBean.destroy()调用");
}
// 自定义初始化方法
@Bean(initMethod = "customInit", destroyMethod = "customDestroy")
public AnotherBean anotherBean() {
return new AnotherBean();
}
}
class AnotherBean {
public void customInit() {
System.out.println("5. 自定义初始化方法");
}
public void customDestroy() {
System.out.println("9. 自定义销毁方法");
}
}
第二部分:Spring AOP面向切面编程
2.1 AOP核心概念
面向切面编程(Aspect-Oriented Programming, AOP)是Spring框架的另一个核心特性,它允许我们分离横切关注点(cross-cutting concerns),如日志、事务、安全性等。
AOP的核心术语:
- 切面(Aspect):封装了横切关注点的模块
- 连接点(Join Point):程序执行过程中的某个点(如方法执行)
- 通知(Advice):切面在特定连接点执行的动作
- 切入点(Pointcut):匹配连接点的表达式
- 目标对象(Target):被代理的对象
- 代理(Proxy):Spring创建的对象,包含目标对象和通知
2.2 Spring AOP实现示例
让我们创建一个完整的日志切面示例:
// 1. 定义切面
@Aspect
@Component
public class LoggingAspect {
private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
// 2. 定义切入点表达式
// 匹配com.example.service包下所有类的所有方法
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceMethods() {}
// 3. 前置通知
@Before("serviceMethods()")
public void logBefore(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
logger.info("执行方法: {},参数: {}", methodName, Arrays.toString(args));
}
// 4. 返回后通知
@AfterReturning(pointcut = "serviceMethods()", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
String methodName = joinPoint.getSignature().getName();
logger.info("方法 {} 执行完成,返回值: {}", methodName, result);
}
// 5. 异常通知
@AfterThrowing(pointcut = "serviceMethods()", throwing = "ex")
public void logAfterThrowing(JoinPoint joinPoint, Exception ex) {
String methodName = joinPoint.getSignature().getName();
logger.error("方法 {} 执行异常: {}", methodName, ex.getMessage(), ex);
}
// 6. 最终通知
@After("serviceMethods()")
public void logAfter(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
logger.info("方法 {} 执行结束", methodName);
}
// 7. 环绕通知(最强大的通知类型)
@Around("serviceMethods()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
try {
Object result = joinPoint.proceed(); // 执行目标方法
long duration = System.currentTimeMillis() - start;
logger.info("方法执行耗时: {} ms", duration);
return result;
} catch (Exception e) {
long duration = System.currentTimeMillis() - start;
logger.error("方法执行失败,耗时: {} ms", duration);
throw e;
}
}
}
更复杂的切入点表达式
@Aspect
@Component
public class AdvancedAspect {
// 匹配所有public方法
@Pointcut("execution(public * *(..))")
public void publicMethods() {}
// 匹配指定包下所有方法
@Pointcut("within(com.example.service..*)")
public void inServicePackage() {}
// 匹配实现了特定接口的类
@Pointcut("this(com.example.service.UserService)")
public void userServiceImplementation() {}
// 匹配带有特定注解的方法
@Pointcut("@annotation(com.example.annotation.Loggable)")
public void annotatedMethods() {}
// 组合切入点
@Pointcut("publicMethods() && inServicePackage()")
public void publicServiceMethods() {}
// 带参数的切入点
@Pointcut("execution(* com.example.service.*.*(Long, ..))")
public void methodsWithLongParam() {}
}
2.3 使用AOP实现事务管理
// 自定义事务切面
@Aspect
@Component
@Transactional
public class TransactionAspect {
@Around("@annotation(transactional)")
public Object manageTransaction(ProceedingJoinPoint joinPoint,
Transactional transactional) throws Throwable {
TransactionStatus status = null;
try {
// 开启事务
status = beginTransaction(transactional);
Object result = joinPoint.proceed();
// 提交事务
commitTransaction(status);
return result;
} catch (Exception e) {
// 回滚事务
rollbackTransaction(status);
throw e;
}
}
private TransactionStatus beginTransaction(Transactional tx) {
// 事务实现细节
return null; // 简化示例
}
private void commitTransaction(TransactionStatus status) {
// 提交逻辑
}
private void rollbackTransaction(TransactionStatus status) {
// 回滚逻辑
}
}
第三部分:Spring Boot快速开发
3.1 Spring Boot简介
Spring Boot是Spring框架的”约定优于配置”理念的完美体现。它通过自动配置和起步依赖,极大地简化了Spring应用的开发过程。
Spring Boot的核心特性:
- 自动配置:根据classpath中的jar包自动配置Bean
- 起步依赖:简化Maven/Gradle配置
- 嵌入式服务器:无需单独部署Servlet容器
- 生产级监控:提供健康检查、指标等
- 外部化配置:灵活的配置管理
3.2 创建第一个Spring Boot应用
方式一:使用Spring Initializr(推荐)
访问 start.spring.io 或使用IDE创建项目。
方式二:手动创建
项目结构:
my-spring-boot-app/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ └── demo/
│ │ │ ├── DemoApplication.java
│ │ │ ├── controller/
│ │ │ ├── service/
│ │ │ └── model/
│ │ └── resources/
│ │ ├── application.properties
│ │ └── static/
│ └── test/
├── pom.xml
pom.xml配置:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>1.0.0</version>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<!-- Web开发起步依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 数据访问 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- 数据库驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- 测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
主应用类:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
3.3 Spring Boot自动配置原理
Spring Boot的自动配置基于条件化配置,通过@Conditional系列注解实现:
// 自动配置类示例
@Configuration
@ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class}) // 当类路径存在指定类时
@ConditionalOnMissingBean(DataSource.class) // 当容器中不存在DataSource Bean时
@EnableConfigurationProperties(DataSourceProperties.class) // 启用配置属性
public class DataSourceAutoConfiguration {
@Configuration
@ConditionalOnEmbeddedDatabase // 嵌入式数据库条件
static class EmbeddedDataSourceConfiguration {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public EmbeddedDataSource dataSource() {
// 创建嵌入式数据源
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.build();
}
}
}
3.4 外部化配置
Spring Boot支持多种配置源,按优先级排序:
// 1. 命令行参数
// java -jar app.jar --server.port=8081 --spring.datasource.url=jdbc:mysql://...
// 2. JVM系统属性
// java -Dserver.port=8081 -jar app.jar
// 3. 环境变量
// export SERVER_PORT=8081
// 4. application.properties/yml
// server.port=8080
// 5. @ConfigurationProperties绑定
@Component
@ConfigurationProperties(prefix = "app")
public class AppProperties {
private String name;
private String version;
private Database database = new Database();
public static class Database {
private String url;
private String username;
private String password;
// getters and setters
}
// getters and setters
}
application.yml示例:
server:
port: 8080
servlet:
context-path: /api
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL8Dialect
app:
name: My Application
version: 1.0.0
database:
url: jdbc:mysql://localhost:3306/mydb
username: root
password: password
第四部分:Spring MVC Web开发
4.1 Spring MVC架构概述
Spring MVC是基于Servlet API的Web框架,采用经典的MVC(Model-View-Controller)设计模式:
- DispatcherServlet:前端控制器,所有请求的入口点
- HandlerMapping:将请求映射到处理器
- HandlerAdapter:执行处理器方法
- ViewResolver:解析视图名称到具体视图
- HandlerInterceptor:请求处理拦截器
4.2 创建RESTful API
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
// GET /api/users - 获取所有用户
@GetMapping
public ResponseEntity<List<User>> getAllUsers() {
List<User> users = userService.findAll();
return ResponseEntity.ok(users);
}
// GET /api/users/{id} - 获取单个用户
@GetMapping("/{id}")
public ResponseEntity<User> getUserById(@PathVariable Long id) {
return userService.findById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
// POST /api/users - 创建用户
@PostMapping
public ResponseEntity<User> createUser(@Valid @RequestBody User user,
BindingResult result) {
if (result.hasErrors()) {
return ResponseEntity.badRequest().build();
}
User savedUser = userService.save(user);
return ResponseEntity.status(HttpStatus.CREATED).body(savedUser);
}
// PUT /api/users/{id} - 更新用户
@PutMapping("/{id}")
public ResponseEntity<User> updateUser(@PathVariable Long id,
@Valid @RequestBody User user) {
return userService.findById(id)
.map(existing -> {
user.setId(id);
return ResponseEntity.ok(userService.save(user));
})
.orElse(ResponseEntity.notFound().build());
}
// DELETE /api/users/{id} - 删除用户
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
if (userService.findById(id).isPresent()) {
userService.delete(id);
return ResponseEntity.noContent().build();
}
return ResponseEntity.notFound().build();
}
// GET /api/users/search?name=John - 条件查询
@GetMapping("/search")
public ResponseEntity<List<User>> searchUsers(
@RequestParam(required = false) String name,
@RequestParam(required = false) String email) {
List<User> users = userService.search(name, email);
return ResponseEntity.ok(users);
}
}
4.3 请求参数验证
// 实体类验证注解
public class User {
@NotNull(message = "ID不能为空")
private Long id;
@NotBlank(message = "用户名不能为空")
@Size(min = 3, max = 20, message = "用户名长度必须在3-20个字符之间")
private String username;
@Email(message = "邮箱格式不正确")
@NotBlank(message = "邮箱不能为空")
private String email;
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
private String phone;
@Min(value = 18, message = "年龄必须大于18岁")
@Max(value = 120, message = "年龄不能超过120岁")
private Integer age;
// getters and setters
}
// 自定义验证注解
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UniqueUsernameValidator.class)
public @interface UniqueUsername {
String message() default "用户名已存在";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
// 验证器实现
public class UniqueUsernameValidator implements ConstraintValidator<UniqueUsername, String> {
@Autowired
private UserRepository userRepository;
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return !userRepository.existsByUsername(value);
}
}
4.4 全局异常处理
// 全局异常处理器
@RestControllerAdvice
public class GlobalExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
// 处理验证异常
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidationExceptions(
MethodArgumentNotValidException ex) {
List<String> errors = ex.getBindingResult()
.getFieldErrors()
.stream()
.map(error -> error.getField() + ": " + error.getDefaultMessage())
.collect(Collectors.toList());
return ResponseEntity.badRequest()
.body(new ErrorResponse("VALIDATION_ERROR", errors.toString()));
}
// 处理资源未找到异常
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleResourceNotFound(
ResourceNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse("NOT_FOUND", ex.getMessage()));
}
// 处理业务异常
@ExceptionHandler(BusinessException.class)
public ResponseEntity<ErrorResponse> handleBusinessException(
BusinessException ex) {
return ResponseEntity.badRequest()
.body(new ErrorResponse("BUSINESS_ERROR", ex.getMessage()));
}
// 处理所有未预期的异常
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleAllExceptions(Exception ex) {
logger.error("Unexpected error occurred", ex);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("INTERNAL_ERROR", "系统内部错误"));
}
}
// 错误响应DTO
public class ErrorResponse {
private String code;
private String message;
private LocalDateTime timestamp;
public ErrorResponse(String code, String message) {
this.code = code;
this.message = message;
this.timestamp = LocalDateTime.now();
}
// getters and setters
}
4.5 拦截器和过滤器
// 自定义拦截器
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// 在控制器方法执行前调用
String token = request.getHeader("Authorization");
if (!isValidToken(token)) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return false;
}
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
// 在控制器方法执行后调用
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
// 在请求完成后调用
}
private boolean isValidToken(String token) {
// Token验证逻辑
return token != null && token.startsWith("Bearer ");
}
}
// 注册拦截器
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private AuthInterceptor authInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor)
.addPathPatterns("/api/**") // 拦截所有/api开头的请求
.excludePathPatterns("/api/public/**"); // 排除公共接口
}
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://localhost:3000")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}
第五部分:Spring Data访问技术
5.1 Spring Data JPA
Spring Data JPA是Spring Data项目的一部分,它简化了JPA(Java Persistence API)的使用。
实体类定义
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true, length = 50)
private String username;
@Column(nullable = false, length = 100)
private String email;
@Column(length = 20)
private String phone;
@Column
private Integer age;
@CreationTimestamp
@Column(updatable = false)
private LocalDateTime createdAt;
@UpdateTimestamp
private LocalDateTime updatedAt;
@Version
private Long version; // 乐观锁
// JPA关系映射
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Order> orders = new ArrayList<>();
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(
name = "user_roles",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id")
)
private Set<Role> roles = new HashSet<>();
// 构造函数
public User() {}
public User(String username, String email) {
this.username = username;
this.email = email;
}
// getters and setters
// equals, hashCode, toString
}
Repository接口
// 基础Repository接口
public interface UserRepository extends JpaRepository<User, Long>,
JpaSpecificationExecutor<User> {
// 方法名查询
Optional<User> findByUsername(String username);
Optional<User> findByEmail(String email);
List<User> findByAgeGreaterThan(Integer age);
List<User> findByUsernameContaining(String keyword);
// 使用@Query注解
@Query("SELECT u FROM User u WHERE u.email = :email")
Optional<User> findByEmailQuery(@Param("email") String email);
// 原生SQL查询
@Query(value = "SELECT * FROM users WHERE age >= :minAge", nativeQuery = true)
List<User> findUsersByMinAge(@Param("minAge") Integer minAge);
// 动态查询
@Query("SELECT u FROM User u WHERE " +
"(:username IS NULL OR u.username LIKE %:username%) AND " +
"(:email IS NULL OR u.email LIKE %:email%)")
List<User> searchUsers(@Param("username") String username,
@Param("email") String email);
// 自定义更新操作
@Modifying
@Query("UPDATE User u SET u.email = :email WHERE u.id = :id")
int updateEmail(@Param("id") Long id, @Param("email") String email);
// 分页查询
Page<User> findByAgeGreaterThan(Integer age, Pageable pageable);
// 排序查询
List<User> findByAgeGreaterThan(Integer age, Sort sort);
// 统计查询
long countByAgeGreaterThan(Integer age);
// 存在性查询
boolean existsByUsername(String username);
// 删除查询
@Modifying
@Query("DELETE FROM User u WHERE u.age < :age")
void deleteByAgeLessThan(@Param("age") Integer age);
}
自定义Repository实现
// 自定义Repository接口
public interface UserRepositoryCustom {
List<User> findComplexUsers(String keyword, Integer minAge, Integer maxAge);
}
// 实现类
@Repository
public class UserRepositoryImpl implements UserRepositoryCustom {
@PersistenceContext
private EntityManager entityManager;
@Override
public List<User> findComplexUsers(String keyword, Integer minAge, Integer maxAge) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<User> query = cb.createQuery(User.class);
Root<User> root = query.from(User.class);
List<Predicate> predicates = new ArrayList<>();
if (keyword != null && !keyword.isEmpty()) {
predicates.add(cb.or(
cb.like(root.get("username"), "%" + keyword + "%"),
cb.like(root.get("email"), "%" + keyword + "%")
));
}
if (minAge != null) {
predicates.add(cb.greaterThanOrEqualTo(root.get("age"), minAge));
}
if (maxAge != null) {
predicates.add(cb.lessThanOrEqualTo(root.get("age"), maxAge));
}
query.where(predicates.toArray(new Predicate[0]));
query.orderBy(cb.desc(root.get("createdAt")));
return entityManager.createQuery(query).getResultList();
}
}
5.2 事务管理
@Service
@Transactional
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private OrderRepository orderRepository;
// 事务传播行为
@Transactional(propagation = Propagation.REQUIRED)
public void createUserWithOrders(User user, List<Order> orders) {
userRepository.save(user);
// 如果save失败,整个事务回滚
for (Order order : orders) {
order.setUser(user);
orderRepository.save(order);
// 如果某个订单保存失败,前面的操作也会回滚
}
}
// 只读事务
@Transactional(readOnly = true)
public User findUserWithOrders(Long id) {
return userRepository.findById(id).orElse(null);
}
// 不同的隔离级别
@Transactional(isolation = Isolation.READ_COMMITTED)
public void updateUser(Long id, String email) {
userRepository.updateEmail(id, email);
}
// 自定义事务回滚
@Transactional(rollbackFor = BusinessException.class)
public void complexOperation() throws BusinessException {
try {
// 业务逻辑
} catch (Exception e) {
// 只回滚指定异常
throw new BusinessException("操作失败", e);
}
}
// 事务传播:REQUIRES_NEW
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void auditLog(String message) {
// 独立事务,即使外层事务回滚,审计日志也会保存
// saveAuditLog(message);
}
}
5.3 多数据源配置
// 主数据源配置
@Configuration
@MapperScan(basePackages = "com.example.mapper.master", sqlSessionFactoryRef = "masterSqlSessionFactory")
public class MasterDataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.master")
public DataSource masterDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
public SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:mapper/master/*.xml"));
return bean.getObject();
}
@Bean
public DataSourceTransactionManager masterTransactionManager(@Qualifier("masterDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
// 从数据源配置
@Configuration
@MapperScan(basePackages = "com.example.mapper.slave", sqlSessionFactoryRef = "slaveSqlSessionFactory")
public class SlaveDataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.slave")
public DataSource slaveDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
public SqlSessionFactory slaveSqlSessionFactory(@Qualifier("slaveDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:mapper/slave/*.xml"));
return bean.getObject();
}
@Bean
public DataSourceTransactionManager slaveTransactionManager(@Qualifier("slaveDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
第六部分:Spring Security安全框架
6.1 Spring Security基础
Spring Security是Spring生态系统中的安全框架,提供认证和授权功能。
基本配置
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable() // 禁用CSRF(用于REST API)
.authorizeHttpRequests(authz -> authz
.requestMatchers("/api/public/**").permitAll() // 公共接口
.requestMatchers("/api/admin/**").hasRole("ADMIN") // 管理员接口
.requestMatchers("/api/user/**").hasAnyRole("USER", "ADMIN") // 用户接口
.anyRequest().authenticated() // 其他需要认证
)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 无状态
)
.httpBasic(); // 使用HTTP Basic认证
return http.build();
}
@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);
}
}
自定义UserDetailsService
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("用户不存在: " + username));
return org.springframework.security.core.userdetails.User
.withUsername(user.getUsername())
.password(user.getPassword())
.authorities(user.getRoles().stream()
.map(role -> new SimpleGrantedAuthority("ROLE_" + role.getName()))
.collect(Collectors.toList()))
.accountExpired(false)
.accountLocked(false)
.credentialsExpired(false)
.disabled(false)
.build();
}
}
6.2 JWT认证实现
// JWT工具类
@Component
public class JwtTokenUtil {
private static final String SECRET_KEY = "your-secret-key-min-256-bits";
private static final long EXPIRATION_TIME = 86400000; // 24小时
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
claims.put("roles", userDetails.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toList()));
return Jwts.builder()
.setClaims(claims)
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
public String extractUsername(String token) {
return extractClaim(token, Claims::getSubject);
}
public Date extractExpiration(String token) {
return extractClaim(token, Claims::getExpiration);
}
public <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());
}
public Boolean validateToken(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
}
// JWT认证过滤器
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
final String authHeader = request.getHeader("Authorization");
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
filterChain.doFilter(request, response);
return;
}
final String jwt = authHeader.substring(7);
final String username = jwtTokenUtil.extractUsername(jwt);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (jwtTokenUtil.validateToken(jwt, userDetails)) {
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
filterChain.doFilter(request, response);
}
}
// 更新Security配置以支持JWT
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private JwtAuthenticationFilter jwtAuthenticationFilter;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeHttpRequests(authz -> authz
.requestMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated()
)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
6.3 方法级安全
@Configuration
@EnableMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig {
}
@Service
public class SecureService {
// 只有ADMIN角色可以访问
@PreAuthorize("hasRole('ADMIN')")
public void adminOnlyMethod() {
// 管理员操作
}
// 只有USER角色可以访问
@PreAuthorize("hasRole('USER')")
public void userOnlyMethod() {
// 用户操作
}
// 方法参数级权限控制
@PreAuthorize("hasRole('ADMIN') or #userId == authentication.principal.id")
public void updateUser(Long userId, String newEmail) {
// 只能更新自己的信息,或管理员可以更新所有
}
// 返回值过滤
@PostFilter("filterObject.owner == authentication.principal.username")
public List<Order> getOrders() {
// 返回的订单列表会被过滤,只保留当前用户的订单
return orderRepository.findAll();
}
// 角色层次结构
@PreAuthorize("hasAuthority('ROLE_ADMIN') or hasAuthority('ROLE_MANAGER')")
public void managerMethod() {
// 管理员和经理都可以访问
}
}
第七部分:Spring测试
7.1 单元测试
@SpringBootTest
class UserServiceTest {
@Autowired
private UserService userService;
@MockBean
private UserRepository userRepository;
@Test
void shouldReturnUserWhenUserExists() {
// Given
User mockUser = new User(1L, "john", "john@example.com");
when(userRepository.findById(1L)).thenReturn(Optional.of(mockUser));
// When
Optional<User> result = userService.findById(1L);
// Then
assertThat(result).isPresent();
assertThat(result.get().getUsername()).isEqualTo("john");
verify(userRepository, times(1)).findById(1L);
}
@Test
void shouldThrowExceptionWhenUserNotFound() {
// Given
when(userRepository.findById(999L)).thenReturn(Optional.empty());
// When & Then
assertThrows(ResourceNotFoundException.class, () -> {
userService.getUser(999L);
});
}
}
7.2 Web层测试
@WebMvcTest(UserController.class)
class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
@Test
void shouldReturnUserWhenExists() throws Exception {
User user = new User(1L, "john", "john@example.com");
when(userService.findById(1L)).thenReturn(Optional.of(user));
mockMvc.perform(get("/api/users/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(1))
.andExpect(jsonPath("$.username").value("john"));
}
@Test
void shouldReturn404WhenUserNotFound() throws Exception {
when(userService.findById(999L)).thenReturn(Optional.empty());
mockMvc.perform(get("/api/users/999"))
.andExpect(status().isNotFound());
}
@Test
void shouldCreateUser() throws Exception {
User newUser = new User(null, "john", "john@example.com");
User savedUser = new User(1L, "john", "john@example.com");
when(userService.save(any(User.class))).thenReturn(savedUser);
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"username\":\"john\",\"email\":\"john@example.com\"}"))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.id").value(1));
}
}
7.3 集成测试
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class UserRepositoryIntegrationTest {
@Autowired
private TestEntityManager entityManager;
@Autowired
private UserRepository userRepository;
@Test
void shouldFindUserByUsername() {
User user = new User("john", "john@example.com");
entityManager.persist(user);
entityManager.flush();
Optional<User> found = userRepository.findByUsername("john");
assertThat(found).isPresent();
assertThat(found.get().getEmail()).isEqualTo("john@example.com");
}
@Test
void shouldReturnEmptyWhenUserNotFound() {
Optional<User> found = userRepository.findByUsername("nonexistent");
assertThat(found).isEmpty();
}
}
第八部分:Spring高级特性
8.1 Spring事件驱动编程
// 自定义事件
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;
}
}
// 事件发布者
@Service
public class UserService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void createUser(User user) {
// 保存用户
userRepository.save(user);
// 发布事件
eventPublisher.publishEvent(new UserCreatedEvent(this, user));
}
}
// 事件监听器
@Component
public class UserEventListener {
@EventListener
public void handleUserCreated(UserCreatedEvent event) {
// 异步处理
sendWelcomeEmail(event.getUser());
logUserCreation(event.getUser());
}
@Async // 异步执行
public void sendWelcomeEmail(User user) {
// 发送欢迎邮件逻辑
}
@Async
public void logUserCreation(User user) {
// 记录日志
}
}
// 异步配置
@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;
}
}
8.2 Spring缓存
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
// 使用Caffeine作为缓存实现
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCaffeine(Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(1000)
.recordStats());
return cacheManager;
}
}
@Service
public class UserService {
@Cacheable(value = "users", key = "#id")
public User getUser(Long 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);
}
@Caching(
put = {
@CachePut(value = "users", key = "#user.id"),
@CachePut(value = "usernames", key = "#user.username")
},
evict = {
@CacheEvict(value = "allUsers", allEntries = true)
}
)
public User createUser(User user) {
return userRepository.save(user);
}
}
8.3 Spring批处理
@Configuration
@EnableBatchProcessing
public class BatchConfig {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Bean
public Job importUserJob(Step step1) {
return jobBuilderFactory.get("importUserJob")
.incrementer(new RunIdIncrementer())
.flow(step1)
.end()
.listener(jobCompletionListener())
.build();
}
@Bean
public Step step1(ItemReader<User> reader,
ItemWriter<User> writer,
ItemProcessor<User, User> processor) {
return stepBuilderFactory.get("step1")
.<User, User>chunk(10)
.reader(reader)
.processor(processor)
.writer(writer)
.build();
}
@Bean
public ItemReader<User> reader() {
// 从CSV文件读取
FlatFileItemReader<User> reader = new FlatFileItemReader<>();
reader.setResource(new ClassPathResource("users.csv"));
reader.setLineMapper(new DefaultLineMapper<User>() {{
setLineTokenizer(new DelimitedLineTokenizer() {{
setNames("username", "email", "age");
}});
setFieldSetMapper(new BeanWrapperFieldSetMapper<User>() {{
setTargetType(User.class);
}});
}});
return reader;
}
@Bean
public ItemProcessor<User, User> processor() {
return user -> {
user.setEmail(user.getEmail().toLowerCase());
return user;
};
}
@Bean
public ItemWriter<User> writer() {
return users -> {
// 批量写入数据库
users.forEach(user -> userRepository.save(user));
};
}
@Bean
public JobExecutionListener jobCompletionListener() {
return new JobExecutionListenerSupport() {
@Override
public void afterJob(JobExecution jobExecution) {
System.out.println("Job completed: " + jobExecution.getStatus());
}
};
}
}
8.4 Spring WebSocket
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new ChatWebSocketHandler(), "/chat")
.setAllowedOrigins("*");
}
}
@Component
public class ChatWebSocketHandler extends TextWebSocketHandler {
private final List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
sessions.add(session);
session.sendMessage(new TextMessage("Connected to chat server"));
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
// 广播消息到所有会话
for (WebSocketSession s : sessions) {
if (s.isOpen()) {
s.sendMessage(message);
}
}
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
sessions.remove(session);
}
}
第九部分:Spring微服务架构
9.1 Spring Cloud基础
Spring Cloud为分布式系统开发提供了一整套工具。
服务注册与发现(Eureka)
# application.yml for Eureka Server
server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://localhost:8761/eureka/
server:
enable-self-preservation: false
// Eureka Server
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
// Eureka Client
@SpringBootApplication
@EnableEurekaClient
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
// 配置
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
服务调用(Feign)
// Feign客户端
@FeignClient(name = "order-service", fallback = OrderServiceFallback.class)
public interface OrderServiceClient {
@GetMapping("/api/orders/user/{userId}")
List<Order> getOrdersByUserId(@PathVariable("userId") Long userId);
@PostMapping("/api/orders")
Order createOrder(@RequestBody Order order);
}
// 熔断器
@Component
public class OrderServiceFallback implements OrderServiceClient {
@Override
public List<Order> getOrdersByUserId(Long userId) {
return Collections.emptyList(); // 返回空列表
}
@Override
public Order createOrder(Order order) {
throw new RuntimeException("Order service unavailable");
}
}
// 使用Feign
@Service
public class UserService {
@Autowired
private OrderServiceClient orderServiceClient;
public UserWithOrders getUserWithOrders(Long userId) {
User user = userRepository.findById(userId).orElse(null);
if (user == null) return null;
List<Order> orders = orderServiceClient.getOrdersByUserId(userId);
return new UserWithOrders(user, orders);
}
}
配置中心(Config Server)
# Config Server application.yml
server:
port: 8888
spring:
cloud:
config:
server:
git:
uri: https://github.com/your-repo/config-repo
search-paths: '{application}'
username: your-username
password: your-password
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
# Config Client bootstrap.yml
spring:
application:
name: user-service
cloud:
config:
uri: http://localhost:8888
profile: dev
熔断器(Hystrix)
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
@HystrixCommand(
fallbackMethod = "getProductFallback",
commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")
},
threadPoolProperties = {
@HystrixProperty(name = "coreSize", value = "10"),
@HystrixProperty(name = "maxQueueSize", value = "100")
}
)
public Product getProduct(Long id) {
// 模拟慢查询
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return productRepository.findById(id).orElse(null);
}
public Product getProductFallback(Long id) {
// 降级返回
return new Product(id, "Fallback Product", 0.0);
}
}
9.2 API网关(Spring Cloud Gateway)
# application.yml
server:
port: 8080
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
factor: 2
basedOnPreviousValue: false
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/orders/**
filters:
- StripPrefix=1
- RateLimit=10, 20s # 20秒内最多10个请求
- id: auth-service
uri: lb://auth-service
predicates:
- Path=/api/auth/**
filters:
- StripPrefix=1
// 自定义过滤器
@Component
public class LoggingFilter implements GlobalFilter, Ordered {
private static final Logger logger = LoggerFactory.getLogger(LoggingFilter.class);
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
logger.info("Request: {} {}",
exchange.getRequest().getMethod(),
exchange.getRequest().getURI());
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
logger.info("Response: {}", exchange.getResponse().getStatusCode());
}));
}
@Override
public int getOrder() {
return -1; // 优先级最高
}
}
9.3 分布式追踪(Sleuth + Zipkin)
# application.yml
spring:
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
probability: 1.0 # 100%采样
// 自定义追踪
@Service
public class TracedService {
@Autowired
private Tracer tracer;
public void processWithTracing() {
Span span = tracer.nextSpan().name("process").start();
try (Tracer.SpanInScope ws = tracer.withSpanInScope(span)) {
// 业务逻辑
logger.info("Processing in span: {}", span.context().traceIdString());
} finally {
span.end();
}
}
}
第十部分:Spring性能优化与最佳实践
10.1 性能优化技巧
1. 连接池优化
# HikariCP配置
spring:
datasource:
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
leak-detection-threshold: 60000
pool-name: MyHikariCP
2. JPA优化
// 使用DTO避免N+1查询
public interface UserSummary {
Long getId();
String getUsername();
String getEmail();
}
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// 只查询需要的字段
@Query("SELECT u.id as id, u.username as username, u.email as email FROM User u")
List<UserSummary> findAllSummaries();
// 使用JOIN FETCH避免N+1
@Query("SELECT u FROM User u JOIN FETCH u.orders WHERE u.id = :id")
Optional<User> findByIdWithOrders(@Param("id") Long id);
// 批量查询
@Query("SELECT u FROM User u WHERE u.id IN :ids")
List<User> findByIds(@Param("ids") List<Long> ids);
}
3. 缓存优化
@CacheConfig(cacheNames = "users")
@Service
public class CachedUserService {
@Cacheable(key = "#id")
public User getUser(Long id) {
return userRepository.findById(id).orElse(null);
}
@CacheEvict(allEntries = true)
public void clearCache() {
// 清空整个缓存
}
@Caching(
evict = {
@CacheEvict(key = "#user.id"),
@CacheEvict(value = "usernames", key = "#user.username")
}
)
public void updateUser(User user) {
userRepository.save(user);
}
}
10.2 监控与健康检查
// 自定义健康检查
@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("connections", getActiveConnections())
.build();
} catch (Exception e) {
return Health.down()
.withDetail("error", e.getMessage())
.build();
}
}
private int getActiveConnections() {
// 获取活跃连接数
return 0; // 简化示例
}
}
// 自定义指标
@Component
public class CustomMetrics {
private final Counter requestCounter = Counter.build()
.name("http_requests_total")
.help("Total HTTP requests")
.labelNames("method", "path", "status")
.register();
private final Histogram requestDuration = Histogram.build()
.name("http_request_duration_seconds")
.help("HTTP request duration in seconds")
.buckets(0.1, 0.5, 1, 2, 5)
.register();
public void recordRequest(String method, String path, String status, double duration) {
requestCounter.labels(method, path, status).inc();
requestDuration.observe(duration);
}
}
10.3 日志配置
<!-- logback-spring.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<springProperty scope="context" name="APP_NAME" source="spring.application.name"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/${APP_NAME}.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/${APP_NAME}.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
<totalSizeCap>1GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="FILE"/>
<queueSize>10000</queueSize>
<discardingThreshold>0</discardingThreshold>
</appender>
<!-- 不同环境不同日志级别 -->
<springProfile name="dev">
<root level="DEBUG">
<appender-ref ref="CONSOLE"/>
</root>
</springProfile>
<springProfile name="prod">
<root level="INFO">
<appender-ref ref="ASYNC_FILE"/>
</root>
<!-- 特定包的日志级别 -->
<logger name="com.example" level="DEBUG"/>
<logger name="org.springframework" level="WARN"/>
<logger name="org.hibernate" level="WARN"/>
</springProfile>
</configuration>
第十一部分:Spring学习路径与资源
11.1 学习路线建议
阶段一:基础入门(1-2周)
- 掌握Java基础(集合、多线程、反射、注解)
- 理解IoC和DI概念
- 学习Spring基础配置(XML和注解)
- 完成简单的控制台应用
阶段二:Web开发(2-3周)
- 学习Spring MVC
- 掌握RESTful API设计
- 理解HTTP协议和状态码
- 实现完整的CRUD应用
阶段三:数据访问(2-3周)
- 学习JPA和Hibernate
- 掌握Spring Data JPA
- 理解事务管理
- 实现复杂的数据查询
阶段四:Spring Boot(2周)
- 理解自动配置原理
- 掌握起步依赖
- 学习外部化配置
- 构建生产级应用
阶段五:安全性(1-2周)
- 学习Spring Security基础
- 掌握认证和授权
- 实现JWT认证
- 理解OAuth2
阶段六:高级特性(2-3周)
- AOP深入
- 缓存和异步处理
- 事件驱动编程
- 批处理
阶段七:微服务(3-4周)
- Spring Cloud基础
- 服务注册与发现
- API网关和熔断器
- 分布式追踪
阶段八:性能优化与最佳实践(持续学习)
- 性能调优
- 监控和日志
- 测试策略
- 代码规范
11.2 推荐学习资源
官方文档:
- Spring Framework官方文档:https://spring.io/projects/spring-framework
- Spring Boot官方文档:https://spring.io/projects/spring-boot
- Spring Cloud官方文档:https://spring.io/projects/spring-cloud
书籍推荐:
- 《Spring实战》(Spring in Action)
- 《Spring Boot编程思想》
- 《Spring Cloud微服务实战》
- 《Spring 5核心原理》
在线课程:
- Spring官方教程:https://spring.io/guides
- Baeldung Spring教程:https://www.baeldung.com/spring-tutorial
- 菜鸟教程Spring部分
社区和论坛:
- Spring官方论坛
- Stack Overflow
- GitHub Spring项目
- 国内技术社区(如掘金、思否)
11.3 实践项目建议
初级项目:
- 用户管理系统(CRUD)
- 博客系统
- 待办事项应用
中级项目:
- 电商后台系统
- 在线考试系统
- 即时通讯应用
高级项目:
- 微服务架构的电商平台
- 大数据处理平台
- 高并发秒杀系统
总结
Spring框架是一个功能强大、生态丰富的Java开发框架。通过本文的学习,你应该已经掌握了从基础概念到高级特性的完整知识体系。记住,理论学习只是第一步,真正的精通来自于不断的实践和项目经验。
关键要点回顾:
- IoC和DI是Spring的核心,理解它们对于掌握Spring至关重要
- AOP帮助我们分离横切关注点,提高代码的可维护性
- Spring Boot通过自动配置大大简化了开发过程
- Spring MVC提供了强大的Web开发能力
- Spring Data简化了数据访问层的开发
- Spring Security提供了全面的安全解决方案
- Spring Cloud为微服务架构提供了完整的工具链
持续学习的建议:
- 阅读Spring源码,理解内部实现机制
- 关注Spring新版本的特性更新
- 参与开源项目,贡献代码
- 在实际项目中应用所学知识
- 与社区保持交流,学习最佳实践
Spring生态系统在不断演进,保持学习的热情和实践的习惯,你将能够掌握这个强大的框架,并在Java开发领域取得更大的成就。祝你学习顺利!
