Spring IoC 容器与依赖注入核心机制详解
一、@Bean 注解的使用规范 1.1 方法注解需配合类注解使用 在 Spring 框架中,方法注解 @Bean 必须配合类注解(如 @Component、@Configuration 等)才能将对象正确注册到 Spring 容器中。示例如下: 1.2 定义多个同类型 Bean 在实际开发中(如多数据源场景),可能需要为同一个类定义多个不同配置的 Bean。可以通过在同一个配置类中编写多个 @Be…

一、@Bean 注解的使用规范 1.1 方法注解需配合类注解使用 在 Spring 框架中,方法注解 @Bean 必须配合类注解(如 @Component、@Configuration 等)才能将对象正确注册到 Spring 容器中。示例如下: 1.2 定义多个同类型 Bean 在实际开发中(如多数据源场景),可能需要为同一个类定义多个不同配置的 Bean。可以通过在同一个配置类中编写多个 @Be…

@Bean在 Spring 框架中,方法注解 @Bean 必须配合类注解(如 @Component、@Configuration 等)才能将对象正确注册到 Spring 容器中。示例如下:
@Component
public class BeanConfig {
@Bean
public User user() {
User user = new User();
user.setName("zhangsan");
user.setAge(18);
return user;
}
}
在实际开发中(如多数据源场景),可能需要为同一个类定义多个不同配置的 Bean。可以通过在同一个配置类中编写多个 @Bean 方法实现:
@Component
public class BeanConfig {
@Bean
public User user1() {
User user = new User();
user.setName("zhangsan");
user.setAge(18);
return user;
}
@Bean
public User user2() {
User user = new User();
user.setName("lisi");
user.setAge(19);
return user;
}
}
注意:当容器中存在多个同类型 Bean 时,若直接使用 context.getBean(User.class) 按类型获取,Spring 会抛出 NoUniqueBeanDefinitionException 异常,提示期望匹配一个但发现了多个(user1, user2)。
解决方案:通过 Bean 名称获取。
ApplicationContext context = SpringApplication.run(SpringIocDemoApplication.class, args);
User u1 = (User) context.getBean("user1");
User u2 = (User) context.getBean("user2");
默认情况下,@Bean 生成的 Bean 名称为方法名。可通过 name 属性自定义名称,且支持配置多个别名:
@Bean(name = {"u1", "user1"})
public User user1() {
User user = new User();
user.setName("zhangsan");
user.setAge(18);
return user;
}
语法简写规则:
name= 和大括号:@Bean("u1")name=:@Bean({"u1", "user1"})注册后,可通过 context.getBean("u1") 或 context.getBean("user1") 获取对象。
| 注解类型 | 命名规则 | 示例 |
|---|---|---|
@Component / @Service / @Controller / @Repository / @Configuration | 默认使用小驼峰命名(首字母小写)。若类名前两个字母均为大写,则保持原样。 | UserService → userServiceHTTPClient → HTTPClient |
@Bean | 默认等于方法名。 | public User user() {} → user |
💡 提示:该规则由 Spring 的
BeanNameGenerator实现,旨在保证 Bean 名称的可读性与唯一性。如需自定义,可直接在注解中指定,如@Service("myUserService")或@Bean("myOrderDao")。
@ComponentScan)使用 @Component 等注解声明的类必须被 Spring 扫描到才会注册为 Bean。Spring Boot 的 @SpringBootApplication 已内置 @ComponentScan,默认扫描启动类所在包及其所有子包。
若 Bean 所在的包不在启动类的包或子包下,将导致 NoSuchBeanDefinitionException。此时需手动配置 @ComponentScan:
@ComponentScan({"com.example.service", "com.example.config"})
@SpringBootApplication
public class SpringIocDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringIocDemoApplication.class, args);
}
}
@ComponentScan 核心用法@ComponentScan({"包路径1", "包路径2"}),需填写完整包名。@ComponentScan(
basePackages = "com.example",
excludeFilters = @ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = UserService.class
)
)
@Configuration 的关联:配置类本身也必须被扫描到,否则其内部的 @Bean 方法不会执行。依赖注入是 IoC 容器在创建 Bean 时,为其提供运行所依赖资源的过程。Spring 提供以下三种方式:
直接在字段上使用 @Autowired 注解。
@Controller
public class UserController {
@Autowired
private UserService userService;
}
在构造方法上添加 @Autowired(Spring 4.3+ 若仅有一个构造方法可省略该注解)。
@Controller
public class UserController {
private final UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
}
在 Setter 方法上添加 @Autowired。
@Controller
public class UserController {
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
}
| 注入方式 | 优点 | 缺点 |
|---|---|---|
| 属性注入 | 代码简洁,使用方便 | 仅适用于 IoC 容器;延迟报错(使用时才抛 NPE);无法注入 final 字段 |
| 构造方法注入 | 支持 final 字段;依赖不可变;实例化时即完成初始化,通用性强(JDK 原生支持) | 依赖较多时构造方法参数冗长 |
| Setter 注入 | 允许在实例化后重新配置或注入 | 无法注入 final 字段;依赖可能被后续调用覆盖 |
📌 官方推荐:Spring 4.3 之后,官方推荐使用构造方法注入,以保证依赖的不可变性和提前校验。
当使用 @Autowired 按类型注入,且容器中存在多个同类型 Bean 时,会抛出 NoUniqueBeanDefinitionException。Spring 提供以下解决方案:
@Primary标记首选 Bean,当存在多个同类型 Bean 时,优先注入被 @Primary 标注的实例。
@Primary
@Bean("u1")
public User user1() { /* ... */ }
@Qualifier配合 @Autowired 使用,通过 value 属性精确指定 Bean 名称。
@Autowired
@Qualifier("user2")
private User user;
@ResourceJDK 提供的注解,默认按名称注入。通过 name 属性指定目标 Bean。
@Resource(name = "user2")
private User user;
@Autowired 与 @Resource 核心区别| 特性 | @Autowired | @Resource |
|---|---|---|
| 来源 | Spring 框架 (org.springframework...) | JDK / Java EE (javax.annotation 或 jakarta.annotation) |
| 默认策略 | 按类型 (byType) | 按名称 (byName) |
| 指定名称 | 需配合 @Qualifier | 直接使用 name 属性 |
| 匹配逻辑 | 先按类型,若多个则按属性名匹配 | 优先按 name/属性名,找不到则降级按类型 |
| 兼容性 | 仅限 Spring 容器 | 通用,兼容所有支持 Java EE/Jakarta 的容器 |
@Autowired,代码更简洁,是 Spring 生态的标准实践。@Resource(name = "xxx") 可直接按名注入,避免类型歧义。@Resource 所属包已迁移至 jakarta.annotation,需确保引入对应依赖。
微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online