每一个程序启动都要加载配置,只是不一样程序读取配置方式不一样,spring也有一套本身规则的配置方式,spring经过beanFactory来加载配置、管理对象,BeanFactory子类树是很是复杂的,若是每个都看很是耗时间,能够找一个典型的子类看一下它的初始化过程,以XmlBeanFactory为例看spring加载配置。
看XmlBeanFactory的入口:java
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this); public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException { super(parentBeanFactory); this.reader.loadBeanDefinitions(resource); }
经过XmlBeanDefinitionReader 加载配置资源, 开始跟踪loadBeanDefinitions的代码,发现XmlBeanDefinitionReader 经过DefaultDocumentLoader对配置文件进行校验并转换成document,到这里配置就算是验证并加载到内存中了,下面就是经过BeanDefinitionDocumentReader解析doc标签,看下面的代码:web
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader { public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); //获取根节点 Element root = doc.getDocumentElement(); //从根节点开始解析标签 doRegisterBeanDefinitions(root); } protected void doRegisterBeanDefinitions(Element root) { //获取beans标签的profile属性 String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); //看spring.profiles.active环境变量中是否有该属性,若是没有则不加载下面的标签 if (!getEnvironment().acceptsProfiles(specifiedProfiles)) { return; } } //标签beans可能会存在递归的状况, 每次都建立本身的解析器 BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(this.readerContext, root, parent); //解析前处理、留给子类实现 preProcessXml(root); //解析bean definition parseBeanDefinitions(root, this.delegate); //解析后处理、留给子类实现 postProcessXml(root); this.delegate = parent; } }
上面就是从根节点开始解析doc,这里支持标签beans嵌套的状况,这样方便咱们在发布的时候改一个环境变量就能够切换多套系统配置,好比以下配置:spring
<beans>
<beans profile="dev">
...
</beans>
<beans profile="test">
...
</beans>
</beans>
在web中使用,在web.xml配置环境变量
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>dev</param-value>
</context-param>数组
加载配置的时序图以下:app
下面就是解析beans下面的标签了,经过命名空间判断是默认标签仍是自定义标签来走不一样的流程。ide
分四种状况import alais bean beans:post
重点看一下解析bean标签的时序图:this
自定义标签在META-INF/spring.handlers定义的,经过标签的命名空间获取到对应的处理类handler,而后调用handler.parse方法,这里主要看命名空间跟handler的对应关系是怎么加载的。spa
看BeanDefinitionParserDelegate的parseCustomElement方法:debug
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) { String namespaceUri = getNamespaceURI(ele); //这个resolve方法里面很重要, namespace的Handler是在这里加载的 NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler == null) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); return null; } return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); }
到resolve中看是怎么获取的NamespaceHandler:
public NamespaceHandler resolve(String namespaceUri) { //加载全部handlers配置 Map<String, Object> handlerMappings = getHandlerMappings(); //获取到对应handler的handler对象或者字符串 Object handlerOrClassName = handlerMappings.get(namespaceUri); if (handlerOrClassName == null) { return null; } else if (handlerOrClassName instanceof NamespaceHandler) { //若是已经初始化过直接返回 return (NamespaceHandler) handlerOrClassName; } else { //未初始化的经过反射实例化对象,而且调用init方法,init方法是把标签跟对应的parser作映射 String className = (String) handlerOrClassName; try { Class<?> handlerClass = ClassUtils.forName(className, this.classLoader); if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) { throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri + "] does not implement the [" + NamespaceHandler.class.getName() + "] interface"); } NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass); namespaceHandler.init(); handlerMappings.put(namespaceUri, namespaceHandler); return namespaceHandler; } catch (ClassNotFoundException ex) { throw new FatalBeanException( "NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "] not found", ex); } catch (LinkageError err) { throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]: problem with handler class file or dependent class", err); } } } private Map<String, Object> getHandlerMappings() { if (this.handlerMappings == null) { synchronized (this) { if (this.handlerMappings == null) { try { //把properties文件加载到map中 Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader); if (logger.isDebugEnabled()) { logger.debug("Loaded NamespaceHandler mappings: " + mappings); } Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>(mappings.size()); CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings); this.handlerMappings = handlerMappings; } catch (IOException ex) { throw new IllegalStateException("Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex); } } } } return this.handlerMappings; }
选一个NamespaceHandler看看它的init方法是作什么的:
public class AopNamespaceHandler extends NamespaceHandlerSupport { /** * Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the ' * {@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}' * and '{@code scoped-proxy}' tags. */ @Override public void init() { // In 2.0 XSD as well as in 2.1 XSD. registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser()); registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser()); registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator()); // Only in 2.0 XSD: moved to context namespace as of 2.1 registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser()); } } public abstract class NamespaceHandlerSupport implements NamespaceHandler { protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) { //元素解析器放入parsers 集合中: this.parsers.put(elementName, parser); } public BeanDefinition parse(Element element, ParserContext parserContext) { //这里调用BeanDefinitionParser的parse方法 return findParserForElement(element, parserContext).parse(element, parserContext); } //获取BeanDefinitionParser private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) { String localName = parserContext.getDelegate().getLocalName(element); //从前面加载的集合中根据标签名称获取Parser BeanDefinitionParser parser = this.parsers.get(localName); if (parser == null) { parserContext.getReaderContext().fatal("Cannot locate BeanDefinitionParser for element [" + localName + "]", element); } return parser; } }
到这里NamespaceHandler就获取到了,回归到上面parseCustomElement方法,handler调用parse方法,parse方法里面首先根据标签到parsers集合里面找到对应的解析器并调用对应解析器的parse方法,时序图: