1 概述
ApplicationContext即应用上下文,它是建立在BeanFactory基础之上的 ApplicationContext有两个主要的实现类:ClassPathXmlApplicationContext:默认从类路径加载配置文件,还有FileSystemXmlApplicationContext:默认从文件系统中装载配置文件,
通常我们使用的比较多的是ClassPathXmlApplicationContext。
2 继承关系
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
... ...
(1)EnvironmentCapable:提供获取环境对象(Environment)功能的接口。
(2)ListableBeanFactory, HierarchicalBeanFactory:这两个都是BeanFactory的实现类,可以看出ApplicationContext扩展了BeanFactory的功能。
(3)MessageSource:提供国际化消息访问的功能。
(4)ApplicationEventPublisher:该接口让容器拥有发布应用上下文事件的功能,例如容器启动和容器关闭等。
(4)ResourcePatternResolver:装载配置文件进入Resource对象。
3 函数
(1)String getId();
返回应用上下文唯一的id。
(2)String getApplicationName();
返回此上下文所属的已部署应用程序的名称。
(3)String getDisplayName();
返回此上下文一个友好的名称。
(4)long getStartupDate();
返回此上下文第一次加载的日期。
(5)ApplicationContext getParent();
返回父上下文,如果没有就为空。
(7)AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
为这个上下文公开autowiablebeanfactory功能。
4 子类
在这里针对这个接口的子类,我们仅仅分析部分的实现和作用。
4.1 ConfigurableApplicationContext
这个接口将由大多数应用程序上下文实现。除了ApplicationContext接口的功能之外,还提供了配置应用上下文的功能。
这个接口继承了Lifecycle接口,Lifecycle接口是定义用于启动/停止生命周期控制的方法的公共接口,通常针对异步处理比较常用。
4.2 AbstractApplicationContext
ApplicationContext接口的抽象实现,简单地实现了公共上下文功能。这个类的设计使用了模板方法的设计模式,具体的实现由子类来实现。
4.2.1 继承关系
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext
(1)DefaultResourceLoader
ResourceLoader接口的默认实现,被ResourceEditor类使用 。
这里我们来看一下此类的getResource函数。
@Override
public Resource getResource(String location) {
Assert.notNull(location, "Location must not be null");
//遍历协议特定资源句柄的解决策略,如果有资源location的匹配策略,则直接返回
for (ProtocolResolver protocolResolver : this.protocolResolvers) {
Resource resource = protocolResolver.resolve(location, this);
//获得配置文件资源
if (resource != null) {
return resource;
}
}
//通过路径获取资源(相对路径)
if (location.startsWith("/")) {
return getResourceByPath(location);
}
//类路径
else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
}
else {
try {
URL url = new URL(location);
return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
}
catch (MalformedURLException ex) {
return getResourceByPath(location);
}
}
}
这个函数的作用其实就是获取资源的Resource对象。支持全路径,classpath类路径和文件的相对路径几种方式。
4.2.2 函数
针对这个类,我们来分析一下refresh函数。
refresh函数的作用是加载或者刷新配置的持久化表示。
源码如下:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//准备刷新上下文
prepareRefresh();
//告述子类刷新内部bean工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//准备在此上下文中使用的Bean工厂
prepareBeanFactory(beanFactory);
try {
//允许在上下文子类中对bean工厂进行后处理,当前此类中对这个函数没有任何实现内容。
postProcessBeanFactory(beanFactory);
//调用在上下文中注册为bean的工厂处理器
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
//初始化上下文的消息资源
initMessageSource();
//初始化容器的事件多播器
initApplicationEventMulticaster();
//初始化特定上下文子类中的其他特殊bean。此函数当前实现为空
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
//完成容器刷新.
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();
}
}
}
prepareRefresh()函数:
这个函数的作用是为刷新做好上下文准备,包括设置她的开始时间、激活状态和执行任何属性资源的初始化。
具体的源码如下:
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
//初始化上下文环境的任何属性资源,这个函数的具体实现被延迟到了子类,默认情况下什么也不做
initPropertySources();
//检测每个属性是否是存在并且非空的
getEnvironment().validateRequiredProperties();
this.earlyApplicationEvents = new LinkedHashSet<>();
}
obtainFreshBeanFactory函数:
这个函数的作用是告述子类刷新内部bean工厂。
具体源码如下:
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//这是一个抽象函数,子类必须实现它,这个也就是模板方法模式中的基本方法。
refreshBeanFactory();
//这也是一个抽象函数,子类必须实现它。子类必须但会内部bean工厂。
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
prepareBeanFactory函数:
这个函数的作用是配置工厂标准的上下文属性,例如上下文的类加载器和后处理器。
具体源码如下:
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//告诉内部bean工厂使用上下文的类加载器等
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
//使用上下文回调配置bean工厂
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
//在普通工厂中,BeanFactory接口没有注册为可解析类型。
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
//注册早期的后处理器,以便将内部bean检测为applicationlistener。
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// Detect a LoadTimeWeaver and prepare for weaving, if found.
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
//注册默认的环境bean
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
invokeBeanFactoryPostProcessors函数:
调用在上下文中注册为bean的工厂处理器,这里需要注意的是要按照给定的顺序调用。
具体源码如下:
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
initMessageSource函数:
初始化容器的消息资源,如果当前上下文的为空则使用父上下文的。
源码如下:
protected void initMessageSource() {
//获取工厂bean
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//bean工厂中包含messageResource bean
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
//设置message resource的父message resource
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
if (hms.getParentMessageSource() == null) {
// Only set parent context as parent MessageSource if no parent MessageSource
// registered already.
hms.setParentMessageSource(getInternalParentMessageSource());
}
}
if (logger.isDebugEnabled()) {
logger.debug("Using MessageSource [" + this.messageSource + "]");
}
}
//bean工厂中不包含messageResource bean
else {
//初始化message resource
DelegatingMessageSource dms = new DelegatingMessageSource();
dms.setParentMessageSource(getInternalParentMessageSource());
this.messageSource = dms;
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate MessageSource with name '" + MESSAGE_SOURCE_BEAN_NAME +
"': using default [" + this.messageSource + "]");
}
}
}
4.3 AbstractRefreshableApplicationContext
ApplicationContext实现的基本类,应该支持对refresh()函数的多次调用。每次创建一个新的bean工厂实例,通常(但不一定),这样的上下文将由一组配置位置驱动,以便从这些配置位置加载bean定义。
4.4 AbstractXmlApplicationContext
这个子类提供从xml文档读取配置和bean定义的功能,这个读取功能通过XmlBeanDefinitionReader实现。
4.4.1 属性
private boolean validating = true;//设置是否需要进行xml校验。
4.4.2 函数
针对这个类,我们来看一下loadBeanDefinitions函数。
这个函数的作用就是通过XmlBeanDefinitionReader来加载bean定义,具体源码如下(针对这个函数的分析此处略显啰嗦,没有优化):
上面的代码,在代码(2)处调用了XmlBeanDefinitionReader的函数loadBeanDefinitions。
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
//获取配置资源(1)
Resource[] configResources = getConfigResources();
if (configResources != null) {
//加载bean定义(2)
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
上面的函数,最终调用如下函数:
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
在这个函数中,调用了public int loadBeanDefinitions(EncodedResource encodedResource)函数,我们可以看见传入了EncodedResource参数,EncodedResource类其实是对Resource,编码和charset的封装。
具体的源码如下:
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
通过上面的代码,我们可以发现获取到inputSource和encodeResource后,调用了doLoadBeanDefinitions函数。
在doLoadBeanDefinitions函数里面生成Document后,调用了registerBeanDefinitions函数。
这个函数的作用其实就是注册包含在被给Document中的bean定义。
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
针对上面的代码我们需要详细说明一下。
A、BeanDefinitionDocumentReader类
用于解析包含Spring bean定义的XML文档的SPI。由XmlBeanDefinitionReader进行实际解析DOM文档。
这个接口拥有的函数如下:
void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) throws BeanDefinitionStoreException;
这个函数的作用就是从xml文档中读取bean定义,并使用readerContext中的注册器对其进行注册。
我们再来看一下这个函数的具体实现干了啥。
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}
重点是获取到root节点后,调用的最终的doRegisterBeanDefinitions函数。
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isInfoEnabled()) {
logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
针对这个函数,最终要的其实是调用parseBeanDefinitions函数。
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
上面这个函数最终会调用parseDefaultElement函数,在parseDefaultElement函数中,调用processBeanDefinition函数来完成bean定义的注册。
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//将Element转换成BeanDefinitionHolder,这里面包含beanDefinition,beanName,aliases
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
//注册bean定义
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
//发起注册事件
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
最终上面的函数会调用到DefaultListableBeanFactory的registerBeanDefinition函数。我们来看一下这个函数。
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition oldBeanDefinition;
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(oldBeanDefinition)) {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
这个函数的this.beanDefinitionMap.put(beanName, beanDefinition);这一步就完成的beanDefinition的注册。
上面就是对AbstractXmlApplicationContext类的loadBeanDefinitions函数的分析,有点啰嗦,但是最终表明了整个函数bean定义的xml配置文件的解析到bean定义的注册的整个过程。
4.5 ClassPathXmlApplicationContext和FileSystemXmlApplicationContext
这两个类是标准的XML应用上下文,不同的是他们获取容器定义文件的路径,ClassPathXmlApplicationContext从class path获取,而FileSystemXmlApplicationContext是从文件系统或者URL。
上面就是对Spring容器(ApplicationContext)的分析,后面我们将继续分析SpringIOC的源码,欢迎交流。