Spring source code analysis 2: Context component (WebApplicationContext)
The previous article analyzed the DispatcherServlet
and ContextLoaderListener
, and analyzed the application initialization and request processing flow, but there are still some components that need to be resolved:
ConfigurableWebApplicationContext.refresh
refresh contextApplicationContext.getBean
Get the bean from the context- The policy processing defined in the
DispatcherServlet.properties
- The policy processing defined in the
ContextLoader.properties
View.render
view rendering
In this chapter, take a look at the policy processing defined in the ContextLoader.properties
Only one strategy is defined in the ContextLoader.properties
org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
By default, XmlWebApplicationContext
(based on XML loading) is used as the application context
spring-web
internally defines 5 application context classes:
- GenericWebApplicationContext
:WebApplicationContext
, but the application configuration and beans cannot be loaded through configuration files and annotations. It is generally used to extend the implementation (such as SpringBoot) and is rarely used directly - StaticWebApplicationContext
: It is alsoWebApplicationContext
, but does not support i18n. It is mainly used for testing and does not require a product environment - XmlWebApplicationContext
WebApplicationContext
implementation of loading application configuration and bean based on XML, which is the default Context of SpringMVC - AnnotationConfigWebApplicationContext
: Based on annotations such as@Configuration, @bean
load application configuration and beanWebApplicationContext
implementation - GroovyWebApplicationContext
: It isXmlWebApplicationContext
the implementation of 06177d1b2d8d4c, but Groovy can be used instead of xml as the configuration file, which is not used much at present
Let's first take a look at the inheritance relationship of these 5 application context classes
- 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
We can find that each class inherits AbstractApplicationContext
, and XmlWebApplicationContext
, AnnotationConfigWebApplicationContext
,GroovyWebApplicationContext
all inherit AbstractRefreshableWebApplicationContext
1. DefaultResourceLoader
DefaultResourceLoader
The main function is to implement resource loading
public class DefaultResourceLoader implements ResourceLoader {}
First look at the interface ResourceLoader
public interface ResourceLoader {
// 根据一个字符位置信息获取资源
Resource getResource(String location);
// 获取资源加载器
ClassLoader getClassLoader();
}
DefaultResourceLoader
Is the default implementation 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
The main function of is to obtain bean instances by name, type or annotation, obtain contextual environment objects and resources, and refresh contextual data
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {}
Interface ConfigurableApplicationContext
And its inherited interfaces mainly define the following methods
public interface ConfigurableApplicationContext {
// 获取bean
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
// 通过类型或注解获取bean
<T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException;
<T> Map<String, T> getBeansOfType(@Nullable Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)
throws BeansException;
Map<String, Object> 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
Get the environment
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
Get bean
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
@Override
public Object getBean(String name) throws BeansException {
return getBeanFactory().getBean(name);
}
@Override
public <T> T getBean(String name, Class<T> 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> T getBean(Class<T> requiredType) throws BeansException {
return getBeanFactory().getBean(requiredType);
}
@Override
public <T> T getBean(Class<T> requiredType, Object... args) throws BeansException {
return getBeanFactory().getBean(requiredType, args);
}
// 留给子类实现
public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}
Because different Context
register beans in getBeanFactory
left to subclasses to implement
2.3. AbstractApplicationContext.getBeansOfType
AbstractApplicationContext.getBeansOfType
Get bean by type or annotation
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
@Override
public <T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException {
return getBeanFactory().getBeansOfType(type);
}
@Override
public <T> Map<String, T> getBeansOfType(@Nullable Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)
throws BeansException {
return getBeanFactory().getBeansOfType(type, includeNonSingletons, allowEagerInit);
}
@Override
public Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType)
throws BeansException {
return getBeanFactory().getBeansWithAnnotation(annotationType);
}
// 留给子类实现
public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}
2.4. AbstractApplicationContext.refresh
AbstractApplicationContext.refresh
Refresh context data
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));
// ... 代码省略
}
}
- Because different
Context
register beans inrefreshBeanFactory, postProcessBeanFactory
left to subclasses to implement ConfigurableListableBeanFactory
how to load and instantiate the bean, and then analyze it later
2.5. AbstractApplicationContext.prepareBeanFactory
AbstractApplicationContext.prepareBeanFactory
Prepare the bean factory
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
How to register the property editor, how to parse the property editor as an object, and then resolve it later
2.6. AbstractApplicationContext.getResources
AbstractApplicationContext.getResources
Get multiple resources based on locationPattern, such as wildcard *
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
How to parse and load the resource specified by locationPattern, and then parse it later
2.7. Summary
In general, the AbstractApplicationContext
class completes most of the functions of the context environment, including environment loading, bean loading and pre- and post-processing, event dispatch, completion of some initialization work, etc.
However, several interfaces are extended to implement subclasses, such as how to load, register, and instantiate beans, etc.
3. GenericApplicationContext
GenericApplicationContext
The main function is to register and manage bean definitions and aliases
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {}
BeanDefinitionRegistry
This interface mainly defines the definition and alias of the registered 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);
}
Take a look at how GenericApplicationContext
implements these interfaces
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);
}
}
Finally settled on beanFactory
4. GenericWebApplicationContext
GenericWebApplicationContext
The main function is to add the source of the configuration bean configuration file, allowing the context environment to be instantiated by configuration
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
extends WebApplicationContext
and defines the context environment allowed to be instantiated by configuration
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
does not implement ConfigurableWebApplicationContext
, so the configuration cannot be loaded through files.
The purpose of this type of design is not web.xml
, but to install programmatically. For example, use WebApplicationInitializers
to build an embedded context; generally it is rarely used
5. StaticWebApplicationContext
Because StaticApplicationContext
There are few implementation functions, so put it here and analyze it together
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
Few implementation functions
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
also does not implement ConfigurableWebApplicationContext
, so the configuration cannot be loaded through files.
The purpose of this type of design is mainly for testing, not for production environments
6. AbstractRefreshableApplicationContext
AbstractRefreshableApplicationContext
The main function is to create a bean factory, refresh the context data
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
The main function is to load the configuration through the file
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
implements theConfigurableWebApplicationContext
, that is, you can load the configuration filePropertySourcesPropertyResolver
resolve the path, and then resolve it later
8. XmlWebApplicationContext
Because AbstractRefreshableWebApplicationContext
There are few implementation functions, so put it here and analyze it together
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
The main function is to define the default configuration file, create a bean definition xml parser, and register the bean definition
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
mainly solves 2 problems:
- The default configuration file is defined, with a servlet-name (such as
testapp
), which is wrapped with a prefix and suffix as/WEB-INF/testapp-servlet.xml
, if there is no servlet-name, it is/WEB-INF/applicationContext.xml
- Create a bean definition xml parser, and load the bean definition through the configuration file
The default loading mechanism of the SpringMVC framework is to use XmlWebApplicationContext
as the context environment to load configuration and bean definitions xml
As for XmlBeanDefinitionReader
parses the bean definition, we will parse it later
9. AnnotationConfigWebApplicationContext
AnnotationConfigWebApplicationContext
The main function is to load configuration and bean definitions through annotations
public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWebApplicationContext
implements AnnotationConfigRegistry {}
First take a look at AnnotationConfigRegistry
public interface AnnotationConfigRegistry {
// 根据类名注册组件
void register(Class<?>... componentClasses);
// 根据包名扫描组件
void scan(String... basePackages);
}
These two methods happen to be the underlying mechanism of registering beans @Configuration, @bean, @Component, @Controller, @Service
AnnotationConfigWebApplicationContext
's see how 06177d1b2da197 is implemented
public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWebApplicationContext
implements AnnotationConfigRegistry {
// 组件类集合
private final Set<Class<?>> componentClasses = new LinkedHashSet<>();
// 扫描包名集合
private final Set<String> 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());
}
}
In fact, the registered bean is AnnotatedBeanDefinitionReader
, and the scanning package is ClassPathBeanDefinitionScanner
. These two classes will be resolved later
10. GroovyWebApplicationContext
GroovyWebApplicationContext
The operating mechanism is similar to XmlWebApplicationContext
, loading configuration and bean definition groovy
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. Summary
WebApplicationContext
Defines the basic process of Web application initialization, there are mainly 5 implementation classes, the commonly used ones are: XmlWebApplicationContext
AnnotationConfigWebApplicationContext
based on annotation loading
- GenericWebApplicationContext、StaticWebApplicationContext
: Both of these are justWebApplicationContext
, neither can load application configuration and beans through configuration files and annotations. They are generally used to extend implementations (such as SpringBoot) and are rarely used directly. - XmlWebApplicationContext
: Load application configuration and bean context based on XML, which is the default Context of SpringMVC - AnnotationConfigWebApplicationContext
: Load application configuration and bean context based on annotations such as@Configuration, @bean
- GroovyWebApplicationContext
: It isXmlWebApplicationContext
the implementation of 06177d1b2da655, but Groovy can be used instead of xml as the configuration file, but currently Groovy is far less popular than Xml, and it is still not used much
12. Unfinished
There are still some points in this section for the next analysis:
ConfigurableListableBeanFactory
How to load and instantiate beansResourceEditorRegistrar
How to register the attribute editor, how to resolve the attribute editor into an objectPathMatchingResourcePatternResolver
How to parse and load the resource specified by locationPatternPropertySourcesPropertyResolver
resolve the pathXmlBeanDefinitionReader
how to parse bean definitionAnnotatedBeanDefinitionReader
how to register beanClassPathBeanDefinitionScanner
scans the package
Follow-up
For more blogs, check out https://github.com/senntyou/blogs
Author: Shen Yuzhi (@senntyou)
Copyright statement: Freely reprinted-non-commercial-non-derivative-keep the signature ( Creative Commons 3.0 License )
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。