JDWA 技术文档
首页
  • 数据库
  • 前端开发
  • 后端开发
  • 开发工具
  • 虚拟化技术
  • KVM显卡直通
  • FPGA仿真固件
  • 项目实战
  • 踩坑记录
  • 开发心得
  • 软件工具
  • 学习资料
  • 开发环境
更新日志
关于我
Gitee
GitHub
首页
  • 数据库
  • 前端开发
  • 后端开发
  • 开发工具
  • 虚拟化技术
  • KVM显卡直通
  • FPGA仿真固件
  • 项目实战
  • 踩坑记录
  • 开发心得
  • 软件工具
  • 学习资料
  • 开发环境
更新日志
关于我
Gitee
GitHub
  • 数据库

    • 数据库教程
    • MySQL免安装版使用指南
    • MySQL性能优化实践
    • Redis入门与实践
    • MinIO快速部署指南
    • MinIO基础使用教程
  • 前端开发

    • 前端开发教程
    • Vue.js开发最佳实践
    • CSS常用技巧与解决方案
    • JavaScript实用技巧与编程模式
    • CSS Grid布局教程
  • 后端开发

    • 后端开发教程
    • Spring Boot实战指南
    • Node.js Express 框架开发实战指南
    • Python Flask 框架开发指南
  • 开发工具

    • 开发工具教程
    • Git 基础教程
    • Git工作流实践指南
    • VS Code 全面使用指南
    • VS Code必装插件推荐
    • Docker基础入门
    • IntelliJ IDEA 使用技巧
    • Eclipse配置与优化
    • Sublime Text 高级技巧
    • Vim 从入门到精通
    • Maven 详解
    • Gradle 入门与进阶
    • Webpack 配置指南
    • npm 与 yarn 使用技巧
    • Makefile 编写指南
    • Navicat 使用指南
    • MCP本地部署教程
  • 虚拟化技术

    • JDWA虚拟化技术专题
    • KVM虚拟机去虚拟化技术详解
  • KVM显卡直通

    • KVM显卡GPU直通教程
  • FPGA仿真固件

    • FPGA仿真固件开发指南
    • 基础-完整设备仿真定制固件开发指南
    • 中级-完整设备仿真定制固件开发指南
    • 高级-完整设备仿真定制固件开发指南

Spring Boot实战指南

Spring Boot是一个快速开发Java应用的框架,它通过自动配置和约定优于配置的理念,大大简化了Spring应用的开发过程。本文将带你从零开始学习Spring Boot,掌握核心概念和最佳实践。

Spring Boot介绍

什么是Spring Boot

Spring Boot是由Pivotal团队开发的一个基于Spring框架的项目,旨在简化Spring应用的初始化、配置和开发过程。它主要有以下特点:

  • 无需XML配置:告别繁琐的XML配置文件
  • 内嵌Web服务器:可以打包成可独立运行的JAR文件
  • 自动配置:根据依赖自动配置应用
  • 起步依赖:简化Maven/Gradle依赖配置
  • 生产就绪特性:如监控、健康检查等
  • 丰富的插件生态:满足各种开发需求

Spring Boot与Spring Framework的关系

Spring Boot建立在Spring Framework之上,提供了更快速和便捷的开发体验:

  • Spring Boot使用了Spring的核心功能,如依赖注入、AOP等
  • Spring Boot通过自动配置简化了Spring的配置
  • Spring Boot是一种使用Spring Framework的方式,而不是替代品

适用场景

Spring Boot适用于以下场景:

  • 微服务开发
  • RESTful API服务
  • Web应用开发
  • 批处理应用
  • 企业级应用开发
  • 云原生应用开发

开发环境搭建

必备工具

  • JDK 8+ (推荐JDK 11或JDK 17)
  • Maven 3.2+ 或 Gradle 7.x+
  • 集成开发环境(IDE):推荐IntelliJ IDEA或Spring Tool Suite
  • Git (可选,用于版本控制)

Windows环境配置

  1. 安装JDK:

    • 下载并安装JDK
    • 设置JAVA_HOME环境变量
    • 添加%JAVA_HOME%\bin到PATH
  2. 安装Maven:

    • 下载Maven二进制包
    • 解压到合适目录
    • 设置M2_HOME环境变量
    • 添加%M2_HOME%\bin到PATH
  3. 安装IDE:

    • 下载并安装IntelliJ IDEA
    • 安装Spring Boot插件

macOS环境配置

可以使用Homebrew简化安装:

# 安装JDK
brew install openjdk@17

# 安装Maven
brew install maven

# 安装IntelliJ IDEA
brew install --cask intellij-idea

