1. 为什么选择Spring Boot?
Spring Boot自2014年发布以来,已经成为Java企业级开发的事实标准。根据2023年JVM生态系统报告,超过78%的Java开发者在其项目中使用Spring Boot。这个数字背后反映的是Spring Boot真正解决了传统Java EE开发中的痛点。
传统Spring项目开发需要大量配置:
- 繁琐的XML配置
- 复杂的依赖管理
- 冗长的部署流程
- 环境差异带来的各种问题
Spring Boot的核心设计哲学是"约定优于配置"。它通过自动配置、起步依赖和嵌入式容器三大特性,将开发者从繁琐的配置中解放出来。我曾在传统Spring和Spring Boot项目间切换开发,配置时间的差异可以达到10:1的比例。
提示:Spring Boot不是Spring的替代品,而是对Spring的增强和简化。它底层仍然基于Spring框架,但通过智能默认值减少了配置工作量。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与项目创建
2.1 开发环境要求
在开始Spring Boot项目前,需要准备以下环境:
- JDK 8或更高版本(推荐JDK 17)
- Maven 3.5+或Gradle 7.x
- IDE(IntelliJ IDEA、Eclipse或VS Code)
我强烈推荐使用IntelliJ IDEA Ultimate版,它对Spring Boot的支持最为完善。社区版虽然免费,但缺少一些高级功能。
2.2 项目初始化
创建Spring Boot项目有三种主流方式:
-
Spring Initializr(最推荐):
访问 https://start.spring.io/,这是一个官方提供的项目生成工具。你可以:- 选择构建工具(Maven/Gradle)
- 指定语言(Java/Kotlin/Groovy)
- 选择Spring Boot版本
- 添加需要的依赖
-
命令行创建:
如果你已经安装了Spring Boot CLI,可以运行:bash复制
spring init --dependencies=web my-project -
IDE集成:
现代IDE都内置了Spring Boot项目创建向导。以IntelliJ为例:- File → New → Project
- 选择Spring Initializr
- 填写项目信息
- 选择依赖
注意:初学者最容易犯的错误是选择了不兼容的Spring Boot版本和Java版本。Spring Boot 3.x需要Java 17+,而Spring Boot 2.x支持Java 8+。
3. Spring Boot核心特性解析
3.1 自动配置(Auto-configuration)
自动配置是Spring Boot最强大的特性之一。它基于类路径上的jar包、已定义的bean以及各种属性设置,自动配置Spring应用。
工作原理:
- Spring Boot启动时扫描classpath
- 检查存在的类和配置
- 根据条件自动配置合适的bean
例如,当你的classpath中有spring-boot-starter-web时,Spring Boot会自动:
- 配置嵌入式Tomcat
- 注册DispatcherServlet
- 设置默认的ViewResolver
你可以通过@SpringBootApplication注解的exclude属性禁用特定自动配置:
java复制@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
3.2 起步依赖(Starter Dependencies)
起步依赖是一组预定义的依赖描述符,可以简化你的构建配置。它们遵循spring-boot-starter-*的命名模式。
常用起步依赖:
spring-boot-starter-web:Web应用开发spring-boot-starter-data-jpa:JPA与Hibernatespring-boot-starter-security:安全认证spring-boot-starter-test:测试支持
起步依赖的优势:
- 解决依赖冲突问题
- 提供经过测试的依赖组合
- 简化pom.xml/gradle.build文件
3.3 嵌入式服务器
Spring Boot内置了Tomcat、Jetty和Undertow三种Servlet容器,默认使用Tomcat。这意味着:
- 无需部署WAR文件到外部服务器
- 应用可以独立运行
- 简化了开发和测试流程
切换服务器示例(Gradle):
groovy复制dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
// 排除Tomcat
implementation 'org.springframework.boot:spring-boot-starter-jetty'
}
3.4 Actuator监控
Spring Boot Actuator提供了生产级监控功能,通过HTTP或JMX暴露端点。
常用端点:
/health:应用健康状态/info:应用信息/metrics:性能指标/env:环境变量
启用Actuator:
xml复制<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
配置端点暴露:
properties复制management.endpoints.web.exposure.include=health,info,metrics
management.endpoint.health.show-details=always
4. 开发第一个REST API
4.1 项目结构
标准的Spring Boot项目结构:
code复制src/
├── main/
│ ├── java/
│ │ └── com/example/
│ │ ├── config/ # 配置类
│ │ ├── controller/ # 控制器
│ │ ├── model/ # 数据模型
│ │ ├── repository/ # 数据访问
│ │ ├── service/ # 业务逻辑
│ │ └── Application.java # 启动类
│ └── resources/
│ ├── static/ # 静态资源
│ ├── templates/ # 模板文件
│ └── application.properties # 配置文件
└── test/ # 测试代码
4.2 创建控制器
java复制@RestController
@RequestMapping("/api/products")
public class ProductController {
private final ProductService productService;
// 构造器注入
public ProductController(ProductService productService) {
this.productService = productService;
}
@GetMapping
public List<Product> getAllProducts() {
return productService.findAll();
}
@GetMapping("/{id}")
public ResponseEntity<Product> getProductById(@PathVariable Long id) {
return productService.findById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Product createProduct(@RequestBody Product product) {
return productService.save(product);
}
}
4.3 服务层实现
java复制@Service
public class ProductServiceImpl implements ProductService {
private final ProductRepository productRepository;
public ProductServiceImpl(ProductRepository productRepository) {
this.productRepository = productRepository;
}
@Override
public List<Product> findAll() {
return productRepository.findAll();
}
@Override
public Optional<Product> findById(Long id) {
return productRepository.findById(id);
}
@Override
public Product save(Product product) {
return productRepository.save(product);
}
}
4.4 数据访问层
java复制public interface ProductRepository extends JpaRepository<Product, Long> {
// 可以添加自定义查询方法
}
5. 配置与自定义
5.1 配置文件
Spring Boot支持多种配置方式:
application.propertiesapplication.yml- 环境变量
- 命令行参数
YAML示例:
yaml复制server:
port: 8081
servlet:
context-path: /api
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: root
password: secret
driver-class-name: com.mysql.cj.jdbc.Driver
5.2 自定义配置类
java复制@Configuration
public class AppConfig {
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder
.setConnectTimeout(Duration.ofSeconds(5))
.setReadTimeout(Duration.ofSeconds(5))
.build();
}
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE");
}
};
}
}
5.3 属性绑定
java复制@ConfigurationProperties(prefix = "app")
public class AppProperties {
private String name;
private String version;
private List<String> allowedIps;
// getters and setters
}
然后在配置文件中:
properties复制app.name=MyApp
app.version=1.0.0
app.allowed-ips=192.168.1.1,127.0.0.1
6. 测试与部署
6.1 单元测试
java复制@SpringBootTest
class ProductServiceTest {
@Autowired
private ProductService productService;
@Test
void shouldSaveProduct() {
Product product = new Product();
product.setName("Test Product");
product.setPrice(BigDecimal.valueOf(99.99));
Product saved = productService.save(product);
assertNotNull(saved.getId());
assertEquals("Test Product", saved.getName());
}
}
6.2 集成测试
java复制@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class ProductControllerIT {
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Test
void shouldReturnProducts() {
ResponseEntity<Product[]> response = restTemplate.getForEntity(
"http://localhost:" + port + "/api/products",
Product[].class);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertTrue(response.getBody().length > 0);
}
}
6.3 打包与运行
构建可执行JAR:
bash复制mvn clean package
运行应用:
bash复制java -jar target/myapp-0.0.1-SNAPSHOT.jar
或者带参数运行:
bash复制java -jar target/myapp-0.0.1-SNAPSHOT.jar --server.port=8081
7. 常见问题与解决方案
7.1 端口冲突
如果遇到端口被占用错误:
properties复制server.port=0 # 随机端口
或者
bash复制java -jar myapp.jar --server.port=8081
7.2 数据库连接问题
确保配置正确:
properties复制spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=secret
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
7.3 跨域问题
解决方案1:全局配置
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*");
}
}
解决方案2:控制器注解
java复制@CrossOrigin(origins = "*")
@RestController
public class MyController {
// ...
}
7.4 静态资源访问
默认情况下,Spring Boot会从以下位置提供静态资源:
/static/public/resources/META-INF/resources
确保你的静态文件放在这些目录下。
8. 进阶主题与扩展
8.1 替换默认Tomcat
Spring Boot支持将Tomcat替换为其他Servlet容器,如宝蓝德(国产中间件)。修改pom.xml:
xml复制<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
8.2 接口签名验证
实现接口签名验证的常见方式:
- 自定义过滤器
- Spring AOP
- 拦截器
示例过滤器:
java复制@Component
public class SignFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
String sign = request.getHeader("X-Sign");
if (!validateSign(sign)) {
response.sendError(HttpStatus.UNAUTHORIZED.value(), "Invalid signature");
return;
}
filterChain.doFilter(request, response);
}
private boolean validateSign(String sign) {
// 实现签名验证逻辑
return true;
}
}
8.3 使用Knife4j生成API文档
Knife4j是Swagger的增强实现,配置简单:
- 添加依赖:
xml复制<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
- 配置类:
java复制@Configuration
@EnableSwagger2
@EnableKnife4j
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.controller"))
.paths(PathSelectors.any())
.build()
.apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("API文档")
.description("Spring Boot API文档")
.version("1.0")
.build();
}
}
访问地址:http://localhost:8080/doc.html
8.4 定时任务与Quartz集成
Spring Boot提供了简单的定时任务支持:
java复制@Component
public class ScheduledTasks {
private static final Logger log = LoggerFactory.getLogger(ScheduledTasks.class);
@Scheduled(fixedRate = 5000)
public void reportCurrentTime() {
log.info("当前时间: {}", LocalDateTime.now());
}
}
对于更复杂的调度需求,可以集成Quartz:
- 添加依赖:
xml复制<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
- 配置任务:
java复制public class SampleJob extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext context) {
// 任务逻辑
}
}
- 配置触发器:
java复制@Configuration
public class QuartzConfig {
@Bean
public JobDetail sampleJobDetail() {
return JobBuilder.newJob(SampleJob.class)
.withIdentity("sampleJob")
.storeDurably()
.build();
}
@Bean
public Trigger sampleJobTrigger() {
SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(10)
.repeatForever();
return TriggerBuilder.newTrigger()
.forJob(sampleJobDetail())
.withIdentity("sampleTrigger")
.withSchedule(scheduleBuilder)
.build();
}
}
在实际项目中,我发现Spring Boot的自动配置虽然强大,但也可能带来一些意想不到的行为。例如,当classpath中存在特定库时,Spring Boot会自动配置相关bean,这有时会导致与显式配置的冲突。解决这类问题的关键是理解自动配置的条件,并通过@Conditional注解或配置排除来控制自动配置的行为。
