Ioc 是在Spring中, 一种控制(依赖)反转模式的实现载体, 而这种模式采用倒置注入的方式解决对象依赖问题,这样可以简化对象依赖管理, 在很大程度上降低面向对象系统开发的复杂性, 控制反转是Spring框架的核心.
1 . 先看一下Spring Ioc设计所关系到的一系列接口与类的继承实现关系
最后的 (ClassPathXmlApplicationContext) 和 (XmlWebApplicationContext) 就是我们平时做SpringMVC开发常用到的初始化类对象。
2 . 介绍说明一下上图中出现的各个接口的作用
(1). BeanFactory: 访问获取 spring bean 容器中 bean 实例最基础的接口.
(2). HierarchicalBeanFactory: 在 BeanFactory 的基础上添加了继承功能, bean工厂可以包含父容器;
(3). ConfigurableBeanFactory: 为 BeanFactory 添加配置能力, 指定bean初始化方式等;
(4). ListableBeanFactory: 可以加载获取到一系列的bean对象;
(5). ConfigurableListableBeanFactory: 提供了分析与修改bean实例的能力, 及单例的预实例化;
(6). AutowireCapableBeanFactory: 可以通过注解的方式为一个bean实例提供它所需的其他bean做为它的属性;
(7). SimpleAliasRegistry: 一个简单的bean别名注册器;
(8). DefaultSingletonBeanRegistry: 注册单例对象实例并运行被所有需要注册的bean所共享, 根据bean name获取;
(9). FactoryBeanRegistrySupport: 在DefaultSingletonBeanRegistry上再做了层封装, 相当于一个管理对象可以安全被用户使用;
(10). AbstractBeanFactory: 具有可配置bean工厂的全部功能, 同时提供了单例bean缓存, 可以处理, bean别名, bean定义及其子类定义合并, 还有bean的销毁方法等;
(11). AbstractAutowireCapableBeanFactory: 实现了默认的bean创建方式, 同时添加了注解注入的功能;
(12). BeanDefinitionRegistry: 注册bean定义在父子上下文容器里面;
(13). DefaultListableBeanFactory: 一个默认的且完整的 Bean Factory 实现类, 具有bean工厂以上全部功能;
(14). EnvironmentCapable: 具有获得一个环境信息对象的能力;
(15). MessageSource: 处理相关信息源的能力, 比如支持国际化的实现等
(16). ApplicationEventPublisher: 支持应用程序事件为bean生命周期管理提供便利;
(17). ResourcePatternResolver: 获取访问资源;
(18). Lifecycle: 定义开始与结束的生命周期控制;
(19). Closeable: 用于释放或关闭某些资源对象数据;
(20). ApplicationContext: Spring的核心接口, 提供对一个应用的配置; 这个对象时只读的, 除非它的子对象进行重新载入;
(21). ConfigurableApplicationContext: 结合了ApplicationContext, 添加了额外的应用程序生命周期等处理入口;
(22). WebApplicationContext: 相比ApplicationContext添加了获取ServletContext的方法, 以支持web应用;
(23). AbstractApplicationContext: ApplicationContext 的一个抽象实现类, 是SpringIoc容器初始化时的关键对象, 里面有一些列bean创建, 资源处理, 过滤器添加, 相关事件通知等;
(24). InitializingBean: 当一个bean实例所依赖所有对象都被Bean factory注入后, 会回调这个接口中的afterPropertiesSet方法;
(25). AbstractRefreshableApplicationContext: 实现了AbstractApplicationContext中的refreshBeanFactory方法, 进行spring bean factory的默认创建和bean定义解析载入;
(26). BeanNameAware: 可以得到bean的名称;
(27). AbstractRefreshableConfigApplicationContext: 在AbstractRefreshableApplicationContext的基础上引入了BeanNameAware和InitializingBean方法;
(28). AbstractXmlApplicationContext: 实现了个装载bean的方法;
(29). ClassPathXmlApplicationContext: 类路径下加载bean配置文件;
(30). ConfigurableWebApplicationContext: 结合WebApplicationContext与ConfigurableApplicationContext;
(31). ThemeSource: 获取Theme对象, 后面做资源转换;
(32). FileSystemXmlApplicationContext: 文件系统路径下加载bean配置文件;
(33). AbstractRefreshableWebApplicationContext:
(34). XmlWebApplicationContext: Spring Web应用默认配置在”org.springframework.web.context.ContextLoader.properties”中的, 由”org.springframework.web.context.ContextLoaderListener”加载启动应用上下文的Class对象, 同时里面有bean定义解析的方法实现;
(35). XmlBeanDefinitionReader: 读取解析spring配置xml文件中的bean定义信息及其他配置信息;
(36). BeanDefinition: Spring bean factory中对bean对象定义的数据对象, 也是Spring Ioc中的核心数据结构对象;
Spring容器加载启动过程
3 . Spring Web应用由web.xml加载启动
(1). 首先会有如下两个配置项, 分别在ContextLoader与FrameworkServlet两个内里面有WebApplicationContext的创建加载解析操作;
<!-- Spring Listener 需要加载的配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/spring-context.xml</param-value>
</context-param>
// 配置Listener加载Spring应用上下文的父容器
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
// 配置Listener加载Spring应用上下文的子容器
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/spring-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
(2). 从配置文件xml解析bean与项目配置信息的关键过程
/**
* Instantiate the WebApplicationContext for this servlet, either a default
* {@link org.springframework.web.context.support.XmlWebApplicationContext}
* or a {@link #setContextClass custom context class}, if set.
* <p>This implementation expects custom contexts to implement the
* {@link org.springframework.web.context.ConfigurableWebApplicationContext}
* interface. Can be overridden in subclasses.
* <p>Do not forget to register this servlet instance as application listener on the
* created context (for triggering its {@link #onRefresh callback}, and to call
* {@link org.springframework.context.ConfigurableApplicationContext#refresh()}
* before returning the context instance.
* @param parent the parent ApplicationContext to use, or {@code null} if none
* @return the WebApplicationContext for this servlet
* @see org.springframework.web.context.support.XmlWebApplicationContext
*/
protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
Class<?> contextClass = getContextClass();
if (this.logger.isDebugEnabled()) {
this.logger.debug("Servlet with name '" + getServletName() +
"' will try to create custom WebApplicationContext context of class '" +
contextClass.getName() + "'" + ", using parent context [" + parent + "]");
}
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw new ApplicationContextException(
"Fatal initialization error in servlet with name '" + getServletName() +
"': custom WebApplicationContext class [" + contextClass.getName() +
"] is not of type ConfigurableWebApplicationContext");
}
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setEnvironment(getEnvironment());
wac.setParent(parent);
wac.setConfigLocation(getContextConfigLocation());
configureAndRefreshWebApplicationContext(wac);
return wac;
}
(3). 创建完WebApplicationContext后进行初始化
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
// The application context id is still set to its original default value
// -> assign a more useful id based on available information
if (this.contextId != null) {
wac.setId(this.contextId);
}
else {
// Generate default id...
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils.getDisplayString(getServletContext().getContextPath()) + "/" + getServletName());
}
}
wac.setServletContext(getServletContext());
wac.setServletConfig(getServletConfig());
wac.setNamespace(getNamespace());
wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
// The wac environment's #initPropertySources will be called in any case when the context
// is refreshed; do it eagerly here to ensure servlet property sources are in place for
// use in any post-processing or initialization that occurs below prior to #refresh
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
}
postProcessWebApplicationContext(wac);
applyInitializers(wac);
wac.refresh();
}
(4). 调用ConfigurableApplicationContext接口的refresh, 这个方法很关键, 里面是真正的bean创建与装配,
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing
// 设置标志量, 这个方式是同步执行的
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 获取到beanFactory, 里面包含了所有bean的定义信息,别名信息等
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// 设置一些默认属性, 包括类加载器, 表达式处理器, 过程处理器和context回调处理器等
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 可以加入额外的bean初始过程处理器, 对于web应用这里就会加入一个为ServletConfigAware类型的bean对象设置servlet上下文的处理器;
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 反转提取其他过程处理器,这里会有一个BeanDefinitionRegistryPostProcessor处理器, 如果项目使用了Mybatis, 那还会有个MapperScannerConfigurer的处理器(进行mybatis里面mapper扫描与dao实例植入);
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 注册一些拦截bean创建过程的处理器, 比如注解注入啊, requestmapping, aop切入等
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 初始化应用上下问的信息源
initMessageSource();
// Initialize event multicaster for this context.
// 为应用上下文注册一个事件多路广播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 处理themeSource
onRefresh();
// Check for listener beans and register them.
// 为事件广播器设置进去需要通知的监听器的名称
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// 单例Bean初始化与装配及相关接口回调
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 事件发布
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
4 . 几个有用的与Spring上下文及bean初始化进程相关的接口
(1). BeanNameAware: setBeanName方法,可以让该bean感知到在beanFactory中自己的名字; 调度时间是在该bean被实例化并装配好自身所依赖的属性后, 但在 InitializingBean#afterPropertiesSet()
之前;
(2). BeanClassLoaderAware: setBeanClassLoader方法,可以让该bean感知到它是被哪个类加载器加载的;调度时间紧跟在 BeanNameAware 之后;
(3). BeanClassLoaderAware: setBeanFactory方法,可以让该bean感知到它所在的BeanFactory;调度时间紧跟在 BeanClassLoaderAware之后;
(4). InitializingBean: afterPropertiesSet方法, 当一个bean被完全装配完后调用的方法;此时这个bean已经具有了它应该有的所有业务功能;
(5). DisposableBean: destroy方法, 在bean被销毁前调用, 可以做一些资源释放或者信息发送等操作;
(6). ApplicationContextAware: setApplicationContext方法, 可以得到spring应用上下文的引用;