1. Spring Boot 应用开发概述
Spring Boot 是 Java 生态中革命性的开发框架,它彻底改变了传统 Spring 应用的开发方式。作为一名使用 Spring Boot 多年的开发者,我见证了这个框架如何将原本需要数天才能完成的环境搭建缩短到几分钟。Spring Boot 的核心价值在于"约定优于配置"的理念,它通过智能的默认配置和自动装配机制,让开发者能够专注于业务逻辑而非基础设施。
在实际项目中,Spring Boot 特别适合以下场景:
- 快速构建微服务架构
- 开发企业级后台管理系统
- 创建 RESTful API 服务
- 传统单体应用的现代化改造
它的优势不仅体现在开发效率上,更在于其完善的生态系统。从数据访问到安全认证,从消息队列到分布式配置,Spring Boot 都提供了开箱即用的解决方案。这也是为什么它能在短短几年内成为 Java 后端开发的事实标准。
2. Spring Boot 核心机制解析
2.1 自动配置原理深度剖析
Spring Boot 的自动配置(Auto-configuration)是其最精妙的设计之一。这个机制基于条件化装配(@Conditional)实现,框架会检测 classpath 中的依赖、已存在的 Bean 以及配置文件等条件,自动配置相应的组件。
举个例子,当你的项目中存在 spring-boot-starter-data-jpa 依赖时,Spring Boot 会自动:
- 配置 Hibernate 作为 JPA 实现
- 设置基本的事务管理器
- 创建 EntityManagerFactory
- 启用 Spring Data JPA 的仓库支持
这种智能的自动配置大幅减少了样板代码。在我的项目经验中,一个典型的数据访问层配置从原来的 50+ 行 XML 缩减到只需几行 application.properties 配置。
2.2 起步依赖的工程实践
起步依赖(Starter)是 Spring Boot 的另一个杀手锏。这些预定义的依赖组合解决了传统 Java 项目中令人头疼的依赖冲突问题。例如:
- spring-boot-starter-web:包含 Web 开发所需的全部依赖(Tomcat + Spring MVC + Jackson)
- spring-boot-starter-data-redis:整合 Redis 客户端和连接池
- spring-boot-starter-actuator:提供应用监控端点
在实际开发中,我建议:
- 优先使用官方提供的 starter
- 检查 starter 包含的具体依赖(可通过 ./mvnw dependency:tree)
- 自定义 starter 用于公司内部通用组件封装
2.3 Actuator 的生产级监控
Actuator 是 Spring Boot 为生产环境准备的监控利器。它通过 HTTP 或 JMX 暴露了一系列端点:
| 端点路径 | 作用描述 | 生产环境建议 |
|---|---|---|
| /health | 应用健康状态 | 建议开放 |
| /metrics | 应用指标数据 | 按需开放 |
| /loggers | 查看和修改日志级别 | 限制访问 |
| /threaddump | 线程转储信息 | 限制访问 |
| /heapdump | 堆内存转储(需谨慎) | 禁止开放 |
在最近的一个电商项目中,我们通过自定义 HealthIndicator 实现了对第三方支付接口的健康检查,这对系统稳定性监控起到了关键作用。
3. Spring Boot 开发环境搭建
3.1 JDK 选型与配置建议
虽然 Spring Boot 支持 Java 8 及以上版本,但根据我的实践经验:
- 新项目建议直接使用 Java 17(当前 LTS 版本)
- 使用 Adoptium Temurin JDK(原 AdoptOpenJDK)获得更好的支持
- 在 ~/.bashrc 或系统环境变量中设置:
bash复制export JAVA_HOME=/path/to/jdk
export PATH=$JAVA_HOME/bin:$PATH
验证安装:
bash复制java -version
javac -version
3.2 IDE 的选择与优化
IntelliJ IDEA 无疑是 Spring Boot 开发的最佳选择。几个提高效率的技巧:
-
安装以下插件:
- Spring Boot Assistant
- Lombok Plugin
- SonarLint
-
配置 Live Templates 快速生成常用代码:
restc→ 生成 @RestController 类模板getm→ 生成 @GetMapping 方法
-
开启 Annotation Processors:
- File → Settings → Build → Compiler → Annotation Processors
3.3 项目初始化实战
使用 Spring Initializr (https://start.spring.io) 创建项目时,我的常用配置组合:
- 打包方式:Jar(微服务首选)或 War(传统部署)
- 依赖选择:
- Spring Web
- Spring Data JPA
- Lombok(减少样板代码)
- Validation(参数校验)
- Spring Security(按需)
创建后的项目结构解析:
code复制src/
├── main/
│ ├── java/
│ │ └── com/example/
│ │ └── DemoApplication.java # 启动类
│ └── resources/
│ ├── static/ # 静态资源
│ ├── templates/ # 模板文件
│ └── application.properties # 配置文件
└── test/ # 测试代码
4. Spring Boot 基础开发实践
4.1 RESTful API 开发规范
现代 Web 开发中,RESTful API 设计尤为重要。以下是一个符合行业标准的控制器实现:
java复制@RestController
@RequestMapping("/api/v1/products")
@RequiredArgsConstructor // Lombok 注解,自动注入final字段
public class ProductController {
private final ProductService productService;
@GetMapping
public ResponseEntity<Page<ProductDTO>> getAllProducts(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
return ResponseEntity.ok(productService.findAll(page, size));
}
@GetMapping("/{id}")
public ResponseEntity<ProductDTO> getProductById(@PathVariable Long id) {
return productService.findById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@PostMapping
public ResponseEntity<ProductDTO> createProduct(
@Valid @RequestBody ProductDTO productDTO) {
ProductDTO savedProduct = productService.save(productDTO);
URI location = ServletUriComponentsBuilder.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(savedProduct.getId())
.toUri();
return ResponseEntity.created(location).body(savedProduct);
}
}
关键实践:
- 使用 @Valid 进行参数校验
- 返回 ResponseEntity 提供精确的 HTTP 状态
- 遵循 REST 资源命名规范
- 实现 HATEOAS 支持(可选)
4.2 数据持久化最佳实践
Spring Data JPA 极大简化了数据库操作,但要注意以下要点:
- 实体类设计规范:
java复制@Entity
@Table(name = "orders")
@Getter @Setter @NoArgsConstructor // Lombok 注解
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 100)
private String orderNumber;
@Enumerated(EnumType.STRING)
private OrderStatus status;
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
private List<OrderItem> items = new ArrayList<>();
@CreatedDate
private LocalDateTime createdAt;
}
- 仓库接口的增强用法:
java复制public interface OrderRepository extends JpaRepository<Order, Long> {
// 方法名查询
List<Order> findByStatus(OrderStatus status);
// @Query 注解自定义查询
@Query("SELECT o FROM Order o WHERE o.createdAt BETWEEN :start AND :end")
List<Order> findOrdersBetweenDates(
@Param("start") LocalDateTime start,
@Param("end") LocalDateTime end);
// 动态查询
interface OrderSpecs {
static Specification<Order> hasStatus(OrderStatus status) {
return (root, query, cb) ->
status == null ? null : cb.equal(root.get("status"), status);
}
}
}
- 事务管理建议:
- 在服务层使用 @Transactional
- 只读操作添加 @Transactional(readOnly = true)
- 注意事务传播行为的选择
4.3 模板引擎整合技巧
虽然前后端分离是主流,但某些场景仍需服务端渲染:
- Thymeleaf 基础配置:
properties复制# application.properties
spring.thymeleaf.cache=false # 开发时关闭缓存
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
- 高级布局管理:
html复制<!-- templates/layout.html -->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title th:text="${title}">Default Title</title>
<th:block th:replace="~{fragments/head :: commonHead}"></th:block>
</head>
<body>
<div th:replace="~{fragments/header :: mainHeader}"></div>
<div class="container">
<th:block th:replace="${content}"></th:block>
</div>
<div th:replace="~{fragments/footer :: mainFooter}"></div>
</body>
</html>
<!-- templates/home.html -->
<html th:replace="~{layout :: layout(~{::title}, ~{::section})}">
<head>
<title>Home Page</title>
</head>
<body>
<section>
<h1>Welcome!</h1>
<!-- 页面具体内容 -->
</section>
</body>
</html>
- 与静态资源配合:
- CSS/JS 放在 src/main/resources/static/
- 使用 thymeleaf 的 @{} 语法引用资源:
html复制<link th:href="@{/css/main.css}" rel="stylesheet">
5. Spring Boot 高级特性
5.1 配置系统深度解析
Spring Boot 的配置系统非常灵活,以下是一些高级用法:
- 类型安全的配置绑定:
java复制@ConfigurationProperties(prefix = "app")
@Getter @Setter
public class AppProperties {
private String name;
private String version;
private Security security = new Security();
@Getter @Setter
public static class Security {
private String secretKey;
private long tokenValidity;
}
}
// application.yml
app:
name: My Application
version: 1.0.0
security:
secretKey: "changeme"
tokenValidity: 86400
- Profile 的多环境管理:
bash复制# 启动时指定profile
java -jar app.jar --spring.profiles.active=prod
- 配置加密(使用 Jasypt):
properties复制# 加密配置
jasypt.encryptor.password=${JASYPT_PASSWORD} # 从环境变量获取
# 加密后的值用ENC()包裹
spring.datasource.password=ENC(密文)
5.2 缓存机制优化实践
缓存是提升性能的利器,但使用不当会导致数据不一致:
- 缓存配置示例(Redis):
java复制@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(30))
.disableCachingNullValues()
.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer()));
return RedisCacheManager.builder(factory)
.cacheDefaults(config)
.transactionAware()
.build();
}
}
- 缓存注解的最佳实践:
java复制@Service
public class ProductService {
@Cacheable(value = "products", key = "#id", unless = "#result == null")
public Product getProduct(Long id) {
// 数据库查询
}
@CachePut(value = "products", key = "#product.id")
public Product updateProduct(Product product) {
// 更新数据库
return productRepository.save(product);
}
@CacheEvict(value = "products", key = "#id")
public void deleteProduct(Long id) {
productRepository.deleteById(id);
}
@Caching(evict = {
@CacheEvict(value = "products", key = "#id"),
@CacheEvict(value = "product-stats", allEntries = true)
})
public void resetProductCache(Long id) {
// 清除多个相关缓存
}
}
- 缓存雪崩防护:
- 为不同的缓存设置不同的TTL
- 使用 @Cacheable 的 sync 属性(本地锁)
- 实现缓存降级策略
5.3 异步处理与事件机制
Spring 的事件机制非常适合解耦业务逻辑:
- 自定义应用事件:
java复制public class OrderCreatedEvent extends ApplicationEvent {
private final Order order;
public OrderCreatedEvent(Object source, Order order) {
super(source);
this.order = order;
}
public Order getOrder() {
return order;
}
}
- 事件发布与监听:
java复制@Service
@RequiredArgsConstructor
public class OrderService {
private final ApplicationEventPublisher eventPublisher;
public Order createOrder(Order order) {
// 保存订单
Order savedOrder = orderRepository.save(order);
// 发布事件
eventPublisher.publishEvent(new OrderCreatedEvent(this, savedOrder));
return savedOrder;
}
}
@Component
public class OrderEventListener {
@Async // 异步处理
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) {
// 发送通知、更新库存等后续处理
}
}
- 异步配置:
java复制@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("Async-");
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
}
6. Spring Boot 安全实践
6.1 Spring Security 核心配置
现代安全配置应基于组件而非继承:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.ignoringAntMatchers("/api/**")) // API禁用CSRF
.authorizeRequests(auth -> auth
.antMatchers("/public/**").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.defaultSuccessUrl("/dashboard")
.permitAll()
)
.logout(logout -> logout
.logoutSuccessUrl("/login?logout")
.permitAll()
)
.rememberMe(remember -> remember
.tokenValiditySeconds(86400)
.key("uniqueAndSecret")
);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
6.2 JWT 认证实现
REST API 通常采用 JWT 认证:
- JWT 工具类:
java复制@Component
public class JwtTokenProvider {
@Value("${app.jwt.secret}")
private String jwtSecret;
@Value("${app.jwt.expiration}")
private int jwtExpiration;
public String generateToken(Authentication authentication) {
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
Date now = new Date();
Date expiryDate = new Date(now.getTime() + jwtExpiration);
return Jwts.builder()
.setSubject(userDetails.getUsername())
.setIssuedAt(now)
.setExpiration(expiryDate)
.signWith(SignatureAlgorithm.HS512, jwtSecret)
.compact();
}
public String getUsernameFromToken(String token) {
return Jwts.parser()
.setSigningKey(jwtSecret)
.parseClaimsJws(token)
.getBody()
.getSubject();
}
public boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token);
return true;
} catch (Exception ex) {
// 处理各种异常情况
}
return false;
}
}
- JWT 认证过滤器:
java复制public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtTokenProvider tokenProvider;
private final UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String jwt = getJwtFromRequest(request);
if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) {
String username = tokenProvider.getUsernameFromToken(jwt);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
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;
}
}
6.3 方法级安全控制
细粒度的权限控制:
java复制@PreAuthorize("hasRole('ADMIN') or #userId == authentication.principal.id")
@GetMapping("/users/{userId}/profile")
public UserProfile getUserProfile(@PathVariable Long userId) {
// 只有管理员或用户本人能访问
}
@PostAuthorize("returnObject.owner == authentication.principal.username")
@GetMapping("/documents/{id}")
public Document getDocument(@PathVariable Long id) {
// 返回后检查权限
}
@Secured({"ROLE_ADMIN", "ROLE_SUPERVISOR"})
@DeleteMapping("/products/{id}")
public void deleteProduct(@PathVariable Long id) {
// 需要特定角色
}
7. Spring Boot 生产准备
7.1 健康检查与指标监控
完善的监控是生产环境的必备:
- 自定义健康检查:
java复制@Component
public class ThirdPartyServiceHealthIndicator implements HealthIndicator {
private final ThirdPartyServiceClient client;
@Override
public Health health() {
try {
boolean isHealthy = client.checkHealth();
if (isHealthy) {
return Health.up().withDetail("responseTime", client.getLastResponseTime()).build();
} else {
return Health.down().withDetail("error", "Service unavailable").build();
}
} catch (Exception e) {
return Health.down(e).build();
}
}
}
- 自定义业务指标:
java复制@Service
public class OrderService {
private final Counter orderCounter;
private final Timer orderProcessingTimer;
public OrderService(MeterRegistry registry) {
this.orderCounter = registry.counter("orders.count");
this.orderProcessingTimer = registry.timer("orders.processing.time");
}
public Order createOrder(Order order) {
return orderProcessingTimer.record(() -> {
// 处理订单逻辑
orderCounter.increment();
return orderRepository.save(order);
});
}
}
7.2 日志配置最佳实践
生产环境日志配置建议:
yaml复制logging:
level:
root: INFO
org.springframework.web: DEBUG
com.myapp: DEBUG
file:
name: logs/app.log
max-size: 50MB
max-history: 30
pattern:
file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
console: "%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID}){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n%wEx"
使用 MDC 实现请求追踪:
java复制@Slf4j
@Component
public class RequestLoggingFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
MDC.put("requestId", UUID.randomUUID().toString());
MDC.put("clientIp", request.getRemoteAddr());
long startTime = System.currentTimeMillis();
try {
filterChain.doFilter(request, response);
} finally {
long duration = System.currentTimeMillis() - startTime;
log.info("{} {} - {}ms",
request.getMethod(),
request.getRequestURI(),
duration);
MDC.clear();
}
}
}
7.3 性能调优实战经验
经过多个生产项目验证的优化建议:
- JVM 参数调优:
bash复制java -jar app.jar \
-Xms512m -Xmx1024m \ # 根据实际内存调整
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-XX:InitiatingHeapOccupancyPercent=35
- Tomcat 优化(application.yml):
yaml复制server:
tomcat:
max-threads: 200
min-spare-threads: 10
accept-count: 100
connection-timeout: 5000
max-connections: 10000
- 数据库连接池配置(HikariCP):
properties复制spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.idle-timeout=30000
spring.datasource.hikari.max-lifetime=1800000
spring.datasource.hikari.connection-timeout=5000
- 其他实用配置:
properties复制# 关闭不需要的自动配置
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
# 禁用JMX(如不需要)
spring.jmx.enabled=false
# 关闭Actuator端点(根据实际需要)
management.endpoints.enabled-by-default=false
management.endpoint.health.enabled=true
8. 常见问题排查指南
8.1 启动类无法扫描组件
典型症状:
- @Service/@Repository 注解的类未被识别
- 出现"No qualifying bean"错误
解决方案:
- 确保启动类位于根包(其他组件在其子包中)
- 检查是否缺少 @ComponentScan
- 确认没有使用错误的注解(如 @Configuration 代替 @SpringBootApplication)
8.2 自动配置不生效
排查步骤:
- 检查依赖是否正确引入(查看 pom.xml/gradle.build)
- 运行 debug 模式查看自动配置条件:
bash复制java -jar app.jar --debug
- 检查是否有自定义配置覆盖了默认配置
8.3 事务不回滚问题
常见原因:
- 方法访问权限不是 public
- 异常类型不是 RuntimeException
- 同一类中方法调用(自调用问题)
解决方案:
java复制@Service
public class OrderService {
private final OrderRepository orderRepository;
private final InventoryService inventoryService;
@Transactional
public void placeOrder(Order order) {
// 保存订单
orderRepository.save(order);
try {
// 调用其他服务
inventoryService.updateInventory(order);
} catch (InventoryException e) {
// 明确标记回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
}
8.4 性能问题诊断工具
推荐工具链:
- Arthas - Java 诊断工具
- VisualVM - JVM 监控
- Spring Boot Actuator 的 /heapdump 端点
- JProfiler - 商业分析工具
关键检查点:
- 内存泄漏(特别是缓存)
- 慢 SQL 查询
- 线程阻塞
- 不合理的循环依赖
9. 项目结构设计与代码规范
9.1 模块化项目结构
经过多个项目验证的标准结构:
code复制src/
├── main/
│ ├── java/
│ │ └── com/
│ │ └── example/
│ │ ├── config/ # 配置类
│ │ ├── controller/ # 控制器
│ │ ├── service/ # 服务层
│ │ │ ├── impl/ # 服务实现
│ │ │ └── dto/ # 数据传输对象
│ │ ├── repository/ # 数据访问
│ │ ├── model/ # 实体类
│ │ ├── exception/ # 异常处理
│ │ ├── util/ # 工具类
│ │ └── Application.java # 启动类
│ └── resources/
│ ├── static/ # 静态资源
│ ├── templates/ # 模板文件
│ ├── application.yml # 主配置
│ ├── application-dev.yml # 开发环境配置
│ └── application-prod.yml # 生产环境配置
└── test/ # 测试代码
9.2 代码规范与检查
推荐配置:
- Checkstyle 配置(google_checks.xml)
- SpotBugs 静态分析
- PMD 代码质量检查
示例 Checkstyle 规则(部分):
xml复制<module name="MethodLength">
<property name="max" value="50"/>
</module>
<module name="ParameterNumber">
<property name="max" value="5"/>
</module>
<module name="CyclomaticComplexity">
<property name="max" value="10"/>
</module>
9.3 测试策略
完整的测试金字塔:
- 单元测试(JUnit 5 + Mockito):
java复制@ExtendWith(MockitoExtension.class)
class OrderServiceTest {
@Mock
private OrderRepository orderRepository;
@InjectMocks
private OrderService orderService;
@Test
void shouldCreateOrder() {
Order order = new Order();
when(orderRepository.save(any())).thenReturn(order);
Order result = orderService.createOrder(order);
assertNotNull(result);
verify(orderRepository).save(order);
}
}
- 集成测试(@SpringBootTest):
java复制@SpringBootTest
@AutoConfigureMockMvc
class OrderControllerIT {
@Autowired
private MockMvc mockMvc;
@Test
void shouldReturnOrders() throws Exception {
mockMvc.perform(get("/api/orders"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.content").isArray());
}
}
- 端到端测试(TestContainers):
java复制@Testcontainers
@SpringBootTest
class OrderE2ETest {
@Container
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:13");
@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgres::getJdbcUrl);
registry.add("spring.datasource.username", postgres::getUsername);
registry.add("spring.datasource.password", postgres::getPassword);
}
@Test
void shouldProcessCompleteOrderFlow() {
// 完整的业务流程测试
}
}
10. 现代化部署方案
10.1 Docker 容器化部署
标准 Dockerfile 示例:
dockerfile复制# 构建阶段
FROM eclipse-temurin:17-jdk-jammy as builder
WORKDIR /app
COPY . .
RUN ./mvnw package -DskipTests
# 运行阶段
FROM eclipse-temurin:17-jre-jammy
WORKDIR /app
COPY --from=builder /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
构建与运行:
bash复制docker build -t myapp .
docker run -p 8080:8080 -e "SPRING_PROFILES_ACTIVE=prod" myapp
10.2 Kubernetes 部署方案
deployment.yaml 示例:
yaml复制apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myregistry/myapp:1.0.0
ports:
- containerPort: 8080
env:
- name: SPRING_PROFILES_ACTIVE
value: "prod"
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"
livenessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
10.3 持续集成与交付
GitLab CI 示例:
yaml复制stages:
- build
- test
- package
- deploy
variables:
MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"
build:
stage: build
image: maven:3.8.4-openjdk-17
script:
- mvn compile
test:
stage: test
image: maven:3.8.4-openjdk-17
script:
- mvn test
package:
stage: package
image: maven:3.8.4-openjdk-17
script:
- mvn package -DskipTests
artifacts:
paths:
- target/*.jar
deploy:
stage: deploy
image: docker:20.10.12
services:
- docker:20.10.12-dind
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
only:
- main
11. 项目演进与架构升级
11.1 从单体到微服务
演进策略:
- 先模块化(垂直拆分)
- 提取独立服务(按业务能力)
- 引入服务发现(如 Spring Cloud Netflix)
- 逐步迁移功能
关键配置(Spring Cloud):
yaml复制spring:
application:
name: order-service
cloud:
consul:
host: localhost
port: 8500
gateway:
routes:
- id: product-service
uri: lb://product-service
predicates:
- Path=/api/products/**
11.2 响应式编程引入
WebFlux 基础示例:
java复制@RestController
@RequestMapping("/api/reactive/products")
public class ReactiveProductController {
private final ReactiveProductService productService;
@GetMapping
public Flux<Product> getAllProducts() {
return productService.findAll();
}
@GetMapping("/{id}")
public Mono<Product> getProductById(@PathVariable String id) {
return productService.findById(id);
}
}
@Service
@RequiredArgsConstructor
public class ReactiveProductService {
private final ReactiveProductRepository repository;
public Flux<Product> findAll() {
return repository.findAll()
.delayElements(Duration.ofMillis(100)) // 背压测试
.log("product-service");
}
}
11.3 云原生适配
Spring Cloud 功能矩阵:
| 功能 | 实现方案 | 适用场景 |
|---|---|---|
| 服务发现 | Cloud Consul/Zookeeper | 多实例服务注册与发现 |
| 客户端负载均衡 | Spring Cloud LoadBalancer | 服务间调用负载均衡 |
| 配置中心 | Cloud Config Server | 集中式配置管理 |
| 熔断器 | Resilience4j | 服务容错保护 |
| API 网关 | Spring Cloud Gateway | 统一入口/路由/过滤 |
| 分布式追踪 | Sleuth + Zipkin | 请求链路追踪 |
12. 开发者效率工具链
12.1 开发辅助工具推荐
必备工具集合:
- Lombok - 减少样板代码
- MapStruct - 对象映射
- Spring Boot DevTools - 热部署
- jQAssistant - 架构分析
12.2 代码生成技巧
自定义代码生成模板(Velocity)示例:
velocity复制#foreach($field in $fields)
#if($field.type == 'String')
@NotBlank
#elseif($field.type == 'Long' || $field.type == 'Integer')
@NotNull
#end
private $field.type $field.name;
#end
12.3 文档自动化
Swagger 集成配置:
java复制@Configuration
@EnableOpenApi
public class SwaggerConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("Order Service API")
.version("1.0")
.description("API for order processing")
.license(new License().name("Apache 2.0")))
.externalDocs(new ExternalDocumentation()
.description("Spring Boot Documentation")
.url("https://spring.io/projects/spring-boot"));
}
}
访问地址:http://localhost:8080/swagger-ui.html
13. 前沿技术整合
13.1 GraphQL 集成
Spring GraphQL 配置:
java复制@Controller
public class ProductGraphQLController {
@QueryMapping
public Flux<Product> products() {
return productService.findAll();
}
@MutationMapping
public Mono<Product> addProduct(@Argument ProductInput product) {
return productService.save(product);
}
}