遇到的问题:看黑马JavaWeb课程时,这里要进行@ComponentScan组件扫描或者@Import导入,但是在分模块开发中却不需要进行组件扫描
答案:SpringBoot项目中的@SpringBootApplication注解,具有包扫描的作用,但是它只会扫描启动类所在的当前包以及子包。也就是下图两个位置不同。
准备工作:在Idea中导入"资料\03. 自动配置原理"下的itheima-utils工程
问题引入
1、在SpringBoot项目 spring-boot-web-config2 工程中,通过坐标引入itheima-utils依赖
@Component
public class TokenParser {
public void parse(){
System.out.println("TokenParser ... parse ...");
}
}
2、在测试类中,添加测试方法
@SpringBootTest
public class AutoConfigurationTests {
@Autowired
private ApplicationContext applicationContext;
@Test
public void testTokenParse(){
System.out.println(applicationContext.getBean(TokenParser.class));
}
//省略其他代码...
}
3、执行测试方法
异常信息描述: 没有com.example.TokenParse类型的bean
说明:在Spring容器中没有找到com.example.TokenParse类型的bean对象
思考:引入进来的第三方依赖当中的bean以及配置类为什么没有生效?
- 原因在我们之前讲解IOC的时候有提到过,在类上添加@Component注解来声明bean对象时,还需要保证@Component注解能被Spring的组件扫描到。
- SpringBoot项目中的@SpringBootApplication注解,具有包扫描的作用,但是它只会扫描启动类所在的当前包以及子包。
- 当前包:com.itheima, 第三方依赖中提供的包:com.example(扫描不到)
那么如何解决以上问题的呢? - 方案1:@ComponentScan 组件扫描
- 方案2:@Import 导入(使用@Import导入的类会被Spring加载到IOC容器中)
GPT4-o的回答
问答一
拾叶: 启动类到底会扫描什么?
gpt-4o: Spring Boot 的启动类默认会扫描启动类所在包及其子包中的所有组件。这是因为 @SpringBootApplication
注解本身包含了 @ComponentScan
注解,默认扫描启动类所在包及其子包。
@SpringBootApplication
注解
@SpringBootApplication
是一个复合注解,它包含了以下几个注解:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
其中,@ComponentScan
是负责组件扫描的注解,它默认会扫描启动类所在包及其子包。
具体扫描范围
假设你的启动类位于 com.example.skyserver
包下:
package com.example.skyserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SkyServerApplication {
public static void main(String[] args) {
SpringApplication.run(SkyServerApplication.class, args);
}
}
在这种情况下,Spring Boot 会默认扫描 com.example.skyserver
包及其子包中的所有组件。
如何扩展扫描范围
如果你需要扫描其他包中的组件(例如,跨模块扫描),你可以使用 @ComponentScan
注解来指定其他包:
package com.example.skyserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan(basePackages = {"com.example.skycommon", "com.example.skyserver"})
public class SkyServerApplication {
public static void main(String[] args) {
SpringApplication.run(SkyServerApplication.class, args);
}
}
项目结构示例
假设你的项目结构如下:
sky-take-out
│
├── sky-common
│ └── src/main/java/com/example/skycommon
│ └── config
│ └── AliOssProperties.java
│
├── sky-pojo
│ └── src/main/java/com/example/skypojo
│ └── entity
│ └── SomeEntity.java
│
├── sky-server
│ └── src/main/java/com/example/skyserver
│ └── SkyServerApplication.java
│ └── controller
│ └── SomeController.java
│
├── pom.xml
在这种情况下,如果 SkyServerApplication
类位于 com.example.skyserver
包下,并且你没有使用 @ComponentScan
或 @Import
注解,Spring Boot 只会扫描 com.example.skyserver
包及其子包中的组件。
依赖管理
确保 sky-server
模块的构建文件(如 Maven 的 pom.xml
或 Gradle 的 build.gradle
)中正确地声明了对 sky-common
和 sky-pojo
模块的依赖,这样可以确保这些模块中的类在运行时被加载到类路径中。
Maven示例:
<!-- sky-server/pom.xml -->
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>sky-common</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>sky-pojo</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
总结
Spring Boot 启动类默认会扫描启动类所在包及其子包中的组件。如果你需要跨模块扫描其他包中的组件,可以显式使用 @ComponentScan
注解来指定要扫描的包。同时,确保正确配置模块之间的依赖关系,以便类路径中包含所有必要的类。
问答二
拾叶: 假设你的启动类位于 com.example包下呢,会扫描哪些?
gpt-4o: 如果你的启动类位于 com.example
包下,Spring Boot 默认会扫描 com.example
包及其子包中的所有组件。这是因为 @SpringBootApplication
注解包含了 @ComponentScan
注解,默认扫描启动类所在包及其子包。
示例项目结构
假设你的项目结构如下:
sky-take-out
│
├── sky-common
│ └── src/main/java/com/example/skycommon
│ └── config
│ └── AliOssProperties.java
│
├── sky-pojo
│ └── src/main/java/com/example/skypojo
│ └── entity
│ └── SomeEntity.java
│
├── sky-server
│ └── src/main/java/com/example/skyserver
│ └── controller
│ └── SomeController.java
│
├── src/main/java/com/example
│ └── SkyServerApplication.java
│
├── pom.xml
启动类示例
假设启动类位于 com.example
包下:
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SkyServerApplication {
public static void main(String[] args) {
SpringApplication.run(SkyServerApplication.class, args);
}
}
扫描范围
在这种情况下,Spring Boot 会默认扫描 com.example
包及其所有子包中的所有组件。这意味着以下包中的组件都会被扫描到:
com.example
com.example.skycommon
com.example.skypojo
com.example.skyserver
- 以及其他任何
com.example
包下的子包
组件示例
假设你有以下组件:
AliOssProperties
类在 sky-common
模块中:
package com.example.skycommon.config;
import org.springframework.stereotype.Component;
@Component
public class AliOssProperties {
// 类的代码
}
SomeEntity
类在 sky-pojo
模块中:
package com.example.skypojo.entity;
public class SomeEntity {
// 类的代码
}
SomeController
类在 sky-server
模块中:
package com.example.skyserver.controller;
import com.example.skycommon.config.AliOssProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SomeController {
@Autowired
private AliOssProperties aliOssProperties;
// 控制器方法
}
依赖管理
确保 sky-server
模块的构建文件(如 Maven 的 pom.xml
或 Gradle 的 build.gradle
)中正确地声明了对 sky-common
和 sky-pojo
模块的依赖,以确保这些模块中的类在运行时被加载到类路径中。
Maven示例:
<!-- sky-server/pom.xml -->
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>sky-common</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>sky-pojo</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
总结
如果你的启动类位于 com.example
包下,Spring Boot 默认会扫描 com.example
包及其所有子包中的组件。这种默认行为使得你不需要显式地使用 @ComponentScan
注解来指定要扫描的包,除非你有特殊的扫描需求。确保正确配置模块之间的依赖关系,以便类路径中包含所有必要的类。
问答三
拾叶: 启动类在这个目录sky-server/src/main/java/com/example
gpt-4o: 如果启动类位于 sky-server/src/main/java/com/example
目录下,Spring Boot 默认会扫描 com.example
包及其所有子包中的组件。
项目结构
假设你的项目结构如下:
sky-take-out
│
├── sky-common
│ └── src/main/java/com/example/skycommon
│ └── config
│ └── AliOssProperties.java
│
├── sky-pojo
│ └── src/main/java/com/example/skypojo
│ └── entity
│ └── SomeEntity.java
│
├── sky-server
│ └── src/main/java/com/example
│ └── SkyServerApplication.java
│ └── skyserver
│ └── controller
│ └── SomeController.java
│
├── pom.xml
启动类示例
假设启动类位于 com.example
包下:
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SkyServerApplication {
public static void main(String[] args) {
SpringApplication.run(SkyServerApplication.class, args);
}
}
默认扫描范围
在这种情况下,Spring Boot 会默认扫描 com.example
包及其所有子包中的所有组件。这意味着以下包中的组件都会被扫描到:
com.example
com.example.skycommon
com.example.skypojo
com.example.skyserver
- 以及其他任何
com.example
包下的子包
组件示例
AliOssProperties
类在 sky-common
模块中:
package com.example.skycommon.config;
import org.springframework.stereotype.Component;
@Component
public class AliOssProperties {
// 类的代码
}
SomeEntity
类在 sky-pojo
模块中:
package com.example.skypojo.entity;
public class SomeEntity {
// 类的代码
}
SomeController
类在 sky-server
模块中:
package com.example.skyserver.controller;
import com.example.skycommon.config.AliOssProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SomeController {
@Autowired
private AliOssProperties aliOssProperties;
// 控制器方法
}
依赖管理
确保 sky-server
模块的构建文件(如 Maven 的 pom.xml
或 Gradle 的 build.gradle
)中正确地声明了对 sky-common
和 sky-pojo
模块的依赖,以确保这些模块中的类在运行时被加载到类路径中。
Maven示例:
<!-- sky-server/pom.xml -->
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>sky-common</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>sky-pojo</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
总结
如果启动类位于 sky-server/src/main/java/com/example
目录下,Spring Boot 会默认扫描 com.example
包及其所有子包中的组件。因此,com.example.skycommon
和 com.example.skypojo
包中的组件也会被扫描并注册到Spring上下文中。这种默认行为使得你不需要显式地使用 @ComponentScan
注解来指定要扫描的包,除非你有特殊的扫描需求。确保正确配置模块之间的依赖关系,以便类路径中包含所有必要的类。