Springboot基础篇(3):Bean管理
前言:Spring 通过扫描类路径(Classpath)来查找带有特定注解(如 @Component、@Service、@Repository 等)的类,并将它们注册为 Spring 容器中的 Bean。
1 Bean扫描
- Bean 扫描是 Spring 框架的核心功能之一,通过注解和配置可以灵活控制 Bean 的注册和扫描范围
- Bean的扫描范围:Spring Boot 默认会扫描主应用程序类(即带有 @SpringBootApplication 注解的类)所在包及其子包中的所有组件【原因在第四点】
- 自定义扫描范围:使用 @ComponentScan 注解指定要扫描的包路径。
@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 注册方式
- 基于注解的注册
/*
用于标注普通组件类。
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 配置仍然支持
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 注册一个 Bean --><bean id="myService" class="com.example.MyService"/>
</beans>
- 基于 Java 配置的 Bean 注册:如果要注册的bean对象来自于第三方(不是自定义的),是无法用 @Component 及衍生注解声明bean的,此时需要在配置类中进行注册
CommonConfig.java
@Configuration// 配置注解
public class CommonConfig {/*** @Bean注解标注的方法会被 Spring容器调用,并将返回值注册为一个 Bean*/@Beanpublic Country country(){return new Country();}/*** 默认情况下,Bean 的名称是方法名。你可以通过name或value属性指定Bean的名称。*/@Bean(name = "customService")public MyService myService() {//Bean 的名称为 customService,而不是默认的 myService。return new MyService();}
}
SpringbootBeanRegisterApplication.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);//获取beanSystem.out.println(country);System.out.println(context.getBean("aa"));}
CommonImportSeletor.java
package com.wfs.config;import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;/*** @ImportSelector:导入选择器* 作用:导入指定配置类*/
public class CommonImportSeletor implements ImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {return new String[]{"com.wfs.config.CommonConfig"};}
}
- 条件化的 Bean 注册:可以结合条件注解(如 @ConditionalOnProperty、@ConditionalOnClass 等)实现条件化的 Bean 注册
@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的依赖注入
- 构造器注入:推荐的方式,适用于强制依赖。
@Service
public class MyService {private final MyRepository repository;@Autowiredpublic MyService(MyRepository repository) {this.repository = repository;}
}
- Setter 注入:适用于可选依赖
@Service
public class MyService {private MyRepository repository;@Autowiredpublic void setRepository(MyRepository repository) {this.repository = repository;}
}
- 字段注入:不推荐,因为不利于测试和代码可读性。
@Service
public class MyService {@Autowiredprivate MyRepository repository;
}