Linux环境配置

Ubuntu/Debian系统:

# 安装JDK
sudo apt update
sudo apt install openjdk-17-jdk

# 安装Maven
sudo apt install maven

# 安装IDEA (通过官网下载或使用snap)
sudo snap install intellij-idea-community --classic

创建第一个Spring Boot应用

使用Spring Initializr

  1. 访问 Spring Initializr
  2. 选择项目类型:Maven/Gradle
  3. 选择语言:Java
  4. 选择Spring Boot版本:如2.7.x或3.x
  5. 填写项目元数据:
    • Group: com.example
    • Artifact: demo
    • Name: demo
    • Description: Demo project for Spring Boot
    • Package name: com.example.demo
  6. 添加依赖:如Spring Web, Spring Data JPA, H2 Database
  7. 生成并下载项目

使用命令行创建

# 使用Spring Boot CLI
spring init --dependencies=web,data-jpa,h2 --build=maven my-project

# 使用Maven命令
mvn archetype:generate -DgroupId=com.example -DartifactId=my-project -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

使用IDE创建

IntelliJ IDEA:

  1. File -> New -> Project
  2. 选择Spring Initializr
  3. 填写项目信息
  4. 选择依赖
  5. 点击Finish

Eclipse/STS:

  1. File -> New -> Spring Starter Project
  2. 填写项目信息
  3. 选择依赖
  4. 点击Finish

项目结构解析

创建好的典型Spring Boot项目结构:

my-project/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/
│   │   │       └── example/
│   │   │           └── demo/
│   │   │               ├── DemoApplication.java      # 主启动类
│   │   │               ├── controller/               # 控制器
│   │   │               ├── service/                  # 服务层
│   │   │               ├── repository/               # 数据访问层
│   │   │               ├── entity/                   # 实体类
│   │   │               └── config/                   # 配置类
│   │   └── resources/
│   │       ├── application.properties  # 应用配置文件
│   │       ├── static/                 # 静态资源
│   │       └── templates/              # 模板文件
│   └── test/                           # 测试代码
├── pom.xml                            # Maven配置
└── README.md                          # 项目说明

启动类解析

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);
    }
}

@SpringBootApplication注解是一个复合注解,包含:

  • @Configuration:标识配置类
  • @EnableAutoConfiguration:启用自动配置
  • @ComponentScan:组件扫描

Spring Boot核心特性

自动配置

Spring Boot根据添加的依赖自动配置应用程序,无需手动配置。例如,添加spring-boot-starter-web依赖后,自动配置Web相关组件。

禁用特定自动配置:

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class DemoApplication {
    // ...
}

外部化配置

Spring Boot允许使用属性文件、YAML文件、环境变量和命令行参数配置应用。配置优先级从高到低:

  1. 命令行参数
  2. 操作系统环境变量
  3. 特定profile的application属性
  4. application.properties/yml

配置示例:

application.properties:

# 服务器配置
server.port=8080
server.servlet.context-path=/api

# 数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# JPA配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

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

配置属性绑定

可以将配置属性绑定到Java对象:

@Component
@ConfigurationProperties(prefix = "mail")
public class MailProperties {
    private String host;
    private int port;
    private String username;
    private String password;
    
    // getters and setters
}

application.properties:

mail.host=smtp.gmail.com
mail.port=587
mail.username=user@example.com
mail.password=secret

Profile配置

使用不同的Profile可以针对不同环境加载不同的配置:

application-dev.properties:

logging.level.root=DEBUG
spring.datasource.url=jdbc:h2:mem:testdb

application-prod.properties:

logging.level.root=WARN
spring.datasource.url=jdbc:mysql://prod-server:3306/mydb

激活Profile:

spring.profiles.active=dev

或者使用命令行:

java -jar myapp.jar --spring.profiles.active=prod

Web应用开发

创建REST API

使用@RestController创建RESTful API:

@RestController
@RequestMapping("/api/users")
public class UserController {
    
    private final UserService userService;
    
    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }
    
    @GetMapping
    public List<User> getAllUsers() {
        return userService.findAll();
    }
    
    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable Long id) {
        return userService.findById(id)
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());
    }
    
    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        User savedUser = userService.save(user);
        return ResponseEntity.created(URI.create("/api/users/" + savedUser.getId()))
                .body(savedUser);
    }
    
    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User user) {
        return userService.update(id, user)
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());
    }
    
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        if (userService.delete(id)) {
            return ResponseEntity.noContent().build();
        }
        return ResponseEntity.notFound().build();
    }
}

请求参数处理

