news 2026/10/1 2:48:57

Spring 声明 Bean 的注解详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring 声明 Bean 的注解详解

Spring 声明 Bean 的注解详解

一、概述

Spring 声明 Bean 的注解分为两大类:类级别注解和方法级别注解。类级别注解标注在类上,Spring 通过组件扫描自动注册;方法级别注解标注在@Configuration类的方法上,手动注册返回值。

类别注解标注位置注册方式
类级别@Component类组件扫描
类级别@Service类组件扫描
类级别@Repository类组件扫描
类级别@Controller类组件扫描
类级别@RestController类组件扫描
类级别@Configuration类组件扫描
方法级别@Bean方法配置类中手动注册

二、@Component:基础组件注解

@Component是最基础的 Bean 声明注解,其他类级别注解都是它的派生注解。

@ComponentpublicclassUserDao{publicvoidsave(){System.out.println("保存用户");}}

Bean 名称规则:默认是类名首字母小写,如UserDao→userDao。可以显式指定名称:

@Component("myUserDao")publicclassUserDao{}

特点:

  • 通用性最强,适合不属于任何特定层次的组件
  • 是@Service、@Repository、@Controller的元注解
  • 被@ComponentScan扫描后注册为 Bean

三、@Service:业务层组件

@Service是@Component的派生注解,语义上表示业务逻辑层。

@ServicepublicclassUserService{@AutowiredprivateUserDaouserDao;publicvoidregister(Useruser){userDao.save(user);}}

为什么用 @Service 而不是 @Component?

功能上完全等价,但语义更清晰。在代码审查时,看到@Service就知道这是业务层组件,看到@Repository就知道这是数据访问层组件。这种语义分层让项目结构更清晰。

四、@Repository:数据访问层组件

@Repository是@Component的派生注解,专门用于数据访问层。它有一个额外功能:异常转换。

@RepositorypublicclassUserDaoImplimplementsUserDao{@AutowiredprivateJdbcTemplatejdbcTemplate;@Overridepublicvoidsave(Useruser){jdbcTemplate.update("INSERT INTO user (name) VALUES (?)",user.getName());}}

当@Repository类抛出数据库异常时,Spring 会自动将其转换为 Spring 的统一数据访问异常体系(DataAccessException)。这样上层代码不需要处理特定数据库厂商的异常类型,切换数据库时业务代码不受影响。

五、@Controller 和 @RestController

@Controller标记 Web 控制层组件,@RestController是@Controller和@ResponseBody的组合。

