引言:在使用 Spring 框架開發應用程式時,依賴註入是一個至關重要的概念。而對於 Bean 容器的註入方式,雖然我們可能都有一定的了解,但實際上很多人在被問及這個問題時可能並不能完整地回答。本文將深入探討 Spring 中 Bean 容器的註入方式,包括 XML 配置方式、基於註解方式、Java 配置方式以及自動掃描方式,並提供了詳細的程式碼範例和解析,以便讀者全面了解並掌握這些方式。
題目
關於 Bean 容器的註入方式,99 % 的人都答不全!
更多題目請見
推薦解析
1)XML配置方式
a) 基於內容註入
透過
<bean>
元素的內容來註入依賴。主要有以下幾種方式:
構造器註入
:
使用
<constructor-arg>
元素配置建構函式參數。
<bean id="exampleBean" class="com.example.ExampleBean">
<constructor-arg ref="dependencyBean" />
</bean>
Setter方法註入:使用
<property>
元素配置Setter方法註入的內容。
<bean id="exampleBean" class="com.example.ExampleBean">
<property name="dependencyBean" ref="dependencyBean" />
</bean>
直接量註入:使用
<constructor-arg>
或
<property>
元素配置基本型別或字串等直接值。
<bean id="exampleBean" class="com.example.ExampleBean">
<constructor-arg value="exampleValue" />
</bean>
b) 基於註解方式
使用
@Autowired
、
@Inject
或
@Resource
註解在類或欄位上進行依賴註入。
構造器註入:在類的構造器上使用
@Autowired
註解。
@Component
public classExampleBean{
private DependencyBean dependency;
@Autowired
publicExampleBean(DependencyBean dependency){
this.dependency = dependency;
}
}
Setter方法註入:在Setter方法上使用
@Autowired
註解。
@Component
public classExampleBean{
private DependencyBean dependency;
@Autowired
publicvoidsetDependency(DependencyBean dependency){
this.dependency = dependency;
}
}
2)Java配置方式
透過Java類來配置Bean,並使用
@Bean
註解將Bean註冊到Spring容器。
@Configuration
public classAppConfig{
@Bean
public ExampleBean exampleBean(){
returnnew ExampleBean(dependencyBean());
}
@Bean
public DependencyBean dependencyBean(){
returnnew DependencyBean();
}
}
3)自動掃描方式
使用
<context:component-scan>
或
@ComponentScan
註解來自動掃描和註冊帶有
@Component
及其衍生註解(如
@Service
、
@Repository
、
@Controller
等)的Bean。
<context:component-scan base-package="com.example" />
或者在Java配置類中使用:
@Configuration
@ComponentScan(basePackages = "com.example")
public classAppConfig{
// 配置其他Bean
}
4)註冊BeanPostProcessor
實作
BeanPostProcessor
介面來在Bean初始化前後進行自訂處理,也可以用來動態註入Bean。
@Component
public classCustomBeanPostProcessorimplementsBeanPostProcessor{
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)throws BeansException {
if (bean instanceof ExampleBean) {
// 自訂處理邏輯,如動態註入其他依賴
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)throws BeansException {
return bean;
}
}
基於條件的 Bean 註冊
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Configuration
public classAppConfig{
@Bean
@Conditional(WindowsCondition. class) // 註冊條件:Windows 作業系統
publicOSInfowindowsInfo() {
returnnew OSInfo("Windows");
}
@Bean
@Conditional(LinuxCondition. class) // 註冊條件:Linux 作業系統
publicOSInfolinuxInfo() {
returnnew OSInfo("Linux");
}
}
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public classWindowsConditionimplementsCondition{
@Override
publicbooleanmatches(ConditionContext context, AnnotatedTypeMetadata metadata){
String osName = System.getProperty("os.name");
return osName.toLowerCase().contains("windows");
}
}
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public classLinuxConditionimplementsCondition{
@Override
publicbooleanmatches(ConditionContext context, AnnotatedTypeMetadata metadata){
String osName = System.getProperty("os.name");
return osName.toLowerCase().contains("linux");
}
}
其他補充
魚聰明 AI 的回答:
魚聰明 AI 地址:https://www.yucongming.com/
初始化階段的回呼
InitializingBean 介面 :
InitializingBean
是 Spring 提供的一個介面,當 Bean 實作該介面時,Spring 容器在例項化 Bean 後會自動呼叫其afterPropertiesSet()
方法,用於執行初始化邏輯。import org.springframework.beans.factory.InitializingBean;
public classMyBeanimplementsInitializingBean{
@Override
publicvoidafterPropertiesSet()throws Exception {
// 執行初始化邏輯
}
}@PostConstruct 註解 :
@PostConstruct
是一個標準的 Java 註解,用於在 Bean 初始化之後執行特定的方法。當一個方法被@PostConstruct
註解標記時,Spring 容器會在例項化 Bean 後立即呼叫該方法。import javax.annotation.PostConstruct;
public classMyBean{
@PostConstruct
publicvoidinit(){
// 執行初始化邏輯
}
}
銷毀階段的回呼
DisposableBean 介面 :
DisposableBean
是 Spring 提供的一個介面,當 Bean 實作該介面時,Spring 容器在銷毀 Bean 之前會自動呼叫其destroy()
方法,用於執行銷毀邏輯。import org.springframework.beans.factory.DisposableBean;
public classMyBeanimplementsDisposableBean{
@Override
publicvoiddestroy()throws Exception {
// 執行銷毀邏輯
}
}@PreDestroy 註解 :
@PreDestroy
是一個標準的 Java 註解,用於在 Bean 銷毀之前執行特定的方法。當一個方法被@PreDestroy
註解標記時,Spring 容器會在銷毀 Bean 之前呼叫該方法。import javax.annotation.PreDestroy;
public classMyBean{
@PreDestroy
publicvoidcleanup(){
// 執行銷毀邏輯
}
}
作用域(Scope)
在 Spring 中,Bean 的作用域決定了在容器中建立的 Bean 的可見範圍和生命周期。Spring 框架提供了以下幾種標準的作用域:
Singleton(預設) :在整個應用程式中只建立一個 Bean 例項,並在容器啟動時就進行建立。所有對該 Bean 的請求都將返回同一個例項。
Prototype :每次請求該 Bean 時都會建立一個新的例項。這意味著每次透過容器獲取該 Bean 時,都會返回一個新的例項。
Request :在每個 HTTP 請求中建立一個新的 Bean 例項,僅在 Web 應用程式上下文中有效。每個 HTTP 請求都會有自己的 Bean 例項,並且該例項僅在當前請求內有效。
Session :在每個 HTTP Session 中建立一個新的 Bean 例項,也僅在 Web 應用程式上下文中有效。每個 HTTP Session 都會有自己的 Bean 例項,並且該例項僅在當前 Session 內有效。
GlobalSession :在一個全域的 HTTP Session 中建立一個 Bean 例項,通常在分布式應用程式中使用。與 Session 作用域類似,但是在集群環境中只有一個 Bean 例項,僅在當前全域 Session 內有效。
生命周期管理
Spring 容器負責管理 Bean 的生命周期,確保它們在正確的時間點被建立、初始化、使用和銷毀。生命周期管理主要涉及以下幾個階段:
例項化 :Spring 容器根據配置資訊或註解建立 Bean 的例項。
內容設定 :Spring 容器將 Bean 的內容(依賴)註入到例項中。
初始化 :如果 Bean 實作了
InitializingBean
介面,容器會呼叫其afterPropertiesSet()
方法,或者如果在方法上使用了@PostConstruct
註解,則在內容設定後立即呼叫被註解標記的方法。使用 :此時 Bean 例項已經完全初始化,可以被應用程式使用。
銷毀 :如果 Bean 實作了
DisposableBean
介面,容器會在銷毀 Bean 之前呼叫其destroy()
方法,或者如果在方法上使用了@PreDestroy
註解,則在 Bean 銷毀前呼叫被註解標記的方法。
自訂作用域和生命周期管理
除了上述提到的標準作用域和生命周期管理方式外,Spring 還允許開發者自訂作用域和生命周期管理策略。可以透過實作
Scope
介面來定義新的作用域,透過實作
BeanPostProcessor
介面來定義 Bean 的自訂初始化和銷毀邏輯。
歡迎交流
本文主要介紹 Bean 容器註入方式和條件註冊,另外有作用域和生命周期勾點函式的使用,面試中也經常會考實戰開發方面的知識,大家可以去關註一下,在文末還有三個問題,歡迎小夥伴在評論多多留言!
1)Bean 容器註入方式有幾個種?
2)Bean 的生命周期是怎麽樣的?
3)怎麽實作基於條件的 Bean 註冊?
點燃求職熱情!每周持續更新,海量面試題和大廠面經等你挑戰!趕緊關註面試鴨公眾號,輕松備戰春招和暑期實習!
往期推薦