Spring Boot提供多种方式处理请求参数:

@GetMapping("/search")
public List<User> searchUsers(
    @RequestParam(required = false) String name, 
    @RequestParam(defaultValue = "0") int page,
    @RequestParam(defaultValue = "10") int size) {
    
    return userService.search(name, page, size);
}

异常处理

全局异常处理:

@RestControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleResourceNotFound(ResourceNotFoundException ex) {
        ErrorResponse error = new ErrorResponse(
            HttpStatus.NOT_FOUND.value(),
            ex.getMessage(),
            System.currentTimeMillis()
        );
        return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
    }
    
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleGlobalException(Exception ex) {
        ErrorResponse error = new ErrorResponse(
            HttpStatus.INTERNAL_SERVER_ERROR.value(),
            "发生未知错误",
            System.currentTimeMillis()
        );
        return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

文件上传

@PostMapping("/upload")
public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) {
    try {
        String fileName = storageService.store(file);
        return ResponseEntity.ok("文件上传成功: " + fileName);
    } catch (Exception e) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body("文件上传失败: " + e.getMessage());
    }
}

静态资源处理

Spring Boot默认从以下路径提供静态资源:

  • /static
  • /public
  • /resources
  • /META-INF/resources

例如,放置在src/main/resources/static/images/logo.png的资源可通过http://localhost:8080/images/logo.png访问。

配置CORS

@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
                .allowedOrigins("http://example.com")
                .allowedMethods("GET", "POST", "PUT", "DELETE")
                .allowedHeaders("*")
                .allowCredentials(true)
                .maxAge(3600);
    }
}

数据访问

整合Spring Data JPA

添加依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

创建实体类:

@Entity
@Table(name = "users")
public class User {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(nullable = false, length = 50)
    private String name;
    
    @Column(nullable = false, unique = true)
    private String email;
    
    @Column(nullable = false)
    private String password;
    
    // getters and setters
}

创建Repository:

public interface UserRepository extends JpaRepository<User, Long> {
    
    Optional<User> findByEmail(String email);
    
    List<User> findByNameContaining(String name);
    
    @Query("SELECT u FROM User u WHERE u.name LIKE %:keyword% OR u.email LIKE %:keyword%")
    List<User> search(@Param("keyword") String keyword);
}

使用MyBatis

添加依赖:

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.2</version>
</dependency>

创建Mapper接口:

@Mapper
public interface UserMapper {
    
    @Select("SELECT * FROM users")
    List<User> findAll();
    
    @Select("SELECT * FROM users WHERE id = #{id}")
    User findById(Long id);
    
    @Insert("INSERT INTO users(name, email, password) VALUES(#{name}, #{email}, #{password})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insert(User user);
    
    @Update("UPDATE users SET name = #{name}, email = #{email}, password = #{password} WHERE id = #{id}")
    int update(User user);
    
    @Delete("DELETE FROM users WHERE id = #{id}")
    int delete(Long id);
}

事务管理

Spring Boot默认开启事务管理,只需使用@Transactional注解:

@Service
public class UserServiceImpl implements UserService {
    
    private final UserRepository userRepository;
    
    @Autowired
    public UserServiceImpl(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
    
    @Override
    @Transactional
    public User registerUser(User user) {
        // 检查邮箱是否已存在
        if (userRepository.findByEmail(user.getEmail()).isPresent()) {
            throw new DuplicateEmailException("Email already exists");
        }
        
        // 加密密码
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        
        // 保存用户
        return userRepository.save(user);
    }
}

整合Redis缓存

添加依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

配置Redis:

spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=

启用缓存:

@Configuration
@EnableCaching
public class CacheConfig {
    
    @Bean
    public RedisCacheConfiguration redisCacheConfiguration() {
        return RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofMinutes(10))
                .serializeKeysWith(
                        RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(
                        RedisSerializationContext.SerializationPair.fromSerializer(
                                new GenericJackson2JsonRedisSerializer()));
    }
}

使用缓存:

@Service
public class UserServiceImpl implements UserService {
    
    private final UserRepository userRepository;
    
    @Autowired
    public UserServiceImpl(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
    
    @Override
    @Cacheable(value = "users", key = "#id")
    public Optional<User> findById(Long id) {
        return userRepository.findById(id);
    }
    
    @Override
    @CachePut(value = "users", key = "#user.id")
    public User save(User user) {
        return userRepository.save(user);
    }
    
    @Override
    @CacheEvict(value = "users", key = "#id")
    public boolean delete(Long id) {
        if (userRepository.existsById(id)) {
            userRepository.deleteById(id);
            return true;
        }
        return false;
    }
}

安全与认证

整合Spring Security

添加依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

基本配置:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Autowired
    private UserDetailsService userDetailsService;
    
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
            .passwordEncoder(passwordEncoder());
    }
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .authorizeRequests()
                .antMatchers("/api/public/**").permitAll()
                .antMatchers("/api/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
            .and()
            .logout()
                .permitAll();
    }
}

JWT认证

添加依赖:

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

JWT工具类:

@Component
public class JwtTokenUtil {
    