@ControllerpublicclassPageController{@GetMapping("/index")publicStringindex(){return"index";// 返回视图名,渲染模板}}@RestControllerpublicclassUserController{@AutowiredprivateUserServiceuserService;@GetMapping("/user/{id}")publicUsergetUser(@PathVariableLongid){returnuserService.getById(id);// 直接返回 JSON}}

@Controller返回视图名,由视图解析器渲染页面。@RestController返回的对象直接作为 HTTP 响应体输出,适合前后端分离的 RESTful API。

六、@Configuration:配置类

@Configuration标记一个类为配置类,可以替代 XML 配置文件。它本身也是一个@Component,会被组件扫描注册。

@ConfigurationpublicclassAppConfig{@BeanpublicDataSourcedataSource(){HikariDataSourceds=newHikariDataSource();ds.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");returnds;}}

@Configuration与@Component的区别:@Configuration类会被 CGLIB 代理,保证@Bean方法之间互相调用时返回容器中的单例。@Component不会被代理,方法间调用直接执行方法体,创建新实例。

@ConfigurationpublicclassAppConfig{@BeanpublicUserDaouserDao(){returnnewUserDao();}@BeanpublicUserServiceuserService(){// 由于 CGLIB 代理,userDao() 返回的是容器中的单例returnnewUserService(userDao());}}

七、@Bean:方法级别声明

@Bean标注在@Configuration类的方法上,把方法返回值注册为 Bean。

@ConfigurationpublicclassAppConfig{@BeanpublicDataSourcedataSource(){returnnewHikariDataSource();}@BeanpublicJdbcTemplatejdbcTemplate(DataSourcedataSource){returnnewJdbcTemplate(dataSource);}}

适用场景:

  • 第三方类无法添加@Component注解时
  • 需要复杂初始化逻辑的对象
  • 需要根据条件动态创建 Bean 时

@Bean方法参数:Spring 会自动从容器中注入匹配的 Bean。

@BeanpublicJdbcTemplatejdbcTemplate(DataSourcedataSource){// dataSource 自动从容器注入returnnewJdbcTemplate(dataSource);}

Bean 名称:默认是方法名,可以通过name或value指定:

@Bean("myDataSource")publicDataSourcedataSource(){...}

初始化和销毁方法:

@Bean(initMethod="init",destroyMethod="cleanup")publicMyBeanmyBean(){returnnewMyBean();}

八、@ComponentScan:组件扫描

@ComponentScan告诉 Spring 扫描哪些包下的组件。

@Configuration@ComponentScan("com.example")publicclassAppConfig{}

常用属性:

属性作用
basePackages指定扫描的包路径
basePackageClasses指定类所在包为扫描根路径
includeFilters包含过滤器
excludeFilters排除过滤器
@ComponentScan(basePackages="com.example",excludeFilters=@ComponentScan.Filter(type=FilterType.ANNOTATION,classes=Service.class))

@SpringBootApplication已经包含了@ComponentScan,默认扫描启动类所在包及其子包。

九、@Import:导入配置

@Import用于导入其他配置类或普通类,被导入的类会注册为 Bean。

@Configuration@Import({DatabaseConfig.class,RedisConfig.class})publicclassAppConfig{}

@Import支持三种类型:

  • 普通配置类(@Configuration类)
  • ImportSelector实现类
  • ImportBeanDefinitionRegistrar实现类

十、条件化声明 Bean

@Conditional

根据条件决定是否注册 Bean:

@ConfigurationpublicclassAppConfig{@Bean@Conditional(WindowsCondition.class)publicFileServicewindowsFileService(){returnnewWindowsFileService();}@Bean@Conditional(LinuxCondition.class)publicFileServicelinuxFileService(){returnnewLinuxFileService();}}

Spring Boot 的条件注解

注解条件
@ConditionalOnClassclasspath 中存在指定类
@ConditionalOnMissingClassclasspath 中不存在指定类
@ConditionalOnBean容器中存在指定 Bean
@ConditionalOnMissingBean容器中不存在指定 Bean
@ConditionalOnProperty配置属性满足条件
@ConditionalOnWebApplication是 Web 应用
@Bean@ConditionalOnMissingBeanpublicObjectMapperobjectMapper(){returnnewObjectMapper();}

@ConditionalOnMissingBean常用于提供默认实现,允许用户通过自定义 Bean 覆盖。

十一、@Profile:环境化声明 Bean

根据激活的 Profile 决定是否注册 Bean:

@Configuration@Profile("dev")publicclassDevConfig{@BeanpublicDataSourcedevDataSource(){// 开发环境数据源}}@Configuration@Profile("prod")publicclassProdConfig{@BeanpublicDataSourceprodDataSource(){// 生产环境数据源}}

也可以通过启动参数激活:

java-jarmyapp.jar--spring.profiles.active=prod

十二、各注解对比总结

注解标注位置语义特殊功能
@Component类通用组件无
@Service类业务层无(语义清晰)
@Repository类数据访问层异常转换
@Controller类Web 控制层视图解析
@RestController类REST 控制器直接返回 JSON
@Configuration类配置类CGLIB 代理
@Bean方法手动注册灵活创建
@ComponentScan类组件扫描指定扫描范围
@Import类导入配置导入其他配置类
@Conditional类/方法条件注册按条件决定
@Profile类/方法环境注册按 Profile 决定

十三、最佳实践

按层选择注解:Controller 层用@Controller或@RestController,Service 层用@Service,Dao 层用@Repository。语义清晰,便于维护。

第三方类用 @Bean:无法修改源码的第三方类,通过@Configuration+@Bean注册。

条件化 Bean 用 @ConditionalOnMissingBean:提供默认实现,允许用户覆盖。

多环境用 @Profile:不同环境的 Bean 分开配置,避免运行时判断。

组件扫描范围控制在合理范围:启动类放在根包下,避免扫描到不需要的包,影响启动速度。

十四、总结

维度核心要点
类级别注解@Component、@Service、@Repository、@Controller、@RestController、@Configuration
方法级别注解@Bean
扫描注解@ComponentScan
导入注解@Import
条件注解@Conditional、@ConditionalOnXxx
环境注解@Profile
选择原则自己的类用类级别注解,第三方类用@Bean

Spring 声明 Bean 的注解体系围绕“类级别自动扫描”和“方法级别手动注册”两条线展开。@Component及其派生注解负责前者,@Bean负责后者。配合@ComponentScan、@Import、@Conditional、@Profile,可以灵活地控制 Bean 的注册范围和条件。理解这些注解的语义和适用场景,是掌握 Spring IoC 注解式开发的基础。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 2:48:20

Zed 补上了这个快捷键,VS Code 和 IDEA 用户终于不用改肌肉记忆了

从 VS Code 或 IDEA 迁到 Zed,第一周最难受的往往不是功能缺失,而是"我那个按了好几年的键呢?" VS Code 用户大概都有这个肌肉记忆:光标停在某一行,不管在行首、行中还是行尾,按下 Ctrl+Enter,当前行保持原样不动,下面凭空多出一行空白,光标已经落在新行上…

作者头像 李华
网站建设 2026/10/1 2:48:04

多Agent智能体架构设计实战:从拆角色到协作编排的工程化落地

好的,直接开始。多Agent智能体架构,这个题目我确实有发言权。最近一年我主导了好几个从"单体Agent"往"多Agent协作"迁移的项目,踩过的坑、推翻重来的设计都不少。2026年业内其实已经形成一个共识:这是工业智能…

作者头像 李华
网站建设 2026/10/1 2:47:57

嘎嘎降AI实操指南:原理、模式选择与降AI率技巧

1. 嘎嘎降AI是什么?为什么你需要它先说结论:嘎嘎降AI是一个专门用来“去掉AI味儿”的文本处理工具。你把它当成一个过滤器就行——左边丢进去一段ChatGPT、DeepSeek、文心一言生成的稿子,右边出来一段读起来更像正常人写的文字,核…

作者头像 李华
网站建设 2026/10/1 2:47:46

搜索系列 · 第 03 篇——核心原理:倒排索引与 BM25

倒排索引 分词映射 相关性打分 段管理 目 录 一、导读 二、倒排索引原理 2.1 正排 vs 倒排 2.2 倒排索引结构 2.3 示例 三、分词器与映射 3.1 Analyzer 处理流程 3.2 常见分词器 3.3 映射:text vs keyword 四、BM25 相关性打分 4.1 从 TF-IDF 到 BM25 4.2 BM25 …

作者头像 李华
网站建设 2026/10/1 2:46:56

ST32 与 ET200SP 通讯翻车后,我总结了这份踩坑指南

西门子PLC SMART G2和ET200SP调通通讯需要多久,相信很对PLC工程师都会说分分钟搞定。我也一样,信誓旦旦的给同事说等我一下,最多10分钟,可这调通之路折腾了我2天时间。给大家分享我的踩坑之路。以为简简单单,5分钟搞定…

作者头像 李华
网站建设 2026/10/1 2:46:38

初识C语言:函数的定义、参数、调用

1.什么是函数(1)定义:函数即子程序,是一个大型程序中的某部分代码,由一个或多个语句块组成。负责完成某项特定的任务,与其他代码相比,有相对的独立性2.C语言中的函数分类(1)库函数:C语言自带的函数总结C语言…

作者头像 李华