org.springframework.context.support.AbstractRefreshableApplicationContext#createBeanFactory
// beanFactory主要用于获取bean
DefaultListableBeanFactory beanFactory = createBeanFactory();
org.springframework.context.support.AbstractRefreshableApplicationContext#createBeanFactory
BeanFactory: 这个获取bean的配置信息
ListableBeanFactory: 这个类是对beanFactory进一步对接口的补充。
HierarchicalBeanFactory: 该接口提供了两个方法一个是获取父容器。第二是否包含bean
protected DefaultListableBeanFactory createBeanFactory() {
// 创建一个默认的bean工厂
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
org.springframework.context.support.AbstractApplicationContext#getInternalParentBeanFactory
/**
* Return the internal bean factory of the parent context if it implements
* ConfigurableApplicationContext; else, return the parent context itself.
* @see org.springframework.context.ConfigurableApplicationContext#getBeanFactory
*/
// 返回bean工厂的父上下文,如果实现了ConfigurableApplicationContext
@Nullable
protected BeanFactory getInternalParentBeanFactory() {
return (getParent() instanceof ConfigurableApplicationContext ?
// 获取spring容器对象 applicationContext
((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent());
}
回到前面源码实现接着分析源码
org.springframework.context.support.AbstractRefreshableApplicationContext#customizeBeanFactory
对 IOC 容器进行定制化,如设置启动参数,开启注解的自动装
customizeBeanFactory(beanFactory);
org.springframework.context.support.AbstractRefreshableApplicationContext#customizeBeanFactory
/**
* Customize the internal bean factory used by this context.
* Called for each {@link #refresh()} attempt.
* <p>The default implementation applies this context's
* {@linkplain #setAllowBeanDefinitionOverriding "allowBeanDefinitionOverriding"}
* and {@linkplain #setAllowCircularReferences "allowCircularReferences"} settings,
* if specified. Can be overridden in subclasses to customize any of
* {@link DefaultListableBeanFactory}'s settings.
* @param beanFactory the newly created bean factory for this context
* @see DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
* @see DefaultListableBeanFactory#setAllowCircularReferences
* @see DefaultListableBeanFactory#setAllowRawInjectionDespiteWrapping
* @see DefaultListableBeanFactory#setAllowEagerClassLoading
*/
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
// 是否允许bean定义覆盖
if (this.allowBeanDefinitionOverriding != null) {
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}{
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// 是否允许bean之间循环引用
if (this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
}
org.springframework.context.support.AbstractRefreshableApplicationContext#loadBeanDefinitions
// 调用载入 Bean 定义的方法,主要这里又使用了一个委派模式,在当前类中只定义了抽象的
// loadBeanDefinitions 方法,具体的实现调用子类容器
loadBeanDefinitions(beanFactory);
org.springframework.context.support.AbstractRefreshableApplicationContext#loadBeanDefinitions
/**
* Load bean definitions into the given bean factory, typically through
* delegating to one or more bean definition readers.
* @param beanFactory the bean factory to load bean definitions into
* @throws BeansException if parsing of the bean definitions failed
* @throws IOException if loading of bean definition files failed
* @see org.springframework.beans.factory.support.PropertiesBeanDefinitionReader
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
*/
protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
throws BeansException, IOException;
org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.support.DefaultListableBeanFactory)
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
//第一步: 创建 XmlBeanDefinitionReader,即创建 Bean 读取器,并通过回调设置到容器中去,容器使用该读取器读
//取 Bean 定义资源
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
//第二步: resource loading environment.
//为 Bean 读取器设置 Spring 资源加载器,AbstractXmlApplicationContext 的
//祖先父类 AbstractApplicationContext 继承 DefaultResourceLoader,因此,容器本身也是一个资源加载器
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
//为 Bean 读取器设置 SAX xml 解析器
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
// 当 Bean 读取器读取 Bean 定义的 Xml 资源文件时,启用 Xml 的校验机
initBeanDefinitionReader(beanDefinitionReader);
// /Bean 读取器真正实现加载的方法
loadBeanDefinitions(beanDefinitionReader);
}
org.springframework.beans.factory.support.AbstractBeanDefinitionReader#setEnvironment
beanDefinitionReader.setEnvironment(this.getEnvironment());
org.springframework.beans.factory.xml.ResourceEntityResolver
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
org/springframework/beans/factory/xml/ResourceEntityResolver.java:66
*/
public ResourceEntityResolver(ResourceLoader resourceLoader) {
super(resourceLoader.getClassLoader());
this.resourceLoader = resourceLoader;
}
org.springframework.beans.factory.xml.DelegatingEntityResolver#DelegatingEntityResolver(java.lang.ClassLoader)
/**
* Create a new DelegatingEntityResolver that delegates to
* a default {@link BeansDtdResolver} and a default {@link PluggableSchemaResolver}.
* <p>Configures the {@link PluggableSchemaResolver} with the supplied
* {@link ClassLoader}.
* @param classLoader the ClassLoader to use for loading
* (can be {@code null}) to use the default ClassLoader)
*/
public DelegatingEntityResolver(@Nullable ClassLoader classLoader) {
创建DTD解析器
this.dtdResolver = new BeansDtdResolver();
// schema解析器
this.schemaResolver = new PluggableSchemaResolver(classLoader);
}
org.springframework.beans.factory.xml.BeansDtdResolver
public class BeansDtdResolver implements EntityResolver {
private static final String DTD_EXTENSION = ".dtd";
private static final String DTD_NAME = "spring-beans";
..............................
}
org.springframework.beans.factory.xml.PluggableSchemaResolver#PluggableSchemaResolver(java.lang.ClassLoader)
public PluggableSchemaResolver(@Nullable ClassLoader classLoader) {
this.classLoader = classLoader;
this.schemaMappingsLocation = DEFAULT_SCHEMA_MAPPINGS_LOCATION;
}
org.springframework.beans.factory.xml.PluggableSchemaResolver
/**
* The location of the file that defines schema mappings.
* Can be present in multiple JAR files.
*/
public static final String DEFAULT_SCHEMA_MAPPINGS_LOCATION = "META-INF/spring.schemas";
org.springframework.context.support.AbstractXmlApplicationContext#initBeanDefinitionReader
// 当 Bean 读取器读取 Bean 定义的 Xml 资源文件时,启用 Xml 的校验机
initBeanDefinitionReader(beanDefinitionReader);
org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.xml.XmlBeanDefinitionReader)
loadBeanDefinitions(beanDefinitionReader);
org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.xml.XmlBeanDefinitionReader)
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
//获取 Bean 定义资源的定位
Resource[] configResources = getConfigResources();
if (configResources != null) {
//Xml Bean 读取器调用其父类 AbstractBeanDefinitionReader 读取定位
//的 Bean 定义资源
reader.loadBeanDefinitions(configResources);
}
//如果子类中获取的 Bean 定义资源定位为空,则获取 FileSystemXmlApplicationContext 构造方法中
// setConfigLocations 方法设置的资源
String[] configLocations = getConfigLocations();
if (configLocations != null) {
//Xml Bean 读取器调用其父类 AbstractBeanDefinitionReader 读取定位
// //的 Bean 定义资源
reader.loadBeanDefinitions(configLocations);
}
}
org.springframework.context.support.AbstractRefreshableConfigApplicationContext#getConfigLocations
// 获取配置文件的地址
@Nullable
protected String[] getConfigLocations() {
return (this.configLocations != null ? this.configLocations : getDefaultConfigLocations());
}
org.springframework.context.support.AbstractRefreshableConfigApplicationContext#setConfigLocation加载配置文件
public void setConfigLocation(String location) {
setConfigLocations(StringUtils.tokenizeToStringArray(location, CONFIG_LOCATION_DELIMITERS));
}
org.springframework.context.support.AbstractRefreshableConfigApplicationContext#setConfigLocations
设置location地址
public void setConfigLocations(@Nullable String... locations) {
// 遍历配置文件、configLocations
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be 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;
}
}
org.springframework.web.context.ConfigurableWebApplicationContext#setConfigLocation
// 第四步: 获取配置文件路径 contextConfigLocation,配置文件可以是多个的,用,换行分开,可以用占位符
String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
if (configLocationParam != null) {
wac.setConfigLocation(configLocationParam);
}
org.springframework.web.context.ContextLoader#CONFIG_LOCATION_PARAM
/**
* Name of servlet context parameter (i.e., {@value}) that can specify the
* config location for the root context, falling back to the implementation's
* default otherwise.
* @see org.springframework.web.context.support.XmlWebApplicationContext#DEFAULT_CONFIG_LOCATION
*/
public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation";
在web.xml里面配置的是servlet,那么启动的时候就会从servlet读取配置信息(参数)
,如何加载多参数
public void setConfigLocation(String location) {
setConfigLocations(StringUtils.tokenizeToStringArray(location, CONFIG_LOCATION_DELIMITERS));
}
org.springframework.context.ConfigurableApplicationContext#CONFIG_LOCATION_DELIMITERS
String CONFIG_LOCATION_DELIMITERS = ",; \t\n";
bean定义配置文件可以是,或;或空格或换行符分开都可以,为了证明这个结论、可以添加
org.springframework.context.support.AbstractRefreshableConfigApplicationContext#setConfigLocations
public void setConfigLocations(@Nullable String... locations) {
// 遍历配置文件、configLocations
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be 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;
}
}
org.springframework.context.support.AbstractRefreshableConfigApplicationContext#resolvePath 解析配置文件的地址
this.configLocations[i] = resolvePath(locations[i]).trim();
org.springframework.context.support.AbstractRefreshableConfigApplicationContext#resolvePath
解析配置文件后把配置文件路径放到spring上下文中
protected String resolvePath(String path) {
return getEnvironment().resolveRequiredPlaceholders(path);
}
org.springframework.core.env.PropertyResolver#resolveRequiredPlaceholders
String resolveRequiredPlaceholders(String text) throws IllegalArgumentException;
org.springframework.core.env.AbstractPropertyResolver#resolveRequiredPlaceholders
public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
if (this.strictHelper == null) {
this.strictHelper = createPlaceholderHelper(false);
}
return doResolvePlaceholders(text, this.strictHelper);
}
org.springframework.beans.factory.support.AbstractBeanDefinitionReader#loadBeanDefinitions(java.lang.String…)
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int count = 0;
for (String location : locations) {
count += loadBeanDefinitions(location);
}
return count;
}
org.springframework.beans.factory.support.AbstractBeanDefinitionReader#loadBeanDefinitions(java.lang.String)
count += loadBeanDefinitions(location);
org.springframework.beans.factory.support.AbstractBeanDefinitionReader#loadBeanDefinitions(java.lang.String)
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return loadBeanDefinitions(location, null);
}
org.springframework.beans.factory.support.AbstractBeanDefinitionReader#loadBeanDefinitions(java.lang.String, java.util.Set<org.springframework.core.io.Resource>)
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
//第一步: 获取资源加载器
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
}
//
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
int count = loadBeanDefinitions(resources);
if (actualResources != null) {
Collections.addAll(actualResources, resources);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
}
return count;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
// Can only load single resources by absolute URL.
Resource resource = resourceLoader.getResource(location);
int count = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
}
return count;
}
}
org.springframework.beans.factory.support.AbstractBeanDefinitionReader#loadBeanDefinitions(java.lang.String, java.util.Set<org.springframework.core.io.Resource>)
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
org.springframework.context.support.AbstractApplicationContext#getResources
public Resource[] getResources(String locationPattern) throws IOException {
return this.resourcePatternResolver.getResources(locationPattern);
}
org.springframework.core.io.support.PathMatchingResourcePatternResolver#getResources
public Resource[] getResources(String locationPattern) throws IOException {
//1、 检测参数不能为空
Assert.notNull(locationPattern, "Location pattern must not be null");
if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
// a class path resource (multiple resources for same name possible)
// 2、 提取"classpath*:下面的资源文件
if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
// a class path resource pattern
// 3、 规则配置
return findPathMatchingResources(locationPattern);
}
else {
// all class path resources with the given name
// 4、所有classpath
return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
}
}
else {
// Generally only look for a pattern after a prefix here,
// and on Tomcat only after the "*/" separator for its "war:" protocol.
int prefixEnd = (locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 :
locationPattern.indexOf(':') + 1);
if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
// a file pattern
return findPathMatchingResources(locationPattern);
}
else {
// a single resource with the given name
return new Resource[] {getResourceLoader().getResource(locationPattern)};
}
}
}
org.springframework.beans.factory.support.AbstractBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.Resource…)
int count = loadBeanDefinitions(resources);
org.springframework.beans.factory.support.AbstractBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.Resource…)
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int count = 0;
for (Resource resource : resources) {
count += loadBeanDefinitions(resource);
}
return count;
}
org.springframework.beans.factory.support.BeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.Resource)
int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;
org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.support.EncodedResource)
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Loading XML bean definitions from " + encodedResource);
}
//
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();
}
}
}