掘金 人工智能 06月03日 10:48
告别 "Bean Not Found"!轻松搞定 Spring Boot 包扫描难题 ✅
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文探讨了在Spring Boot应用中,由于包结构调整导致无法扫描到Bean定义的问题,并分析了其原因。文章通过一个案例,详细阐述了@SpringBootApplication注解的ComponentScan机制,以及如何通过调整包结构或显式配置ComponentScan来解决该问题,最终确保应用能够正确识别和加载所需的Bean。

💡 案例演示:文章首先通过一个具体的案例,展示了在调整Spring Boot项目的包结构后,应用无法识别新添加的Controller的问题,引发了对Bean扫描机制的关注。

🔍 深入分析:文章深入剖析了@SpringBootApplication注解的工作原理,特别是其内嵌的@ComponentScan注解。@ComponentScan默认扫描声明@SpringBootApplication注解的类所在的包及其子包,从而实现Bean的自动扫描和注册。

✅ 解决方案:针对案例中出现的问题,文章提供了两种解决方案:一是调整包结构,确保Controller类位于@SpringBootApplication注解类所在的包或其子包下;二是显式配置@ComponentScan,明确指定需要扫描的包路径。文章还介绍了@ComponentScans注解,用于配置多个扫描包范围。

本文已收录在Github关注我,紧跟本系列专栏文章,咱们下篇再续!

0 前言

SpringBoot约定大于配置,但不熟悉所有约定,所以经常写bug!

1 案例:扫描不到Bean定义

Spring Boot服务包结构:

BestPractiseApplication:

package com.javaedge.spring.aop;/** * @author JavaEdge */@SpringBootApplicationpublic class BestPractiseApplication {    public static void main(String[] args) {        SpringApplication.run(BestPractiseApplication.class, args);    }}

MyController:

package com.javaedge.spring.app;/** * @author JavaEdge */@RestControllerpublic class MyController {    @GetMapping("hello")    public String hello() {        return "hello Java";    }}

访问http://localhost:12345/hello

紧急需求,需添加多个Controller,常规操作调整包结构:

发现应用不识别MyController,找不到 MyController 这 Bean,why?

2 解惑

2.1 之前为啥生效?

@SpringBootApplication继承了其它注解:

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })public @interface SpringBootApplication {

SpringBootApplication默认开启ComponentScan。SpringBoot应用启动时,ComponentScan扫描所有定义的 Bean,扫描位置由 ComponentScan 的 basePackages 属性指定:

package org.springframework.context.annotation;@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documented@Repeatable(ComponentScans.class)public @interface ComponentScan {@AliasFor("basePackages")String[] value() default {};@AliasFor("value")String[] basePackages() default {};

但basePackages默认空,那它扫描的啥包?debug 到 ComponentScanAnnotationParser#parse:

即declaringClass所在包,即com.javaedge.app

3 修正

如下两种方案:

3.1 放好位置

3.2 显式配置

@ComponentScan

package com.javaedge.spring.app;@SpringBootApplication()@ComponentScan("com.javaedge.spring.controller")public class BestPractiseApplication {    public static void main(String[] args) {        SpringApplication.run(BestPractiseApplication.class, args);    }}

@ComponentScans

package com.javaedge.spring.app;@SpringBootApplication()@ComponentScans(value = {@ComponentScan(value = "com.javaedge.spring.controller")})public class BestPractiseApplication {    public static void main(String[] args) {        SpringApplication.run(BestPractiseApplication.class, args);    }}

ComponentScans 相比 ComponentScan,可指定扫描多个包范围。

本文由博客一文多发平台 OpenWrite 发布!

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

SpringBoot ComponentScan Bean扫描 依赖注入
相关文章