前言:Spring 通过扫描类路径(Classpath)来查找带有特定注解(如 @Component、@Service、@Repository 等)的类,并将它们注册为 Spring 容器中的 Bean。
1 Bean扫描
- Bean 扫描是 Spring 框架的核心功能之一,通过注解和配置可以灵活控制 Bean 的注册和扫描范围
- Bean的扫描范围:Spring Boot 默认会扫描主应用程序类(即带有 @SpringBootApplication 注解的类)所在包及其子包中的所有组件【原因在第四点】
- 自定义扫描范围:使用 @ComponentScan 注解指定要扫描的包路径。
java
@SpringBootApplication
@ComponentScan(basePackages = {"com.example", "com.anotherpackage"})
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
- @SpringBootApplication 是一个组合注解,包含以下三个核心注解:
@SpringBootConfiguration:标记该类为 Spring Boot 的配置类。
@EnableAutoConfiguration:启用 Spring Boot 的自动配置功能。
@ComponentScan: 启用组件扫描功能,默认扫描主应用程序类所在的包及其子包。
2 Bean注册
2.1 概念
Bean 注册是指将 Java 对象交给 Spring 容器管理,使其成为 Spring Bean 的过程
2.2 注册方式
- 基于注解的注册
java
/*
用于标注普通组件类。
Spring 会自动扫描并注册该类为 Bean
*/
@Component
public class MyComponent {
// 组件逻辑
}
/*
用于标注服务层组件。
是 @Component 的特化形式,语义上更明确
*/
@Service
public class MyService {
// 服务逻辑
}
/*
很少用
用于标注数据访问层(DAO)组件。
是 @Component 的特化形式,支持异常转换
*/
@Repository
public class MyRepository {
// 数据访问逻辑
}
/*
用于标注控制器层组件(如 Spring MVC 控制器)。
是 @Component 的特化形式。
*/
@Controller
public class MyController {
// 控制器逻辑
}
- 基于 XML 的 Bean 注册:在早期的 Spring 版本中,Bean 通常通过 XML 配置文件注册。虽然现在推荐使用注解,但 XML 配置仍然支持
xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 注册一个 Bean -->
<bean id="myService" class="com.example.MyService"/>
</beans>
- 基于 Java 配置的 Bean 注册:如果要注册的bean对象来自于第三方(不是自定义的),是无法用 @Component 及衍生注解声明bean的,此时需要在配置类中进行注册
CommonConfig.java
java
@Configuration// 配置注解
public class CommonConfig {
/**
* @Bean注解标注的方法会被 Spring容器调用,并将返回值注册为一个 Bean
*/
@Bean
public Country country(){
return new Country();
}
/**
* 默认情况下,Bean 的名称是方法名。你可以通过name或value属性指定Bean的名称。
*/
@Bean(name = "customService")
public MyService myService() {
//Bean 的名称为 customService,而不是默认的 myService。
return new MyService();
}
}
SpringbootBeanRegisterApplication.java
java
/*
1@Import 是 Spring 框架中的一个注解,用于将其他配置类或组件类导入到当前配置类中
2@Import 可以标注在 @Configuration 类或 @Component 类上,用于导入其他配置类或组件类
3@Import 可以同时导入多个配置类。
4@Import 还可以导入实现了 ImportSelector 接口的类,用于动态选择需要导入的配置类或组件类
*/
@Import(com.wfs.config.CommonImportSeletor.class)//使用@Import导入ImportSelector
//@Import(com.wfs.config.CommonConfig.class)
@SpringBootApplication
public class SpringbootBeanRegisterApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(SpringbootBeanRegisterApplication.class, args);//获取ioc容器
Country country = context.getBean(Country.class);//获取bean
System.out.println(country);
System.out.println(context.getBean("aa"));
}
CommonImportSeletor.java
java
package com.wfs.config;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
/**
* @ImportSelector:导入选择器
* 作用:导入指定配置类
*/
public class CommonImportSeletor implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.wfs.config.CommonConfig"};
}
}
- 条件化的 Bean 注册:可以结合条件注解(如 @ConditionalOnProperty、@ConditionalOnClass 等)实现条件化的 Bean 注册
java
@Configuration
public class CommonConfig {
/**
* 1 Bean对象的名字默认是方法名
* 2 @Bean("aa")自定义对象名
* 3 方法注入:Spring会自动将容器中的 Bean 注入到方法的参数中。
* 4 使用@ConditionalOnProperty 条件注入:配置文件中前缀是province,属性名为name的值若是wfs,则声明此Bean
* 5 @ConditionalOnMissingBean 当不存在当前类型的bean时,才声明该bean
* 6 @ConditionalOnClass 当classpath下存在指定类时,才声明该bean
* @return
*/
@Bean("aa")
@ConditionalOnProperty(prefix = "province",name = "name" ,havingValue = "wfs")
@ConditionalOnMissingBean
@ConditionalOnClass(name = "com.wfs.config.CommonConfig")
public Province province(@Value("${province.name}") String name,
@Value("${province.direction}") String direction) {
Province province = new Province();
province.setName(name);
province.setDirection(direction);
return province;
}
}
3 Bean的依赖注入
- 构造器注入:推荐的方式,适用于强制依赖。
java
@Service
public class MyService {
private final MyRepository repository;
@Autowired
public MyService(MyRepository repository) {
this.repository = repository;
}
}
- Setter 注入:适用于可选依赖
java
@Service
public class MyService {
private MyRepository repository;
@Autowired
public void setRepository(MyRepository repository) {
this.repository = repository;
}
}
- 字段注入:不推荐,因为不利于测试和代码可读性。
java
@Service
public class MyService {
@Autowired
private MyRepository repository;
}