Spring Boot 详解
Spring Boot是一个基于Spring框架的快速开发平台,它通过约定优于配置的理念,简化了Spring应用的配置和部署。Spring Boot提供了自动配置、内嵌服务器、生产就绪特性等,大大提高了开发效率。
1. Spring Boot基础概念
1.1 什么是Spring Boot?
Spring Boot是Spring框架的扩展,它简化了Spring应用的初始搭建和开发过程。通过自动配置、起步依赖、内嵌服务器等特性,让开发者能够快速构建生产就绪的Spring应用。
1.2 Spring Boot的核心特性
- 自动配置:根据依赖自动配置应用
- 起步依赖:简化Maven/Gradle依赖管理
- 内嵌服务器:内置Tomcat、Jetty等服务器
- 生产就绪:监控、健康检查等
2. 自动配置原理
Spring Boot的自动配置基于条件注解和Spring Factories机制,是其核心功能之一。
🚀 自动配置:Spring Boot会根据添加的jar依赖自动配置Spring应用上下文,减少开发者手动配置的工作量。
2.1 自动配置流程
自动配置的基本流程如下:
- 应用启动时,通过
@SpringBootApplication注解上的@EnableAutoConfiguration启用自动配置功能 AutoConfigurationImportSelector读取所有依赖中的META-INF/spring.factories文件- 收集所有
org.springframework.boot.autoconfigure.EnableAutoConfiguration项下的配置类 - 根据条件注解(
@ConditionalOnXXX)筛选出符合条件的配置类 - 创建并注册这些配置类中定义的Bean
- Spring Boot应用
- spring.factories文件
1@SpringBootApplication // 包含@EnableAutoConfiguration2public class MyApplication {3 public static void main(String[] args) {4 SpringApplication.run(MyApplication.class, args);5 }6}1# Auto Configure2org.springframework.boot.autoconfigure.EnableAutoConfiguration=\3com.example.autoconfigure.DataSourceAutoConfiguration,\4com.example.autoconfigure.JpaRepositoriesAutoConfiguration,\5com.example.autoconfigure.WebMvcAutoConfiguration2.2 条件注解详解
条件注解是自动配置的核心机制,决定了配置是否应该被应用。
主要条件注解
| 条件注解 | 描述 | 示例 |
|---|---|---|
@ConditionalOnClass | 当指定类存在于类路径时 | @ConditionalOnClass(DataSource.class) |
@ConditionalOnMissingClass | 当指定类不存在于类路径时 | @ConditionalOnMissingClass("org.hibernate.Session") |
@ConditionalOnBean | 当指定Bean存在于容器中时 | @ConditionalOnBean(name = "dataSource") |
@ConditionalOnMissingBean | 当指定Bean不存在于容器中时 | @ConditionalOnMissingBean(DataSource.class) |
@ConditionalOnProperty | 当配置属性满足条件时 | @ConditionalOnProperty(prefix = "app", name = "cache", havingValue = "true") |
@ConditionalOnResource | 当指定资源存在时 | @ConditionalOnResource(resources = "classpath:config.properties") |
@ConditionalOnWebApplication | 当应用是Web应用时 | @ConditionalOnWebApplication(type = Type.SERVLET) |
@ConditionalOnNotWebApplication | 当应用不是Web应用时 | @ConditionalOnNotWebApplication |
@ConditionalOnExpression | 当SpEL表达式为true时 | @ConditionalOnExpression("'${spring.profiles.active}' == 'dev'") |
1@Configuration2@ConditionalOnClass(DataSource.class) // 当类路径下有DataSource类时3@ConditionalOnProperty(prefix = "spring.datasource", name = "url") // 当配置了spring.datasource.url属性时4public class DataSourceAutoConfiguration {5 6 @Bean7 @ConditionalOnMissingBean // 当容器中不存在DataSource类型的Bean时8 public DataSource dataSource() {9 // 创建默认数据源10 return DataSourceBuilder.create().build();11 }12 13 @Bean14 @ConditionalOnProperty(prefix = "spring.datasource", name = "initialize", havingValue = "true", matchIfMissing = true)15 public DataSourceInitializer dataSourceInitializer(DataSource dataSource) {16 // 初始化数据源17 return new DataSourceInitializer(dataSource);18 }19}2.3 自动配置的实现原理
Spring Boot自动配置的核心实现基于@EnableAutoConfiguration注解和AutoConfigurationImportSelector选择器。
- EnableAutoConfiguration
- ImportSelector
1@Target(ElementType.TYPE)2@Retention(RetentionPolicy.RUNTIME)3@Documented4@Inherited5@AutoConfigurationPackage6@Import(AutoConfigurationImportSelector.class)7public @interface EnableAutoConfiguration {8 9 String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";10 11 // 排除特定的自动配置类12 Class<?>[] exclude() default {};13 14 // 按名称排除自动配置类15 String[] excludeName() default {};16}@EnableAutoConfiguration注解通过@Import导入AutoConfigurationImportSelector,这个选择器负责加载和筛选自动配置类。
1public class AutoConfigurationImportSelector implements DeferredImportSelector {2 3 @Override4 public String[] selectImports(AnnotationMetadata annotationMetadata) {5 // 判断是否启用自动配置6 if (!isEnabled(annotationMetadata)) {7 return NO_IMPORTS;8 }9 10 // 加载自动配置元数据11 AutoConfigurationMetadata autoConfigurationMetadata = 12 AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);13 14 // 获取自动配置条目15 AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(16 autoConfigurationMetadata, annotationMetadata);17 18 return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());19 }20 21 protected AutoConfigurationEntry getAutoConfigurationEntry(22 AutoConfigurationMetadata autoConfigurationMetadata,23 AnnotationMetadata annotationMetadata) {24 // 从spring.factories加载自动配置类25 List<String> configurations = getCandidateConfigurations(26 annotationMetadata, attributes);27 28 // 去重29 configurations = removeDuplicates(configurations);30 31 // 获取排除项32 Set<String> exclusions = getExclusions(annotationMetadata, attributes);33 34 // 从候选配置中排除指定的配置类35 configurations.removeAll(exclusions);36 37 // 根据条件注解过滤配置类38 configurations = filter(configurations, autoConfigurationMetadata);39 40 // 触发自动配置导入事件41 fireAutoConfigurationImportEvents(configurations, exclusions);42 43 return new AutoConfigurationEntry(configurations, exclusions);44 }45}AutoConfigurationImportSelector通过读取各个JAR包中的META-INF/spring.factories文件,收集所有声明的自动配置类,然后根据条件注解进行筛选。
2.4 自定义自动配置
你可以创建自己的自动配置类,实现特定功能的自动配置。
1// 步骤1:创建配置属性类2@ConfigurationProperties(prefix = "acme")3public class AcmeProperties {45 private boolean enabled = false;6 private String apiKey;7 private List<String> allowedOrigins = new ArrayList<>();8 9 // getter和setter10}1112// 步骤2:创建自动配置类13@Configuration14@ConditionalOnClass(AcmeClient.class)15@EnableConfigurationProperties(AcmeProperties.class)16public class AcmeAutoConfiguration {1718 private final AcmeProperties properties;19 20 public AcmeAutoConfiguration(AcmeProperties properties) {21 this.properties = properties;22 }23 24 @Bean25 @ConditionalOnMissingBean26 @ConditionalOnProperty(prefix = "acme", name = "enabled", havingValue = "true")27 public AcmeClient acmeClient() {28 return new AcmeClient(properties.getApiKey(), properties.getAllowedOrigins());29 }30}3132// 步骤3:注册自动配置类(在META-INF/spring.factories文件中)33// org.springframework.boot.autoconfigure.EnableAutoConfiguration=\34// com.example.AcmeAutoConfiguration创建自定义自动配置时,需要遵循以下原则:
- 尽量使用条件注解,避免强制用户使用你的配置
- 提供合理的默认值,但允许用户自定义
- 使用spring-boot-configuration-processor生成元数据,提供IDE支持
- 遵循命名约定:XxxAutoConfiguration作为配置类名,XxxProperties作为属性类名
3. 配置管理
Spring Boot提供了灵活且强大的配置机制,支持多种配置方式和配置优先级。
🔧 配置管理:Spring Boot允许通过属性文件、YAML文件、环境变量、命令行参数等多种方式配置应用,并提供了灵活的属性绑定功能。
3.1 配置文件格式
Spring Boot支持Properties和YAML两种主要的配置文件格式。
- Properties格式
- YAML格式
Properties是传统的Java配置文件格式,使用键值对方式:
1# 服务器配置2server.port=80803server.servlet.context-path=/api45# 数据源配置6spring.datasource.url=jdbc:mysql://localhost:3306/mydb7spring.datasource.username=user8spring.datasource.password=password9spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver1011# JPA配置12spring.jpa.hibernate.ddl-auto=update13spring.jpa.show-sql=true14spring.jpa.properties.hibernate.format_sql=true1516# 自定义属性17app.name=My Spring Boot App18app.description=A sample Spring Boot application19app.version=1.0.0Properties格式特点
优点:
- 传统格式,兼容性好
- 工具支持广泛
- 语法简单直观
缺点:
- 层次结构不直观
- 不支持复杂数据类型
- 配置项多时不易维护
YAML格式更现代化,支持层次结构,更易于阅读和维护:
1# 服务器配置2server:3 port: 80804 servlet:5 context-path: /api67 # 数据源配置8spring:9 datasource:10 url: jdbc:mysql://localhost:3306/mydb11 username: user12 password: password13 driver-class-name: com.mysql.cj.jdbc.Driver14 15 # JPA配置16 jpa:17 hibernate:18 ddl-auto: update19 show-sql: true20 properties:21 hibernate:22 format_sql: true23 24 # 自定义属性25 app:26 name: My Spring Boot App27 description: A sample Spring Boot application28 version: 1.0.029 30 # 复杂类型示例31 security:32 enabled: true33 roles:34 - USER35 - ADMIN36 rate-limits:37 basic: 1038 premium: 100YAML格式特点
优点:
- 层次结构清晰
- 支持复杂数据类型(列表、映射等)
- 支持文档分隔符(可在同一文件中定义多环境配置)
- 减少重复前缀
- 支持引用和锚点
缺点:
- 对缩进敏感
- 语法相对复杂
3.2 多环境配置
Spring Boot通过profiles机制支持多环境配置,可以根据不同的环境(如开发、测试、生产)加载不同的配置。
- 多Profile配置
- 单文件多Profile
- Profile激活方式
使用不同文件配置不同环境:
1spring:2 application:3 name: my-application45logging:6level:7 root: INFO1spring:2 datasource:3 url: jdbc:h2:mem:devdb4 username: sa5 password: 6 7logging:8 level:9 com.example: DEBUG1spring:2 datasource:3 url: jdbc:mysql://prod-server:3306/proddb4 username: produser5 password: prodpass6 7logging:8 level:9 root: WARN10 com.example: INFO在同一个YAML文件中使用文档分隔符(---)配置不同环境:
1# 默认配置2spring:3 application:4 name: my-application5 6logging:7 level:8 root: INFO9 10---11# 开发环境配置12spring:13 config:14 activate:15 on-profile: dev16datasource:17 url: jdbc:h2:mem:devdb18 username: sa19 password: 2021logging:22level:23 com.example: DEBUG2425---26# 生产环境配置27spring:28 config:29 activate:30 on-profile: prod31datasource:32 url: jdbc:mysql://prod-server:3306/proddb33 username: produser34 password: prodpass3536logging:37level:38 root: WARN39 com.example: INFO有多种方式可以激活特定的profile:
1spring:2 profiles:3 active: dev1# 使用--spring.profiles.active激活指定的profile2java -jar myapp.jar --spring.profiles.active=dev1# 使用SPRING_PROFILES_ACTIVE环境变量2export SPRING_PROFILES_ACTIVE=dev3java -jar myapp.jar1public static void main(String[] args) {2 SpringApplication application = new SpringApplication(MyApplication.class);3 application.setAdditionalProfiles("dev");4 application.run(args);5}Profile激活优先级
激活Profile的优先级(从高到低):
- 命令行参数:
--spring.profiles.active=dev - 测试中通过
@ActiveProfiles注解激活 - JVM系统属性:
-Dspring.profiles.active=dev - 环境变量:
SPRING_PROFILES_ACTIVE=dev application.properties或application.yml文件中的spring.profiles.active属性
3.3 配置属性绑定
Spring Boot提供了强大的属性绑定机制,可以将配置文件中的属性绑定到Java对象。
- @Value注解
- @ConfigurationProperties
- @EnableConfigurationProperties
@Value注解是属性注入的基本方式,用于单个属性的注入:
1@RestController2public class AppController {3 4 @Value("${app.name}")5 private String appName;6 7 @Value("${app.description:Default description}") // 提供默认值8 private String appDescription;9 10 @Value("${server.port}")11 private int serverPort;12 13 @Value("${app.enabled:false}") // 默认为false14 private boolean appEnabled;15 16 @Value("${app.list-values}")17 private String[] listValues;18 19 @Value("#{${app.map-values}}") // 注入Map需要SpEL表达式20 private Map<String, Integer> mapValues;21 22 @GetMapping("/config")23 public Map<String, Object> getConfig() {24 Map<String, Object> config = new HashMap<>();25 config.put("name", appName);26 config.put("description", appDescription);27 config.put("port", serverPort);28 config.put("enabled", appEnabled);29 config.put("listValues", listValues);30 config.put("mapValues", mapValues);31 return config;32 }33}@ConfigurationProperties注解用于绑定相关配置到一个Java Bean,适合批量属性绑定:
1@Component2@ConfigurationProperties(prefix = "app")3public class AppProperties {4 5 private String name;6 private String description;7 private String version;8 private boolean enabled;9 private List<String> listValues = new ArrayList<>();10 private Map<String, Integer> mapValues = new HashMap<>();11 12 // 嵌套配置13 private Security security = new Security();14 15 // getter和setter方法...16 17 public static class Security {18 private boolean enabled;19 private List<String> roles = new ArrayList<>();20 private Map<String, Integer> rateLimits = new HashMap<>();21 22 // getter和setter方法...23 }24}1@Service2public class AppService {3 4 private final AppProperties appProperties;5 6 public AppService(AppProperties appProperties) {7 this.appProperties = appProperties;8 }9 10 public void doSomething() {11 if (appProperties.isEnabled()) {12 // 使用配置属性...13 System.out.println("App name: " + appProperties.getName());14 System.out.println("Security enabled: " + 15 appProperties.getSecurity().isEnabled());16 }17 }18}使用@EnableConfigurationProperties注解可以在不使用@Component的情况下创建配置属性类的Bean:
1@Configuration2@EnableConfigurationProperties(MyServiceProperties.class)3public class MyServiceConfiguration {4 5 @Bean6 public MyService myService(MyServiceProperties properties) {7 return new MyService(properties.getApiUrl(), 8 properties.getTimeout(), 9 properties.isSecure());10 }11}1213@ConfigurationProperties(prefix = "service")14public class MyServiceProperties {15 16 /**17 * Service API URL.18 */19 private String apiUrl;20 21 /**22 * Connection timeout in milliseconds.23 */24 private int timeout = 1000;25 26 /**27 * Whether to use secure connection.28 */29 private boolean secure = false;30 31 // getter和setter方法...32}@ConfigurationProperties vs @Value
| 特性 | @ConfigurationProperties | @Value |
|---|---|---|
| 松散绑定 | 支持(如my-service-url绑定到myServiceUrl) | 不支持 |
| 元数据支持 | 支持(可生成配置元数据) | 不支持 |
| 复杂类型 | 支持嵌套对象、列表、Map等 | 有限支持 |
| 默认值 | 在类中定义 | 在注解中定义 |
| 批量导入 | 一个类绑定多个属性 | 每个属性单独绑定 |
| 表达式语言 | 不支持 | 支持SpEL |
| 属性转换 | 自动类型转换 | 有限的类型转换 |
| 校验 | 支持JSR-303注解 | 不支持 |
Spring Boot配置的优先级从高到低:
- 命令行参数
- Java系统属性(
System.getProperties()) - 操作系统环境变量
application-{profile}.properties外部文件application.properties外部文件application-{profile}.properties内部文件application.properties内部文件@PropertySource注解引入的属性文件- 默认属性
3.4 属性加密与敏感信息
在实际应用中,配置文件可能包含敏感信息(如数据库密码、API密钥等),Spring Boot提供了多种方式处理敏感配置:
1// 添加Jasypt依赖2// implementation 'com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.4'34@SpringBootApplication5@EnableEncryptableProperties6public class MyApplication {7 8 public static void main(String[] args) {9 SpringApplication.run(MyApplication.class, args);10 }11}1spring:2 datasource:3 url: jdbc:mysql://localhost:3306/mydb4 username: dbuser5 # 加密的密码6 password: ENC(G5n+K5LQum+dFiNbgd+F5kAm0FyYpaIP)1# 加密密码2java -jar jasypt-1.9.3.jar encrypt.bat input=mypassword password=mysecretkey4. Spring Boot启动流程
Spring Boot启动过程是一个复杂而精巧的流程,其中包含了多个关键步骤和事件。
🚀 启动流程:Spring Boot应用启动时会经历创建SpringApplication对象、准备环境、创建上下文、加载Bean定义和刷新上下文等一系列步骤,每个步骤都有特定的作用和事件通知机制。
4.1 启动流程详解
Spring Boot的启动流程可以分为以下几个关键步骤:
Spring Boot启动流程步骤
-
创建SpringApplication对象
- 推断应用类型(SERVLET、REACTIVE、NONE)
- 设置初始化器(ApplicationContextInitializer)
- 设置监听器(ApplicationListener)
- 推断主应用类
-
运行SpringApplication
- 创建并启动StopWatch(用于记录启动时间)
- 创建应用上下文环境(ConfigurableEnvironment)
- 准备上下文(ApplicationContext)
- 刷新上下文
- 应用上下文后置处理
- 发布应用启动完成事件
-
准备Environment
- 创建和配置环境对象
- 读取所有配置源的配置属性
- 处理profiles
-
创建ApplicationContext
- 根据应用类型创建对应的上下文
- SERVLET类型:
AnnotationConfigServletWebServerApplicationContext - REACTIVE类型:
AnnotationConfigReactiveWebServerApplicationContext - 非Web应用:
AnnotationConfigApplicationContext
- SERVLET类型:
- 根据应用类型创建对应的上下文
-
刷新ApplicationContext
- 处理Bean定义
- 初始化非延迟加载的单例Bean
- 启动嵌入式Web服务器(如果是Web应用)
-
执行Runner
- 按顺序执行所有
CommandLineRunner和ApplicationRunner
- 按顺序执行所有
SpringApplication启动源码分析
1public ConfigurableApplicationContext run(String... args) {2 StopWatch stopWatch = new StopWatch();3 stopWatch.start();4 ConfigurableApplicationContext context = null;5 Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();6 7 // 1. 配置headless属性8 configureHeadlessProperty();9 10 // 2. 获取并启动所有的SpringApplicationRunListener11 SpringApplicationRunListeners listeners = getRunListeners(args);12 listeners.starting();13 14 try {15 // 3. 创建ApplicationArguments对象16 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);17 18 // 4. 准备环境19 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);20 configureIgnoreBeanInfo(environment);21 22 // 5. 打印Banner23 Banner printedBanner = printBanner(environment);24 25 // 6. 创建ApplicationContext26 context = createApplicationContext();27 28 // 7. 获取异常报告器29 exceptionReporters = getSpringFactoriesInstances(30 SpringBootExceptionReporter.class,31 new Class[] { ConfigurableApplicationContext.class }, context);32 33 // 8. 准备上下文34 prepareContext(context, environment, listeners, applicationArguments, printedBanner);35 36 // 9. 刷新上下文37 refreshContext(context);38 39 // 10. 刷新上下文后的操作40 afterRefresh(context, applicationArguments);41 42 // 11. 停止计时器并输出启动日志43 stopWatch.stop();44 if (this.logStartupInfo) {45 new StartupInfoLogger(this.mainApplicationClass)46 .logStarted(getApplicationLog(), stopWatch);47 }48 49 // 12. 发布应用已启动事件50 listeners.started(context);51 52 // 13. 调用所有Runner53 callRunners(context, applicationArguments);54 }55 catch (Throwable ex) {56 handleRunFailure(context, ex, exceptionReporters, listeners);57 throw new IllegalStateException(ex);58 }59 60 try {61 // 14. 发布应用就绪事件62 listeners.running(context);63 }64 catch (Throwable ex) {65 handleRunFailure(context, ex, exceptionReporters, null);66 throw new IllegalStateException(ex);67 }68 69 // 15. 返回上下文70 return context;71}4.2 事件监听机制
Spring Boot启动过程中会发布一系列事件,应用可以通过监听这些事件来执行特定的操作。
- 事件监听器
- 运行器
Spring Boot支持两种方式注册事件监听器:
1@Component2public class MyApplicationStartingListener 3 implements ApplicationListener<ApplicationStartingEvent> {4 5 private static final Logger logger = LoggerFactory.getLogger(MyApplicationStartingListener.class);6 7 @Override8 public void onApplicationEvent(ApplicationStartingEvent event) {9 logger.info("应用正在启动...");10 // 在应用启动开始时执行一些操作11 }12}1@Component2public class MyEventListener {3 4 private static final Logger logger = LoggerFactory.getLogger(MyEventListener.class);5 6 @EventListener7 public void handleApplicationReady(ApplicationReadyEvent event) {8 logger.info("应用已准备就绪!");9 // 应用准备就绪时执行一些操作10 }11 12 @EventListener13 public void handleContextRefreshed(ContextRefreshedEvent event) {14 logger.info("上下文已刷新!");15 // 上下文刷新时执行一些操作16 }17}对于在Spring上下文创建之前触发的事件(如ApplicationStartingEvent),监听器不能通过@Component注册,必须通过META-INF/spring.factories文件或在SpringApplication.addListeners()方法中显式添加。
1# 注册早期事件监听器2org.springframework.context.ApplicationListener=\3com.example.MyApplicationStartingListener,\4com.example.MyEnvironmentPreparedListenerSpring Boot提供了两种类型的运行器接口,用于在应用上下文刷新后、应用完全启动前执行代码:
1@Component2@Order(1) // 较低的数值意味着更高的优先级3public class MyCommandLineRunner implements CommandLineRunner {4 5 private final Logger logger = LoggerFactory.getLogger(getClass());6 7 @Override8 public void run(String... args) throws Exception {9 logger.info("在应用启动时执行,命令行参数:{}", Arrays.toString(args));10 // 初始化操作...11 }12}1@Component2@Order(2)3public class MyApplicationRunner implements ApplicationRunner {4 5 private final Logger logger = LoggerFactory.getLogger(getClass());6 7 @Override8 public void run(ApplicationArguments args) throws Exception {9 logger.info("在应用启动时执行");10 logger.info("选项参数: {}", args.getOptionNames());11 logger.info("非选项参数: {}", args.getNonOptionArgs());12 // 初始化操作...13 }14}Runner对比
| 特性 | CommandLineRunner | ApplicationRunner |
|---|---|---|
| 参数类型 | 原始字符串数组 | ApplicationArguments接口 |
| 参数处理 | 需要手动解析 | 已经解析好的参数 |
| 执行顺序 | @Order控制 | @Order控制 |
| 适用场景 | 简单参数处理 | 复杂参数处理 |
4.3 嵌入式容器启动
对于Web应用,Spring Boot会在启动过程中自动配置和启动嵌入式Web服务器。
1// ServletWebServerApplicationContext类中的createWebServer方法2private void createWebServer() {3 WebServer webServer = this.webServer;4 ServletContext servletContext = getServletContext();5 6 if (webServer == null && servletContext == null) {7 // 获取ServletWebServerFactory8 ServletWebServerFactory factory = getWebServerFactory();9 10 // 创建WebServer11 this.webServer = factory.getWebServer(getSelfInitializer());12 13 // 注册特殊的Bean14 getBeanFactory().registerSingleton("webServerGracefulShutdown",15 new WebServerGracefulShutdownLifecycle(this.webServer));16 getBeanFactory().registerSingleton("webServerStartStop",17 new WebServerStartStopLifecycle(this, this.webServer));18 }19 else if (servletContext != null) {20 try {21 getSelfInitializer().onStartup(servletContext);22 }23 catch (ServletException ex) {24 throw new ApplicationContextException("Cannot initialize servlet context", ex);25 }26 }27 28 // 初始化属性源29 initPropertySources();30}4.4 自动配置的处理
在Spring Boot启动过程中,自动配置是一个重要的环节,它发生在ApplicationContext刷新阶段。
自动配置的核心过程:
- 在应用上下文刷新阶段,处理配置类上的
@Import注解 - 检测到
@EnableAutoConfiguration注解,调用AutoConfigurationImportSelector AutoConfigurationImportSelector从META-INF/spring.factories中加载自动配置类- 对这些自动配置类应用条件过滤(
@ConditionalOnXXX) - 将筛选后的自动配置类注册为Bean定义
- 在Bean初始化阶段创建和配置这些Bean
5. 起步依赖
Spring Boot的起步依赖是一组精心设计的依赖描述符,用于简化依赖管理。
📦 起步依赖:Spring Boot的起步依赖是一种特殊的Maven依赖,它可以传递引入所有需要的依赖项,简化项目的依赖管理,保证依赖版本的兼容性。
5.1 起步依赖原理
Spring Boot起步依赖的核心原理是通过Maven的依赖传递机制,将一组相关的依赖聚合在一起,形成针对特定功能的依赖集合。
起步依赖的工作原理
- 依赖聚合:将一组相关的依赖项聚合在一个POM文件中
- 依赖传递:通过Maven的依赖传递机制,将所有必要的依赖项引入项目
- 版本管理:通过
spring-boot-dependencies统一管理所有依赖项的版本 - 自动配置:与自动配置机制结合,根据依赖自动配置应用
1<dependency>2 <groupId>org.springframework.boot</groupId>3 <artifactId>spring-boot-starter-parent</artifactId>4 <version>2.7.0</version>5 <type>pom</type>6 <scope>import</scope>7</dependency>1<dependency>2 <groupId>org.springframework.boot</groupId>3 <artifactId>spring-boot-starter-web</artifactId>4</dependency>56<!-- 这个依赖会传递性地引入以下依赖 -->7<!-- spring-boot-starter(核心启动器) -->8<!-- spring-boot-starter-json(JSON支持) -->9<!-- spring-boot-starter-tomcat(Tomcat服务器) -->10<!-- spring-web(Spring Web核心) -->11<!-- spring-webmvc(Spring MVC) -->12<!-- ... 以及其他传递性依赖 -->5.2 常用起步依赖
Spring Boot提供了许多常用的起步依赖,涵盖了不同的应用场景和功能。
- Web应用
- 数据访问
- 测试支持
- 其他起步依赖
1<!-- Spring MVC Web应用 -->2<dependency>3 <groupId>org.springframework.boot</groupId>4 <artifactId>spring-boot-starter-web</artifactId>5</dependency>67<!-- 响应式Web应用 -->8<dependency>9 <groupId>org.springframework.boot</groupId>10 <artifactId>spring-boot-starter-webflux</artifactId>11</dependency>1213<!-- WebSocket支持 -->14<dependency>15 <groupId>org.springframework.boot</groupId>16 <artifactId>spring-boot-starter-websocket</artifactId>17</dependency>1819<!-- 安全支持 -->20<dependency>21 <groupId>org.springframework.boot</groupId>22 <artifactId>spring-boot-starter-security</artifactId>23</dependency>Web起步依赖特点
spring-boot-starter-web包含:
- Spring MVC
- 内嵌Tomcat服务器
- Jackson JSON处理
- 验证框架
- 日志和监控
spring-boot-starter-webflux包含:
- Spring WebFlux(响应式Web框架)
- Netty或Undertow服务器
- Reactive Streams支持
spring-boot-starter-security包含:
- Spring Security
- 认证和授权支持
- 安全过滤器链
1<!-- JPA数据访问 -->2 <dependency>3 <groupId>org.springframework.boot</groupId>4 <artifactId>spring-boot-starter-data-jpa</artifactId>5 </dependency>67<!-- JDBC数据访问 -->8 <dependency>9 <groupId>org.springframework.boot</groupId>10 <artifactId>spring-boot-starter-jdbc</artifactId>11 </dependency>12 13<!-- MongoDB数据访问 -->14<dependency>15 <groupId>org.springframework.boot</groupId>16 <artifactId>spring-boot-starter-data-mongodb</artifactId>17</dependency>1819<!-- Redis数据访问 -->20<dependency>21 <groupId>org.springframework.boot</groupId>22 <artifactId>spring-boot-starter-data-redis</artifactId>23</dependency>2425<!-- ElasticSearch数据访问 -->26<dependency>27 <groupId>org.springframework.boot</groupId>28 <artifactId>spring-boot-starter-data-elasticsearch</artifactId>29</dependency>数据访问依赖特点
spring-boot-starter-data-jpa包含:
- Hibernate
- Spring Data JPA
- 事务管理
- 连接池(默认HikariCP)
spring-boot-starter-jdbc包含:
- 基本JDBC支持
- 事务管理
- 连接池
spring-boot-starter-data-redis包含:
- Lettuce或Jedis客户端
- Spring Data Redis
- 连接池管理
1<dependency>2 <groupId>org.springframework.boot</groupId>3 <artifactId>spring-boot-starter-test</artifactId>4 <scope>test</scope>5</dependency>测试起步依赖内容
spring-boot-starter-test包含:
- JUnit 5
- Spring Test
- AssertJ
- Hamcrest
- Mockito
- JSONassert
- JsonPath
提供全面的测试支持,包括:
- 单元测试
- 集成测试
- Spring MVC测试
- JSON测试
- 模拟对象
1<!-- 监控和管理 -->2<dependency>3 <groupId>org.springframework.boot</groupId>4 <artifactId>spring-boot-starter-actuator</artifactId>5</dependency>67<!-- AOP支持 -->8<dependency>9 <groupId>org.springframework.boot</groupId>10 <artifactId>spring-boot-starter-aop</artifactId>11</dependency>1213<!-- 缓存支持 -->14<dependency>15 <groupId>org.springframework.boot</groupId>16 <artifactId>spring-boot-starter-cache</artifactId>17</dependency>1819<!-- 邮件发送 -->20<dependency>21 <groupId>org.springframework.boot</groupId>22 <artifactId>spring-boot-starter-mail</artifactId>23</dependency>2425<!-- 消息队列 -->26<dependency>27 <groupId>org.springframework.boot</groupId>28 <artifactId>spring-boot-starter-amqp</artifactId>29</dependency>常用起步依赖表
| 起步依赖 | 主要功能 | 主要组件 |
|---|---|---|
| spring-boot-starter | 核心依赖 | 自动配置、日志、YAML |
| spring-boot-starter-web | Web应用 | Spring MVC、Tomcat |
| spring-boot-starter-data-jpa | JPA数据访问 | Hibernate、Spring Data JPA |
| spring-boot-starter-security | 安全框架 | Spring Security |
| spring-boot-starter-test | 测试支持 | JUnit、Mockito、Spring Test |
| spring-boot-starter-actuator | 监控管理 | Actuator端点、Micrometer |
| spring-boot-starter-aop | 面向切面编程 | Spring AOP、AspectJ |
| spring-boot-starter-webflux | 响应式编程 | Spring WebFlux、Reactor |
5.3 自定义起步依赖
在实际项目中,你可能需要创建自己的起步依赖,以统一项目或团队的依赖管理。
- 自动配置模块
- 起步依赖模块
- 注册自动配置
- 使用自定义起步依赖
1<project>2 <modelVersion>4.0.0</modelVersion>3 <groupId>com.example</groupId>4 <artifactId>example-spring-boot-autoconfigure</artifactId>5 <version>1.0.0</version>6 <name>Example Spring Boot Autoconfigure</name>7 8 <dependencies>9 <dependency>10 <groupId>org.springframework.boot</groupId>11 <artifactId>spring-boot-autoconfigure</artifactId>12 </dependency>13 14 <!-- 可选依赖,用于配置属性处理 -->15 <dependency>16 <groupId>org.springframework.boot</groupId>17 <artifactId>spring-boot-configuration-processor</artifactId>18 <optional>true</optional>19 </dependency>20 21 <!-- 核心功能依赖 -->22 <dependency>23 <groupId>com.example</groupId>24 <artifactId>example-library</artifactId>25 <version>1.0.0</version>26 </dependency>27</dependencies>28</project>1@ConfigurationProperties(prefix = "example")2public class ExampleProperties {3 4 /**5 * 是否启用该功能6 */7 private boolean enabled = true;8 9 /**10 * API基础URL11 */12 private String baseUrl = "https://api.example.com";13 14 /**15 * 连接超时时间(毫秒)16 */17 private int timeout = 3000;18 19 // getter和setter方法20}1@Configuration2@ConditionalOnClass(ExampleService.class)3@EnableConfigurationProperties(ExampleProperties.class)4public class ExampleAutoConfiguration {5 6 private final ExampleProperties properties;7 8 public ExampleAutoConfiguration(ExampleProperties properties) {9 this.properties = properties;10 }11 12 @Bean13 @ConditionalOnMissingBean14 @ConditionalOnProperty(prefix = "example", name = "enabled", havingValue = "true", matchIfMissing = true)15 public ExampleService exampleService() {16 ExampleService service = new ExampleService();17 service.setBaseUrl(properties.getBaseUrl());18 service.setTimeout(properties.getTimeout());19 return service;20 }21 22 @Bean23 @ConditionalOnMissingBean24 @ConditionalOnBean(ExampleService.class)25 public ExampleClient exampleClient(ExampleService service) {26 return new ExampleClient(service);27 }28}1<project>2 <modelVersion>4.0.0</modelVersion>3 <groupId>com.example</groupId>4 <artifactId>example-spring-boot-starter</artifactId>5 <version>1.0.0</version>6 <name>Example Spring Boot Starter</name>7 8 <dependencies>9 <!-- 依赖自动配置模块 -->10 <dependency>11 <groupId>com.example</groupId>12 <artifactId>example-spring-boot-autoconfigure</artifactId>13 <version>1.0.0</version>14 </dependency>15 16 <!-- 其他必要的依赖 -->17 <dependency>18 <groupId>com.example</groupId>19 <artifactId>example-library</artifactId>20 <version>1.0.0</version>21 </dependency>22 23 <!-- 可能需要的其他依赖 -->24 <dependency>25 <groupId>org.apache.commons</groupId>26 <artifactId>commons-lang3</artifactId>27 </dependency>28 </dependencies>29</project>1# Auto Configure2org.springframework.boot.autoconfigure.EnableAutoConfiguration=\3com.example.ExampleAutoConfiguration1{2 "groups": [3 {4 "name": "example",5 "type": "com.example.ExampleProperties",6 "sourceType": "com.example.ExampleProperties"7 }8 ],9 "properties": [10 {11 "name": "example.enabled",12 "type": "java.lang.Boolean",13 "description": "是否启用该功能",14 "sourceType": "com.example.ExampleProperties",15 "defaultValue": true16 },17 {18 "name": "example.base-url",19 "type": "java.lang.String",20 "description": "API基础URL",21 "sourceType": "com.example.ExampleProperties",22 "defaultValue": "https://api.example.com"23 },24 {25 "name": "example.timeout",26 "type": "java.lang.Integer",27 "description": "连接超时时间(毫秒)",28 "sourceType": "com.example.ExampleProperties",29 "defaultValue": 300030 }31 ]32}1<dependencies>2 <!-- 引入自定义起步依赖 -->3 <dependency>4 <groupId>com.example</groupId>5 <artifactId>example-spring-boot-starter</artifactId>6 <version>1.0.0</version>7 </dependency>8</dependencies>1# 在application.yml中配置2example:3 enabled: true4 base-url: https://api.mycompany.com/v15 timeout: 50001@Service2public class MyService {3 4 private final ExampleClient exampleClient;5 6 public MyService(ExampleClient exampleClient) {7 this.exampleClient = exampleClient;8 }9 10 public void doSomething() {11 // 使用自动配置的客户端12 exampleClient.callApi();13 }14}创建自定义起步依赖时,应遵循以下最佳实践:
- 分离自动配置模块和起步依赖模块,使得用户可以选择性使用自动配置
- 使用条件注解避免强制配置,允许用户覆盖默认配置
- 提供配置属性类,允许用户通过配置文件自定义行为
- 生成元数据,提供良好的IDE支持
- 遵循命名约定:
xxx-spring-boot-autoconfigure和xxx-spring-boot-starter - 不要将
spring-boot-starter-*作为依赖的名称(避免与官方起步依赖混淆)
6. 监控与管理
Spring Boot Actuator是Spring Boot的一个子项目,提供了生产就绪特性,帮助你监控和管理应用。
📊 Actuator:Spring Boot Actuator提供了监控和管理Spring Boot应用程序的生产就绪功能,包括健康检查、指标收集、环境信息和HTTP跟踪等。
6.1 Actuator基础配置
Spring Boot Actuator提供了一系列的HTTP端点,可以用来监控和管理应用程序。
- 基础配置
- 安全配置
- 自定义信息
1<dependency>2 <groupId>org.springframework.boot</groupId>3 <artifactId>spring-boot-starter-actuator</artifactId>4</dependency>1management:2endpoints:3 web:4 exposure:5 # 暴露所有端点6 include: "*"7 # 排除敏感端点8 exclude: "env,beans"9endpoint:10 health:11 show-details: always12 shutdown:13 enabled: true14 info:15 env:16 enabled: trueActuator端点访问
默认情况下,所有端点都通过HTTP暴露在/actuator路径下:
/actuator/health- 应用健康状态/actuator/info- 应用信息/actuator/metrics- 应用指标/actuator/env- 环境变量/actuator/mappings- 请求映射/actuator/beans- 应用中的所有Bean/actuator/configprops- 配置属性/actuator/loggers- 日志级别管理
Actuator端点包含敏感信息,在生产环境中应该进行安全保护:
1<dependency>2 <groupId>org.springframework.boot</groupId>3 <artifactId>spring-boot-starter-security</artifactId>4</dependency>1@Configuration2public class ActuatorSecurityConfig extends WebSecurityConfigurerAdapter {3 4 @Override5 protected void configure(HttpSecurity http) throws Exception {6 http7 .csrf().disable()8 .authorizeRequests()9 // 允许所有人访问健康检查和信息10 .antMatchers("/actuator/health", "/actuator/info").permitAll()11 // 其他Actuator端点需要ADMIN角色12 .antMatchers("/actuator/**").hasRole("ADMIN")13 .anyRequest().authenticated()14 .and()15 .httpBasic();16 }17}1spring:2 security:3 user:4 name: admin5 password: secret6 roles: ADMIN你可以通过多种方式自定义应用信息:
1info:2 app:3 name: "My Spring Boot App"4 description: "A sample Spring Boot application"5 version: "1.0.0"6 java:7 version: "${java.version}"8 spring:9 framework:10 version: "${spring-framework.version}"11 boot:12 version: "${spring-boot.version}"13 build:14 artifact: "@project.artifactId@"15 name: "@project.name@"16 description: "@project.description@"17 version: "@project.version@"1@Component2public class CustomInfoContributor implements InfoContributor {3 4 @Override5 public void contribute(Info.Builder builder) {6 Map<String, Object> details = new HashMap<>();7 details.put("serverTime", new Date());8 details.put("serverIp", getServerIp());9 details.put("activeProfiles", getActiveProfiles());10 11 builder.withDetail("serverInfo", details);12 }13 14 // 实现细节...15}6.2 健康检查
健康检查是Actuator的核心功能,用于监控应用及其依赖的状态。
1@Component2public class CustomHealthIndicator implements HealthIndicator {3 4 @Override5 public Health health() {6 boolean isHealthy = checkHealth(); // 自定义健康检查逻辑7 8 if (isHealthy) {9 return Health.up()10 .withDetail("message", "服务运行正常")11 .withDetail("timestamp", System.currentTimeMillis())12 .build();13 } else {14 return Health.down()15 .withDetail("message", "服务异常")16 .withDetail("timestamp", System.currentTimeMillis())17 .withDetail("error", "具体错误信息")18 .build();19 }20 }21 22 private boolean checkHealth() {23 // 实现健康检查逻辑24 try {25 // 检查关键服务是否可用26 // 例如:数据库连接、缓存连接、外部服务调用等27 return true;28 } catch (Exception e) {29 return false;30 }31 }32}6.3 度量指标
Spring Boot 2.x引入了Micrometer作为应用指标门面,支持多种监控系统,如Prometheus、InfluxDB、New Relic等。
- Micrometer基础
- 自定义指标
- 切面指标
1<dependency>2 <groupId>io.micrometer</groupId>3 <artifactId>micrometer-registry-prometheus</artifactId>4</dependency>1management:2 endpoints:3 web:4 exposure:5 include: prometheus6 metrics:7 export:8 prometheus:9 enabled: true1scrape_configs:2 - job_name: 'spring-boot-app'3 scrape_interval: 5s4 metrics_path: '/actuator/prometheus'5 static_configs:6 - targets: ['localhost:8080']1@Service2public class OrderService {3 4 private final Counter orderCounter;5 private final DistributionSummary orderSummary;6 7 public OrderService(MeterRegistry registry) {8 this.orderCounter = registry.counter("app.orders.created");9 this.orderSummary = registry.summary("app.orders.amount");10 }11 12 public void createOrder(Order order) {13 // 处理订单逻辑14 15 // 增加订单计数16 orderCounter.increment();17 18 // 记录订单金额19 orderSummary.record(order.getAmount());20 }21}1@Service2public class ProductService {3 4 private final Timer searchTimer;5 6 public ProductService(MeterRegistry registry) {7 this.searchTimer = registry.timer("app.product.search");8 }9 10 public List<Product> searchProducts(String keyword) {11 // 使用计时器记录方法执行时间12 return searchTimer.record(() -> {13 // 执行产品搜索逻辑14 return findProductsByKeyword(keyword);15 });16 }17 18 // 也可以使用Timer.Sample手动控制19 public List<Product> listProducts() {20 Timer.Sample sample = Timer.start(registry);21 try {22 // 执行获取产品列表逻辑23 return getAllProducts();24 } finally {25 sample.stop(registry.timer("app.product.list"));26 }27 }28}1@Aspect2@Component3public class TimedAspect {4 5 private final MeterRegistry registry;6 7 public TimedAspect(MeterRegistry registry) {8 this.registry = registry;9 }10 11 @Around("@annotation(timed)")12 public Object timeMethod(ProceedingJoinPoint joinPoint, Timed timed) throws Throwable {13 String metricName = timed.value().isEmpty() 14 ? joinPoint.getSignature().toShortString() 15 : timed.value();16 17 Timer.Sample sample = Timer.start(registry);18 try {19 return joinPoint.proceed();20 } finally {21 sample.stop(Timer.builder(metricName)22 .description(timed.description())23 .tags(timed.extraTags())24 .register(registry));25 }26 }27}2829@Target({ElementType.METHOD})30@Retention(RetentionPolicy.RUNTIME)31public @interface Timed {32 String value() default "";33 String description() default "";34 String[] extraTags() default {};35}1@Service2public class ReportService {3 4 @Timed(value = "app.report.generation", description = "Report generation time")5 public byte[] generateReport(ReportRequest request) {6 // 生成报表逻辑7 return reportData;8 }9}6.4 自定义端点
你可以创建自己的Actuator端点来暴露特定于应用的信息或操作。
1@Component2@Endpoint(id = "application-status")3public class ApplicationStatusEndpoint {4 5 private final StatusService statusService;6 7 public ApplicationStatusEndpoint(StatusService statusService) {8 this.statusService = statusService;9 }10 11 @ReadOperation12 public Map<String, Object> status() {13 Map<String, Object> status = new HashMap<>();14 status.put("status", statusService.getStatus());15 status.put("uptime", statusService.getUptime());16 status.put("startTime", statusService.getStartTime());17 status.put("activeSessions", statusService.getActiveSessions());18 status.put("systemLoad", statusService.getSystemLoad());19 return status;20 }21 22 @WriteOperation23 public Map<String, String> updateStatus(@Selector String action) {24 Map<String, String> result = new HashMap<>();25 switch (action) {26 case "pause":27 statusService.pauseProcessing();28 result.put("result", "Processing paused");29 break;30 case "resume":31 statusService.resumeProcessing();32 result.put("result", "Processing resumed");33 break;34 default:35 result.put("error", "Unknown action: " + action);36 }37 return result;38 }39}7. 部署与打包
Spring Boot提供了多种灵活的部署选项,从传统的WAR部署到现代的容器化部署。
📦 Spring Boot打包:Spring Boot应用可以打包成可执行的JAR或WAR文件,包含所有依赖和嵌入式服务器,实现"一次构建,到处运行"。
7.1 打包选项
- 可执行JAR
- 传统WAR
- Docker容器
1<build>2 <plugins>3 <plugin>4 <groupId>org.springframework.boot</groupId>5 <artifactId>spring-boot-maven-plugin</artifactId>6 <configuration>7 <executable>true</executable>8 <excludes>9 <exclude>10 <groupId>org.projectlombok</groupId>11 <artifactId>lombok</artifactId>12 </exclude>13 </excludes>14 </configuration>15 </plugin>16 </plugins>17</build>1# Maven打包2mvn clean package34# 运行JAR5java -jar target/myapp-0.0.1-SNAPSHOT.jar可执行JAR特点
- 包含应用的所有代码和依赖
- 内置嵌入式Web服务器
- 无需额外安装Tomcat等容器
- 可以直接通过
java -jar命令运行 - 支持命令行参数配置
1<packaging>war</packaging>23<dependencies>4 <!-- 将内嵌Tomcat标记为provided -->5 <dependency>6 <groupId>org.springframework.boot</groupId>7 <artifactId>spring-boot-starter-tomcat</artifactId>8 <scope>provided</scope>9 </dependency>10</dependencies>1112<build>13 <plugins>14 <plugin>15 <groupId>org.springframework.boot</groupId>16 <artifactId>spring-boot-maven-plugin</artifactId>17 </plugin>18 </plugins>19</build>1public class ServletInitializer extends SpringBootServletInitializer {2 3 @Override4 protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {5 return application.sources(MyApplication.class);6 }7}WAR特点
- 可以部署到外部Servlet容器(如Tomcat、JBoss)
- 适合传统Java EE环境
- 可以与其他WAR应用共享同一个容器
- 可以利用外部容器的高级功能
1FROM openjdk:11-jre-slim23WORKDIR /app45COPY target/*.jar app.jar67# JVM调优参数8ENV JAVA_OPTS="-Xmx512m -Xms256m"910# 定义变量,方便运行时覆盖11ENV SPRING_PROFILES_ACTIVE=prod12ENV SERVER_PORT=80801314EXPOSE $SERVER_PORT1516# 启动命令17ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar --spring.profiles.active=$SPRING_PROFILES_ACTIVE --server.port=$SERVER_PORT"]1# 构建镜像2docker build -t myapp:latest .34# 运行容器5docker run -p 8080:8080 -e "SPRING_PROFILES_ACTIVE=prod" myapp:latest1version: '3'2services:3 app:4 image: myapp:latest5 ports:6 - "8080:8080"7 environment:8 - SPRING_PROFILES_ACTIVE=prod9 - SERVER_PORT=808010 depends_on:11 - db12 networks:13 - app-network14 15 db:16 image: mysql:8.017 ports:18 - "3306:3306"19 environment:20 - MYSQL_ROOT_PASSWORD=root21 - MYSQL_DATABASE=myapp22 volumes:23 - mysql-data:/var/lib/mysql24 networks:25 - app-network2627volumes:28 mysql-data:2930networks:31 app-network:7.2 部署方式
Spring Boot应用支持多种部署方式,从传统到云原生:
部署方式比较
| 部署方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 独立JAR部署 | 简单、自包含 | 资源隔离弱 | 简单应用、开发环境 |
| 传统服务器部署 | 利用服务器高级特性 | 配置复杂 | 传统企业环境 |
| Docker容器化 | 环境一致性、隔离性好 | 需要容器运行环境 | 微服务、DevOps环境 |
| Kubernetes编排 | 高可用、自动伸缩 | 复杂度高 | 大规模微服务集群 |
| 云平台PaaS | 低运维成本 | 供应商锁定 | 初创企业、中小规模应用 |
7.3 生产环境最佳实践
在将Spring Boot应用部署到生产环境时,应遵循以下最佳实践:
- 配置管理
- 日志管理
- 监控与告警
1# 通过环境变量注入关键配置2spring:3 datasource:4 url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:myapp}5 username: ${DB_USER:root}6 password: ${DB_PASSWORD:secret}1# 使用外部配置文件2java -jar app.jar --spring.config.location=file:///path/to/production.yml34# 指定活动profile5java -jar app.jar --spring.profiles.active=prod67# 覆盖特定配置8java -jar app.jar --server.port=9000 --logging.level.root=WARN- 使用环境变量注入敏感信息
- 避免在代码中硬编码配置
- 使用配置服务器集中管理配置
- 使用多环境profile分离配置
- 使用密文存储敏感信息
1logging:2 file:3 name: /var/log/myapp.log4 max-size: 10MB5 max-history: 76 level:7 root: WARN8 org.springframework: WARN9 com.example.myapp: INFO10 pattern:11 file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"- 配置适当的日志级别
- 实施日志轮转
- 使用结构化日志
- 集中化日志收集(ELK、Graylog)
- 包含足够的上下文信息
- 避免敏感信息泄露
1# Actuator配置2management:3 endpoints:4 web:5 exposure:6 include: health,info,metrics,prometheus7 endpoint:8 health:9 show-details: when-authorized10 metrics:11 export:12 prometheus:13 enabled: true- 实施健康检查
- 收集关键业务指标
- 设置适当的告警阈值
- 监控系统资源(CPU、内存、磁盘)
- 监控关键业务指标
- 可视化监控数据(Grafana)
- 配置通知渠道(邮件、短信、Slack)
8. 总结
Spring Boot通过简化配置、提供默认实现,极大地提高了Spring应用的开发效率,成为现代Java应用开发的标准工具。
🚀 Spring Boot学习建议:
- 掌握Spring基础知识(IoC、AOP)
- 理解自动配置和起步依赖的原理
- 学习配置管理和属性绑定
- 了解启动流程和生命周期事件
- 熟悉Actuator监控和管理
- 掌握不同的部署选项
- 实践微服务和云原生开发
Spring Boot让开发者能够专注于业务逻辑的开发,而不必过多关注底层框架的配置细节。它与Spring Cloud生态系统的完美结合,更是为微服务架构和云原生应用开发提供了强大的支持。
9. 面试题精选
Q1: 什么是Spring Boot?它有什么优势?
答: Spring Boot是Spring框架的扩展,专注于简化Spring应用的初始搭建和开发过程。主要优势包括:
- 自动配置:减少配置,自动配置大部分组件
- 起步依赖:简化依赖管理,解决版本兼容性问题
- 内嵌服务器:内置Tomcat等服务器,无需部署WAR文件
- Actuator:提供监控和管理功能
- 无代码生成和XML配置:减少样板代码
- 独立运行:可以像普通Java程序一样运行
Q2: Spring Boot的自动配置原理是什么?
答: Spring Boot自动配置基于以下机制:
- 通过
@EnableAutoConfiguration注解启用自动配置 - 该注解通过
@Import导入AutoConfigurationImportSelector类 AutoConfigurationImportSelector会从所有JAR包中的META-INF/spring.factories文件加载EnableAutoConfiguration配置项- 根据条件注解(
@ConditionalOnClass,@ConditionalOnBean等)判断哪些配置类生效 - 匹配条件的配置类会被注册为Bean,创建需要的组件
Q3: Spring Boot常用的核心注解有哪些?
答: Spring Boot常用的核心注解:
@SpringBootApplication:包含三个注解(@Configuration,@EnableAutoConfiguration,@ComponentScan)@EnableAutoConfiguration:启用自动配置@Configuration:标记配置类@ComponentScan:组件扫描@ConfigurationProperties:绑定配置属性@ConditionalOnXXX:条件化配置(如@ConditionalOnClass,@ConditionalOnBean,@ConditionalOnProperty等)@SpringBootConfiguration:特定于Spring Boot的配置类@EnableConfigurationProperties:启用@ConfigurationProperties注解
Q4: Spring Boot如何管理配置文件?配置文件的优先级如何?
答: Spring Boot支持多种配置方式,主要有:
application.properties或application.yml文件- 特定环境的配置文件(如
application-dev.yml) - 环境变量
- 命令行参数
配置优先级从高到低:
- 命令行参数
- Java系统属性(
System.getProperties()) - 操作系统环境变量
application-{profile}.properties(外部配置)application.properties(外部配置)application-{profile}.properties(内部配置)application.properties(内部配置)@PropertySource注解引入的属性- 默认属性
Q5: 如何理解Spring Boot的起步依赖(Starter)?
答: Spring Boot起步依赖是一种特殊的Maven或Gradle依赖,用于简化项目依赖管理:
- 一个起步依赖通常会引入一组功能相关的传递性依赖
- 通过
spring-boot-starter-*命名,如spring-boot-starter-web - 提供了版本管理,确保依赖组件间的兼容性
- 与自动配置协同工作,自动配置需要的组件
- 减少了手动添加依赖的工作量和版本冲突的风险
Q6: Spring Boot的启动流程是怎样的?
答: Spring Boot启动流程主要包括:
- 创建
SpringApplication对象- 确定应用类型(SERVLET、REACTIVE、NONE)
- 设置初始化器和监听器
- 推断主应用类
- 运行
SpringApplication- 创建并启动计时器
- 发布
ApplicationStartingEvent事件 - 准备环境并加载配置
- 创建
ApplicationContext - 准备上下文,加载Bean定义
- 刷新上下文,实例化单例Bean
- 发布
ApplicationStartedEvent事件 - 调用
ApplicationRunner和CommandLineRunner - 发布
ApplicationReadyEvent事件
Q7: 如何在Spring Boot中集成自定义配置?
答: 在Spring Boot中集成自定义配置有多种方式:
- 使用
@Value注解直接注入单个属性java1@Value("${custom.property}")2private String customProperty; - 使用
@ConfigurationProperties绑定配置到Java类java1@Component2@ConfigurationProperties(prefix = "custom")3public class CustomProperties {4 private String property;5 // getters and setters6} - 创建自定义的配置类:
java1@Configuration2public class CustomConfiguration {3 @Bean4 public SomeBean someBean() {5 return new SomeBean();6 }7}
Q8: Spring Boot中如何实现安全认证?
答: Spring Boot中实现安全认证主要通过Spring Security:
- 添加依赖:
spring-boot-starter-security - 创建配置类:
java1@Configuration2@EnableWebSecurity3public class SecurityConfig extends WebSecurityConfigurerAdapter {45 @Override6 protected void configure(HttpSecurity http) throws Exception {7 http8 .authorizeRequests()9 .antMatchers("/public/**").permitAll()10 .anyRequest().authenticated()11 .and()12 .formLogin()13 .loginPage("/login")14 .permitAll()15 .and()16 .logout()17 .permitAll();18 }1920 @Override21 protected void configure(AuthenticationManagerBuilder auth) throws Exception {22 auth.inMemoryAuthentication()23 .withUser("user").password("{noop}password").roles("USER");24 }25}
- 对于生产环境,可以配置JDBC认证、OAuth2、LDAP等认证方式
Q9: Spring Boot Actuator的作用是什么?有哪些常用端点?
答: Spring Boot Actuator提供生产就绪功能,用于监控和管理应用:
作用:
- 监控应用健康状态
- 收集应用指标
- 查看应用配置
- 查看环境信息
- 管理日志级别
- 查看线程信息
常用端点:
/actuator/health:健康状态/actuator/info:应用信息/actuator/metrics:指标收集/actuator/env:环境变量/actuator/configprops:配置属性/actuator/mappings:请求映射/actuator/beans:应用中的Bean/actuator/loggers:日志配置
Q10: 如何自定义Spring Boot的Banner?
答: 自定义Spring Boot启动Banner的方法:
- 在
src/main/resources目录下创建banner.txt文件 - 使用文本/ASCII艺术设计Banner
- 也可以通过代码方式设置:
java1SpringApplication app = new SpringApplication(MyApp.class);2app.setBannerMode(Banner.Mode.OFF); // 关闭Banner3// 或者设置自定义Banner4app.setBanner(new ResourceBanner(new ClassPathResource("path/to/banner.txt")));5app.run(args);
- 可以在配置文件中设置:
properties1spring.main.banner-mode=off2# 或者指定文件3spring.banner.location=classpath:path/to/banner.txt
评论