spring之ApplicationContext分析

1:类图

在这里插入图片描述
从类图中可以看出来主要的父接口以及提供的能力如下:

类名作用
BeanFactory比较基础和简单的bean容器,主要通过getBean(xxx)的API提供了获取bean的操作,通过isPrototype,isSingleton等方法判断是原型bean,还是单例bean,通过containerBean(xxx)判断是否包含某bean的能力。
HierarchicalBeanFactory是BeanFactory的子接口,提供了通过getParentBeanFactory(xxx)方法获取父容器的操作,正是名字中Hierarchical层级的由来
ListableBeanFactory提供了列举bean,即获取bean列表的能力,如通过getBeansOfType(xxx)获取某类型的bean的集合,getBeanNamesForType(xxx),获取某类型的bean的名称的集合
ApplicationEventPublisher函数式接口,用于向事件监听器发布事件
ResourceLoader资源获取接口,如获取xml文件,jar,jar中的class,基于http的远端文件等各种资源,具体可以参考:https://blog.csdn.net/wang0907/article/details/113913888
ResourcePatternResolverResourceLoader的子类,提供了批量获取资源的操作,具体可以参考:https://blog.csdn.net/wang0907/article/details/113913888
MessageSource解析message的策略接口,用于实现i18n
EnvironmentCapable函数式接口,通过getEnvironment方法定义获取Environment的操作,关于Environment可以参考:https://blog.csdn.net/wang0907/article/details/116232260

2:ApplicationContext子接口

ApplicationContext的子接口主要有2个,一个是WebApplicationContext,另一个是ConfigurableApplicationContext,我们来分别看下这两个接口提供的能力。

2.1:WebApplicationContext

该接口只有一个方法getServletContext,用来获取Servlet的上下文对象,另外还定义了一些web相关的一些常量,源码如下:

public interface WebApplicationContext extends ApplicationContext {

	// 用于定义root应用程序上线文的key,web容器启动成功后保存在servletcontext中使用的key,如果是启动失败的话,这里保存的是失败的原因
	String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";

	// 定义bean的Request级别的作用域,即一个请求一个bean
	// 作为singleton和prototype作用域的补充
	String SCOPE_REQUEST = "request";

	// 定义bean的session级别的作用域,即一个会话一个bean
	// 作为singleton,prototype作用域的补充
	String SCOPE_SESSION = "session";

	// 定义bean的application级别的作用域
	String SCOPE_APPLICATION = "application";

	// 定义ServletContext,即servlet上线文对象在容器中的
	// bean名称
	String SERVLET_CONTEXT_BEAN_NAME = "servletContext";

	String CONTEXT_PARAMETERS_BEAN_NAME = "contextParameters";

	String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes";

	// 返回servlet 标准API中的当前应用程序对应的ServletContext对象
	@Nullable
	ServletContext getServletContext();

}

2.2:ConfigurableApplicationContext

从名字中的Configurable就可以知道,该类是扩展ApplicationContext,提供了相关配置的能力,下面我们通过源码看下到底是提供了哪些可配置项:

public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
	// 定义configlocation多个时可用的分隔符
	String CONFIG_LOCATION_DELIMITERS = ",; \t\n";

	// 设置容器中ConversionService属性类型转换API的bean名称
	String CONVERSION_SERVICE_BEAN_NAME = "conversionService";

	// 设置在bean工厂容器中Environment的bean名称
	// 关于Environment可以参考:https://blog.csdn.net/wang0907/article/details/116232260
	String ENVIRONMENT_BEAN_NAME = "environment";

	// 设置应用程序上下文的唯一ID
	void setId(String id);
	// 设置父容器
	void setParent(@Nullable ApplicationContext parent);

	/**
	 * Set the {@code Environment} for this application context.
	 * @param environment the new environment
	 * @since 3.1
	 */
	// 设置Environment
	// 关于Environment可以参考:https://blog.csdn.net/wang0907/article/details/116232260
	void setEnvironment(ConfigurableEnvironment environment);

	// 获取应用程序的Environment
	@Override
	ConfigurableEnvironment getEnvironment();

	// 添加BeanFactoryPostProcessor,在refresh时,bean definition
	// 被解析为bean之前注册到容器中,在生成bean之前会被应用可以用来
	// 修改bean定义信息,关于BeanFactoryPostProcessor,可以参考
	// https://blog.csdn.net/wang0907/article/details/115440135
	// https://blog.csdn.net/wang0907/article/details/115443697
	// https://blog.csdn.net/wang0907/article/details/115483144
	void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);

	// 注册应用程序监听器,在context进行refresh时,或者是context进行
	// 关闭时会被应用,或者其他
	void addApplicationListener(ApplicationListener<?> listener);

	// 注册协议解析器
	void addProtocolResolver(ProtocolResolver resolver);

	// 加载或者是刷新配置->生成bean定义->生成bean
	// 以及应用相关的beanpostprocessor,这是一个启动方法,如果是启动失败的话,应该负责销毁已经创建的单例bean
	// ,换句话说就是,要么所有的单例bean都完成了注册,要么是所有的单例bean
	// 都没有完成注册,如果是初始化失败则抛出BeanException
	// 如果是进行了多次的初始化则抛IllegalStateException,因为refresh只
	// 支持一次
	void refresh() throws BeansException, IllegalStateException;

	// 注册虚拟机关闭钩子
	void registerShutdownHook();

	// 关闭应用程序上线文,是方法所有的资源和锁,销毁所有缓存的单例bean,
	// 本方法可以多次调用,后续的调用直接忽略,而不会抛出异常
	@Override
	void close();

	// 获取应用程序环境是否是激活状态的,即refresh方法调用完毕
	// 但是close方法还没有被调用
	boolean isActive();

	ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;

}

