Spring IOC 原理
IOC(Inversion of Control)即控制反转,可以说是 Spring 最核心的部分,IOC 是一种思想,使得开发者从繁琐的对象交互中解脱出来,进而专注对象本身,更进一步突出面向对象。了解 IOC,需要先了解下依赖注入(Dependency Inversion,DI)。
依赖注入就是把底层类作为参数传递给上层类,实现上层对下层的 “控制”。
依赖注入的方式:
- Set 注入;
- 接口注入;
- 构造方法注入;
- 注解注入。
下面看下依赖倒置原则、IOC、依赖注入(DI)、IOC 容器的关系:
正式依赖倒置原则的指导,才有了 IOC 的思路,而实现 IOC 离不开依赖注入(DI)的支撑,Spring 框架基于 IOC 提出了 IOC 容器的概念。对于 IOC 来说,最重要的就是容器了,容器管理着 Bean 的生命周期,控制着 Bean 依赖注入。
IOC 容器的优势:
- 避免在各处使用 new 来创建类,并且可以做到统一维护。
下面来看下 Spring IOC 容器。
Spring 启动的时候,会读取应用程序提供的 Bean 配置信息(XML Config、Java Config、注解 @Autowired),并在 Spring 容器中生成一份 Bean 定义注册表,然后根据这张注册表去实例化 Bean,装配好 Bean 之间的依赖关系,为上层提供准备就绪的运行环境。
Spring 提供一个配置文件描述 Bean 之间的依赖关系,利用 Java 语言的反射功能,实例化 Bean,并建立 Bean 之间的依赖关系。
Spring IOC 支持以下功能:
- 依赖注入;
- 依赖检查;
- 自动装配;
- 支持集合;
- 指定初始化方法和销毁方法;
- 支持回调方法(需要实现 Spring 接口,略带侵入性,谨慎使用)。
Spring IOC 容器的核心接口:
- BeanFactory;
- ApplicationContext。
为了进一步分析 BeanFactory 和 ApplicationContext,需要先弄清楚 BeanDefinition 接口:
BeanDefinition 接口主要是用来描述 Bean 的定义的。
<!-- 事务配置 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="mobileDataSource"/> </bean>
@Service public class MyService { @Autowired private ConnectionSettings connection; //... }
Spring 容器在启动的时候,会将 XML Config、Java Config 或者注解里的 Bean 的定义解析成 Spring 内部的 BeanDefinition。
第二个需要了解的是 BeanDefinitionRegistry 接口,BeanDefinitionRegistry 接口提供了向 IOC 容器注册 BeanDefinition 对象的方法。
BeanFactory 是 Spring 框架最核心的接口,它提供了 IOC 的配置机制,包含了 Bean 的各种定义,便于实例化 Bean,BeanFactory 实例化 Bean 的时候会建立 Bean 之间的依赖关系。除此之外,BeanFactory 还包含了 Bean 生命周期的控制。
package org.springframework.beans.factory; public interface BeanFactory { Object getBean(String name) throws BeansException; boolean containsBean(String name); boolean isSingleton(String name) throws NoSuchBeanDefinitionException; // 省略部分代码... }
由于 BeanFactory 的功能还不够强大,所以 Spring 在 BeanFactory 的基础上还设计了一个更为高级的接口 ApplicationContext,ApplicationContext 是 BeanFactory 的子接口之一。
package org.springframework.context; import org.springframework.beans.factory.HierarchicalBeanFactory; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.core.env.EnvironmentCapable; import org.springframework.core.io.support.ResourcePatternResolver; public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver { String getApplicationName(); ApplicationContext getParent(); // 省略部分代码... }
package org.springframework.beans.factory; public interface ListableBeanFactory extends BeanFactory { boolean containsBeanDefinition(String beanName); int getBeanDefinitionCount(); String[] getBeanDefinitionNames(); // 省略部分代码... }
BeanFactory 和 ApplicationContext 的比较:
- BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身;
- ApplicationContext 面向使用 Spring 框架的开发者;
- BeanFactory 可以理解为 “发动机”,而 ApplicationContext 可以理解为 “汽车”。
ApplicationContext 的功能:
- 继承 BeanFactory 接口:能够管理、装配 Bean;
- 继承 ResourcePatternResolver 接口:能够加载资源文件;
- 继承 MessageSource 接口:能够实现国际化等功能;
- 继承 ApplicationEventPublisher 接口:能够注册监听器,实现监听机制。
Java Config 中,使用注解 @Configuration 可以将 @Bean 注解的方法返回的实例注入到 Spring IOC 容器中。
@Configuration public class ApplicationConfig { @Bean(name = "person") public Person initPerson() { return new Person(100L, "Jack"); // id, name } }
Bean 注入的原理?
下来分析一下容器的创建、配置和 getBean() 两个源码。
Spring IOC 容器创建好之后就会调用 refresh() 方法。
- Spring IOC 的 refresh() 源码解析
AbstractApplicationContext 是 ApplicationContext 接口的实现类。
package org.springframework.context.support; public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext, DisposableBean { @Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 准备刷新上下文 prepareRefresh(); // 获取BeanFactory实例 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 对BeanFactory进行相关设置(设置ClassLoader用来加载Bean、设置表达式解析器等), 为后续使用做准备 prepareBeanFactory(beanFactory); try { // 在BeanFactory进行相关设置后需要做的逻辑, 方法体为空, 不同的Spring容器会重写它 postProcessBeanFactory(beanFactory); // 这个方法比较重要, 调用工厂后处理器, 处理各类Bean标签, 扫描Bean文件, 并解析成一个个的Bean invokeBeanFactoryPostProcessors(beanFactory); // 注册实现了BeanPostProcessors接口的Bean registerBeanPostProcessors(beanFactory); // 初始化国际化相关属性 initMessageSource(); // 初始化事件广播器, 事件广播器用于事件发布 initApplicationEventMulticaster(); // 模板方法, 方法体为空, 不同的Spring容器会重写它 onRefresh(); // 注册事件监听器 registerListeners(); // 实例化所有已经被注册但未被实例化的Bean(排除懒加载Bean) finishBeanFactoryInitialization(beanFactory); // 做一些初始化生命周期处理器等事情 finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } destroyBeans(); cancelRefresh(ex); throw ex; } finally { resetCommonCaches(); } } } // 省略部分代码... }
refresh() 方法:
- 为 IOC 容器以及 Bean 的生命周期管理提供条件;
- 刷新 Spring 上下文信息,定义整个 Spring 上下文加载的流程。
- Spring IOC 的 getBean() 源码解析
AbstractBeanFactory 是 BeanFactory 接口的实现类。
package org.springframework.beans.factory.support; public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory { @Override public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); } protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { // 获取beanName final String beanName = transformedBeanName(name); Object bean; // 根据beanName获取共享的实例 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { // 尝试从缓存或者实例工厂中获取实例 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } // 尝试从ParentBeanFactory中获取Bean实例 BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { //... } if (!typeCheckOnly) { markBeanAsCreated(beanName); } try { // 将父类的属性合并到子类里 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); // 获取依赖关系 String[] dependsOn = mbd.getDependsOn(); // 如果存在依赖, 递归实例化依赖的Bean if (dependsOn != null) { for (String dep : dependsOn) { //... } } // 判断Bean的作用域是否是单例的, 如果是单例就去看先前有没有创建过这个Bean, 如果有就直接返回, 没有就创建一个 if (mbd.isSingleton()) { //... } else if (mbd.isPrototype()) { // 如果作用域是Prototype, 就new一个Bean实例出来 //... } else { //... } } catch (BeansException ex) { cleanupAfterBeanCreationFailure(beanName); throw ex; } } // 类型检查 if (requiredType != null && !requiredType.isInstance(bean)) { //... } return (T) bean; } protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { //... Object object = null; if (mbd == null) { // 从缓存中获取实例 object = getCachedObjectForFactoryBean(beanName); } if (object == null) { //... boolean synthetic = (mbd != null && mbd.isSynthetic()); // 从实例工厂中获取实例 object = getObjectFromFactoryBean(factory, beanName, !synthetic); } return object; } }
getBean() 方法的代码逻辑:
- 转换 beanName;
- 尝试从缓存中加载实例;
- 实例化Bean;
- 检查 parentBeanFactory;
- 初始化依赖的 Bean;
- 创建 Bean。
下面看两个常见的面试问题:
- Spring Bean 的作用域?
- singleton:Spring 的默认作用域,容器里拥有唯一的 Bean 实例;
- prototype:针对每个 getBean() 请求,容器都会创建一个 Bean 实例;
如果是 Web 容器,还支持以下三种作用域:
- request:会为每个 http 请求创建一个 Bean 实例;
- session:会为每个 session 创建一个 Bean 实例;
- globalSession:会为每个全局 http session 创建一个 Bean 实例,该作用域仅对 Portlet 有效。
- Spring Bean 的生命周期?
容器创建之后会解析并创建出来 Bean,Spring Bean 的生命周期是由容器来管理的。
Bean 创建的过程:
- 实例化 Bean;
- Aware (注入 Bean ID、BeanFactory 和 AppCtx),Aware 接口是为了能够感知到自身的属性;
- 调用 BeanPostProcessor 的前置初始化方法 postProcessBeforeInitialization();
- 如果实现了 InitializingBean 接口,则会调用 InitializingBean 的 afterPropertiesSet() 方法,做一些属性被自定义后的事情;
- 调用 Bean 自身定义的 init() 方法;
- 调用 BeanPostProcessor 的后置初始化方法 postProcessAfterInitialization();
- Bean 的初始化完毕。
Bean 销毁的过程:
- 如果 Bean 实现了 DisposableBean 接口,则会调用 destroy() 方法;
- 如果Bean 自身定义了 destroy-method 属性,则会调用其定义的销毁方法;
- Bean 的销毁完毕。
#2.AOP原理
- 技术交流笔记——SPRING IOC 原理
- Spring IOC(控制反转/依赖注入)原理解析
- spring ioc原理(看完后大家可以自己写一个spring)
- spring ioc原理
- Spring IOC原理详解
- spring ioc原理(看完后大家可以自己写一个spring)
- Spring IOC 和 DI原理 (面试必备)
- Spring IOC和AOP 原理彻底搞懂
- spring ioc原理(看完后大家可以自己写一个spring)
- 理解spring ioc 原理
- Spring IOC和AOP 原理彻底搞懂
- spring IOC和AOP的原理
- 170511、Spring IOC和AOP 原理彻底搞懂
- spring ioc和aop原理理解
- Spring IOC和AOP 原理彻底搞懂
- spring IoC和AOP的原理
- spring ioc原理(看完后大家可以自己写一个spring)
- spring ioc 原理 spring aop原理
- Spring IOC原理之Java反射机制
- spring IOC核心原理