尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Spring 全注解开发详解
Spring 全注解开发详解一、什么是全注解开发全注解开发是指完全摆脱 XML 配置文件用 Java 类 注解来构建 Spring 应用。配置类替代了applicationContext.xml注解替代了bean、property、constructor-arg等标签。传统 XML 方式需要维护多个配置文件配置和代码分离修改配置要改 XML。全注解方式把配置和代码放在一起类上标注解就能被 Spring 管理方法参数自动注入依赖配置类替代 XML 文件。Spring Boot 就是全注解开发的极致体现但理解全注解开发需要先掌握 Spring Framework 层面的注解体系。二、从 XML 到注解的演进XML 时代beaniduserDaoclasscom.example.UserDao/beaniduserServiceclasscom.example.UserServicepropertynameuserDaorefuserDao//bean注解时代RepositorypublicclassUserDao{}ServicepublicclassUserService{AutowiredprivateUserDaouserDao;}配置从 XML 转移到了 Java 类上。类的职责和依赖关系一目了然不需要在 XML 和 Java 之间来回切换。三、核心注解体系1. 声明 Bean注解语义适用层Component通用组件任意Service业务层ServiceRepository数据访问层DaoController控制层ControllerRestControllerREST 控制器ControllerConfiguration配置类配置ServicepublicclassUserService{}RepositorypublicclassUserDao{}Bean 名称默认是类名首字母小写可以显式指定Service(userService)publicclassUserService{}2. 配置类与 BeanConfiguration标记一个类为配置类替代 XML 文件。Bean标记方法把返回值注册为 Bean。ConfigurationpublicclassAppConfig{BeanpublicDataSourcedataSource(){HikariDataSourcedsnewHikariDataSource();ds.setJdbcUrl(jdbc:mysql://localhost:3306/mydb);returnds;}BeanpublicJdbcTemplatejdbcTemplate(DataSourcedataSource){returnnewJdbcTemplate(dataSource);}}Configuration类会被 CGLIB 代理Bean方法之间互相调用返回容器中的单例。Component不会被代理方法间调用直接执行方法体。3. 组件扫描ConfigurationComponentScan(com.example)publicclassAppConfig{}SpringBootApplication已经包含了ComponentScan默认扫描启动类所在包及其子包。4. 依赖注入ServicepublicclassUserService{privatefinalUserDaouserDao;privatefinalEmailServiceemailService;publicUserService(UserDaouserDao,EmailServiceemailService){this.userDaouserDao;this.emailServiceemailService;}}构造器注入是 Spring 官方推荐的方式。类只有一个构造方法时Autowired可以省略。5. 配置值注入ComponentpublicclassAppConfig{Value(${app.name})privateStringappName;Value(${app.timeout:30})privateinttimeout;}或者用ConfigurationProperties批量绑定ComponentConfigurationProperties(prefixapp)GetterSetterpublicclassAppProperties{privateStringname;privateinttimeout;privateListStringservers;}四、配置类详解1. Configuration 的本质Configuration本身被Component标注所以它也是一个 Bean。但 Spring 对Configuration类做了特殊处理——通过 CGLIB 生成子类拦截Bean方法的调用。ConfigurationpublicclassAppConfig{BeanpublicUserDaouserDao(){returnnewUserDao();}BeanpublicUserServiceuserService(){// 由于 CGLIB 代理userDao() 返回容器中的单例returnnewUserService(userDao());}}如果换成ComponentuserDao()每次调用都会执行方法体创建新实例。2. Bean 方法参数注入BeanpublicJdbcTemplatejdbcTemplate(DataSourcedataSource){returnnewJdbcTemplate(dataSource);}Spring 会自动从容器中查找DataSource类型的 Bean 注入到方法参数。3. Bean 的生命周期回调Bean(initMethodinit,destroyMethodcleanup)publicMyBeanmyBean(){returnnewMyBean();}也可以在 Bean 类中用PostConstruct和PreDestroy。4. 条件化配置ConfigurationpublicclassAppConfig{BeanConditionalOnMissingBeanpublicObjectMapperobjectMapper(){returnnewObjectMapper();}BeanConditionalOnProperty(nameapp.cache.enabled,havingValuetrue)publicCacheManagercacheManager(){returnnewCaffeineCacheManager();}}5. 环境化配置ConfigurationProfile(dev)publicclassDevConfig{BeanpublicDataSourcedevDataSource(){...}}ConfigurationProfile(prod)publicclassProdConfig{BeanpublicDataSourceprodDataSource(){...}}五、AOP 全注解1. 开启 AOPConfigurationEnableAspectJAutoProxypublicclassAopConfig{}Spring Boot 中引入spring-boot-starter-aop后自动生效。2. 定义切面AspectComponentpublicclassLoggingAspect{Pointcut(execution(* com.example.service.*.*(..)))publicvoidserviceLayer(){}Around(serviceLayer())publicObjectaround(ProceedingJoinPointpjp)throwsThrowable{longstartSystem.currentTimeMillis();Objectresultpjp.proceed();longcostSystem.currentTimeMillis()-start;System.out.println(pjp.getSignature().getName() 耗时costms);returnresult;}}五种通知注解Before、After、AfterReturning、AfterThrowing、Around。3. 自定义注解 AOPTarget(ElementType.METHOD)Retention(RetentionPolicy.RUNTIME)publicinterfaceLog{Stringvalue()default;}AspectComponentpublicclassLogAspect{Around(annotation(log))publicObjectlog(ProceedingJoinPointpjp,Loglog)throwsThrowable{System.out.println(执行log.value());returnpjp.proceed();}}六、事务全注解ConfigurationEnableTransactionManagementpublicclassTransactionConfig{BeanpublicPlatformTransactionManagertransactionManager(DataSourcedataSource){returnnewDataSourceTransactionManager(dataSource);}}业务方法上使用TransactionalServicepublicclassOrderService{Transactional(rollbackForException.class,timeout30)publicvoidcreateOrder(Orderorder){orderDao.save(order);inventoryDao.decrease(order.getProductId(),order.getQuantity());}}Spring Boot 中DataSourceTransactionManager自动配置不需要手动声明。七、Web 层全注解1. 传统 Spring MVC 配置XML 时代需要web.xmlspring-mvc.xml。全注解方式用WebApplicationInitializer替代web.xmlpublicclassWebAppInitializerimplementsWebApplicationInitializer{OverridepublicvoidonStartup(ServletContextservletContext){// 创建 Spring 根容器AnnotationConfigWebApplicationContextrootContextnewAnnotationConfigWebApplicationContext();rootContext.register(AppConfig.class);// 创建 Spring MVC 容器AnnotationConfigWebApplicationContextwebContextnewAnnotationConfigWebApplicationContext();webContext.register(WebConfig.class);// 注册 DispatcherServletServletRegistration.DynamicdispatcherservletContext.addServlet(dispatcher,newDispatcherServlet(webContext));dispatcher.setLoadOnStartup(1);dispatcher.addMapping(/);}}2. WebMvcConfigurer替代spring-mvc.xmlConfigurationEnableWebMvcComponentScan(com.example.controller)publicclassWebConfigimplementsWebMvcConfigurer{OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){registry.addInterceptor(newLoginInterceptor()).addPathPatterns(/**).excludePathPatterns(/login,/register);}OverridepublicvoidaddResourceHandlers(ResourceHandlerRegistryregistry){registry.addResourceHandler(/static/**).addResourceLocations(classpath:/static/);}OverridepublicvoidconfigureMessageConverters(ListHttpMessageConverter?converters){converters.add(newMappingJackson2HttpMessageConverter());}}3. 控制器RestControllerRequestMapping(/api/users)publicclassUserController{AutowiredprivateUserServiceuserService;GetMapping(/{id})publicUsergetUser(PathVariableLongid){returnuserService.getById(id);}PostMappingpublicUsercreate(RequestBodyValidUseruser){returnuserService.save(user);}}4. 全局异常处理RestControllerAdvicepublicclassGlobalExceptionHandler{ExceptionHandler(BusinessException.class)publicResponseEntityErrorResponsehandleBusiness(BusinessExceptione){returnResponseEntity.badRequest().body(newErrorResponse(e.getMessage()));}ExceptionHandler(Exception.class)publicResponseEntityErrorResponsehandleException(Exceptione){returnResponseEntity.status(500).body(newErrorResponse(服务器内部错误));}}八、全注解项目结构src/main/java/com/example/ ├── config/ │ ├── AppConfig.java # 根配置 │ ├── WebConfig.java # Web 配置 │ ├── AopConfig.java # AOP 配置 │ └── TransactionConfig.java # 事务配置 ├── controller/ │ └── UserController.java ├── service/ │ ├── UserService.java │ └── impl/ │ └── UserServiceImpl.java ├── dao/ │ └── UserDao.java ├── entity/ │ └── User.java └── WebAppInitializer.java # 替代 web.xml九、全注解 vs XML对比维度全注解XML配置位置代码内独立文件可读性类与配置合一配置集中但分离修改成本需重新编译改 XML 即可类型安全编译期检查运行时才发现错误重构支持IDE 自动重构手动修改适用场景业务类、Controller、Service第三方类、动态配置现代趋势主流逐步淘汰混合使用自己写的类用注解第三方类用Bean方法或 XML。全注解不等于完全不用 XML而是以注解为主。十、常见问题1. Configuration 与 Component 混用Configuration类会被 CGLIB 代理Bean方法间调用返回单例。Component不会被代理方法间调用创建新实例。配置类一律用Configuration。2. Bean 方法返回类型与注入类型不匹配BeanpublicDataSourcedataSource(){returnnewHikariDataSource();// 返回 HikariDataSource注册为 DataSource 类型}注入时按DataSource类型查找可以找到按HikariDataSource查找也可以Spring 会判断实际类型。3. 组件扫描范围ComponentScan默认扫描当前类所在包及其子包。启动类放在根包下确保所有组件都在扫描范围内。4. 循环依赖构造器注入的循环依赖无法解决启动报BeanCurrentlyInCreationException。字段注入可以通过三级缓存解决但应通过重构消除循环依赖。5. EnableWebMvc 与 Spring BootSpring Boot 中不要手动加EnableWebMvc它会关闭 Spring Boot 的 Web 自动配置。需要自定义 Web 配置时实现WebMvcConfigurer接口即可。十一、总结分类核心注解声明 BeanComponent、Service、Repository、Controller、RestController配置类Configuration、Bean、ComponentScan、Import依赖注入Autowired、Qualifier、Resource、Value配置绑定ConfigurationProperties、PropertySource条件化Conditional、ConditionalOnXxx、ProfileAOPAspect、Pointcut、Before、Around事务EnableTransactionManagement、TransactionalWebEnableWebMvc、WebMvcConfigurer、RestControllerAdvice测试SpringBootTest、MockBean全注解开发是 Spring 现代开发的主流方式。它把配置从 XML 转移到 Java 类和注解上让代码和配置合一类型安全重构友好。Spring Boot 在此基础上进一步简化通过自动配置和 Starter 机制让开发者几乎不需要写配置类。理解全注解开发是掌握 Spring Boot 自动配置原理的基础。
RELATED