其中的Lifecycle接口,是spring定义的context生命周期管理的接口,定义了startstop方法来启动和停止组件,Closable接口是jdk中定义的接口,代表该资源是可关闭的,比如配合该接口可以使用try-with-resource语法糖等。

2.3:ConfigurableWebApplication

这是WebApplicationContext和ConfigurableApplicationContext的公共的子接口,拥有了这两个接口的能力,提供了一个可配置configurable,可管理生命周期,可关闭closable的接口,看下源码:

public interface ConfigurableWebApplicationContext extends WebApplicationContext, ConfigurableApplicationContext {
	// 设置servletcontext
	void setServletContext(@Nullable ServletContext servletContext);

	// 设置和获取servletconfig
	void setServletConfig(@Nullable ServletConfig servletConfig);
	@Nullable
	ServletConfig getServletConfig();

	// 设置和获取config location(s)
	void setConfigLocation(String configLocation);
	void setConfigLocations(String... configLocations);
	@Nullable
	String[] getConfigLocations();

}

对于ApplicationContext,如基于xml配置文件的ClassPathXmlAppplicationContext,基于注解的AnnotationConfigApplicationContext等,下面我们以ClassPathXmlApplicationContext为例,来看下。

3:ClassPathXmlApplicationContext

我们先来看下类图,然后再依次分析每个类和接口的作用。

3.1:类图

在这里插入图片描述
我们以ApplicationContext这条主线来看下主要的的层级结构:

AbstractApplicationContext
	AbstractRefreshableApplicationContext
		AbstractRefreshableConfigApplicationContext
			AbstractXmlApplicationContext
				ClassPathXmlApplicationContext

接着再来看下其它的接口:

BeanFactory:bean容器的顶层接口,提供了基础的bean的管理
MessageSource:消息message相关,实现国际化
ResourceLoader:资源加载,参考:https://blog.csdn.net/wang0907/article/details/113913888
ApplicationEventPublisher:事件发布
Lifecycle:管理生命周期
Closable:关闭,释放资源
InitializingBean:自定义初始化,调用完毕populateBean方法设置属性后调用
BeanNameAware:感知bean名称
EnvironmentCapable:系统Environment相关,properties,profiles

3.2:MessageSource

源码如下:

// 解析消息的策略接口,支持参数化和国际化诸如此类的消息,spring为生产环境
// 提供了2个开箱即用的是实现类,ResourceBundleMessageResouce,
// ReloadableResouceBundleMessage
public interface MessageSource {
	// 解析消息。如果根据code没有获取到消息则返回默认消息
	@Nullable
	String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale);
	// 解析消息,如果是根据code没有获取到,则抛出NoSuchMessageException
	String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException;
	// 通过自定义的消息解析器解析消息
	String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;

}

在AbstractApplicationContext中提供了getMessage(xxx)的具体的实现,源码如下:

org.springframework.context.support.AbstractApplicationContext#getMessage(java.lang.String, java.lang.Object[], java.util.Locale)
public String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException {
	// <20210504 1923>
	return getMessageSource().getMessage(code, args, locale);
}

<20210504 1923>getMessageSource.getMessage(xx)执行的方法在AbstractMessageSource中,具体源码我没看,大概贴在这里吧。

org.springframework.context.support.AbstractMessageSource#getMessage(java.lang.String, java.lang.Object[], java.util.Locale)
public final String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException {
	String msg = getMessageInternal(code, args, locale);
	if (msg != null) {
		return msg;
	}
	String fallback = getDefaultMessage(code);
	if (fallback != null) {
		return fallback;
	}
	throw new NoSuchMessageException(code, locale);
}

3.3:ResourcePatternResolver

提供了路径批量转换为Resource的策略接口,最终的实现了是PathMatchingResoucePatternResolver,接口定义如下:

// 将路径模式(如ant风格的模式)转换为一组Resource对象。是ResourceLoader
// 的扩展接口,扩展为支持多个资源的同时获取,而不用循环多次获取,
// PathMatchingResourcePatternResolver是其常用的实现类
// 路径模式可以形如:/WEB-INF/*-context.xml,同时该接口鼓励
// 使用形如classpath*:来匹配classpath下多个资源
public interface ResourcePatternResolver extends ResourceLoader {

	// 在classpath下单次加载多个资源文件的"假的classpath前缀",内部会
	// 按照真正支持的classpath方式进行处理和获取资源
	String CLASSPATH_ALL_URL_PREFIX = "classpath*:";

