講一講Spring框架中的控制反轉(IoC)
一、 Ioc的概念
控制反轉(Inversion of Control,IoC)是一種軟件設計原則,它將傳統程序流程的控制權從應用程序代碼轉移到了框架或容器中。在傳統編程中,對象負責創建和管理它所依賴的對象;而在IoC模式下,這種責任被反轉了——由外部容器負責創建和管理組件及其依賴關系。
依賴注入(Dependency Injection)是實現IoC的主要方式之一。Martin Fowler在其文章中將依賴注入與IoC容器視為同一概念的不同表述:
- IoC:強調控制權的反轉
- DI:強調依賴關系的注入方式
Spring框架同時實現了這兩種理念,通過DI機制來實現IoC容器。
好萊塢原則:
"Don't call us, we'll call you"——這一好萊塢原則很好地詮釋了IoC的思想。組件不再主動獲取依賴,而是被動等待容器注入所需依賴。
二、Spring IoC容器核心實現
2.1 Spring IoC容器的核心接口體系
// 基礎容器接口
public interface BeanFactory {
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
// 其他方法...
}
// 應用上下文接口,擴展了BeanFactory
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory,
HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
// 擴展方法...
}2.2 容器啟動流程
Spring IoC容器的初始化過程:
- 資源定位:通過ResourceLoader定位配置文件
- 加載解析:將配置信息加載為BeanDefinition
- 注冊:將BeanDefinition注冊到BeanDefinitionRegistry
- 依賴注入:根據依賴關系實例化并注入Bean
詳細入口在refresh方法中;
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1. 準備刷新上下文
prepareRefresh();
// 2. 創建并配置BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3. 準備BeanFactory使用
prepareBeanFactory(beanFactory);
try {
// 4. 后處理BeanFactory
postProcessBeanFactory(beanFactory);
// 5. 執行BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
// 6. 注冊BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// 7. 初始化消息源
initMessageSource();
// 8. 初始化事件廣播器
initApplicationEventMulticaster();
// 9. 初始化特殊Bean
onRefresh();
// 10. 注冊監聽器
registerListeners();
// 11. 完成BeanFactory初始化,實例化所有非延遲單例Bean
finishBeanFactoryInitialization(beanFactory);
// 12. 完成刷新
finishRefresh();
} catch (BeansException ex) {
// 異常處理...
}
}
}2.3 BeanDefinition解析
Spring將配置的Bean信息解析為BeanDefinition對象,包含:
- 類名
- 作用域(scope)
- 構造函數參數值
- 屬性值
- 初始化方法
- 銷毀方法
使用示例:
// 方式1:使用 RootBeanDefinition
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClassName("com.example.MyBean");
beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
// 方式2:使用 GenericBeanDefinition
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(MyBean.class);
beanDefinition.setLazyInit(true);
// 方式3:使用 BeanDefinitionBuilder (推薦)
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.rootBeanDefinition(MyBean.class)
.setScope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
.setLazyInit(true);
BeanDefinition beanDefinition = builder.getBeanDefinition();DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 注冊單個BeanDefinition
beanFactory.registerBeanDefinition("myBean", beanDefinition);
// 批量注冊
Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
beanDefinitionMap.put("serviceA", serviceABeanDefinition);
beanDefinitionMap.put("serviceB", serviceBBeanDefinition);
beanFactory.registerBeanDefinitions(beanDefinitionMap);2.4 Bean生命周期管理
完整的Bean生命周期:
- 實例化(Instantiation)
- 屬性填充(Populate properties)
- 設置BeanName(如果實現了BeanNameAware)
- 設置BeanFactory(如果實現了BeanFactoryAware)
- 前置初始化(BeanPostProcessor.postProcessBeforeInitialization)
- 初始化(InitializingBean.afterPropertiesSet或自定義init-method)
- 后置初始化(BeanPostProcessor.postProcessAfterInitialization)
- 使用
- 銷毀(Destroy)
圖示:
Bean實例化
|
v
屬性賦值(依賴注入)
|
v
Aware接口回調(BeanNameAware等)
|
v
BeanPostProcessor.postProcessBeforeInitialization()
|
v
@PostConstruct注解方法
|
v
InitializingBean.afterPropertiesSet()
|
v
自定義init-method
|
v
BeanPostProcessor.postProcessAfterInitialization()
|
v
Bean就緒可用
|
v
容器關閉時@PreDestroy注解方法
|
v
DisposableBean.destroy()
|
v
自定義destroy-method2.5 循環依賴解決方案
Spring通過三級緩存解決循環依賴問題:
- singletonObjects:一級緩存,存放完全初始化好的Bean
- earlySingletonObjects:二級緩存,存放早期暴露的Bean(已實例化但未初始化)
- singletonFactories:三級緩存,存放Bean工廠,用于生成早期引用
源碼分析:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 1. 從一級緩存獲取
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 2. 從二級緩存獲取
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 3. 從三級緩存獲取ObjectFactory
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}2.6 Spring支持多種Bean作用域
- singleton (默認):每個容器一個實例
- prototype:每次請求新實例
- request:每個HTTP請求一個實例
- session:每個HTTP會話一個實例
- application:ServletContext生命周期
使用示例:
@Bean
@Scope("prototype")
public PrototypeBean prototypeBean() {
return new PrototypeBean();
}三、Spring IoC的使用
3.1 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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userService" class="com.example.UserServiceImpl">
<property name="userRepository" ref="userRepository"/>
</bean>
<bean id="userRepository" class="com.example.UserRepositoryImpl"/>
</beans>使用容器
// 加載Spring配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 獲取bean實例
UserService userService = (UserService) context.getBean("userService");3.2 注解方式
@Configuration
public class AppConfig {
@Bean
public UserRepository userRepository() {
return new UserRepositoryImpl();
}
@Bean
public UserService userService(UserRepository userRepository) {
return new UserServiceImpl(userRepository);
}
}使用容器
// 使用AnnotationConfigApplicationContext加載配置類
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 獲取bean
UserService userService = context.getBean(UserService.class);3.3 自動裝配方式
@Component
public class UserServiceImpl implements UserService {
@Autowired // 按類型自動裝配
private UserRepository userRepository;
// 構造器注入(Spring 4.3+可以省略@Autowired)
@Autowired
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
// Setter注入
@Autowired
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
}核心注解:
@Component:標識一個類為Spring組件@Repository:標識數據訪問層組件@Service:標識服務層組件@Controller:標識控制器層組件@Autowired:自動裝配依賴
啟動注解掃描:
<!-- 在XML中開啟注解掃描 -->
<context:component-scan base-package="com.example"/>或
@Configuration
@ComponentScan("com.example")
public class AppConfig {
// 其他配置...
}3.4 延遲初始化
<bean id="lazyBean" class="com.example.ExpensiveBean" lazy-init="true"/>@Bean
@Lazy
public ExpensiveBean expensiveBean() {
return new ExpensiveBean();
}3.5 條件化裝配
@Bean
@Conditional(DataSourceAvailableCondition.class)
public DataSource dataSource() {
// 僅當條件滿足時創建DataSource
}3.6 @Profile按環境注冊Bean
@Configuration
public class AppConfig {
@Bean
@Profile("dev")
public DataSource devDataSource() {
// 開發環境數據源
}
@Bean
@Profile("prod")
public DataSource prodDataSource() {
// 生產環境數據源
}
}配置文件
spring:
profiles:
active: dev


