    @Value("${jwt.secret}")
    private String secret;
    
    @Value("${jwt.expiration}")
    private long expiration;
    
    public String generateToken(UserDetails userDetails) {
        Map<String, Object> claims = new HashMap<>();
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(userDetails.getUsername())
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + expiration * 1000))
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }
    
    public String getUsernameFromToken(String token) {
        return getClaimFromToken(token, Claims::getSubject);
    }
    
    public boolean validateToken(String token, UserDetails userDetails) {
        final String username = getUsernameFromToken(token);
        return username.equals(userDetails.getUsername()) && !isTokenExpired(token);
    }
    
    private boolean isTokenExpired(String token) {
        final Date expiration = getClaimFromToken(token, Claims::getExpiration);
        return expiration.before(new Date());
    }
    
    private <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = getAllClaimsFromToken(token);
        return claimsResolver.apply(claims);
    }
    
    private Claims getAllClaimsFromToken(String token) {
        return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
    }
}

JWT过滤器:

public class JwtRequestFilter extends OncePerRequestFilter {
    
    @Autowired
    private UserDetailsService userDetailsService;
    
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    
    @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);
            try {
                username = jwtTokenUtil.getUsernameFromToken(jwt);
            } catch (Exception e) {
                // Token不合法或过期
            }
        }
        
        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
            
            if (jwtTokenUtil.validateToken(jwt, userDetails)) {
                UsernamePasswordAuthenticationToken authToken = 
                        new UsernamePasswordAuthenticationToken(
                                userDetails, null, userDetails.getAuthorities());
                authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authToken);
            }
        }
        filterChain.doFilter(request, response);
    }
}

测试

单元测试

使用JUnit 5和Mockito进行单元测试:

@ExtendWith(MockitoExtension.class)
public class UserServiceTest {
    
    @Mock
    private UserRepository userRepository;
    
    @InjectMocks
    private UserServiceImpl userService;
    
    @Test
    void findById_WhenUserExists_ReturnUser() {
        // Arrange
        Long userId = 1L;
        User expectedUser = new User();
        expectedUser.setId(userId);
        expectedUser.setName("Test User");
        
        when(userRepository.findById(userId)).thenReturn(Optional.of(expectedUser));
        
        // Act
        Optional<User> result = userService.findById(userId);
        
        // Assert
        assertTrue(result.isPresent());
        assertEquals(expectedUser.getId(), result.get().getId());
        assertEquals(expectedUser.getName(), result.get().getName());
        
        verify(userRepository).findById(userId);
    }
    
    @Test
    void findById_WhenUserDoesNotExist_ReturnEmpty() {
        // Arrange
        Long userId = 1L;
        when(userRepository.findById(userId)).thenReturn(Optional.empty());
        
        // Act
        Optional<User> result = userService.findById(userId);
        
        // Assert
        assertFalse(result.isPresent());
        
        verify(userRepository).findById(userId);
    }
}

集成测试

使用@SpringBootTest进行集成测试:

@SpringBootTest
class UserControllerIntegrationTest {
    
    @Autowired
    private TestRestTemplate restTemplate;
    
    @Autowired
    private UserRepository userRepository;
    
    @BeforeEach
    void setup() {
        userRepository.deleteAll();
    }
    
    @Test
    void createUser_WhenValidInput_ReturnCreatedUser() {
        // Arrange
        User user = new User();
        user.setName("Test User");
        user.setEmail("test@example.com");
        user.setPassword("password");
        
        // Act
        ResponseEntity<User> response = restTemplate.postForEntity(
                "/api/users",
                user,
                User.class);
        
        // Assert
        assertEquals(HttpStatus.CREATED, response.getStatusCode());
        assertNotNull(response.getBody());
        assertNotNull(response.getBody().getId());
        assertEquals(user.getName(), response.getBody().getName());
        assertEquals(user.getEmail(), response.getBody().getEmail());
        
        // Verify in database
        Optional<User> savedUser = userRepository.findById(response.getBody().getId());
        assertTrue(savedUser.isPresent());
    }
}

Web层测试