相关推荐

Loop:免费开源的 macOS 窗口管理工具,按住一个键窗口立刻去你指的方向

Loop:免费开源的 macOS 窗口管理工具,按住一个键窗口立刻去你指的方向

Loop:免费开源的 macOS 窗口管理工具,按住一个键窗口立刻去你指的方向 【免费下载链接】Loop Window management made elegant. 项目地址: https://gitcode.com/GitHub_Trending/lo/Loop 编辑器、终端、参考文档全开着,每多一个窗口屏…

📅 2026/10/3 20:32:19
gitoxide 威胁模型(Threat Model)全面解析:纯 Rust Git 实现的安全边界、STRIDE 分析与缓解策略

gitoxide 威胁模型(Threat Model)全面解析:纯 Rust Git 实现的安全边界、STRIDE 分析与缓解策略

版本控制CLI 【免费下载链接】gitoxide An idiomatic, lean, fast & safe pure Rust implementation of Git 项目地址: https://gitcode.com/GitHub_Trending/gi/gitoxide 点击查看 免费下载 本文基于 gitoxide 仓库中 etc/security/threat-model.md&#xff0…

📅 2026/10/3 20:32:19
shadPS4 PS4 模拟器安装指南:从源码编译到第一帧

shadPS4 PS4 模拟器安装指南:从源码编译到第一帧

