ApplicationContext源码及其IOC容器初始化过程的简单介绍!
回顾一下IOC容器
IOC容器,就是为用户提供创建、管理、获取它们的类实例的容器,让用户在需要使用类对象的时候,只需要向IOC容器要就可以了,进而能够达到与具体的类解耦,为其他的高级功能和特性提供基础。
IOC容器在被使用之前,需要完成以下工作:
使用Spring的三种方式
- XML配置的方式
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="girl" class="di.MagicGirl"
init-method="start" destroy-method="end">
<constructor-arg type="java.lang.String" value="girl"></constructor-arg>
<property name="friend" ref="boy"></property>
</bean>
<bean id="boy" class="di.Lad">
<constructor-arg type="java.lang.String" value="boy"></constructor-arg>
<constructor-arg type="di.MagicGirl" value="girl"></constructor-arg>
</bean>
</beans>
通过XML的方式来指定扫描包的范围:
<context:component-scan base-package="demo.beans" />
通过ApplicationContext来使用:
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
- 注解配置的方式
@Component(initMethodName = "init", destroyMethodName = "destroy")
public class Lad implements Boy {
@Autowired
private Girl friend;
public Lad(String name) {
this.name = name;
}
@Autowired
public Lad(@Value("tony") String name, @Qualifier("flower") Girl gf) {
this.name = name;
this.friend = gf;
System.out.println("调用了含有Girl参数的构造方法");
}
}
通过注解的方式指定扫描包的范围:
@Configuration
@ComponentScan(basePackages = "demo.beans")
public class AppConfig {
}
或者使用下面代码的方式:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
context.scan("demo.beans");
context.refresh();
- JavaBean配置的方式
@Configuration
@ComponentScan(basePackages = "demo.beans")
public class AppConfig {
@Bean
public Lad lad() {
return new Lad("");
}
}
通过上面简单的介绍,可以知道,当要使用Spring的时候,只需要使用Spring提供的ApplicationContext的API,而ApplicationContext就是IOC容器
ApplicationContext的继承体系
首先在看源码之前需要清楚ApplicationContext是什么,能够做些什么事情,怎么去使用它,以及它的实现类有哪些,有什么区别,初始化的过程又是什么样的?
ApplicationContext就是IOC容器,是提供IOC容器应用配置的普通接口。
下面看下ApplicationContext这个接口:
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
}
下面是ApplicationContext这个接口提供的方法:
每个方法具体的作用如下:
方法名 | 作用 |
---|---|
getId() | IOC容器唯一的id |
getApplicationName() | 返回这个应用的名称 |
getDisplayName() | 展示名,说明用的,让别人比较容易理解 |
getStartupDate() | 容器启动的时间 |
getParent() | 获得父容器,类似于父子工厂 |
getAutowireCapableBeanFactory() | 获得自动装配的Bean工厂 |
ApplicationContext的父级接口
从上面的源码可以看到,ApplicationContext的父级接口也有很多:
下面是每个父级接口的作用:
父接口 | 作用 |
---|---|
EnvironmentCapable | 具有获取环境相关参数的功能,propertiess文件 |
ListableBeanFactory | 提供Bean迭代功能的BeanFactory |
HierarchicalBeanFactory | 提供父容器的访问功能的BeanFactory |
MessageSource | 对国际化文件支持的基础接口 |
ApplicationEventPublisher | 应用事件的发布接口 |
ResourcePatternResolver | 资源解析和加载的接口 |
下面是UML类图:
Environment接口,是用来表示整个应用在运行时的环境,为了更加形象的理解Environment接口,可以把Spring的运行环境想象成两部分,一部分是Spring应用本身,另一部分就是Spring应用所处的环境。
HierarchicalBeanFactory接口,可以获得父工厂,只能子获取父,containsLocalBean方法是用来判断本工厂是否包含某个Bean的:
public interface HierarchicalBeanFactory extends BeanFactory {
/**
* Return the parent bean factory, or {@code null} if there is none.
*/
@Nullable
BeanFactory getParentBeanFactory();
/**
* Return whether the local bean factory contains a bean of the given name,
* ignoring beans defined in ancestor contexts.
* <p>This is an alternative to {@code containsBean}, ignoring a bean
* of the given name from an ancestor bean factory.
* @param name the name of the bean to query
* @return whether a bean with the given name is defined in the local factory
* @see BeanFactory#containsBean
*/
boolean containsLocalBean(String name);
}
ApplicationContext的实现体系
从上图可以看到,从AbstractApplicationContext之后分成了两个部分,一部分是XML的实现,另一部分是通用的实现。
- ConfigurableApplicationContext接口
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
...
}
从上图可以看到,ConfigurableApplicationContext接口里面提供了很多的set方法,而ApplicationContext接口中只有get方法,所以可以知道,ConfigurableApplicationContext接口是可以配置的ApplicationContext,提供了父容器、环境、BeanFactory后置处理器、监听器等配置方法。
而且还提供了获取ConfigurableListableBeanFactory的方法,并且实现了Lifecycle, Closeable接口,这意味着它能够进行生命周期的控制和关闭的操作。
- AbstractApplicationContext抽象实现类
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
...
}
AbstractApplicationContext继承了DefaultResourceLoader,默认为classpath资源加载器
查看源码可以看到,这个类实现了很多的通用方法,包括ApplicationContext、ConfigurableApplicationContext、BeanFactory、ListableBeanFactory、HierarchicalBeanFactory、MessageSource、ResourcePatternResolver、Lifecycle 8个父接口的方法实现,主要的目的就是为子类的实现进行了大量的减负,主要遗留了refreshBeanFactory、closeBeanFactory、getBeanFactory方法,这三个是具体的子类来实现的
//---------------------------------------------------------------------
// Abstract methods that must be implemented by subclasses
//---------------------------------------------------------------------
protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;
protected abstract void closeBeanFactory();
@Override
public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
从AbstractApplicationContext之后就出现了两个分支:AbstractRefreshableApplicationContext、GenericApplicationContext
- AbstractRefreshableApplicationContext类
* @author Juergen Hoeller
* @author Chris Beams
* @since 1.1.3
* @see #loadBeanDefinitions
* @see org.springframework.beans.factory.support.DefaultListableBeanFactory
* @see org.springframework.web.context.support.AbstractRefreshableWebApplicationContext
* @see AbstractXmlApplicationContext
* @see ClassPathXmlApplicationContext
* @see FileSystemXmlApplicationContext
* @see org.springframework.context.annotation.AnnotationConfigApplicationContext
*/
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
}
自1.1.3版本提供的抽象实现,提供了Bean工厂刷新方法的实现,可以配置是否可以重写Bean定义以及循环依赖
- AbstractRefreshableConfigApplicationContext类
public abstract class AbstractRefreshableConfigApplicationContext extends AbstractRefreshableApplicationContext
implements BeanNameAware, InitializingBean {
}
AbstractRefreshableConfigApplicationContext则增加了资源配置入口,通过Environment解析出配置的真实资源路径字符串。
- AbstractXmlApplicationContext
public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {
}
AbstractXmlApplicationContext里面主要实现了一些Bean定义的加载
ClassPathXmlApplicationContext、FileSystemXmlApplicationContext是xml资源加载方式的具体实现
- GenericApplicationContext
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
private final DefaultListableBeanFactory beanFactory;
}
它实现了BeanDefinitionRegistry接口,该接口定义了bean定义信息的注册行为。即我们可
以直接往GenericApplicationContext中注册bean定义
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}
相关实现有:
AnnotationConfigApplicationContext 注解配置
GenericGroovyApplicationContext groovy方式配置
GenericXmlApplicationContext 通用的xml配置
StaticApplicationContext 静态资源配置方式
从源码可以看出AbstractRefreshableApplicationContext是继承式逐步扩展,GenericApplicationContext则是组合式扩展
上述类使用的例子:
@Configuration
@ComponentScan("edu.dongnao.courseware")
public class Application {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
Lad cs = context.getBean("swk", Lad.class);
cs.sayLove();
ApplicationContext context1 = new FileSystemXmlApplicationContext("F:/workspace/idea/vip/spring-source/src/main/resources/application.xml");
cs = context1.getBean("lad", Lad.class);
cs.sayLove();
context1 = new GenericXmlApplicationContext("file:F:/workspace/idea/vip/spring-source/src/main/resources/application.xml");
cs = context1.getBean("swk", Lad.class);
cs.sayLove();
// 注解的方式
ApplicationContext context2 = new AnnotationConfigApplicationContext(Application.class);
Lad cs2 = context2.getBean(Lad.class);
cs2.sayLove();
System.out.println("------------------------------------------------------");
GenericApplicationContext context3 = new GenericApplicationContext();
new XmlBeanDefinitionReader(context3).loadBeanDefinitions("classpath:application.xml");
new ClassPathBeanDefinitionScanner(context3).scan("edu.dongnao.courseware");
// 一定要刷新
context3.refresh();
cs2 = context3.getBean("swk", Lad.class);
cs2.sayLove();
MagicGril ab = context3.getBean(MagicGril.class);
ab.start();
// 用法跟GenericApplicationContext一样
// ApplicationContext context4 = new StaticApplicationContext();
}
}
ApplicationContext的初始化过程
以ClassPathXmlApplicationContext为例:
跟踪代码路径:
refresh方法是最主要的部分,里面的每一个方法都是很重要的步骤:
@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,并且返回刷新后的BeanFactory
//可以关注下refreshBeanFactory方法,两个子类对它重写的差异
// AbstractRefreshableApplicationContext#refreshBeanFactory中重新构建,完成 BeanDefinition的解析构建 // GenericApplicationContext#refreshBeanFactory则是设置ID,并且只能刷新一次
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//给容器准备BeanFactory,并且配置相关的属性
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//允许子类处理后置BeanFactory
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//调用注册了BeanFactory后置处理器接口实例Bean对应的方法
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
//注册bean后置处理器接口的实例bean
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
//初始化国际化资源
initMessageSource();
// Initialize event multicaster for this context.
//初始化事件传播者
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//Refresh事件,初始化一些指定的bean
onRefresh();
// Check for listener beans and register them.
//注册监听器bean
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//完成bean工厂的初始化,初始化所有非懒加载的单例bean
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
//最后,发布finishRefresh事件
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.
//销毁了所有已经创建了的单例bean
destroyBeans();
// Reset 'active' flag.
//重置active标记
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();
}
}
}
本篇内容是对ApplicationContext的源码做一些简单的了解,以及对初始化过程的了解,后续会进行源码的分析。