springboot-bean
-------------------------------------------------------------------------------------------------------
@Autowired 是 Spring 框架中用于依赖注入(Dependency Injection, DI)的核心注解,用于自动装配 Bean 之间的依赖关系,减少手动配置的工作量。以下是其详细使用说明:1. 作用与原理
- 作用:自动将 Spring 容器中已存在的 Bean 注入到当前类的属性、构造方法或方法中,无需手动创建对象。
- 原理:Spring 容器启动时,会扫描带有
@Autowired的位置,根据类型(默认)或名称查找匹配的 Bean 并注入。
2. 使用位置
@Autowired 可用于 属性、构造方法、普通方法 上:(1)属性注入(最常用)
@Autowired,Spring 会自动注入匹配的 Bean:@Service
public class UserService {
// 自动注入 UserDao 类型的 Bean
@Autowired
private UserDao userDao;
public void addUser() {
userDao.insert(); // 直接使用注入的 userDao
}
}
(2)构造方法注入(推荐,尤其适合必填依赖)
@Autowired,Spring 会在创建当前 Bean 时,通过构造方法传入依赖的 Bean:@Service
public class UserService {
private final UserDao userDao;
// 构造方法注入(Spring 4.3+ 中,若类只有一个构造方法,@Autowired 可省略)
@Autowired
public UserService(UserDao userDao) {
this.userDao = userDao;
}
}
- 优势:依赖在对象创建时就已初始化,避免
NullPointerException;便于单元测试时手动传入依赖。
(3)方法注入(包括 setter 方法)
@Autowired,Spring 会在 Bean 初始化时调用该方法,并注入参数对应的 Bean:@Service
public class UserService {
private UserDao userDao;
// setter 方法注入
@Autowired
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
// 普通方法注入(可注入多个参数)
@Autowired
public void init(UserDao userDao, RoleDao roleDao) {
this.userDao = userDao;
// 处理 roleDao...
}
}
3. 注入规则
(1)默认按类型(Type)匹配
@Autowired 默认根据属性 / 参数的类型在 Spring 容器中查找对应的 Bean。若容器中存在 唯一 匹配类型的 Bean,则直接注入。(2)类型不唯一时的处理
UserDao 实现类),会抛出 NoUniqueBeanDefinitionException。此时需结合以下方式指定具体 Bean:@Qualifier注解:通过 Bean 的名称(默认是类名首字母小写)指定注入的 Bean:java运行@Service public class UserService { // 注入名称为 "userDaoImpl" 的 Bean @Autowired @Qualifier("userDaoImpl") private UserDao userDao; }@Primary注解:在多个同类型 Bean 中,用@Primary标记一个 “首选” Bean,@Autowired会优先注入它:java运行@Repository @Primary // 首选 Bean public class UserDaoImpl implements UserDao { ... } @Repository public class UserDaoOtherImpl implements UserDao { ... } // 此时 @Autowired 会注入 UserDaoImpl
(3)非必需依赖(允许为 null)
@Autowired 要求依赖必须存在,否则会抛出 NoSuchBeanDefinitionException。若允许依赖为 null,可添加 required = false:@Autowired(required = false) // 若没有匹配的 Bean,注入 null
private UserDao userDao;
4. 注意事项
- 注入的是 Spring 容器管理的 Bean:被注入的类必须被 Spring 管理(如添加
@Component、@Service、@Repository等注解,或通过 XML 配置)。 - 避免循环依赖:若 A 依赖 B,B 又依赖 A,会导致循环依赖。Spring 可解决构造方法以外的循环依赖,但应尽量避免设计上的循环依赖。
- 与
@Resource的区别:@Resource是 JDK 自带注解,默认按名称匹配,而@Autowired默认按类型匹配(需结合@Qualifier按名称匹配)。 - 静态属性无法注入:
@Autowired不能用于静态属性,因为 Spring 注入的是对象实例,而静态属性属于类。
总结
@Autowired 是 Spring 依赖注入的核心工具,通过自动装配减少了手动管理依赖的代码。实际开发中,推荐使用 构造方法注入(明确依赖关系,便于测试),并在必要时结合 @Qualifier 或 @Primary 处理复杂依赖场景。@Autowired 注解对 OrganizationMapper 类型的属性进行依赖注入,这在 Spring 或 Spring Boot 项目中非常常见,尤其在整合 MyBatis 或 MyBatis-Plus 时(Mapper 接口通常用于数据库操作)。这段代码的含义与注意事项:
-
作用告诉 Spring 容器:在初始化当前类(比如
Service层的类)时,自动从容器中查找OrganizationMapper类型的 Bean,并注入到organizationMapper属性中,无需手动创建实例。 -
前提条件
OrganizationMapper必须是一个被 Spring 管理的 Bean。在 MyBatis 中,通常通过@Mapper注解标记 Mapper 接口,或在配置类中使用@MapperScan扫描 Mapper 所在包,使 Spring 自动生成其实现类(代理对象)并纳入容器管理。例:java运行@Mapper // 标记为 MyBatis Mapper,Spring 会生成代理 Bean public interface OrganizationMapper { // 数据库操作方法... }
-
可能的问题与解决
-
若启动时报错
No qualifying bean of type 'OrganizationMapper' available:原因通常是OrganizationMapper未被 Spring 扫描到(比如缺少@Mapper注解,或@MapperScan路径配置错误)。解决:检查 Mapper 接口是否添加@Mapper,或确保@MapperScan("com.xxx.mapper")扫描路径正确。 -
若存在多个
OrganizationMapper类型的 Bean(极少出现,除非自定义了多个实现):需结合@Qualifier指定具体 Bean 的名称(默认是接口名首字母小写,即organizationMapper)。
-
推荐写法
- 依赖在对象创建时就初始化,避免
NullPointerException; - 明确显示类的依赖关系,便于代码维护和单元测试。
@Service
public class OrganizationService {
private final OrganizationMapper organizationMapper;
// 构造方法注入(Spring 会自动传入容器中的 OrganizationMapper Bean)
@Autowired
public OrganizationService(OrganizationMapper organizationMapper) {
this.organizationMapper = organizationMapper;
}
// 使用 organizationMapper 进行数据库操作...
}
@Autowired 可省略)@ComponentScan(basePackages = {"ptr.oa"}) 是 Spring 框架中用于指定组件扫描路径的注解,其核心作用是告诉 Spring 容器:去 ptr.oa 包及其子包下扫描并加载所有标注了特定注解的类(如 @Component、@Service、@Controller、@Repository 等),并将这些类实例化为 Bean 纳入 Spring 容器管理。详细说明:
-
注解作用Spring 容器启动时,会根据
@ComponentScan指定的路径,自动扫描符合条件的类(被@Component及其派生注解标记的类),并将它们注册为容器中的 Bean,后续可通过@Autowired等注解进行依赖注入。 -
basePackages参数basePackages = {"ptr.oa"}表示扫描的根路径为ptr.oa包。- 扫描范围包括
ptr.oa包下的所有类,以及该包的所有子包(如ptr.oa.service、ptr.oa.controller、ptr.oa.mapper等)。
例如:- 若存在类
ptr.oa.service.UserService并标注@Service,会被扫描并注册为 Bean; - 若存在类
ptr.oa.controller.OrgController并标注@Controller,也会被扫描并注册为 Bean。
-
使用场景该注解通常配合
@Configuration使用(标注在配置类上),用于手动指定 Spring 的组件扫描范围。例如:java运行@Configuration @ComponentScan(basePackages = {"ptr.oa"}) public class AppConfig { // 其他配置... }在 Spring Boot 项目中,主启动类上的@SpringBootApplication已内置@ComponentScan,默认扫描主类所在包及其子包。若需要自定义扫描路径,可通过@ComponentScan额外指定(如扩展扫描其他包)。
注意事项:
- 若不指定
basePackages,默认扫描当前类所在的包及其子包。 - 可指定多个路径,如
basePackages = {"ptr.oa", "ptr.common"},表示同时扫描两个包。 - 路径支持通配符,如
basePackages = {"ptr.oa.*.service"}(但不推荐过度使用,以免扫描范围混乱)。
@ConfigurationProperties 本身不是一个 Bean,它是 Spring Boot 提供的一个注解,用于将外部配置(如 application.properties、application.yml 等)绑定到 Java 类的属性上,实现配置的自动注入。关键说明:
-
注解的作用
@ConfigurationProperties的核心功能是 “属性绑定”:通过指定前缀(如@ConfigurationProperties(prefix = "myapp")),将配置文件中以该前缀开头的配置项(如myapp.name=xxx)自动映射到当前类的对应属性上。示例:java运行// 配置类(需被 Spring 管理才能生效) @Component // 或 @Configuration 等,使其成为 Bean @ConfigurationProperties(prefix = "myapp") public class MyAppConfig { private String name; // 绑定配置 myapp.name private int port; // 绑定配置 myapp.port // getter/setter 必须存在,否则无法绑定 } -
为何它不是 Bean
- 注解本身只是一个 “标记”,告诉 Spring Boot 该类需要进行属性绑定,但其自身并不具备 Bean 的特性(如被 Spring 容器管理、可被注入等)。
- 被
@ConfigurationProperties标注的类需要额外通过@Component、@Configuration或在配置类中用@EnableConfigurationProperties注册,才能成为 Spring 容器中的 Bean。
-
成为 Bean 的条件只有当被
@ConfigurationProperties标注的类同时被 Spring 容器扫描并注册为 Bean 时,它才是一个 Bean。常见方式:- 类上添加
@Component(或其派生注解如@Service等),结合@ComponentScan扫描; - 在配置类中通过
@EnableConfigurationProperties(MyAppConfig.class)显式注册。
- 类上添加
总结:
@ConfigurationProperties 是用于属性绑定的注解,本身不是 Bean,但被它标注的类可以通过 Spring 的组件扫描或显式注册成为 Bean,从而实现配置与 Java 类的自动映射。-------------------------------------------------------------------------------------------------------
@SpringBootApplication 和 @EnableDiscoveryClient 与 @ComponentScan 的关系如下:1. @SpringBootApplication 已包含 @ComponentScan
@SpringBootApplication 是一个复合注解,其内部已经集成了 @ComponentScan,默认扫描当前类所在的包及其所有子包。例如:若主启动类 Application 位于 com.example.demo 包下,则默认扫描 com.example.demo 及其子包(如 com.example.demo.controller、com.example.demo.service 等)中的组件(@Controller、@Service、@Component 等)。@ComponentScan,除非需要:- 扩展扫描范围(例如扫描其他包中的组件);
- 缩小扫描范围(例如排除某些不需要的包)。
2. @EnableDiscoveryClient 不影响组件扫描
@EnableDiscoveryClient 的作用是开启服务注册与发现功能(如集成 Eureka、Nacos 等注册中心),它仅与服务注册发现相关,不涉及组件扫描逻辑,也不会影响 @SpringBootApplication 自带的 @ComponentScan 行为。何时需要额外添加 @ComponentScan?
@ComponentScan,例如:- 项目中存在不在主启动类包及其子包下的组件(如
com.other.service中的@Service类),需要通过@ComponentScan(basePackages = {"com.example.demo", "com.other"})扩展扫描路径; - 需要排除某些包或类(如
@ComponentScan(excludeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = "com.example.demo.exclude.*")))。
总结
- 默认情况:
@SpringBootApplication已包含@ComponentScan,无需额外添加; - 特殊需求:如需扩展 / 缩小扫描范围,可手动添加
@ComponentScan并指定basePackages等参数; @EnableDiscoveryClient与组件扫描无关,不影响上述规则。
-------------------------------------------------------------------------------------------------------
@ComponentScan 并非可以随意放在任何类上,它的生效需要满足特定条件:必须放在被 Spring 容器识别为 “配置类” 的类上,否则注解不会生效。具体说明:
-
生效的前提
@ComponentScan的作用是告诉 Spring 容器 “去哪里扫描组件”,但 Spring 容器只会解析被标记为配置类的类上的@ComponentScan注解。哪些类会被 Spring 识别为配置类?- 被
@Configuration标注的类(最标准的配置类); - 被
@SpringBootApplication标注的类(Spring Boot 主启动类,内部包含@Configuration); - 被
@Component及其派生注解(@Service、@Controller等)标注的类(不推荐,但 Spring 会兼容解析其上面的@ComponentScan)。
- 被
-
不生效的情况若将
@ComponentScan放在非配置类上(即未被上述注解标记的普通类),Spring 容器不会扫描该类,因此@ComponentScan也不会生效。例如,以下写法无效:java运行// 普通类,未被任何配置相关注解标记 public class MyClass { @ComponentScan(basePackages = "com.example") // 不会生效 } -
最佳实践
@ComponentScan应只放在配置类上,推荐与@Configuration配合使用,或直接使用包含@Configuration的复合注解(如@SpringBootApplication)。示例(正确用法):java运行@Configuration // 标记为配置类 @ComponentScan(basePackages = "com.example") // 生效 public class AppConfig { // 配置内容... }
总结
@ComponentScan 不能随意放在任何类上,必须放在被 Spring 识别为配置类的类上(如 @Configuration 或 @SpringBootApplication 标注的类)才能生效。这是因为 Spring 容器只会解析配置类上的组件扫描注解,普通类上的 @ComponentScan 会被忽略。-------------------------------------------------------------------------------------------------------
@Autowired 功能类似(用于依赖注入)的注解有多个,它们各自有不同的特性和适用场景。以下是常见的相关注解及其区别:1. @Autowired(Spring 自带)
- 核心功能:按类型(
byType)自动装配依赖,是 Spring 依赖注入的核心注解。 - 特性:
- 默认要求依赖必须存在(否则抛出异常),可通过
required = false允许为null。 - 当存在多个同类型 Bean 时,需配合
@Qualifier按名称(byName)指定具体 Bean。 - 可用于属性、构造方法、普通方法(如 setter)。
- 默认要求依赖必须存在(否则抛出异常),可通过
- 示例:
java运行
@Autowired @Qualifier("userService") // 配合指定 Bean 名称 private UserService userService;
2. @Resource(JDK 自带,javax.annotation.Resource)
- 核心功能:默认按名称(
byName)自动装配,若名称匹配失败则按类型(byType)匹配。 - 特性:
- 属于 JDK 标准注解,不依赖 Spring,通用性更强。
- 支持通过
name属性指定 Bean 名称(如@Resource(name = "userService"))。 - 不支持
required = false,若依赖不存在会抛出异常。 - 可用于属性、setter 方法,但不能用于构造方法。
- 示例:
java运行
@Resource(name = "userService") // 按名称注入 private UserService userService;
3. @Inject(JSR-330 标准,javax.inject.Inject)
- 核心功能:按类型(
byType)自动装配,与@Autowired功能类似,但属于 Java 标准注解。 - 特性:
- 需引入依赖(如
javax.inject:javax.inject:1),Spring 对其提供支持。 - 没有
required属性,若依赖不存在会抛出异常。 - 当存在多个同类型 Bean 时,需配合
@Named注解按名称指定(类似@Qualifier)。 - 可用于属性、构造方法、普通方法。
- 需引入依赖(如
- 示例:
java运行
@Inject @Named("userService") // 配合指定 Bean 名称 private UserService userService;
4. @Qualifier(Spring 自带,配合 @Autowired 或 @Inject)
- 核心功能:指定依赖的 Bean 名称,解决同类型多个 Bean 的装配冲突。
- 特性:
- 不能单独使用,必须与
@Autowired或@Inject配合。 value属性用于指定 Bean 名称(默认是类名首字母小写)。
- 不能单独使用,必须与
- 示例:
java运行
@Autowired @Qualifier("userDaoImpl") // 明确注入名称为 userDaoImpl 的 Bean private UserDao userDao;
5. @Primary(Spring 自带)
- 核心功能:标记同类型 Bean 中的 “首选 Bean”,当
@Autowired按类型装配时,会优先选择被@Primary标记的 Bean。 - 特性:
- 用于解决 “同类型多个 Bean 时的默认选择” 问题,无需手动指定
@Qualifier。 - 若多个 Bean 都标记
@Primary,会抛出异常(只能有一个首选)。
- 用于解决 “同类型多个 Bean 时的默认选择” 问题,无需手动指定
- 示例:
java运行
@Repository @Primary // 首选 Bean public class UserDaoImpl implements UserDao { ... } @Repository public class UserDaoOtherImpl implements UserDao { ... } // 注入时会自动选择 UserDaoImpl @Autowired private UserDao userDao;
6. @Named(JSR-330 标准,配合 @Inject)
- 核心功能:类似
@Qualifier,用于指定 Bean 名称,配合@Inject使用。 - 特性:
- 属于 Java 标准注解,替代 Spring 的
@Qualifier。
- 属于 Java 标准注解,替代 Spring 的
- 示例:
java运行
@Inject @Named("userService") // 等价于 @Qualifier("userService") private UserService userService;
注解对比总结
| 注解 | 来源 | 匹配方式 | 支持位置 | 解决冲突方式 |
|---|---|---|---|---|
@Autowired |
Spring | 先类型,后名称 | 属性、构造方法、方法 | @Qualifier / @Primary |
@Resource |
JDK | 先名称,后类型 | 属性、setter 方法 | name 属性 |
@Inject |
JSR-330 | 先类型,后名称 | 属性、构造方法、方法 | @Named |
选择建议
- 优先使用
@Autowired(Spring 生态下最常用,功能完善)。 - 若需跨框架通用性(如非 Spring 环境),可使用
@Resource或@Inject+@Named。 - 解决同类型 Bean 冲突时,推荐
@Qualifier(精确指定)或@Primary(默认首选)。
-------------------------------------------------------------------------------------------------------
@Resource 注入依赖时,若存在两个同名的 Bean(即 Spring 容器中存在多个 Bean 名称相同的实例),会直接抛出异常,因为 @Resource 无法确定要注入哪个 Bean。具体分析:
-
@Resource的匹配逻辑@Resource默认按 Bean 名称 匹配(byName)。当不指定name属性时,默认使用属性名作为 Bean 名称去匹配;若指定name,则按指定名称匹配。例如:java运行@Resource // 等价于 @Resource(name = "userService") private UserService userService; -
两个同名 Bean 的冲突Spring 容器中不允许存在名称相同的 Bean(无论类型是否相同)。Bean 的名称默认是类名首字母小写(如
UserService对应的默认名称是userService),若手动定义了两个同名 Bean(如通过@Bean(name = "userService")重复定义),Spring 启动时会直接报错:plaintextorg.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'xxx.UserService' available: expected single matching bean but found 2: userService,userService这种情况下,无论是否使用@Resource,只要容器中存在同名 Bean,启动阶段就会失败,因为 Spring 不允许 Bean 名称重复。 -
特殊情况:同类型不同名,但
@Resource匹配到多个类型若两个 Bean 类型相同但名称不同,而@Resource按类型匹配(当名称匹配失败时),此时会因存在多个同类型 Bean 而报错。例如:java运行@Service("userService1") public class UserService implements IUserService { ... } @Service("userService2") public class UserService2 implements IUserService { ... } // 注入时,@Resource 先按名称 "userService" 匹配失败,再按类型 IUserService 匹配,发现两个 Bean @Resource private IUserService userService; // 报错:NoUniqueBeanDefinitionException这种情况的解决方式是通过@Resource(name = "userService1")明确指定 Bean 名称。
总结:
- Spring 容器中不允许存在同名 Bean,即使类型不同,同名定义也会导致启动失败,与
@Resource无关。 - 若两个 Bean 类型相同但名称不同,
@Resource若按类型匹配(名称匹配失败时),会因存在多个同类型 Bean 而报错,需通过name属性指定具体 Bean 名称解决。
@Resource 本身不会导致同名 Bean 问题,因为 Spring 容器在注册阶段就不允许同名 Bean 存在;若因类型相同导致匹配冲突,需显式指定 name 属性。-------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------

浙公网安备 33010602011771号