前言: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;
}