講一講Spring框架中的控制反轉(zhuǎn)(IoC)
一、 Ioc的概念
控制反轉(zhuǎn)(Inversion of Control,IoC)是一種軟件設(shè)計原則,它將傳統(tǒng)程序流程的控制權(quán)從應(yīng)用程序代碼轉(zhuǎn)移到了框架或容器中。在傳統(tǒng)編程中,對象負(fù)責(zé)創(chuàng)建和管理它所依賴的對象;而在IoC模式下,這種責(zé)任被反轉(zhuǎn)了——由外部容器負(fù)責(zé)創(chuàng)建和管理組件及其依賴關(guān)系。
依賴注入(Dependency Injection)是實現(xiàn)IoC的主要方式之一。Martin Fowler在其文章中將依賴注入與IoC容器視為同一概念的不同表述:
- IoC:強(qiáng)調(diào)控制權(quán)的反轉(zhuǎn)
 - DI:強(qiáng)調(diào)依賴關(guān)系的注入方式
 
Spring框架同時實現(xiàn)了這兩種理念,通過DI機(jī)制來實現(xiàn)IoC容器。
好萊塢原則:
"Don't call us, we'll call you"——這一好萊塢原則很好地詮釋了IoC的思想。組件不再主動獲取依賴,而是被動等待容器注入所需依賴。
二、Spring IoC容器核心實現(xiàn)
2.1 Spring IoC容器的核心接口體系
// 基礎(chǔ)容器接口
public interface BeanFactory {
    Object getBean(String name) throws BeansException;
    <T> T getBean(String name, Class<T> requiredType) throws BeansException;
    // 其他方法...
}
// 應(yīng)用上下文接口,擴(kuò)展了BeanFactory
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, 
    HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
    // 擴(kuò)展方法...
}2.2 容器啟動流程
Spring IoC容器的初始化過程:
- 資源定位:通過ResourceLoader定位配置文件
 - 加載解析:將配置信息加載為BeanDefinition
 - 注冊:將BeanDefinition注冊到BeanDefinitionRegistry
 - 依賴注入:根據(jù)依賴關(guān)系實例化并注入Bean
 
詳細(xì)入口在refresh方法中;
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // 1. 準(zhǔn)備刷新上下文
        prepareRefresh();
        // 2. 創(chuàng)建并配置BeanFactory
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        // 3. 準(zhǔn)備BeanFactory使用
        prepareBeanFactory(beanFactory);
        try {
            // 4. 后處理BeanFactory
            postProcessBeanFactory(beanFactory);
            // 5. 執(zhí)行BeanFactoryPostProcessor
            invokeBeanFactoryPostProcessors(beanFactory);
            // 6. 注冊BeanPostProcessor
            registerBeanPostProcessors(beanFactory);
            // 7. 初始化消息源
            initMessageSource();
            // 8. 初始化事件廣播器
            initApplicationEventMulticaster();
            // 9. 初始化特殊Bean
            onRefresh();
            // 10. 注冊監(jiān)聽器
            registerListeners();
            // 11. 完成BeanFactory初始化,實例化所有非延遲單例Bean
            finishBeanFactoryInitialization(beanFactory);
            // 12. 完成刷新
            finishRefresh();
        } catch (BeansException ex) {
            // 異常處理...
        }
    }
}2.3 BeanDefinition解析
Spring將配置的Bean信息解析為BeanDefinition對象,包含:
- 類名
 - 作用域(scope)
 - 構(gòu)造函數(shù)參數(shù)值
 - 屬性值
 - 初始化方法
 - 銷毀方法
 
使用示例:
// 方式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)
 - 設(shè)置BeanName(如果實現(xiàn)了BeanNameAware)
 - 設(shè)置BeanFactory(如果實現(xiàn)了BeanFactoryAware)
 - 前置初始化(BeanPostProcessor.postProcessBeforeInitialization)
 - 初始化(InitializingBean.afterPropertiesSet或自定義init-method)
 - 后置初始化(BeanPostProcessor.postProcessAfterInitialization)
 - 使用
 - 銷毀(Destroy)
 
圖示:
Bean實例化
    |
    v
屬性賦值(依賴注入)
    |
    v
Aware接口回調(diào)(BeanNameAware等)
    |
    v
BeanPostProcessor.postProcessBeforeInitialization()
    |
    v
@PostConstruct注解方法
    |
    v
InitializingBean.afterPropertiesSet()
    |
    v
自定義init-method
    |
    v
BeanPostProcessor.postProcessAfterInitialization()
    |
    v
Bean就緒可用
    |
    v
容器關(guān)閉時@PreDestroy注解方法
    |
    v
DisposableBean.destroy()
    |
    v
自定義destroy-method2.5 循環(huán)依賴解決方案
Spring通過三級緩存解決循環(huán)依賴問題:
- 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 (默認(rèn)):每個容器一個實例
 - 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;
    // 構(gòu)造器注入(Spring 4.3+可以省略@Autowired)
    @Autowired
    public UserServiceImpl(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
    // Setter注入
    @Autowired
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}核心注解:
@Component:標(biāo)識一個類為Spring組件@Repository:標(biāo)識數(shù)據(jù)訪問層組件@Service:標(biāo)識服務(wù)層組件@Controller:標(biāo)識控制器層組件@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() {
    // 僅當(dāng)條件滿足時創(chuàng)建DataSource
}3.6 @Profile按環(huán)境注冊Bean
@Configuration
public class AppConfig {
    @Bean
    @Profile("dev")
    public DataSource devDataSource() {
        // 開發(fā)環(huán)境數(shù)據(jù)源
    }
    @Bean
    @Profile("prod")
    public DataSource prodDataSource() {
        // 生產(chǎn)環(huán)境數(shù)據(jù)源
    }
}配置文件
spring:
  profiles:
    active: dev














 
 
 









 
 
 
 