Spring創(chuàng)建Bean的八種主要方式詳解
引言
Spring(尤其是 Spring Boot)提供了多種方式來讓容器創(chuàng)建和管理 Bean。@Component、@Configuration + @Bean、@EnableConfigurationProperties 都是常見方式。
下面我為你系統(tǒng)地梳理 Spring 創(chuàng)建 Bean 的所有主要方式,并說明它們的使用場景和區(qū)別。
一、Spring 創(chuàng)建 Bean 的 8 種主要方式
| 方式 | 注解/方法 | 適用場景 |
|---|---|---|
| 1 | @Component 及其衍生注解 | 掃描普通類為 Bean |
| 2 | @Configuration + @Bean | 手動(dòng)配置第三方類或復(fù)雜對(duì)象 |
| 3 | @EnableConfigurationProperties + @ConfigurationProperties | 將配置文件映射為 Bean |
| 4 | @Import | 導(dǎo)入配置類或直接注冊(cè) Bean |
| 5 | 實(shí)現(xiàn) FactoryBean<T> | 創(chuàng)建復(fù)雜或條件性對(duì)象 |
| 6 | 使用 @Conditional 系列注解 | 條件化注冊(cè) Bean |
| 7 | 編程式注冊(cè):BeanDefinitionRegistryPostProcessor | 動(dòng)態(tài)注冊(cè) Bean(高級(jí)) |
| 8 | XML 配置(傳統(tǒng)方式) | 老項(xiàng)目兼容 |
1. @Component 及其衍生注解(最常用)
@Component @Service @Repository @Controller @RestController @Configuration // @Configuration 也是 @Component
- 原理:配合
@ComponentScan,Spring 會(huì)掃描這些類并注冊(cè)為 Bean。 - 適用:你自己寫的業(yè)務(wù)類(Service、DAO、Controller 等)。
@Service
public class UserService {
public void save() { ... }
}
? 自動(dòng)注冊(cè)為 userService Bean。
2. @Configuration + @Bean(手動(dòng)注冊(cè))
用于注冊(cè)不能加 @Component 的類(如第三方庫的類)。
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
return template;
}
}
- 適用:數(shù)據(jù)源、RedisTemplate、RabbitMQ、RocketMQ、OkHttp、HttpClient 等第三方組件。
3. @EnableConfigurationProperties + @ConfigurationProperties
將 application.yml 中的配置自動(dòng)綁定為 Bean。
app: title: MyApp version: 1.0.0
@Component
@ConfigurationProperties(prefix = "app")
public class AppProperties {
private String title;
private String version;
// getter/setter
}
@Configuration
@EnableConfigurationProperties(AppProperties.class)
public class AppConfig {
}
? AppProperties 會(huì)被 Spring 創(chuàng)建并注入配置值,且可被 @Autowired。
在 Spring Boot 2.2+ 中,@EnableConfigurationProperties 通??梢允÷裕灰惣恿?@ConfigurationProperties 并被掃描到即可。
4. @Import(導(dǎo)入配置類或直接注冊(cè))
三種用法:
(1) 導(dǎo)入 @Configuration 類
@Import(DatabaseConfig.class)
@SpringBootApplication
public class Application { }
(2) 導(dǎo)入 @Component 類
@Import(UserService.class)
(3) 導(dǎo)入 ImportSelector 或 ImportBeanDefinitionRegistrar
@Import(MyImportSelector.class)
public class Application { }
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{MyService.class.getName()};
}
}
? 用于實(shí)現(xiàn)“條件導(dǎo)入”、“SPI 擴(kuò)展”等高級(jí)功能。
5. 實(shí)現(xiàn) FactoryBean<T>(創(chuàng)建復(fù)雜對(duì)象)
當(dāng)你需要復(fù)雜的創(chuàng)建邏輯時(shí)使用。
public class MyFactoryBean implements FactoryBean<MyService> {
@Override
public MyService getObject() throws Exception {
MyService service = new MyService();
service.init(); // 復(fù)雜初始化
return service;
}
@Override
public Class<?> getObjectType() {
return MyService.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
@Component
public class MyFactoryBean { } // Spring 會(huì)調(diào)用 getObject() 創(chuàng)建 MyService Bean
? 適合創(chuàng)建代理對(duì)象、動(dòng)態(tài)對(duì)象、SPI 實(shí)現(xiàn)等。
6. @Conditional 系列注解(條件化注冊(cè))
只有滿足條件時(shí)才創(chuàng)建 Bean。
@Bean
@ConditionalOnMissingBean(DataSource.class)
public DataSource dataSource() {
return new HikariDataSource();
}
常見條件注解:
| 注解 | 說明 |
|---|---|
| @ConditionalOnClass | 類路徑存在某個(gè)類 |
| @ConditionalOnMissingBean | 容器中沒有某個(gè) Bean |
| @ConditionalOnProperty | 配置文件中有某個(gè)屬性 |
| @ConditionalOnWebApplication | 是 Web 應(yīng)用 |
| @ConditionalOnExpression | SpEL 表達(dá)式為 true |
? 這是 Spring Boot 自動(dòng)配置的核心機(jī)制。
7. 編程式注冊(cè):BeanDefinitionRegistryPostProcessor
最強(qiáng)大、最靈活的方式,可以在容器啟動(dòng)時(shí)動(dòng)態(tài)注冊(cè) Bean。
@Component
public class DynamicBeanRegistrar implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(UserService.class);
AbstractBeanDefinition definition = builder.getBeanDefinition();
registry.registerBeanDefinition("userService", definition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// do nothing
}
}
? 適合插件化、動(dòng)態(tài)加載、AOP 增強(qiáng)等場景。
8. XML 配置(傳統(tǒng)方式)
<bean id="userService" class="com.example.UserService"/>
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
? 現(xiàn)在已不推薦,但在老項(xiàng)目中仍可見。
總結(jié)對(duì)比
| 方式 | 何時(shí)使用 | 推薦度 |
|---|---|---|
| @Component | 自己寫的類 | ????? |
| @Configuration + @Bean | 第三方類、復(fù)雜配置 | ????? |
| @ConfigurationProperties | 配置文件映射 | ???? |
| @Import | 模塊化導(dǎo)入 | ??? |
| FactoryBean | 復(fù)雜對(duì)象創(chuàng)建 | ??? |
| @Conditional | 條件注冊(cè) | ????(自動(dòng)配置核心) |
| BeanDefinitionRegistryPostProcessor | 動(dòng)態(tài)注冊(cè) | ??(高級(jí)) |
| XML | 老項(xiàng)目 | ? |
最佳實(shí)踐建議
- 優(yōu)先使用
@Component和@Bean,簡單直接; - 配置參數(shù)用
@ConfigurationProperties,類型安全; - 避免重復(fù)注冊(cè),善用
@ConditionalOnMissingBean; - 復(fù)雜邏輯用
@Import或FactoryBean; - 動(dòng)態(tài)場景用
BeanDefinitionRegistryPostProcessor(謹(jǐn)慎使用)。
以上就是Spring創(chuàng)建Bean的八種主要方式詳解的詳細(xì)內(nèi)容,更多關(guān)于Spring創(chuàng)建Bean方式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
基于SpringBoot實(shí)現(xiàn)代碼在線運(yùn)行工具
這篇文章主要介紹了如何利用SpringBoot實(shí)現(xiàn)簡單的代碼在線運(yùn)行工具(類似于菜鳥工具),文中的示例代碼講解詳細(xì),需要的可以參考一下2022-06-06
java eclipse 整個(gè)項(xiàng)目或包查找只定字符串并替換操作
這篇文章主要介紹了java eclipse 整個(gè)項(xiàng)目或包查找只定字符串并替換操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-09-09
實(shí)例解析Java關(guān)于static的作用
只要是有學(xué)過Java的都一定知道static,也一定能多多少少說出一些作用和注意事項(xiàng)。文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
Mybatis-plus中QueryWrapper的多種用法小結(jié)
本文主要介紹了Mybatis-plus中QueryWrapper的多種用法小結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04
Java工程使用ffmpeg進(jìn)行音視頻格式轉(zhuǎn)換的實(shí)現(xiàn)
FFmpeg是一套可以用來記錄、轉(zhuǎn)換數(shù)字音頻、視頻,并能將其轉(zhuǎn)化為流的開源計(jì)算機(jī)程序,本文主要介紹了Java工程使用ffmpeg進(jìn)行音視頻格式轉(zhuǎn)換的實(shí)現(xiàn)2024-02-02
Java創(chuàng)建多線程異步執(zhí)行實(shí)現(xiàn)代碼解析
這篇文章主要介紹了Java創(chuàng)建多線程異步執(zhí)行實(shí)現(xiàn)代碼解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07