	// 通过模式路径获取一组Resouce对象
	Resource[] getResources(String locationPattern) throws IOException;

}

3.4:EnvironmentCapable

有能力提供Environment的接口类,通过方法getEnvironment(xxx)方法返回Environment,接口源码如下:

// 表明拥有一个Environment引用的接口。
public interface EnvironmentCapable {

	// 返回Environment组件
	Environment getEnvironment();

}

实现在AbstractApplicationContext中,源码如下:

org.springframework.context.support.AbstractApplicationContext#getEnvironment
public ConfigurableEnvironment getEnvironment() {
	if (this.environment == null) {
		this.environment = createEnvironment();
	}
	return this.environment;
}
org.springframework.context.support.AbstractApplicationContext#createEnvironment
protected ConfigurableEnvironment createEnvironment() {
	return new StandardEnvironment();
}

3.5:Lifecycle

生命周期声明的接口,源码如下:

public interface Lifecycle {

	// 启动组件,注意如果组件已经启动了也不应该抛出异常
	void start();

	// 停止组件
	void stop();

	// 检查组件是否在运行中
	boolean isRunning();

}

看下AbstractApplicationContext中提供的具体实现:

// 管理context中bean的生命周期的类
@Nullable
private LifecycleProcessor lifecycleProcessor;

@Override
public void start() {
	getLifecycleProcessor().start();
	// 启动后,发布ContextStartEvent
	publishEvent(new ContextStartedEvent(this));
}

@Override
public void stop() {
	getLifecycleProcessor().stop();
	// 停止后发布ContextStoppedEvent
	publishEvent(new ContextStoppedEvent(this));
}

@Override
public boolean isRunning() {
	return (this.lifecycleProcessor != null && this.lifecycleProcessor.isRunning());
}

3.6:Closable

用于释放资源和进行其它清理的工作的接口,源码如下:

// 该接口代表是可以关闭的,通过调用close()方法来释放持有的资源(如文件句柄)
public interface Closeable extends AutoCloseable {

    // 通过该方法关闭对象关联的资源,如果是已经关闭,则该方法的调用没有任何效果
    public void close() throws IOException;
}

在AbstractApplicationContext中的实现如下:

org.springframework.context.support.AbstractApplicationContext#close
// 关闭应用程序上下文,销毁bean工厂中所有的bean,最终委托方法doClose执行
// 具体的关闭过程。如果是注册了虚拟机关闭钩子,如果是不在需要的话同样会将其移除
@Override
public void close() {
	synchronized (this.startupShutdownMonitor) {
		// <20210505 1453>
		doClose();
		// 如果注册了虚拟机关闭钩子,则将其移除
		// 关于虚拟机关闭钩子可参考:https://blog.csdn.net/wang0907/article/details/116419006
		if (this.shutdownHook != null) {
			try {
				Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
			}
			catch (IllegalStateException ex) {
			}
		}
	}
}

<20210505 1453>处源码如下:

org.springframework.context.support.AbstractApplicationContext#doClose
// 真正执行上线文关闭的方法。发布ContextClosedEvent事件,并销毁bean工厂中
// 所有的单例bean。会被close方法调用,或者是被虚拟机关闭钩子调用(如果有的话)
protected void doClose() {
	// 检测状态
	if (this.active.get() && this.closed.compareAndSet(false, true)) {
		...snip...
		try {
			// 发布ContextClosedEvent
			publishEvent(new ContextClosedEvent(this));
		}
		catch (Throwable ex) {
			...snip...	
		}
		...snip...
		// 销毁bean工厂中缓存的所有单例bean
		destroyBeans();
		// 关闭bean工厂
		closeBeanFactory();
		// 留给子类的模板方法,以便子类有需要关闭的资源
		onClose();
		// 修改bean工厂的状态为未激活
		this.active.set(false);
	}
}

3.7:InitializingBean

该方法在属性设置完毕后会被调用,只有一个方法afterPropertiesSet,源码如下:

org.springframework.beans.factory.InitializingBean
// bean如果是实现了该接口,会在所有的属性设置完毕后被调用一次,可以执行
// 定制化的初始化工作,或者是仅仅对强制的属性做检查。但是这种是侵入式
// 的编程方式了,如果是不想这样,也可以通过配置init-method的方式来实现
public interface InitializingBean {

	// 当bean工厂设置当前bean的属性完毕后调用的方法
	void afterPropertiesSet() throws Exception;
}

在ApplicationContext体系中的实现类是AbstractRefreshableConfigApplicationContext,源码如下:

org.springframework.context.support.AbstractRefreshableConfigApplicationContext#afterPropertiesSet
@Override
publicvoid afterPropertiesSet() {
	if (!isActive()) {
		// <20210505 1517>
		refresh();
	}
}

<20210505 1517>关于refresh方法参考这里

3.8:BeanNameAware

用于设置bean名称,在AbstractRefreshableConfigApplicationContext中提供具体实现,源码如下:

org.springframework.context.support.AbstractRefreshableConfigApplicationContext#setBeanName
@Override
public void setBeanName(String name) {
	if (!this.setIdCalled) {
		super.setId(name);
		setDisplayName("ApplicationContext '" + name + "'");
	}
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值