引言
Spring框架是Java企业级开发的事实标准,它提供了全面的基础设施支持,让开发者能够专注于业务逻辑而非底层技术细节。本指南将从基础概念讲起,逐步深入到高级特性,并通过实战案例展示Spring在实际项目中的应用,最后解析常见问题及解决方案。
第一部分:Spring基础概念
1.1 Spring框架概述
Spring是一个开源的Java平台,最初由Rod Johnson在2002年提出。它的核心理念是控制反转(IoC)和面向切面编程(AOP)。Spring框架的主要模块包括:
- Spring Core:提供IoC容器和依赖注入功能
- Spring AOP:提供面向切面编程支持
- Spring MVC:Web框架
- Spring Data:数据访问抽象
- Spring Security:安全框架
- Spring Boot:快速开发工具
1.2 控制反转(IoC)与依赖注入(DI)
控制反转是一种设计原则,它将对象的创建和管理权从应用程序代码转移到容器中。依赖注入是实现IoC的具体方式。
示例:传统方式 vs Spring方式
传统方式:
// 传统方式:手动创建和管理对象
public class UserService {
private UserRepository userRepository;
public UserService() {
this.userRepository = new UserRepositoryImpl(); // 紧耦合
}
public User getUser(Long id) {
return userRepository.findById(id);
}
}
Spring方式:
// Spring方式:通过容器管理依赖
@Component
public class UserService {
private final UserRepository userRepository;
// 构造器注入(推荐方式)
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User getUser(Long id) {
return userRepository.findById(id);
}
}
@Repository
public class UserRepositoryImpl implements UserRepository {
@Override
public User findById(Long id) {
// 数据库查询逻辑
return new User(id, "John Doe");
}
}
配置类示例:
@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
// Spring Boot会自动配置,这里展示传统配置方式
}
1.3 Spring Bean的作用域
Spring Bean有以下作用域:
- singleton(默认):每个容器中一个Bean实例
- prototype:每次请求都创建新实例
- request:每个HTTP请求一个实例(Web环境)
- session:每个HTTP会话一个实例(Web环境)
- global-session:全局HTTP会话(Portlet环境)
示例:
@Component
@Scope("prototype") // 每次获取都创建新实例
public class PrototypeBean {
private final String id = UUID.randomUUID().toString();
public String getId() {
return id;
}
}
第二部分:Spring Boot快速入门
2.1 Spring Boot简介
Spring Boot是Spring框架的扩展,它:
- 简化了Spring应用的配置
- 提供了嵌入式Web服务器
- 提供了生产级监控和管理功能
- 遵循”约定优于配置”原则
2.2 创建第一个Spring Boot应用
使用Spring Initializr创建项目
- 访问 start.spring.io
- 选择:
- Project: Maven
- Language: Java
- Spring Boot: 3.x
- Group: com.example
- Artifact: demo
- Dependencies: Spring Web
- 下载项目并导入IDE
主应用类:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
创建第一个REST控制器:
package com.example.demo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello, Spring Boot!";
}
@GetMapping("/hello/{name}")
public String helloWithName(@PathVariable String name) {
return "Hello, " + name + "!";
}
}
运行应用:
mvn spring-boot:run
# 或者
java -jar target/demo-0.0.1-SNAPSHOT.jar
2.3 Spring Boot配置
application.properties vs application.yml
application.properties:
server.port=8080
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=secret
spring.jpa.hibernate.ddl-auto=update
application.yml (推荐):
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: root
password: secret
jpa:
hibernate:
ddl-auto: update
多环境配置:
# application-dev.yml
spring:
profiles: dev
datasource:
url: jdbc:mysql://localhost:3306/mydb_dev
# application-prod.yml
spring:
profiles: prod
datasource:
url: jdbc:mysql://prod-db:3306/mydb_prod
第三部分:Spring核心特性深入
3.1 依赖注入详解
三种注入方式对比:
1. 构造器注入(推荐):
@Service
public class OrderService {
private final PaymentService paymentService;
private final NotificationService notificationService;
@Autowired
public OrderService(PaymentService paymentService,
NotificationService notificationService) {
this.paymentService = paymentService;
this.notificationService = notificationService;
}
}
2. Setter注入:
@Service
public class OrderService {
private PaymentService paymentService;
@Autowired
public void setPaymentService(PaymentService paymentService) {
this.paymentService = paymentService;
}
}
3. 字段注入(不推荐):
@Service
public class OrderService {
@Autowired
private PaymentService paymentService;
}
条件装配:
@Configuration
public class AppConfig {
@Bean
@ConditionalOnProperty(name = "app.feature.enabled", havingValue = "true")
public FeatureService featureService() {
return new FeatureService();
}
@Bean
@ConditionalOnMissingBean(DataSource.class)
public DataSource defaultDataSource() {
return new HikariDataSource();
}
}
3.2 AOP(面向切面编程)
AOP核心概念:
- 切面(Aspect):横切关注点的模块化
- 连接点(Join Point):程序执行过程中的某个点
- 通知(Advice):切面在特定连接点执行的动作
- 切点(Pointcut):匹配连接点的表达式
示例:日志切面
@Aspect
@Component
public class LoggingAspect {
private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
// 切点:所有Service方法
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceMethods() {}
// 前置通知
@Before("serviceMethods()")
public void logBefore(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
logger.info("Executing method: {}", methodName);
}
// 后置通知
@After("serviceMethods()")
public void logAfter(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
logger.info("Finished executing method: {}", methodName);
}
// 环绕通知
@Around("serviceMethods()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
try {
Object result = joinPoint.proceed();
long endTime = System.currentTimeMillis();
logger.info("Method {} executed in {} ms",
joinPoint.getSignature().getName(),
endTime - startTime);
return result;
} catch (Exception e) {
logger.error("Exception in method {}: {}",
joinPoint.getSignature().getName(),
e.getMessage());
throw e;
}
}
}
自定义注解实现AOP:
// 自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecutionTime {
}
// 切面
@Aspect
@Component
public class ExecutionTimeAspect {
@Around("@annotation(logExecutionTime)")
public Object logExecutionTime(ProceedingJoinPoint joinPoint,
LogExecutionTime logExecutionTime) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = joinPoint.proceed();
long endTime = System.currentTimeMillis();
System.out.println("Method " + joinPoint.getSignature().getName() +
" took " + (endTime - startTime) + " ms");
return result;
}
}
3.3 Spring事务管理
编程式事务:
@Service
public class TransactionalService {
@Autowired
private PlatformTransactionManager transactionManager;
public void performTransaction() {
TransactionStatus status = transactionManager.getTransaction(
new DefaultTransactionDefinition());
try {
// 业务逻辑
transactionManager.commit(status);
} catch (Exception e) {
transactionManager.rollback(status);
throw e;
}
}
}
声明式事务(推荐):
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private PaymentService paymentService;
@Transactional
public Order createOrder(Order order) {
// 保存订单
orderRepository.save(order);
// 处理支付
paymentService.processPayment(order);
return order;
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void logOrderCreation(Order order) {
// 独立事务,即使主事务回滚,日志也会保存
orderRepository.saveLog(order);
}
}
事务传播行为:
// REQUIRED - 如果当前存在事务,则加入;否则新建(默认)
@Transactional(propagation = Propagation.REQUIRED)
// REQUIRES_NEW - 总是新建事务,挂起当前事务
@Transactional(propagation = Propagation.REQUIRES_NEW)
// NESTED - 如果当前存在事务,则在嵌套事务中执行
@Transactional(propagation = Propagation.NESTED)
// SUPPORTS - 如果当前存在事务,则加入;否则以非事务方式执行
@Transactional(propagation = Propagation.SUPPORTS)
// NOT_SUPPORTED - 以非事务方式执行,挂起当前事务
@Transactional(propagation = Propagation.NOT_SUPPORTED)
// MANDATORY - 必须在事务中执行,否则抛出异常
@Transactional(propagation = Propagation.MANDATORY)
// NEVER - 必须在非事务中执行,否则抛出异常
@Transactional(propagation = Propagation.NEVER)
第四部分:Spring Data JPA实战
4.1 JPA基础
实体类定义:
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "username", nullable = false, unique = true)
private String username;
@Column(name = "email")
private String email;
@Column(name = "created_at")
private LocalDateTime createdAt;
// 关联关系
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<Order> orders = new ArrayList<>();
// 构造函数、getter/setter...
}
Repository接口:
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// 方法名查询
User findByUsername(String username);
// 使用@Query注解
@Query("SELECT u FROM User u WHERE u.email = :email")
User findByEmail(@Param("email") String email);
// 原生SQL查询
@Query(value = "SELECT * FROM users WHERE username = :username",
nativeQuery = true)
User findByUsernameNative(@Param("username") String username);
// 分页查询
Page<User> findByUsernameContaining(String username, Pageable pageable);
// 自定义查询
@Query("SELECT new com.example.dto.UserDTO(u.id, u.username) " +
"FROM User u WHERE u.createdAt > :date")
List<UserDTO> findUsersCreatedAfter(@Param("date") LocalDateTime date);
}
4.2 高级查询技巧
动态查询(QueryDSL集成):
// 1. 添加依赖
// pom.xml
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
<version>5.0.0</version>
</dependency>
// 2. 创建QueryDSL实体
@Entity
@QueryEntity
public class User {
// ... 实体定义
}
// 3. 创建Repository
public interface UserRepository extends JpaRepository<User, Long>,
QuerydslPredicateExecutor<User> {
}
// 4. 使用示例
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public List<User> searchUsers(String username, String email,
LocalDateTime startDate) {
QUser user = QUser.user;
BooleanExpression predicate = user.id.isNotNull();
if (username != null && !username.isEmpty()) {
predicate = predicate.and(user.username.contains(username));
}
if (email != null && !email.isEmpty()) {
predicate = predicate.and(user.email.eq(email));
}
if (startDate != null) {
predicate = predicate.and(user.createdAt.after(startDate));
}
return (List<User>) userRepository.findAll(predicate);
}
}
多表关联查询:
// 1. 实体关联
@Entity
public class Order {
@Id
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
@OneToMany(mappedBy = "order")
private List<OrderItem> items = new ArrayList<>();
}
@Entity
public class OrderItem {
@Id
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "order_id")
private Order order;
private String productName;
private Integer quantity;
}
// 2. 自定义查询
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
@Query("SELECT o FROM Order o " +
"JOIN FETCH o.user u " +
"JOIN FETCH o.items i " +
"WHERE o.id = :id")
Order findOrderWithDetails(@Param("id") Long id);
// 使用DTO投影
@Query("SELECT new com.example.dto.OrderSummaryDTO(" +
"o.id, u.username, COUNT(i.id), SUM(i.quantity * i.price)) " +
"FROM Order o " +
"JOIN o.user u " +
"JOIN o.items i " +
"GROUP BY o.id, u.username")
List<OrderSummaryDTO> getOrdersSummary();
}
4.3 Spring Data JPA性能优化
1. N+1查询问题及解决方案
问题代码:
// 会导致N+1查询问题
List<Order> orders = orderRepository.findAll();
for (Order order : orders) {
// 每次访问都会触发新的查询
System.out.println(order.getUser().getUsername());
}
解决方案1:使用JOIN FETCH
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
@Query("SELECT o FROM Order o JOIN FETCH o.user WHERE o.status = :status")
List<Order> findOrdersWithUserByStatus(@Param("status") String status);
}
解决方案2:使用EntityGraph
@EntityGraph(attributePaths = {"user", "items"})
List<Order> findByStatus(String status);
2. 批量操作优化
@Service
public class BatchService {
@Autowired
private UserRepository userRepository;
@Transactional
public void batchInsert(List<User> users) {
// Spring Data JPA默认会批量插入
userRepository.saveAll(users);
}
@Transactional
public void batchUpdate(List<User> users) {
// 批量更新需要特殊处理
int batchSize = 50;
for (int i = 0; i < users.size(); i += batchSize) {
int end = Math.min(i + batchSize, users.size());
List<User> batch = users.subList(i, end);
userRepository.saveAll(batch);
}
}
}
第五部分:Spring Security实战
5.1 基础配置
1. 添加依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2. 基础配置类:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable() // 根据需要启用或禁用
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/api/**").authenticated()
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.defaultSuccessUrl("/dashboard")
.permitAll()
)
.logout(logout -> logout
.logoutUrl("/logout")
.logoutSuccessUrl("/login?logout")
.permitAll()
);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
5.2 自定义用户认证
1. 用户实体:
@Entity
@Table(name = "users")
public class User implements UserDetails {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true, nullable = false)
private String username;
@Column(nullable = false)
private String password;
@Column
private String email;
@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "user_roles", joinColumns = @JoinColumn(name = "user_id"))
@Column(name = "role")
private Set<String> roles = new HashSet<>();
// UserDetails方法
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return roles.stream()
.map(role -> new SimpleGrantedAuthority("ROLE_" + role))
.collect(Collectors.toList());
}
@Override
public boolean isAccountNonExpired() { return true; }
@Override
public boolean isAccountNonLocked() { return true; }
@Override
public boolean isCredentialsNonExpired() { return true; }
@Override
public boolean isEnabled() { return true; }
}
2. 自定义UserDetailsService:
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found: " + username));
return user;
}
}
5.3 JWT认证实现
1. JWT工具类:
@Component
public class JwtUtil {
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private Long expiration;
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
claims.put("roles", userDetails.getAuthorities());
return Jwts.builder()
.setClaims(claims)
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + expiration))
.signWith(SignatureAlgorithm.HS256, secret)
.compact();
}
public Boolean validateToken(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
public String extractUsername(String token) {
return getClaims(token).getSubject();
}
private Claims getClaims(String token) {
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
}
private Boolean isTokenExpired(String token) {
return getClaims(token).getExpiration().before(new Date());
}
}
2. JWT认证过滤器:
@Component
public class JwtRequestFilter extends OncePerRequestFilter {
@Autowired
private JwtUtil jwtUtil;
@Autowired
private CustomUserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
final String authorizationHeader = request.getHeader("Authorization");
String username = null;
String jwt = null;
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
jwt = authorizationHeader.substring(7);
username = jwtUtil.extractUsername(jwt);
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (jwtUtil.validateToken(jwt, userDetails)) {
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
filterChain.doFilter(request, response);
}
}
3. 配置JWT过滤器:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private JwtRequestFilter jwtRequestFilter;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated()
)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
);
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
第六部分:Spring Boot高级特性
6.1 Spring Boot Actuator
1. 添加依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2. 配置application.yml:
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: always
metrics:
export:
prometheus:
enabled: true
3. 自定义健康检查:
@Component
public class CustomHealthIndicator implements HealthIndicator {
@Autowired
private DataSource dataSource;
@Override
public Health health() {
try (Connection connection = dataSource.getConnection()) {
if (connection.isValid(2)) {
return Health.up()
.withDetail("database", "connected")
.withDetail("timestamp", System.currentTimeMillis())
.build();
}
} catch (Exception e) {
return Health.down()
.withDetail("error", e.getMessage())
.build();
}
return Health.down().build();
}
}
6.2 Spring Boot缓存
1. 添加依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2. 启用缓存:
@SpringBootApplication
@EnableCaching
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
3. 缓存配置:
@Configuration
public class CacheConfig {
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(10))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.build();
}
}
4. 使用缓存:
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Cacheable(value = "users", key = "#id")
public User getUserById(Long id) {
// 这个方法只有在缓存中没有对应key时才会执行
System.out.println("Fetching user from database...");
return userRepository.findById(id).orElse(null);
}
@CacheEvict(value = "users", key = "#id")
public void updateUser(Long id, User user) {
// 更新用户,同时清除缓存
userRepository.save(user);
}
@CachePut(value = "users", key = "#user.id")
public User updateUserAndCache(User user) {
// 更新用户,同时更新缓存
return userRepository.save(user);
}
@Cacheable(value = "users", key = "#username", unless = "#result == null")
public User getUserByUsername(String username) {
return userRepository.findByUsername(username).orElse(null);
}
}
6.3 Spring Boot异步处理
1. 启用异步支持:
@SpringBootApplication
@EnableAsync
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
2. 配置线程池:
@Configuration
public class AsyncConfig {
@Bean(name = "taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("Async-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
executor.initialize();
return executor;
}
}
3. 异步方法:
@Service
public class EmailService {
@Async("taskExecutor")
public CompletableFuture<Void> sendEmail(String to, String subject, String content) {
try {
// 模拟发送邮件耗时操作
Thread.sleep(2000);
System.out.println("Email sent to: " + to);
return CompletableFuture.completedFuture(null);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return CompletableFuture.failedFuture(e);
}
}
@Async
public CompletableFuture<List<String>> processBatch(List<String> items) {
// 并行处理
return CompletableFuture.supplyAsync(() -> {
return items.parallelStream()
.map(item -> processItem(item))
.collect(Collectors.toList());
});
}
private String processItem(String item) {
// 处理逻辑
return "Processed: " + item;
}
}
4. 异步调用示例:
@RestController
public class EmailController {
@Autowired
private EmailService emailService;
@PostMapping("/send-email")
public ResponseEntity<String> sendEmail(@RequestBody EmailRequest request) {
// 异步发送邮件,立即返回
CompletableFuture<Void> future = emailService.sendEmail(
request.getTo(),
request.getSubject(),
request.getContent()
);
// 可以添加回调
future.thenRun(() -> {
System.out.println("Email sent successfully");
}).exceptionally(ex -> {
System.err.println("Failed to send email: " + ex.getMessage());
return null;
});
return ResponseEntity.accepted().body("Email will be sent asynchronously");
}
}
第七部分:Spring Cloud微服务实战
7.1 Spring Cloud基础
1. 服务注册与发现(Eureka)
Eureka Server:
// 1. 添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
// 2. 启动类
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
// 3. 配置
server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false
server:
enable-self-preservation: false
Eureka Client:
// 1. 添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
// 2. 启动类
@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
// 3. 配置
server:
port: 8081
spring:
application:
name: user-service
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
2. 服务调用(Feign)
// 1. 添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
// 2. 启用Feign
@SpringBootApplication
@EnableFeignClients
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
// 3. Feign客户端接口
@FeignClient(name = "user-service", fallback = UserFeignClientFallback.class)
public interface UserFeignClient {
@GetMapping("/users/{id}")
User getUserById(@PathVariable("id") Long id);
@PostMapping("/users")
User createUser(@RequestBody User user);
}
// 4. 降级处理
@Component
public class UserFeignClientFallback implements UserFeignClient {
@Override
public User getUserById(Long id) {
// 返回默认用户或缓存数据
return new User(id, "Default User");
}
@Override
public User createUser(User user) {
throw new RuntimeException("User service is unavailable");
}
}
7.2 Spring Cloud Gateway
1. 添加依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
2. 配置路由:
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- StripPrefix=1
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
key-resolver: "#{@userKeyResolver}"
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/orders/**
filters:
- StripPrefix=1
- name: Hystrix
args:
name: fallbackcmd
fallbackUri: forward:/fallback
- id: auth-service
uri: lb://auth-service
predicates:
- Path=/api/auth/**
filters:
- StripPrefix=1
- JwtAuthenticationFilter
3. 自定义过滤器:
@Component
public class JwtAuthenticationFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
// 验证JWT逻辑
String jwt = token.substring(7);
if (!validateToken(jwt)) {
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -1; // 在其他过滤器之前执行
}
}
第八部分:常见问题解析
8.1 依赖注入相关问题
问题1:循环依赖
现象: Bean A依赖Bean B,Bean B又依赖Bean A
解决方案:
- 重构代码:引入第三方组件或使用事件驱动
- 使用@Lazy延迟注入
@Service
public class ServiceA {
@Autowired
@Lazy
private ServiceB serviceB;
}
@Service
public class ServiceB {
@Autowired
private ServiceA serviceA;
}
- 使用Setter注入代替构造器注入
问题2:Bean创建失败
常见原因:
- 缺少依赖:检查pom.xml中是否包含所需依赖
- 配置错误:检查application.yml中的配置项
- Bean名称冲突:使用@Qualifier指定Bean名称
示例:
@Configuration
public class AppConfig {
@Bean
public DataSource dataSource1() {
return new HikariDataSource();
}
@Bean
public DataSource dataSource2() {
return new HikariDataSource();
}
}
@Service
public class UserService {
@Autowired
@Qualifier("dataSource1")
private DataSource dataSource;
}
8.2 事务管理问题
问题1:事务不生效
常见原因:
- 方法不是public
- 自调用问题:在同一个类中调用另一个事务方法
- 异常类型不匹配:默认只回滚RuntimeException
解决方案:
@Service
public class OrderService {
@Transactional(rollbackFor = Exception.class)
public void processOrder() {
// 业务逻辑
}
// 自调用问题解决方案
@Autowired
private OrderService self; // 注入自己
public void methodA() {
self.methodB(); // 通过代理调用
}
@Transactional
public void methodB() {
// 事务方法
}
}
问题2:事务传播行为错误
示例:
@Service
public class OrderService {
@Transactional
public void outerMethod() {
// 外层事务
innerMethod(); // 调用内部方法
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void innerMethod() {
// 独立事务
}
}
8.3 性能问题
问题1:N+1查询问题
解决方案:
- 使用JOIN FETCH
- 使用@EntityGraph
- 使用DTO投影
- 批量查询
// 批量查询示例
@Service
public class BatchService {
@Autowired
private UserRepository userRepository;
public List<User> getUsersByIds(List<Long> ids) {
// 分批查询,避免一次查询过多数据
List<User> result = new ArrayList<>();
int batchSize = 100;
for (int i = 0; i < ids.size(); i += batchSize) {
int end = Math.min(i + batchSize, ids.size());
List<Long> batchIds = ids.subList(i, end);
result.addAll(userRepository.findAllById(batchIds));
}
return result;
}
}
问题2:内存泄漏
常见原因:
- 缓存未清理
- 静态集合未清理
- 数据库连接未关闭
解决方案:
// 使用WeakHashMap避免内存泄漏
@Component
public class CacheManager {
private Map<String, Object> cache = new WeakHashMap<>();
public void put(String key, Object value) {
cache.put(key, value);
}
public Object get(String key) {
return cache.get(key);
}
}
8.4 配置相关问题
问题1:配置不生效
排查步骤:
- 检查配置文件名称是否正确(application.yml或application.properties)
- 检查配置文件位置是否正确(src/main/resources)
- 检查配置项是否正确(注意大小写和缩进)
- 检查是否有多环境配置覆盖
示例:
# application.yml
spring:
profiles:
active: dev
# application-dev.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb_dev
问题2:配置注入失败
解决方案:
@Component
public class ConfigProperties {
@Value("${app.name}")
private String appName;
@Value("${app.version}")
private String appVersion;
// 使用@ConfigurationProperties
@ConfigurationProperties(prefix = "app")
@Component
public static class AppProperties {
private String name;
private String version;
private List<String> features = new ArrayList<>();
// getter/setter
}
}
8.5 Spring Boot启动问题
问题1:启动失败
常见错误:
- 端口冲突
server:
port: 8080 # 修改为其他端口
- 依赖冲突
# 查看依赖树
mvn dependency:tree
- 数据库连接失败
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: root
password: secret
hikari:
connection-timeout: 30000
maximum-pool-size: 10
问题2:启动速度慢
优化方案:
- 排除不必要的自动配置
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
SecurityAutoConfiguration.class
})
- 使用懒加载
spring:
main:
lazy-initialization: true
- 减少类路径扫描
@SpringBootApplication
@ComponentScan(excludeFilters = {
@ComponentScan.Filter(type = FilterType.REGEX, pattern = "com\\.example\\.test.*")
})
第九部分:最佳实践与性能优化
9.1 代码组织最佳实践
1. 分层架构:
src/main/java/com/example/
├── config/ # 配置类
├── controller/ # 控制器层
├── service/ # 业务逻辑层
├── repository/ # 数据访问层
├── entity/ # 实体类
├── dto/ # 数据传输对象
├── exception/ # 自定义异常
├── util/ # 工具类
└── aspect/ # 切面类
2. 命名规范:
- 实体类:使用名词,如User, Order
- Repository:使用名词+Repository,如UserRepository
- Service:使用名词+Service,如UserService
- Controller:使用名词+Controller,如UserController
- DTO:使用名词+DTO,如UserDTO
9.2 性能优化技巧
1. 数据库优化:
// 1. 使用索引
@Entity
@Table(indexes = {
@Index(name = "idx_username", columnList = "username"),
@Index(name = "idx_email", columnList = "email")
})
public class User {
// ...
}
// 2. 使用批量操作
@Service
public class BatchService {
@Transactional
public void batchInsert(List<User> users) {
int batchSize = 50;
for (int i = 0; i < users.size(); i += batchSize) {
int end = Math.min(i + batchSize, users.size());
List<User> batch = users.subList(i, end);
userRepository.saveAll(batch);
}
}
}
2. 缓存策略:
@Service
public class CacheService {
@Cacheable(value = "users", key = "#id",
unless = "#result == null",
cacheManager = "redisCacheManager")
public User getUser(Long id) {
// 数据库查询
return userRepository.findById(id).orElse(null);
}
@CacheEvict(value = "users", key = "#id",
cacheManager = "redisCacheManager")
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
}
3. 异步处理:
@Service
public class AsyncService {
@Async
public CompletableFuture<Void> processAsync(Runnable task) {
return CompletableFuture.runAsync(task);
}
@Async
public <T> CompletableFuture<List<T>> processBatchAsync(List<T> items,
Function<T, T> processor) {
return CompletableFuture.supplyAsync(() -> {
return items.parallelStream()
.map(processor)
.collect(Collectors.toList());
});
}
}
9.3 测试策略
1. 单元测试:
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
void shouldReturnUserWhenExists() {
// Given
User user = new User(1L, "john");
when(userRepository.findById(1L)).thenReturn(Optional.of(user));
// When
User result = userService.getUserById(1L);
// Then
assertThat(result).isNotNull();
assertThat(result.getUsername()).isEqualTo("john");
verify(userRepository, times(1)).findById(1L);
}
}
2. 集成测试:
@SpringBootTest
@AutoConfigureMockMvc
class UserControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Test
void shouldGetUserById() throws Exception {
mockMvc.perform(get("/users/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(1))
.andExpect(jsonPath("$.username").value("john"));
}
}
3. 测试配置:
@TestConfiguration
public class TestConfig {
@Bean
public DataSource testDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("classpath:schema.sql")
.addScript("classpath:test-data.sql")
.build();
}
}
第十部分:Spring 6和Spring Boot 3新特性
10.1 Java 17+要求
Spring Boot 3要求:
- Java 17+(最低要求)
- Jakarta EE 9+(包名从javax.改为jakarta.)
迁移示例:
// Spring Boot 2.x (javax.*)
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.servlet.http.HttpServletRequest;
// Spring Boot 3.x (jakarta.*)
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.servlet.http.HttpServletRequest;
10.2 新特性
1. 虚拟线程(Project Loom)支持:
// 启用虚拟线程
spring:
threads:
virtual:
enabled: true
// 自定义线程池使用虚拟线程
@Bean
public ExecutorService virtualThreadExecutor() {
return Executors.newVirtualThreadPerTaskExecutor();
}
2. 响应式编程增强:
@RestController
public class ReactiveController {
@GetMapping("/flux")
public Flux<String> getFlux() {
return Flux.just("A", "B", "C")
.delayElements(Duration.ofMillis(100));
}
@GetMapping("/mono")
public Mono<String> getMono() {
return Mono.just("Hello")
.delayElement(Duration.ofMillis(100));
}
}
3. GraalVM原生镜像支持:
<!-- 添加原生镜像支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-graalvm-native</artifactId>
</dependency>
4. 改进的AOT处理:
// 使用AOT处理优化启动时间
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
结语
Spring框架是一个功能强大且不断发展的生态系统。从基础的IoC容器到复杂的微服务架构,Spring提供了全面的解决方案。通过本指南的学习,你应该能够:
- 理解Spring核心概念:IoC、DI、AOP
- 掌握Spring Boot快速开发:配置、自动配置、启动器
- 深入Spring Data JPA:实体映射、查询优化、性能调优
- 实现Spring Security:认证、授权、JWT
- 构建微服务架构:服务注册、发现、网关
- 解决常见问题:依赖注入、事务、性能问题
- 遵循最佳实践:代码组织、性能优化、测试策略
记住,Spring的学习是一个持续的过程。建议:
- 定期阅读官方文档
- 参与开源项目
- 关注Spring社区动态
- 在实际项目中不断实践
祝你在Spring开发之旅中取得成功!
