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原理