使用@WebMvcTest测试控制器:

@WebMvcTest(UserController.class)
class UserControllerTest {
    
    @Autowired
    private MockMvc mockMvc;
    
    @MockBean
    private UserService userService;
    
    @Autowired
    private ObjectMapper objectMapper;
    
    @Test
    void getUserById_WhenUserExists_ReturnUser() throws Exception {
        // Arrange
        Long userId = 1L;
        User user = new User();
        user.setId(userId);
        user.setName("Test User");
        user.setEmail("test@example.com");
        
        when(userService.findById(userId)).thenReturn(Optional.of(user));
        
        // Act & Assert
        mockMvc.perform(get("/api/users/{id}", userId))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.id").value(userId))
                .andExpect(jsonPath("$.name").value("Test User"))
                .andExpect(jsonPath("$.email").value("test@example.com"));
        
        verify(userService).findById(userId);
    }
    
    @Test
    void getUserById_WhenUserDoesNotExist_Return404() throws Exception {
        // Arrange
        Long userId = 1L;
        when(userService.findById(userId)).thenReturn(Optional.empty());
        
        // Act & Assert
        mockMvc.perform(get("/api/users/{id}", userId))
                .andExpect(status().isNotFound());
        
        verify(userService).findById(userId);
    }
}

部署与监控

构建可执行JAR

使用Maven构建:

mvn clean package

运行应用:

java -jar target/myapp-0.0.1-SNAPSHOT.jar

Docker部署

创建Dockerfile:

FROM openjdk:17-jdk-slim
VOLUME /tmp
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

构建和运行Docker镜像:

docker build -t myapp .
docker run -p 8080:8080 myapp

应用监控

添加Actuator依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

配置Actuator端点:

# 启用所有端点
management.endpoints.web.exposure.include=*
# 显示详细健康信息
management.endpoint.health.show-details=always

访问监控端点:

  • http://localhost:8080/actuator/health - 健康状态
  • http://localhost:8080/actuator/info - 应用信息
  • http://localhost:8080/actuator/metrics - 指标
  • http://localhost:8080/actuator/env - 环境变量

添加Prometheus和Grafana监控

添加依赖:

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

配置Prometheus端点:

management.endpoints.web.exposure.include=prometheus,health,info

Spring Boot最佳实践

代码组织

  • 遵循分层架构:控制器、服务、数据访问
  • 使用合适的包结构:按功能或领域划分
  • 保持代码简洁,每个类和方法只做一件事

配置管理

  • 区分不同环境的配置:dev, test, prod
  • 敏感信息使用环境变量或外部配置
  • 配置参数化,避免硬编码

错误处理

  • 集中处理异常,提供统一的错误响应格式
  • 记录详细的错误日志
  • 区分用户错误和系统错误

性能优化

  • 使用缓存减少数据库访问
  • 合理配置连接池
  • 异步处理长时间运行的任务
  • 定期进行性能测试和优化

安全措施

  • 所有用户输入进行验证
  • 敏感数据加密
  • 定期更新依赖,修复安全漏洞
  • 使用HTTPS保护通信

常见问题与解决方案

自动配置不生效

问题: 添加了依赖但自动配置不生效

解决方案:

  1. 检查依赖是否正确添加
  2. 确认是否有排除自动配置的代码
  3. 查看启动日志,了解自动配置情况

数据库连接问题

问题: 无法连接到数据库

解决方案:

  1. 检查数据库连接参数
  2. 确认数据库服务是否运行
  3. 测试网络连接
  4. 检查用户权限

内存溢出

问题: 应用运行时出现内存溢出

解决方案:

  1. 增加JVM堆内存: java -Xmx512m -jar app.jar
  2. 排查内存泄漏
  3. 优化大对象使用

循环依赖

问题: Bean循环依赖导致应用启动失败

解决方案:

  1. 重新设计类结构,消除循环
  2. 使用@Lazy注解延迟初始化
  3. 使用setter注入代替构造器注入

总结

Spring Boot极大地简化了Spring应用的开发流程,通过自动配置、起步依赖和内嵌服务器等特性,让开发者能够快速构建企业级应用。本文介绍了Spring Boot的基本概念、核心特性以及实际开发中的最佳实践,希望能够帮助你在项目中更好地使用Spring Boot。

随着经验的积累,你可以进一步探索Spring Cloud微服务生态系统,将应用拆分为多个协同工作的微服务,构建更加灵活和可扩展的系统架构。

如有任何Spring Boot相关问题或讨论,欢迎联系我进行交流。

Prev
后端开发教程
Next
Node.js Express 框架开发实战指南