前言
接着上次的spring上下文加载过程的源码解析
正文
上次主要介绍到刷新beanFactory,找到这个方法org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory的这行代码
@Override protected final void refreshBeanFactory() throws BeansException { // 如果存在beanFactory if (hasBeanFactory()) { // 销毁bean destroyBeans(); // 关闭beanFactory closeBeanFactory(); }
bean销毁介绍完了,找到这行代码
closeBeanFactory();
@Override protected final void closeBeanFactory() { synchronized (this.beanFactoryMonitor) { if (this.beanFactory != null) { this.beanFactory.setSerializationId(null); this.beanFactory = null; } } }
操作beanFactory是同步的。
找到这行代码,创建banFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
protected DefaultListableBeanFactory createBeanFactory() { return new DefaultListableBeanFactory(getInternalParentBeanFactory()); }
@Nullable protected BeanFactory getInternalParentBeanFactory() { // 如果父上下文是配置上下文 return (getParent() instanceof ConfigurableApplicationContext) ? ((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent(); }
返回到这个方法
org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory
customizeBeanFactory(beanFactory);
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) { // 是否允许bean定义覆盖 if (this.allowBeanDefinitionOverriding != null) { beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } // 是否允许bean之间循环引用 if (this.allowCircularReferences != null) { beanFactory.setAllowCircularReferences(this.allowCircularReferences); } }
返回到这个方法
org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory
loadBeanDefinitions(beanFactory);
这一行代码,加载bean定义。
进入到这个方法
org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.support.DefaultListableBeanFactory)通过XmlBeanDefinitionReader加载bean定义。
@Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory.为给定的BeanFactory创建一个新的XmlBeanDefinitionReader。 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment.使用该上下文的资源加载环境配置bean定义阅读器。 beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions.允许子类提供读取器的自定义初始化,然后继续加载bean定义。 initBeanDefinitionReader(beanDefinitionReader); // 加载bean定义 loadBeanDefinitions(beanDefinitionReader); }
// 加载资源 beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
public ResourceEntityResolver(ResourceLoader resourceLoader) { super(resourceLoader.getClassLoader()); this.resourceLoader = resourceLoader; }
进入调用了父类构造器的方法
public DelegatingEntityResolver(@Nullable ClassLoader classLoader) { // 创建DTD解析器 this.dtdResolver = new BeansDtdResolver(); // 创建schema解析器 this.schemaResolver = new PluggableSchemaResolver(classLoader); }
可以看到解析的是这个DTD
public class BeansDtdResolver implements EntityResolver { // dtd解析 private static final String DTD_EXTENSION = ".dtd"; private static final String DTD_NAME = "spring-beans";
public PluggableSchemaResolver(@Nullable ClassLoader classLoader) { this.classLoader = classLoader; this.schemaMappingsLocation = DEFAULT_SCHEMA_MAPPINGS_LOCATION; }
org.springframework.beans.factory.xml.PluggableSchemaResolver
// spring.schemas解析,这个路径下面的schemas都会被解析 META-INF/spring.schemas public static final String DEFAULT_SCHEMA_MAPPINGS_LOCATION = "META-INF/spring.schemas";
从这个地方加载的schema
找到这个方法
org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.support.DefaultListableBeanFactory)的这行代码
// 初始化bean定义 initBeanDefinitionReader(beanDefinitionReader);
// 加载bean定义 loadBeanDefinitions(beanDefinitionReader);
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } }
// 获取配置文件路径 String[] configLocations = getConfigLocations();
@Nullable protected String[] getConfigLocations() { return (this.configLocations != null ? this.configLocations : getDefaultConfigLocations()); }
我们看下configLocations变量在哪里赋值的
public void setConfigLocation(String location) { setConfigLocations(StringUtils.tokenizeToStringArray(location, CONFIG_LOCATION_DELIMITERS)); }
我们看下location变量在哪里赋值的
找到了这个方法org.springframework.web.context.ContextLoader#configureAndRefreshWebApplicationContext
String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM); if (configLocationParam != null) { wac.setConfigLocation(configLocationParam); }
public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation";
是从servlet容器启动时初始化的参数配置中获取的
返回到这个方法
org.springframework.context.support.AbstractRefreshableConfigApplicationContext#setConfigLocation
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) { 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; } }
// 解析配置文件后把配置文件路径放到spring上下文中 this.configLocations[i] = resolvePath(locations[i]).trim();
bean定义配置文件中如果有占位符就替换占位符
protected String resolvePath(String path) { return getEnvironment().resolveRequiredPlaceholders(path); }
@Override public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException { if (this.strictHelper == null) { this.strictHelper = createPlaceholderHelper(false); } // 替换占位符 return doResolvePlaceholders(text, this.strictHelper); }
返回到这个方法
org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.xml.XmlBeanDefinitionReader)的这一行代码
// 加载bean定义 reader.loadBeanDefinitions(configLocations);
@Override public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException { Assert.notNull(locations, "Location array must not be null"); int counter = 0; for (String location : locations) { counter += loadBeanDefinitions(location); } return counter; }
org.springframework.beans.factory.support.AbstractBeanDefinitionReader#loadBeanDefinitions(java.lang.String)
@Override 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>)
这段代码
// 从classpath下面加载 if (resourceLoader instanceof ResourcePatternResolver) { // Resource pattern matching available. try { Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); int loadCount = loadBeanDefinitions(resources); if (actualResources != null) { for (Resource resource : resources) { actualResources.add(resource); } } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]"); } return loadCount; } catch (IOException ex) { throw new BeanDefinitionStoreException( "Could not resolve bean definition resource pattern [" + location + "]", ex); } }
找到这行代码
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
进入到这个方法
org.springframework.core.io.support.PathMatchingResourcePatternResolver#getResources
@Override public Resource[] getResources(String locationPattern) throws IOException { Assert.notNull(locationPattern, "Location pattern must not be null"); // 配置路径以classpath*:开头 if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) { // a class path resource (multiple resources for same name possible) if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) { // a class path resource pattern 从classpath*路径下匹配的的jar,war包等文件中查找配置文件 return findPathMatchingResources(locationPattern); } else { // all class path resources with the given name 从classpath下面加载jar、war文件中的配置文件 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(java.lang.String, java.util.Set<org.springframework.core.io.Resource>)
递归调用 int loadCount = loadBeanDefinitions(resources);
@Override public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException { Assert.notNull(resources, "Resource array must not be null"); int counter = 0; for (Resource resource : resources) { counter += loadBeanDefinitions(resource); } return counter; }
org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.Resource)
@Override public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { return loadBeanDefinitions(new EncodedResource(resource)); }
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.isInfoEnabled()) { logger.info("Loading XML bean definitions from " + encodedResource.getResource()); } // resourcesCurrentlyBeingLoaded threadLocal保证线程安全 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()); } // 加载bean定义 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(); } } }
找到这行代码
// 加载bean定义 return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
内容太多,下篇文章接着解析。
最后
本次介绍到这里,以上内容仅供参考。大家从spring源码解析第一篇文章开始看,更容易点,否则可读性可能不台好,因为spring源码体系太庞大,不太好归类,按每篇文章的篇幅不太好拆分。
扫码关注
进群讨论
快到碗里来
!