Spring Boot
🌟 模块一:Spring 纯注解配置 (告别 XML)
本模块详解如何用 5 个核心注解完全替代 applicationContext.xml。
1. @Bean ------ 手动注册组件
- 核心作用:将方法的返回值对象放入 Spring IOC 容器。
- 等价 XML :
<bean id="xxx" class="com.xxx.Xxx"/> - 关键属性 :
value/name:指定 Bean 在容器中的唯一标识(ID)。若不写,默认为方法名。
- 使用场景 :第三方包中的类(无法添加
@Component注解),需要手动配置时。
💻 示例代码
java
@Configuration
public class MyDataSourceConfig {
// 等价于:<bean id="myDruidDataSource" class="com.alibaba.druid.pool.DruidDataSource"/>
@Bean("myDruidDataSource")
public DruidDataSource dataSource() {
DruidDataSource ds = new DruidDataSource();
ds.setUrl("jdbc:mysql://localhost:3306/db_test");
ds.setUsername("root");
ds.setPassword("123456");
return ds;
}
// 默认 ID 为 "userService"
@Bean
public UserService userService() {
return new UserServiceImpl();
}
}
2. @PropertySource ------ 加载外部属性文件
- 核心作用 :加载指定的
.properties文件到 Spring 环境变量中。 - 等价 XML :
<context:property-placeholder location="classpath:db.properties"/> - 关键属性 :
value:文件路径,支持数组加载多个文件。encoding:指定编码(如utf-8),防止中文乱码。
- 配合使用 :通常与
@Value("${key}")搭配使用。
💻 示例代码
配置文件 db.properties:
properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_db
jdbc.user=root
jdbc.password=secret
Java 配置类:
java
@Configuration
// 加载单个文件
@PropertySource(value = "classpath:db.properties", encoding = "utf-8")
// 也可以加载多个:@PropertySource({"classpath:a.properties", "classpath:b.properties"})
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Bean
public DataSource dataSource() {
// 使用加载到的属性值
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
return ds;
}
}
3. @ComponentScan ------ 组件扫描
- 核心作用 :指定 Spring 扫描哪些包下的注解(
@Component,@Service,@Controller,@Repository)。 - 等价 XML :
<context:component-scan base-package="com.hg"/> - 关键属性 :
value/basePackages:要扫描的包名数组。excludeFilters:排除某些组件。includeFilters:只包含某些组件。
- 注意:如果配置类在根包下,有时可以省略,但显式声明更稳妥。
💻 示例代码
java
@Configuration
// 扫描 com.hg 及其子包
@ComponentScan("com.hg")
// 或者排除特定的控制器
// @ComponentScan(value = "com.hg", excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = Controller.class))
public class ScanConfig {
// Spring 会自动发现 @Service, @Controller 等并注册为 Bean
}
4. @Import ------ 导入配置类
- 核心作用:导入其他的配置类,实现配置的分模块管理;或者直接导入普通类将其注册为 Bean。
- 等价 XML :
<import resource="spring-dao.xml"/> - 关键属性 :
value:要导入的类的 Class 对象。
- 高阶用法 :
- 导入
@Configuration类:合并配置。 - 导入普通类:Spring 会直接将该类注册为 Bean,ID 为类名首字母小写。
- 导入
ImportSelector或ImportBeanDefinitionRegistrar:实现高级动态注册(如@EnableXXX的原理)。
- 导入
💻 示例代码
子配置类 RedisConfig.java:
java
@Configuration
public class RedisConfig {
@Bean
public JedisConnectionFactory jedisConnectionFactory() {
return new JedisConnectionFactory();
}
}
主配置类 AllConfig.java:
java
@Configuration
@ComponentScan("com.hg")
// 导入其他配置类,相当于把 RedisConfig 里的 Bean 也加进来了
@Import({RedisConfig.class, MyDataSourceConfig.class})
public class AllConfig {
// 这里可以直接注入 RedisConfig 中定义的 Bean
}
5. @Configuration ------ 配置类标识
- 核心作用 :告诉 Spring 这是一个配置类,替代
applicationContext.xml的地位。 - 特点 :
- 类中通常包含
@Bean方法。 - 会被 CGLIB 代理,保证
@Bean方法调用的单例性(即方法内互相调用不会创建新对象)。
- 类中通常包含
- 等价物 :整个
applicationContext.xml文件。
💻 示例代码
java
// 必须加这个注解,否则 @Bean 不生效
@Configuration
@ComponentScan("com.hg")
@PropertySource("classpath:app.properties")
public class SpringMainConfig {
@Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}
🚀 模块二:Spring Boot 入门
一、Spring Boot 介绍
- 定义 :Spring + Spring MVC 的快速开发脚手架。不是 对 Spring 功能的增强,而是简化配置。
- 三大特点 :
- 简化 XML:零配置或极少配置。
- 简化 Maven:通过 Starter 解决依赖版本冲突。
- 内嵌 Tomcat:无需部署 WAR,直接运行 JAR。
二、入门案例实操
1. pom.xml 核心配置
xml
<project xmlns="http://maven.apache.org/POM/4.0.0" ...>
<!-- ① 继承父工程:锁定所有依赖版本 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<!-- ② 引入 Web 启动器:包含 Spring MVC, Tomcat, Jackson -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
2. Controller 层代码
java
package com.hg.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController // 组合注解:@Controller + @ResponseBody
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello Spring Boot! 欢迎进入快速开发时代 🚀";
}
}
3. 启动类 (关键!)
⚠️ 包结构要求 :启动类必须在所有业务包(controller, service, mapper)的父级目录,否则默认扫描不到。
java
package com.hg; // 【重要】必须是根包
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication // 核心:开启自动配置 + 组件扫描
public class SpringbootHelloworldApp {
public static void main(String[] args) {
// 启动应用,返回 ApplicationContext
SpringApplication.run(SpringbootHelloworldApp.class, args);
System.out.println("✅ 启动成功!访问 http://localhost:8080/hello");
}
}
三、Spring Boot 启动器 (Starter)
1. 概念
Starter 是一组便捷的依赖描述符。引入一个 Starter,就等于引入了该功能所需的所有 Jar 包和自动配置类。
2. 命名规范
| 类型 | 命名格式 | 示例 | 说明 |
|---|---|---|---|
| 官方 | spring-boot-starter-模块名 |
spring-boot-starter-web |
Spring 官方提供 |
| 第三方 | 模块名-spring-boot-starter |
mybatis-spring-boot-starter |
第三方组织提供 (如 MyBatis-Plus) |
💡 知识补充:常用 Starter
spring-boot-starter-data-jpa: JPA 数据访问spring-boot-starter-data-redis: Redis 支持spring-boot-starter-test: 测试支持 (JUnit, Mockito)spring-boot-starter-security: 安全认证
四、配置文件 (Properties vs YML)
1. application.properties
properties
# 修改 Tomcat 端口
server.port=8090
# 修改项目上下文路径
server.servlet.context-path=/springboot_helloworld
# 设置日志级别
logging.level.com.hg=debug
2. application.yml (推荐)
语法重点:
- 层级用缩进(空格,不能 Tab)。
- 键值对用
:(冒号后必须有空格)。 - 大小写敏感。
yaml
server:
port: 8090
servlet:
context-path: /springboot_helloworld
logging:
level:
com.hg: debug
五、两种发布方式
1. JAR 方式 (主流 ✅)
- 原理:内嵌 Tomcat,自包含运行环境。
- 步骤 :
-
插件配置 (
pom.xml):xml<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <!-- 自动寻找 main 方法作为入口 --> </plugin> </plugins> </build> -
打包 :
mvn clean package -
运行 :
java -jar target/springboot_helloworld.jar
-
2. WAR 方式 (传统部署)
- 场景:需部署到外部独立的 Tomcat/Jetty 服务器。
- 步骤详解 :
-
修改打包方式 :
xml<packaging>war</packaging> -
排除内嵌 Tomcat (防止冲突):
xml<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> <!-- 打包时不包含,运行时由外部 Tomcat 提供 --> </dependency> -
修改启动类 (继承初始化器):
javaimport org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; // 必须继承 SpringBootServletInitializer public class SpringBootHelloworldApp extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { // 指向当前的启动类 return builder.sources(SpringBootHelloworldApp.class); } // 保留 main 方法,方便本地调试 public static void main(String[] args) { SpringApplication.run(SpringBootHelloworldApp.class, args); } } -
部署 :将生成的
.war包复制到外部 Tomcat 的webapps/目录下,启动 Tomcat 即可。
-
🛠️ 模块三:进阶整合 (异常、测试、多环境、日志)
一、全局异常处理器
1. 前后端分离架构 (重点 🔥)
返回 JSON 数据给前端,而不是跳转错误页面。
- 核心注解 :
@ControllerAdvice:全局增强,拦截所有 Controller 的异常。@ExceptionHandler:指定捕获的异常类型。@ResponseBody:返回数据而非视图。
java
package com.hg.exception;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap;
import java.util.Map;
@ControllerAdvice
public class GlobalExceptionResolver {
// 捕获所有 Exception 类型的异常
@ExceptionHandler({Exception.class})
@ResponseBody
public Map<String, Object> handleException(Exception e) {
e.printStackTrace(); // 控制台打印堆栈
Map<String, Object> result = new HashMap<>();
result.put("code", 500);
result.put("msg", "服务器内部错误:" + e.getMessage());
result.put("data", null);
return result;
}
// 也可以针对特定异常做处理
@ExceptionHandler(ArithmeticException.class)
@ResponseBody
public Map<String, Object> handleArithmeticException(ArithmeticException e) {
Map<String, Object> result = new HashMap<>();
result.put("code", 400);
result.put("msg", "数学计算错误:" + e.getMessage());
return result;
}
}
2. 非前后端分离 (了解)
实现 HandlerExceptionResolver 接口,返回 ModelAndView 跳转到错误页。
(注:现代开发极少使用此方式,通常直接用上面的注解方式)
二、整合 JUnit 单元测试
1. 依赖引入
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
2. 三种启动方式的对比与代码
方式 A:Main 方法手动启动 (原始)
java
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = ctx.getBean(UserService.class);
方式 B:Spring 整合 JUnit (老式)
java
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class OldSpringTest { ... }
方式 C:Spring Boot 整合 JUnit (推荐 ✅)
- 特点 :
@SpringBootTest自动加载配置,无需 XML,无需 Runner。
java
package com.hg.test;
import com.hg.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
// 加载完整的 Spring 上下文,默认查找启动类
@SpringBootTest(classes = SpringbootHelloworldApp.class)
public class SpringbootJunitTest {
@Autowired
private UserService userService;
@Test
public void testFindUser() {
// 直接调用,如果配置正确,userService 不为 null
assert userService != null;
System.out.println("测试通过!用户服务已注入。");
// 执行具体业务逻辑测试
// User user = userService.findById(1L);
}
}
三、多环境配置 (Profiles)
解决开发、测试、生产环境配置不同的问题。
1. 文件命名规则
主文件:application.yml
子文件:application-环境名.yml
application-dev.yml(开发环境)application-test.yml(测试环境)application-prod.yml(生产环境)
2. 配置文件内容示例
application-dev.yml:
yaml
server:
port: 8081
spring:
datasource:
url: jdbc:mysql://localhost:3306/dev_db
username: dev_user
password: dev_pass
application-test.yml:
yaml
server:
port: 8082
spring:
datasource:
url: jdbc:mysql://test-server:3306/test_db
username: test_user
password: test_pass
application-prod.yml:
yaml
server:
port: 8083
spring:
datasource:
url: jdbc:mysql://prod-cluster:3306/prod_db
username: prod_user
password: prod_strong_pass
3. 激活环境
在主文件 application.yml 中指定默认激活的环境:
yaml
spring:
profiles:
active: dev # 默认激活 dev 环境,修改此处可切换
💡 命令行动态切换 :
打包后运行:java -jar app.jar --spring.profiles.active=prod
这样无需修改配置文件即可切换环境。
四、整合 Logback 日志
Spring Boot 默认使用 Logback 作为日志框架,无需额外引入依赖。
1. 配置文件 src/main/resources/logback-spring.xml
使用 -spring 后缀可以让 Logback 读取 Spring Boot 的配置(如 ${APP_NAME})。
xml
<configuration scan="true" scanPeriod="30 seconds">
<!-- 定义变量 -->
<property name="LOG_HOME" value="./logs"/>
<property name="APP_NAME" value="springboot_helloworld"/>
<!-- 控制台输出格式 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 文件输出:按天滚动 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/${APP_NAME}.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天生成一个文件,保留30天 -->
<fileNamePattern>${LOG_HOME}/${APP_NAME}.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 根节点配置 -->
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
<!-- 单独配置某个包的日志级别 -->
<logger name="com.hg.service" level="DEBUG"/>
<logger name="org.springframework.web" level="INFO"/>
</configuration>
2. 代码中使用日志
推荐使用 Lombok 的 @Slf4j 简化代码。
java
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j // 自动生成 private static final Logger log = ...
@RestController
public class LogDemoController {
@GetMapping("/log-test")
public String logTest() {
log.trace("这是 TRACE 级别日志 (最详细)");
log.debug("这是 DEBUG 级别日志 (调试用)");
log.info("这是 INFO 级别日志 (一般信息)");
log.warn("这是 WARN 级别日志 (警告)");
log.error("这是 ERROR 级别日志 (错误)");
try {
int i = 1 / 0;
} catch (Exception e) {
log.error("发生算术异常", e); // 自动打印堆栈
}
return "日志已记录,请查看 logs 目录或控制台";
}
}
🎁 额外补充知识点 (加分项)
1. @ConfigurationProperties vs @Value
@Value:逐个注入,适合少量配置。@ConfigurationProperties:批量注入,支持松散绑定(my-prop对应myProp),支持 JSR303 校验,推荐用于复杂配置。
java
@Component
@ConfigurationProperties(prefix = "myapp")
@Data // Lombok
public class MyAppProperties {
private String name;
private int version;
private List<String> features;
}
// yml: myapp.name=xxx, myapp.features[0]=a
2. Spring Boot 自动配置原理简述
- 启动类上的
@EnableAutoConfiguration是关键。 - 它通过
SPI机制加载META-INF/spring.factories(Spring Boot 2.7+ 改为META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports) 中的所有配置类。 - 这些配置类上使用
@ConditionalOnClass,@ConditionalOnMissingBean等注解,按需加载 。例如:只有当类路径下有JdbcTemplate类时,才自动配置数据源相关 Bean。
3. 热部署 (DevTools)
开发效率神器,修改代码后自动重启应用。
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
- IDEA 设置:File -> Settings -> Build, Execution, Deployment -> Compiler -> 勾选 "Build project automatically"。
- Registry:Ctrl+Shift+Alt+/ -> Registry -> 勾选 "compiler.automake.allow.when.app.running"。