在 Spring 中,自动化装配和显式 Java 配置装配是两种核心方式。下面分别说明。
一、自动化装配
自动化装配包含两个步骤:
-
组件扫描:Spring 自动发现上下文中的 Bean
-
自动装配:Spring 自动满足 Bean 之间的依赖
1. 创建可被发现的 Bean
使用 @Component 注解标记一个类:
java
@Component
public class UserService {
public void save() {
System.out.println("保存用户");
}
}
2. 开启组件扫描
Java 配置类
java
@Configuration
@ComponentScan(basePackages = "com.example.service")
public class AppConfig {
}
Spring Boot 自动扫描(在主类上)
java
@SpringBootApplication // 内含 @ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
3. 自动装配依赖
使用 @Autowired:
java
@Component
public class UserController {
@Autowired
private UserService userService;
public void handle() {
userService.save();
}
}
也可以用在构造器(推荐,方便单元测试):
java
@Component
public class UserController {
private final UserService userService;
@Autowired // 只有一个构造器时可省略
public UserController(UserService userService) {
this.userService = userService;
}
}
4. 处理歧义性
当多个 Bean 实现同一接口时,用 @Primary 或 @Qualifier:
java
@Component
@Primary // 优先使用
public class DataSourceA implements DataSource {}
@Component
@Qualifier("dataSourceB")
public class DataSourceB implements DataSource {}
使用处指定:
java
@Autowired
@Qualifier("dataSourceB")
private DataSource dataSource;
二、通过 Java 代码装配 Bean(显式配置)
适合:第三方类库、无法加注解的类、需要复杂初始化逻辑的 Bean。
1. 基本用法
java
@Configuration
public class AppConfig {
@Bean
public UserService userService() {
return new UserService();
}
}
@Bean 告诉 Spring:该方法返回一个对象,应注册为 Spring 应用上下文中的 Bean。
2. 注入依赖
方式一:方法调用(简洁)
java
@Bean
public UserController userController() {
return new UserController(userService());
}
方式二:方法参数注入(推荐,更灵活)
java
@Bean
public UserController userController(UserService userService) {
return new UserController(userService);
}
Spring 会自动从上下文中找到 UserService 类型的 Bean 传入。
3. 复杂初始化示例
java
@Bean
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/test");
config.setUsername("root");
config.setPassword("123456");
return new HikariDataSource(config);
}
4. 混合使用
Java 配置中可以引用通过 @Component 扫描得到的 Bean:
java
@Configuration
@ComponentScan("com.example.service")
public class AppConfig {
@Bean
public ReportService reportService(UserService userService) {
// userService 来自组件扫描
return new ReportService(userService);
}
}
三、对比总结
| 特性 | 自动化装配 (@Component + @Autowired) |
Java 显式配置 (@Configuration + @Bean) |
|---|---|---|
| 适用场景 | 自己编写的类 | 第三方类、复杂初始化、需要控制实例化次数 |
| 代码侵入性 | 有(需要加注解) | 无侵入 |
| 灵活性 | 一般 | 很高(可写任意初始化逻辑) |
| 推荐原则 | 优先使用自动化(约定优于配置) | 自动化无法满足时使用 |
四、完整小示例
java
@Component
public class UserService {
public void save() {
System.out.println("User saved");
}
}
@Configuration
@ComponentScan("com.example")
public class JavaConfig {
// 可额外定义 @Bean
}
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(JavaConfig.class);
UserService service = ctx.getBean(UserService.class);
service.save();
}
}