shadPS4 PS4 模拟器安装指南:从源码编译到第一帧 【免费下载链接】shadPS4 PlayStation 4 emulator for Windows, Linux, macOS and FreeBSD written in C 项目地址: https://gitcode.com/GitHub_Trending/sh/shadPS4 shadPS4 是 C 编写的 PlayStation 4 模拟…

📅 2026/10/3 20:32:19
MORE NEWS

更多资讯

📰

鸿业市政道路软件避坑指南:版本匹配、横断面与土方计算常见问题

简介:针对鸿业市政道路软件用户的常见问题解答文档,内容覆盖软件运行、土方、平面、纵断、横断、交叉口设计及其他模块,面向市政道路设计人员与相关专业学生,帮助解决菜单加载失败、土方计算异常、图面显示错乱等高频问题。压缩包…

📰

超级多智能体架构实战:DeepAgents编排、MCP工具接入与A2A通信

1. 从单体到集群:为什么我们需要超级多智能体1.1 一个真实的需求场景去年下半年我接手了一个企业内部知识助手的项目,需求听起来不复杂:帮员工查制度文档、走审批流程、生成周报。一开始我用的是单体 Agent 方案,一个模型加一堆工…

📰

hindsight:面向LLM应用的事后可观测性工程实践

1. 项目概述:hindsight 不是回溯,而是“事后视角”的工程化实践“hindsight”这个词在日常英语里常被译作“后见之明”,指事情发生之后才看清因果、识别关键节点的能力。但在当前技术语境下,尤其结合 Python、OpenAI、Anthropic、…

📰

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

📰

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

📰

QuickBlue:企业AI应用底座,打通模型到业务落地的最后一公里

上个月和一位做工业质检的老友吃饭,他公司的AI项目在测试集上准确率做到了99.3%,可项目就是迟迟上不了产线。我问他卡在哪,他掰着手指头给我数:现场数据传不上来、接口协议没人维护、操作员的反馈没有回流通道,最后还有…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