Spring Boot 核心机制解析:IoC、依赖注入、测试集成与配置绑定
一、JavaConfig 配置方式
传统 Spring 开发过度依赖 XML 描述,导致配置文件膨胀、维护困难。Spring 3.0 推出 JavaConfig 方案,允许用纯 Java 类替代 XML,但直到 Spring Boot 普及后才被广泛接受。JavaConfig 的核心优势在于:充分利用 Java 的面向对象特性(继承、多态)、彻底消除 XML、借助泛型实现类型安全的容器检索。
以下所有示例均基于 Maven 项目,首先引入基础依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
1. XML 与 JavaConfig 的 IoC 对比
1.1 待管理的实体类
public class ProductService {
private OrderService orderService;
public void setOrderService(OrderService orderService) {
this.orderService = orderService;
}
public ProductService() {
System.out.println("ProductService 实例化");
}
public void startup() {
System.out.println("ProductService 初始化完成");
}
public void cleanup() {
System.out.println("ProductService 销毁");
}
}
public class OrderService {
public OrderService() {
System.out.println("OrderService 实例化");
}
}
1.2 XML 配置方式
<!-- spring-context.xml -->
<bean id="productService" class="demo.ProductService"/>
public class ContainerDemo {
@Test
public void xmlApproach() {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-context.xml");
ProductService service = context.getBean(ProductService.class);
System.out.println(service);
}
}
1.3 JavaConfig 配置方式
关键注解说明:
@Configuration:标识该类为 Spring 配置类,等效于 XML 文件@Bean:方法返回值纳入容器管理,等效于<bean>标签AnnotationConfigApplicationContext:基于注解配置的容器实现
@Configuration
public class AppConfig {
@Bean
public ProductService productService() {
return new ProductService();
}
}
public class ContainerDemo {
@Test
public void javaConfigApproach() {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
ProductService service = context.getBean(ProductService.class);
System.out.println(service);
}
}
2. @Bean 高级属性配置
@Bean 注解支持多种属性,对应 XML 中的常用配置:
| 属性 | 说明 | XML 对应 |
|---|---|---|
| name | 指定别名 | name 属性 |
| initMethod | 初始化回调 | init-method |
| destroyMethod | 销毁回调 | destroy-method |
默认规则:方法名即为 bean 的标识符;作用域通过 @Scope("prototype") 调整,默认为单例。
3. 依赖注入的两种实现
3.1 参数注入法
@Bean
public ProductService productService(OrderService orderService) {
ProductService service = new ProductService();
service.setOrderService(orderService);
return service;
}
3.2 方法调用法
@Bean
public ProductService productService() {
ProductService service = new ProductService();
service.setOrderService(orderService());
return service;
}
原理:Spring 会拦截配置类中的实例方法,检查返回类型是否已存在于容器。若存在则直接复用,不存在才执行方法体创建新实例。
4. 注解驱动简化配置
当 bean 数量庞大时,@Bean 方法会导致配置类臃肿。可通过组件扫描 + 注解标记实现自动装配:
@Component
public class ProductService {
private OrderService orderService;
@Autowired
public void setOrderService(OrderService orderService) {
this.orderService = orderService;
}
}
@Component
public class OrderService { }
@Configuration
@ComponentScan // 默认扫描当前包及子包
public class AppConfig { }
注意:第三方库的类无法添加 @Component,仍需在配置类中用 @Bean 声明,两种方式可共存。
二、Spring Test 与 JUnit 集成
引入测试依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.8.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
>groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
1. JUnit 4 测试模式
// 基于 XML
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-context.xml")
public class SpringTestCase {
@Autowired
private ProductService productService;
@Test
public void test() {
System.out.println(productService);
}
}
// 基于配置类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class SpringTestCase {
@Autowired
private ProductService productService;
@Test
public void test() {
System.out.println(productService);
}
}
2. JUnit 5 测试模式
@SpringJUnitConfig(AppConfig.class)
class SpringTestCase {
@Autowired
private ProductService productService;
@Test
void test() {
System.out.println(productService);
}
}
3. 多配置类整合
// 从配置类
@Configuration
public class DataConfig { }
// 主配置类
@Configuration
@Import(DataConfig.class)
public class AppConfig { }
// 测试加载主配置即可
@SpringJUnitConfig(AppConfig.class)
public class SpringTestCase { }
若需引入遗留 XML 配置,使用 @ImportResource("classpath:legacy-context.xml")。
三、Spring Boot 快速上手
1. 核心特性
Spring Boot 作为 Spring 生态的脚手架框架,设计目标是降低 Spring 应用的启动门槛。其标志性特点包括:内嵌 Servlet 容器(默认 Tomcat)、Starter 依赖机制、自动配置、独立 JAR 运行。
2. 项目构建
通过 Maven 手动搭建:
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.3.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<//dependencies>
启动类:
@SpringBootApplication
public class LaunchApplication {
public static void main(String[] args) {
SpringApplication.run(LaunchApplication.class, args);
}
}
控制器:
@RestController
public class GreetingController {
@GetMapping("/greet")
public String greet() {
return "Spring Boot 应用运行中";
}
}
3. 关键机制解析
spring-boot-starter-parent:统一管理依赖版本,子模块声明时无需指定 version。其中 dependencyManagement 仅做版本声明,实际引入需子模块显式声明;dependencies 中的依赖则全局继承。
Starter 命名规范:官方 spring-boot-starter-*,第三方 *-spring-boot-starter,严禁使用 spring-boot 前缀。
打包插件:必须引入 spring-boot-maven-plugin 才能生成可执行 JAR,通过 java -jar 直接运行。
四、参数配置与绑定
1. 配置文件优先级
从高到低:
项目/config/application.properties项目/application.propertiesclasspath:config/application.propertiesclasspath:application.properties
2. 属性绑定方式
2.1 @Value 逐个注入
@Component
public class DatabaseSettings {
@Value("${db.driver}")
private String driverClassName;
@Value("${db.url}")
private String jdbcUrl;
@Value("${db.username}")
private String user;
@Value("${db.password}")
private String password;
}
2.2 @ConfigurationProperties 批量绑定
@Component
@ConfigurationProperties(prefix = "db")
public class DatabaseSettings {
private String driver;
private String url;
private String username;
private String password;
// getters and setters
}
若配置类使用 @Configuration 而非 @SpringBootApplication,需额外标注 @EnableConfigurationProperties 开启绑定支持。
2.3 Environment 编程式获取
@Configuration
@PropertySource("classpath:custom.properties")
public class AppConfig {
@Autowired
private Environment env;
@Bean
public DatabaseSettings databaseSettings() {
DatabaseSettings settings = new DatabaseSettings();
settings.setDriver(env.getProperty("db.driver"));
settings.setUrl(env.getProperty("db.url"));
settings.setUsername(env.getProperty("db.username"));
settings.setPassword(env.getProperty("db.password"));
return settings;
}
}
优先级规则:application.properties 高于 @PropertySource 引入的自定义属性文件。
3. YAML 格式配置
db:
driver: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/demo
username: root
password: secret
相比 properties 的扁平结构,YAML 的层级缩进更适合表达复杂的配置关系。