Spring 源码解析二(上下文组件(WebApplicationContext))
Spring 源码解析二:上下文组件(WebApplicationContext)
上一篇解析了 DispatcherServlet
与 ContextLoaderListener
这两个类,解析了应用初始化与请求处理的流程,但还有一些组件需要解析:
ConfigurableWebApplicationContext.refresh
刷新上下文ApplicationContext.getBean
从上下文中获取 beanDispatcherServlet.properties
文件中定义的策略处理ContextLoader.properties
文件中定义的策略处理View.render
视图渲染
ContextLoader.properties
文件中定义的策略处理ContextLoader.properties
文件中只定义了一个策略org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
【Spring 源码解析二(上下文组件(WebApplicationContext))】默认使用
XmlWebApplicationContext
(基于 XML 加载)作为应用上下文spring-web
内部定义 5 个应用上下文类:- GenericWebApplicationContext
:WebApplicationContext
的基础实现,但不能通过配置文件和注解加载应用配置与 bean,一般用于扩展实现(如 SpringBoot),很少直接使用 - StaticWebApplicationContext
:也是WebApplicationContext
的基础实现,但不支持 i18n,主要用于测试,不用产品环境 - XmlWebApplicationContext
:基于 XML 加载应用配置与 bean 的WebApplicationContext
实现,是 SpringMVC 的默认 Context - AnnotationConfigWebApplicationContext
:基于注解如@Configuration, @bean
等加载应用配置与 bean 的WebApplicationContext
实现 - GroovyWebApplicationContext
:与XmlWebApplicationContext
的实现差不多,但可以用 Groovy 代替 xml 做配置文件,目前用得不多
- DefaultResourceLoader
- AbstractApplicationContext
- GenericApplicationContext
- GenericWebApplicationContext- DefaultResourceLoader
- AbstractApplicationContext
- GenericApplicationContext
- StaticApplicationContext
- StaticWebApplicationContext- DefaultResourceLoader
- AbstractApplicationContext
- AbstractRefreshableApplicationContext
- AbstractRefreshableConfigApplicationContext
- AbstractRefreshableWebApplicationContext
- XmlWebApplicationContext- DefaultResourceLoader
- AbstractApplicationContext
- AbstractRefreshableApplicationContext
- AbstractRefreshableConfigApplicationContext
- AbstractRefreshableWebApplicationContext
- AnnotationConfigWebApplicationContext- DefaultResourceLoader
- AbstractApplicationContext
- AbstractRefreshableApplicationContext
- AbstractRefreshableConfigApplicationContext
- AbstractRefreshableWebApplicationContext
- GroovyWebApplicationContext
我们可以发现每个类都继承
AbstractApplicationContext
,而 XmlWebApplicationContext
, AnnotationConfigWebApplicationContext
,GroovyWebApplicationContext
都继承 AbstractRefreshableWebApplicationContext
1. DefaultResourceLoader DefaultResourceLoader
的主要功能是实现资源加载
public class DefaultResourceLoader implements ResourceLoader {}
先来看看接口ResourceLoader
public interface ResourceLoader {
// 根据一个字符位置信息获取资源
Resource getResource(String location);
// 获取资源加载器
ClassLoader getClassLoader();
}
DefaultResourceLoader
是
ResourceLoader
的默认实现public class DefaultResourceLoader implements ResourceLoader {
@Override
public ClassLoader getClassLoader() {
// 如果有指定的classLoader,则返回指定的,没有则返回默认的
return (this.classLoader != null ? this.classLoader : ClassUtils.getDefaultClassLoader());
}@Override
public Resource getResource(String location) {
// 自定义协议解析
for (ProtocolResolver protocolResolver : getProtocolResolvers()) {
Resource resource = protocolResolver.resolve(location, this);
if (resource != null) {
return resource;
}
}// 如果以/开头,则认为是classpath资源
if (location.startsWith("/")) {
return getResourceByPath(location);
}
// 如果以classpath:开头的classpath资源
else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
}
else {
try {
// 尝试以文件或url对待
URL url = new URL(location);
return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
}
catch (MalformedURLException ex) {
// 失败则默认是classpath资源
return getResourceByPath(location);
}
}
}
}
2. AbstractApplicationContext AbstractApplicationContext
的主要功能是通过名字、类型或注解获取 bean 实例,获取上下文的环境对象与资源、刷新上下文数据
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {}
接口 ConfigurableApplicationContext
及其继承的接口主要定义以下的方法
public interface ConfigurableApplicationContext {
// 获取bean
Object getBean(String name) throws BeansException;
T getBean(String name, Class requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
T getBean(Class requiredType) throws BeansException;
T getBean(Class requiredType, Object... args) throws BeansException;
// 通过类型或注解获取bean
Map getBeansOfType(@Nullable Class type) throws BeansException;
Map getBeansOfType(@Nullable Class type, boolean includeNonSingletons, boolean allowEagerInit)
throws BeansException;
Map getBeansWithAnnotation(Class extends Annotation> annotationType) throws BeansException;
// 获取环境
ConfigurableEnvironment getEnvironment();
// 刷新上下文数据
void refresh() throws BeansException, IllegalStateException;
// 根据locationPattern获取多个资源,如通配符*
Resource[] getResources(String locationPattern) throws IOException;
}
2.1. AbstractApplicationContext.getEnvironment
AbstractApplicationContext.getEnvironment
获取环境
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
@Override
public ConfigurableEnvironment getEnvironment() {
if (this.environment == null) {
this.environment = createEnvironment();
}
return this.environment;
}protected ConfigurableEnvironment createEnvironment() {
// 内置的标准环境(也可以通过setEnvironment方法自定义环境处理机制)
// 这是可以使用 `application-dev.yml, application-test.yml, application-prod.yml, ...` 来根据环境加载不同的配置的底层实现
// 是spring-boot的基本功能
return new StandardEnvironment();
}
}
2.2. AbstractApplicationContext.getBean
AbstractApplicationContext.getBean
获取 bean
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
@Override
public Object getBean(String name) throws BeansException {
return getBeanFactory().getBean(name);
}@Override
public T getBean(String name, Class requiredType) throws BeansException {
return getBeanFactory().getBean(name, requiredType);
}@Override
public Object getBean(String name, Object... args) throws BeansException {
return getBeanFactory().getBean(name, args);
}@Override
public T getBean(Class requiredType) throws BeansException {
return getBeanFactory().getBean(requiredType);
}@Override
public T getBean(Class requiredType, Object... args) throws BeansException {
return getBeanFactory().getBean(requiredType, args);
}// 留给子类实现
public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}
因为不同的
Context
注册 bean 的方式不一样,所以getBeanFactory
留给子类来实现2.3. AbstractApplicationContext.getBeansOfType
AbstractApplicationContext.getBeansOfType
通过类型或注解获取 bean
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
@Override
public Map getBeansOfType(@Nullable Class type) throws BeansException {
return getBeanFactory().getBeansOfType(type);
}@Override
public Map getBeansOfType(@Nullable Class type, boolean includeNonSingletons, boolean allowEagerInit)
throws BeansException {
return getBeanFactory().getBeansOfType(type, includeNonSingletons, allowEagerInit);
}@Override
public Map getBeansWithAnnotation(Class extends Annotation> annotationType)
throws BeansException {
return getBeanFactory().getBeansWithAnnotation(annotationType);
}// 留给子类实现
public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}
2.4. AbstractApplicationContext.refresh
AbstractApplicationContext.refresh
刷新上下文数据
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// ... 代码省略// 初始化事件容器与监听器,检查必须的属性配置,并载入必要的实例
prepareRefresh();
// 刷新上下文的bean,获取bean工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 预备bean工厂
prepareBeanFactory(beanFactory);
try {
// 后置处理bean工厂
postProcessBeanFactory(beanFactory);
// ... 代码省略// 调用bean工厂的后置处理器,以使在所有bean实例化之前,可以自定义添加自己的BeanPostProcessor(bean实例化后置操作)
invokeBeanFactoryPostProcessors(beanFactory);
// 给bean工厂注册BeanPostProcessor(bean实例化后置操作)
registerBeanPostProcessors(beanFactory);
// ... 代码省略// 实例化applicationEventMulticaster bean,作为应用事件广播器
initApplicationEventMulticaster();
// 扩展实现,留给开发者,默认不实现
onRefresh();
// 注册应用事件监听器
registerListeners();
// 初始化所有单例的bean
finishBeanFactoryInitialization(beanFactory);
// 刷新上下文数据完成,做一些后续处理
finishRefresh();
}catch (BeansException ex) {
// ... 代码省略
}finally {
// ... 代码省略
}
}
}// 刷新上下文的bean,获取bean工厂
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 刷新上下文的bean
refreshBeanFactory();
// 获取bean工厂
return getBeanFactory();
}// 刷新上下文的bean,由子类实现
protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;
// 获取bean工厂,由子类实现
public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
// 扩展实现,留给开发者,默认不实现
protected void onRefresh() throws BeansException {}// 初始化所有单例的bean
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// ... 代码省略// 固化所有bean的配置,后面不再更改
beanFactory.freezeConfiguration();
// 初始化所有单例的bean
beanFactory.preInstantiateSingletons();
}// 刷新上下文数据完成,做一些后续处理
protected void finishRefresh() {
// 清除一些资源缓存
clearResourceCaches();
// 实例化lifecycleProcessor bean
initLifecycleProcessor();
// 实例化Lifecycle bean,并调用这些bean的start方法
getLifecycleProcessor().onRefresh();
// 派发事件
publishEvent(new ContextRefreshedEvent(this));
// ... 代码省略
}
}
- 因为不同的
Context
注册 bean 的方式不一样,所以refreshBeanFactory, postProcessBeanFactory
留给子类来实现 ConfigurableListableBeanFactory
如何加载、实例化 bean,后面再解析
AbstractApplicationContext.prepareBeanFactory
预备 bean 工厂
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// ... 代码省略// 添加对 #{} SpEL Spring 表达式语言的支持
if (!shouldIgnoreSpel) {
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
}// 添加属性编辑器,xml、yaml 中定义的值转换成对象就是依赖这里实现的
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 添加一个BeanPostProcessor,后置处理器
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// ... 代码省略// 注册几个可以autowirable自动载入的实例
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// ... 代码省略// 注册几个单例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());
}
if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
}
}
}
ResourceEditorRegistrar
如何注册属性编辑器、属性编辑器如何解析为对象,后面再解析
AbstractApplicationContext.getResources
根据 locationPattern 获取多个资源,如通配符*
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
private ResourcePatternResolver resourcePatternResolver;
public AbstractApplicationContext() {
this.resourcePatternResolver = getResourcePatternResolver();
}protected ResourcePatternResolver getResourcePatternResolver() {
return new PathMatchingResourcePatternResolver(this);
}@Override
public Resource[] getResources(String locationPattern) throws IOException {
return this.resourcePatternResolver.getResources(locationPattern);
}
}
PathMatchingResourcePatternResolver
如何解析、加载 locationPattern 指定的资源,后面再解析
总的来说,
AbstractApplicationContext
类完成上下文环境的大部分功能,包括环境加载、bean 的加载与前置后置处理、事件派发、完成一些初始化工作等,但扩展了几个接口给子类实现,如如何加载、注册、实例化 bean 等
3. GenericApplicationContext GenericApplicationContext
的主要功能是注册、管理 bean 的定义与别名
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {}
BeanDefinitionRegistry
这个接口主要定义了注册 bean 的定义及别名
public interface BeanDefinitionRegistry {
// 注册bean定义
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException;
// 删除bean定义
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
// 获取bean定义
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
// 检查bean定义
boolean containsBeanDefinition(String beanName);
// 注册bean别名
void registerAlias(String name, String alias);
// 删除bean别名
void removeAlias(String alias);
// 检查bean别名
boolean isAlias(String name);
// 获取bean别名
String[] getAliases(String name);
}
来看看
GenericApplicationContext
如何实现这些接口的public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}@Override
public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
this.beanFactory.removeBeanDefinition(beanName);
}@Override
public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
return this.beanFactory.getBeanDefinition(beanName);
}@Override
public void registerAlias(String beanName, String alias) {
this.beanFactory.registerAlias(beanName, alias);
}@Override
public void removeAlias(String alias) {
this.beanFactory.removeAlias(alias);
}@Override
public boolean isAlias(String beanName) {
return this.beanFactory.isAlias(beanName);
}
}
最终还是落脚在
beanFactory
上4. GenericWebApplicationContext GenericWebApplicationContext
的主要功能是添加了设置 bean 配置文件来源,允许通过配置的方式实例化上下文环境
public class GenericWebApplicationContext extends GenericApplicationContext
implements ConfigurableWebApplicationContext, ThemeSource {}
ConfigurableWebApplicationContext
public interface ConfigurableWebApplicationContext {
// 设置bean配置文件来源
void setConfigLocation(String configLocation);
// 设置多个bean配置文件来源
void setConfigLocations(String... configLocations);
// 获取bean配置文件来源
String[] getConfigLocations();
}
ConfigurableWebApplicationContext
扩展了WebApplicationContext
,定义了允许通过配置的方式实例化上下文环境public class GenericWebApplicationContext extends GenericApplicationContext
implements ConfigurableWebApplicationContext, ThemeSource {
@Override
protected ConfigurableEnvironment createEnvironment() {
// StandardServletEnvironment扩展了StandardEnvironment
// 增加了可以从Servlet context init parameters和Servlet config init parameters增加应用配置来源
return new StandardServletEnvironment();
}// 不可设置bean配置文件来源
@Override
public void setConfigLocation(String configLocation) {
if (StringUtils.hasText(configLocation)) {
throw new UnsupportedOperationException(
"GenericWebApplicationContext does not support setConfigLocation(). " +
"Do you still have an 'contextConfigLocations' init-param set?");
}
}@Override
public void setConfigLocations(String... configLocations) {
if (!ObjectUtils.isEmpty(configLocations)) {
throw new UnsupportedOperationException(
"GenericWebApplicationContext does not support setConfigLocations(). " +
"Do you still have an 'contextConfigLocations' init-param set?");
}
}@Override
public String[] getConfigLocations() {
throw new UnsupportedOperationException(
"GenericWebApplicationContext does not support getConfigLocations()");
}
}
GenericWebApplicationContext
并未实现 ConfigurableWebApplicationContext
的核心方法,也就不能通过文件加载配置,该类设计的目的不是在
web.xml
中进行声明式的安装,而是编程式的安装,例如使用WebApplicationInitializers
来构建内嵌的上下文;一般很少用到5. StaticWebApplicationContext 因为 StaticApplicationContext
实现功能比较少,放在这里一起解析
public class StaticApplicationContext extends GenericApplicationContext {
private final StaticMessageSource staticMessageSource;
public StaticApplicationContext(@Nullable ApplicationContext parent) throws BeansException {
super(parent);
// 上下文对象中有一个messageSource组件,实现了i18n功能
// 而StaticMessageSource实现的是由程序载入文本,而非文件,便是去掉了i18n功能
this.staticMessageSource = new StaticMessageSource();
getBeanFactory().registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.staticMessageSource);
}
}
StaticWebApplicationContext
实现功能也比较少
public class StaticWebApplicationContext extends StaticApplicationContext
implements ConfigurableWebApplicationContext, ThemeSource {
// 不可设置bean配置文件来源
@Override
public void setConfigLocation(String configLocation) {
throw new UnsupportedOperationException("StaticWebApplicationContext does not support config locations");
}@Override
public void setConfigLocations(String... configLocations) {
throw new UnsupportedOperationException("StaticWebApplicationContext does not support config locations");
}@Override
public String[] getConfigLocations() {
return null;
}
}
StaticWebApplicationContext
也并未实现 ConfigurableWebApplicationContext
的核心方法,也就不能通过文件加载配置,该类设计的目的主要用于测试,不用于产品环境
6. AbstractRefreshableApplicationContext AbstractRefreshableApplicationContext
的主要功能是创建 bean 工厂,刷新上下文数据
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
@Override
protected final void refreshBeanFactory() throws BeansException {
// ... 代码省略
try {
// 创建bean工厂
DefaultListableBeanFactory beanFactory = createBeanFactory();
// ... 代码省略// 加载bean的定义
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}// 创建bean工厂
protected DefaultListableBeanFactory createBeanFactory() {
// 默认使用DefaultListableBeanFactory创建bean工厂
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}// 加载bean的定义,由子类实现
protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
throws BeansException, IOException;
}
7. AbstractRefreshableConfigApplicationContext AbstractRefreshableConfigApplicationContext
的主要功能是可以通过文件加载配置
public abstract class AbstractRefreshableConfigApplicationContext extends AbstractRefreshableApplicationContext
implements BeanNameAware, InitializingBean {
// 设置配置文件来源,以",;
\t\n"分隔多个
public void setConfigLocation(String location) {
setConfigLocations(StringUtils.tokenizeToStringArray(location, CONFIG_LOCATION_DELIMITERS));
}public void setConfigLocations(@Nullable String... locations) {
if (locations != null) {
this.configLocations = new String[locations.length];
for (int i = 0;
i < locations.length;
i++) {
// 解析路径,替换${}占位符
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}// 获取配置文件来源集,如果没有,则返回默认的
protected String[] getConfigLocations() {
return (this.configLocations != null ? this.configLocations : getDefaultConfigLocations());
}// 默认的配置文件来源集由子类实现
protected String[] getDefaultConfigLocations() {
return null;
}// 解析路径,替换${}占位符,有PropertySourcesPropertyResolver.resolveRequiredPlaceholders实现此功能
protected String resolvePath(String path) {
return getEnvironment().resolveRequiredPlaceholders(path);
}
}
AbstractRefreshableConfigApplicationContext
实现了ConfigurableWebApplicationContext
的核心方法,也就是可以文件加载配置PropertySourcesPropertyResolver
如何是解析路径的,后面再解析
实现功能比较少,放在这里一起解析
public abstract class AbstractRefreshableWebApplicationContext extends AbstractRefreshableConfigApplicationContext
implements ConfigurableWebApplicationContext, ThemeSource {
@Override
protected ConfigurableEnvironment createEnvironment() {
// StandardServletEnvironment扩展了StandardEnvironment
// 增加了可以从Servlet context init parameters和Servlet config init parameters增加应用配置来源
return new StandardServletEnvironment();
}
}
XmlWebApplicationContext
的主要功能是定义了默认的配置文件,创建一个 bean 定义的 xml 解析器,并注册 bean 定义
public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {
// 默认配置文件
public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";
// 默认配置文件前缀
public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";
// 默认配置文件后缀
public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 创建一个bean定义的xml解析器,用XmlBeanDefinitionReader实现
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// ... 代码省略// 载入bean定义
loadBeanDefinitions(beanDefinitionReader);
}protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String configLocation : configLocations) {
// 通过配置文件载入bean定义
reader.loadBeanDefinitions(configLocation);
}
}
}@Override
protected String[] getDefaultConfigLocations() {
if (getNamespace() != null) {
// 如果有servlet-name(如testapp),用前缀后缀包裹为"/WEB-INF/testapp-servlet.xml"
return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};
}
else {
// 如果没有,默认为"/WEB-INF/applicationContext.xml"文件
return new String[] {DEFAULT_CONFIG_LOCATION};
}
}
}
XmlWebApplicationContext
主要解决了 2 个问题:- 定义了默认的配置文件,有 servlet-name(如
testapp
),用前缀后缀包裹为/WEB-INF/testapp-servlet.xml
,如果没有 servlet-name,则为/WEB-INF/applicationContext.xml
- 创建一个 bean 定义的 xml 解析器,并通过配置文件载入 bean 定义
XmlWebApplicationContext
作为上下文环境,从 xml
文件加载配置与 bean 定义至于
XmlBeanDefinitionReader
如何是解析 bean 定义的,后面再解析9. AnnotationConfigWebApplicationContext AnnotationConfigWebApplicationContext
的主要功能是可以通过注解载入配置和 bean 定义
public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWebApplicationContext
implements AnnotationConfigRegistry {}
先来看看 AnnotationConfigRegistry
public interface AnnotationConfigRegistry {
// 根据类名注册组件
void register(Class>... componentClasses);
// 根据包名扫描组件
void scan(String... basePackages);
}
这两个方法正好是通过注解如
@Configuration, @bean, @Component, @Controller, @Service
等注册 bean 的底层机制来看看
AnnotationConfigWebApplicationContext
是如何实现的public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWebApplicationContext
implements AnnotationConfigRegistry {
// 组件类集合
private final Set> componentClasses = new LinkedHashSet<>();
// 扫描包名集合
private final Set basePackages = new LinkedHashSet<>();
// 注册组件
@Override
public void register(Class>... componentClasses) {
Collections.addAll(this.componentClasses, componentClasses);
}// 添加扫描包名
@Override
public void scan(String... basePackages) {
Collections.addAll(this.basePackages, basePackages);
}// 加载bean定义
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
// 创建一个bean定义的注解解析器,用AnnotatedBeanDefinitionReader实现
AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
// 创建一个基于包名的bean注解扫描器,用ClassPathBeanDefinitionScanner实现
ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);
// 创建一个bean命名生成器
BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
if (beanNameGenerator != null) {
reader.setBeanNameGenerator(beanNameGenerator);
scanner.setBeanNameGenerator(beanNameGenerator);
beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
}// 创建一个bean作用域元信息解析器,判断注册的bean是原生类型(prototype)还是单例类型(singleton)
ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
if (scopeMetadataResolver != null) {
reader.setScopeMetadataResolver(scopeMetadataResolver);
scanner.setScopeMetadataResolver(scopeMetadataResolver);
}// 注册组件类
if (!this.componentClasses.isEmpty()) {
reader.register(ClassUtils.toClassArray(this.componentClasses));
}// 扫描包
if (!this.basePackages.isEmpty()) {
scanner.scan(StringUtils.toStringArray(this.basePackages));
}// 通过定义的配置来源注册组件类或扫描包名
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String configLocation : configLocations) {
try {
Class> clazz = ClassUtils.forName(configLocation, getClassLoader());
reader.register(clazz);
}
catch (ClassNotFoundException ex) {
int count = scanner.scan(configLocation);
// ... 代码省略
}
}
}
}// 创建一个bean定义的注解解析器,用AnnotatedBeanDefinitionReader实现
protected AnnotatedBeanDefinitionReader getAnnotatedBeanDefinitionReader(DefaultListableBeanFactory beanFactory) {
return new AnnotatedBeanDefinitionReader(beanFactory, getEnvironment());
}// 创建一个基于包名的bean注解扫描器,用ClassPathBeanDefinitionScanner实现
protected ClassPathBeanDefinitionScanner getClassPathBeanDefinitionScanner(DefaultListableBeanFactory beanFactory) {
return new ClassPathBeanDefinitionScanner(beanFactory, true, getEnvironment());
}
}
实际上,注册 bean 是由
AnnotatedBeanDefinitionReader
完成,扫描包是由ClassPathBeanDefinitionScanner
完成,这两个类后面再解析10. GroovyWebApplicationContext GroovyWebApplicationContext
的运行机制与
XmlWebApplicationContext
差不多,从 groovy
文件加载配置与 bean 定义public class GroovyWebApplicationContext extends AbstractRefreshableWebApplicationContext implements GroovyObject {
// 默认配置文件
public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.groovy";
// 默认配置文件前缀
public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";
// 默认配置文件后缀
public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".groovy";
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 创建一个bean定义的Groovy解析器,用GroovyBeanDefinitionReader实现
GroovyBeanDefinitionReader beanDefinitionReader = new GroovyBeanDefinitionReader(beanFactory);
// ... 代码省略// 载入bean定义
loadBeanDefinitions(beanDefinitionReader);
}protected void loadBeanDefinitions(GroovyBeanDefinitionReader reader) throws IOException {
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String configLocation : configLocations) {
// 通过配置文件载入bean定义
reader.loadBeanDefinitions(configLocation);
}
}
}@Override
protected String[] getDefaultConfigLocations() {
if (getNamespace() != null) {
// 如果有servlet-name(如testapp),用前缀后缀包裹为"/WEB-INF/testapp-servlet.groovy"
return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};
}
else {
// 如果没有,默认为"/WEB-INF/applicationContext.groovy"文件
return new String[] {DEFAULT_CONFIG_LOCATION};
}
}
}
11. 综述 WebApplicationContext
定义了 Web 应用初始化的基本流程,主要有 5 个实现类,常用的是:基于 Xml 加载的
XmlWebApplicationContext
与基于注解加载的
AnnotationConfigWebApplicationContext
- GenericWebApplicationContext、StaticWebApplicationContext
:这两者都只是WebApplicationContext
的基础实现,都不能通过配置文件和注解加载应用配置与 bean,一般用于扩展实现(如 SpringBoot),很少直接使用 - XmlWebApplicationContext
:基于 XML 加载应用配置与 bean 的上下文环境,是 SpringMVC 的默认 Context - AnnotationConfigWebApplicationContext
:基于注解如@Configuration, @bean
等加载应用配置与 bean 的上下文环境 - GroovyWebApplicationContext
:与XmlWebApplicationContext
的实现差不多,但可以用 Groovy 代替 xml 做配置文件,但目前 Groovy 远不及 Xml 普及,用的仍然不多
ConfigurableListableBeanFactory
如何加载、实例化 beanResourceEditorRegistrar
如何注册属性编辑器、属性编辑器如何解析为对象PathMatchingResourcePatternResolver
如何解析、加载 locationPattern 指定的资源PropertySourcesPropertyResolver
如何是解析路径的XmlBeanDefinitionReader
如何是解析 bean 定义的AnnotatedBeanDefinitionReader
是如何注册 bean 的ClassPathBeanDefinitionScanner
是如何扫描包的
作者:深予之 (@senntyou)
版权声明:自由转载-非商用-非衍生-保持署名(创意共享 3.0 许可证)
推荐阅读
- Activiti(一)SpringBoot2集成Activiti6
- SpringBoot调用公共模块的自定义注解失效的解决
- 解决SpringBoot引用别的模块无法注入的问题
- Android事件传递源码分析
- 2018-07-09|2018-07-09 Spring 的DBCP,c3p0
- Quartz|Quartz 源码解析(四) —— QuartzScheduler和Listener事件监听
- Java内存泄漏分析系列之二(jstack生成的Thread|Java内存泄漏分析系列之二:jstack生成的Thread Dump日志结构解析)
- [源码解析]|[源码解析] NVIDIA HugeCTR,GPU版本参数服务器---(3)
- ffmpeg源码分析01(结构体)
- spring|spring boot项目启动websocket