- 浏览: 421716 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (318)
- js (20)
- JQuery (2)
- Java (46)
- Oracle (4)
- mysql (21)
- ExtJs (17)
- Excel (2)
- Linux (8)
- Sql (8)
- Jsp (2)
- hibernate (12)
- jbpm (17)
- eclipse (8)
- 名博收藏 (1)
- Junit (2)
- 应用集成 (3)
- web (10)
- jboss (3)
- Rest (3)
- 其它 (7)
- 磁盘分区管理 (1)
- spring (18)
- SSO (4)
- tomcat (4)
- CSS (7)
- MemCached (6)
- EhCache (4)
- weblogic (1)
- apache (6)
- Exception design (1)
- db (1)
- 分析模式 (1)
- jstl (1)
- jsf (0)
- firefox (2)
- MongoDB (4)
- androidpn (1)
- hadoop (1)
- cvs (1)
- 微信公众号 (2)
- 高并发 (4)
- 技术论坛 (1)
- CDN (1)
- JVM (16)
- 加密 (4)
- maven (2)
- jenkins (1)
- hessian (1)
- 大数据处理 (2)
- NIO (0)
- netty (1)
- redis (1)
- git (1)
- Elastic Job (0)
最新评论
-
zgw06629:
或者<pre>aaaabbbbcccc</p ...
javaDoc注释换行 -
ddnzero:
...
StringBuffer换行 -
maosijun:
。。。。
EXT CExt.form.ComboBox选择一次后只剩一个选项 -
ysa198584:
你这有问题,当我的代码出现User.class的时候,反编绎的 ...
java的class文件批量反编译 -
dongj0325:
看到您的博客,很受启发,但还有关于jbpm4.4 timer使 ...
JBPM定时器(Timer)之Repeat属性不能使用变量
原文:http://www.iteye.com/topic/743997
最近在看Spring源代码,对配置文件信息的载入是使用Spring的第一步 ,而这第一步就是一个非常复杂的过程....
Spring通过定义BeanDefination来管理Ioc中的各种对象以及它们之间的依赖关系,所以载入的过程其实就是将XML文件读取并解析成BeanDefination数据的过程。
我们以最常使用的ClassPathXmlApplicationContext为切入点
1. 创建一个ClassPathXmlApplicationContext对象,传入文件路径
- ClassPathXmlApplicationContext re = new ClassPathXmlApplicationContext("applicationContext.xml");
ClassPathXmlApplicationContext re = new ClassPathXmlApplicationContext("applicationContext.xml");
这个构造方法会重载到
- public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
- throws BeansException {
- super(parent);
- setConfigLocations(configLocations);
- if (refresh) {
- refresh();
- }
- }
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); } }
其中首先设置配置路径 setConfigLocations(configLocations) ,而后进行刷新 refresh(), 而这个refresh()方法是Ioc容器初始化的入口
2.refresh方法的结构
refresh方法由AbstractApplicationContext实现
- public void refresh() throws BeansException, IllegalStateException {
- synchronized (this.startupShutdownMonitor) {
- // Prepare this context for refreshing.
- prepareRefresh();
- // Tell the subclass to refresh the internal bean factory.
- ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
- // Prepare the bean factory for use in this context.
- prepareBeanFactory(beanFactory);
- try {
- // Allows post-processing of the bean factory in context subclasses.
- postProcessBeanFactory(beanFactory);
- // Invoke factory processors registered as beans in the context.
- invokeBeanFactoryPostProcessors(beanFactory);
- // Register bean processors that intercept bean creation.
- registerBeanPostProcessors(beanFactory);
- // Initialize message source for this context.
- initMessageSource();
- // Initialize event multicaster for this context.
- initApplicationEventMulticaster();
- // Initialize other special beans in specific context subclasses.
- onRefresh();
- // Check for listener beans and register them.
- registerListeners();
- // Instantiate all remaining (non-lazy-init) singletons.
- finishBeanFactoryInitialization(beanFactory);
- // Last step: publish corresponding event.
- finishRefresh();
- }
- catch (BeansException ex) {
- // Destroy already created singletons to avoid dangling resources.
- destroyBeans();
- // Reset 'active' flag.
- cancelRefresh(ex);
- // Propagate exception to caller.
- throw ex;
- }
- }
- }
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } } }
这个方法中描述了ApplicationContext的整个初始化过程,包括BeanFactory的更新,还有messagesource以及一些生命周期有关属性的注册,而我们关心的是BeanFactory的更新,即obtainFreshBeanFactory()方法
3.启动对BeanDefination的载入
还是在ApplicationContext类中
- protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
- refreshBeanFactory();
- ConfigurableListableBeanFactory beanFactory = getBeanFactory();
- if (logger.isDebugEnabled()) {
- logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
- }
- return beanFactory;
- }
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; }
它的第一步交给一个抽象方法refreshBeanFactory(), 具体的实现在AbstractRefreshableApplicationContext类中
- @Override
- protected final void refreshBeanFactory() throws BeansException {
- if (hasBeanFactory()) {
- destroyBeans();
- closeBeanFactory();
- }
- try {
- DefaultListableBeanFactory beanFactory = createBeanFactory();
- beanFactory.setSerializationId(getId());
- customizeBeanFactory(beanFactory);
- loadBeanDefinitions(beanFactory);
- synchronized (this.beanFactoryMonitor) {
- this.beanFactory = beanFactory;
- }
- }
- catch (IOException ex) {
- throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
- }
- }
@Override protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
第一步是判断是否已经创建过BeanFactory,如果是,将它销毁,重新创建
第二步就是创建各种ApplicationContext持有的真正容器实现类DefaultListableBeanFactory,创建Ioc容器
最后启动BeanDefination的载入 loadBeanDefinitions(beanFactory)方法
4.BeanFactory将载入工作交给BeanDefinationReader
loadBeanDefinitions(beanFactory)方法是抽象的,又因为我们的配置文件是XML格式的,所以具体实现实在AbstractXmlApplicationConext中
- @Override
- protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
- // Create a new XmlBeanDefinitionReader for the given BeanFactory.
- XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
- // Configure the bean definition reader with this context's
- // resource loading environment.
- 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.
- initBeanDefinitionReader(beanDefinitionReader);
- loadBeanDefinitions(beanDefinitionReader);
- }
@Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. 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. initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); }
这里创建了一个XmlBeanDefinitionReader 对象,它专门用来读取基于XML文件格式的BeanDefinition配置,接下来重载到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);
- }
- }
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); } }
首先载入Resource对象用来定位资源,Resource对象的生成在ClassPathXmlApplicationContext 中setConfigLocations(configLocations)方法实现
然后调用XmlBeanDefinitionReader基类AbstractBeanDefinitionReader的loadBeanDefinitions方法
- 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;
- }
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; }
然后调用loadBeanDefinitions(resource)方法,此方法的具体实现在XmlBeanDefinitionReader 中
- public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
- return loadBeanDefinitions(new EncodedResource(resource));
- }
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { return loadBeanDefinitions(new EncodedResource(resource)); }
重载到
- 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());
- }
- Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
- if (currentResources == null) {
- currentResources = new HashSet<EncodedResource>(4);
- this.resourcesCurrentlyBeingLoaded.set(currentResources);
- }
- if (!currentResources.add(encodedResource)) {
- throw new BeanDefinitionStoreException(
- "Detected recursive 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.set(null);
- }
- }
- }
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()); } Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet<EncodedResource>(4); this.resourcesCurrentlyBeingLoaded.set(currentResources); } if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected recursive 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.set(null); } } }
在此类中主要是对输入流进行编码操作,然后调用doLoadBeanDefinitions(inputSource, encodedResource.getResource())方法
5.XmlBeanDefinitionReader将载入工作交给W3C的dom
因为读入的文件是XML格式的,所以底层的实现肯定是要和W3C的dom结构打交道
doLoadBeanDefinitions(inputSource, encodedResource.getResource())方法正式引入dom
- protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
- throws BeanDefinitionStoreException {
- try {
- int validationMode = getValidationModeForResource(resource);
- Document doc = this.documentLoader.loadDocument(
- inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
- return registerBeanDefinitions(doc, resource);
- }
- catch (BeanDefinitionStoreException ex) {
- throw ex;
- }
- catch (SAXParseException ex) {
- throw new XmlBeanDefinitionStoreException(resource.getDescription(),
- "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
- }
- catch (SAXException ex) {
- throw new XmlBeanDefinitionStoreException(resource.getDescription(),
- "XML document from " + resource + " is invalid", ex);
- }
- catch (ParserConfigurationException ex) {
- throw new BeanDefinitionStoreException(resource.getDescription(),
- "Parser configuration exception parsing XML from " + resource, ex);
- }
- catch (IOException ex) {
- throw new BeanDefinitionStoreException(resource.getDescription(),
- "IOException parsing XML document from " + resource, ex);
- }
- catch (Throwable ex) {
- throw new BeanDefinitionStoreException(resource.getDescription(),
- "Unexpected exception parsing XML document from " + resource, ex);
- }
- }
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { int validationMode = getValidationModeForResource(resource); Document doc = this.documentLoader.loadDocument( inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware()); return registerBeanDefinitions(doc, resource); } catch (BeanDefinitionStoreException ex) { throw ex; } catch (SAXParseException ex) { throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex); } catch (SAXException ex) { throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", ex); } catch (ParserConfigurationException ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, ex); } catch (IOException ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, ex); } catch (Throwable ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, ex); } }
在此方法中生成了Document类的对象,下一步是进行对象的注册,registerBeanDefinitions(doc, resource)方法
- public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
- // Read document based on new BeanDefinitionDocumentReader SPI.
- BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
- int countBefore = getRegistry().getBeanDefinitionCount();
- documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
- return getRegistry().getBeanDefinitionCount() - countBefore;
- }
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { // Read document based on new BeanDefinitionDocumentReader SPI. BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; }
此方法统计了注册的BeanDefinition的个数,返回一个int值,而具体的注册工作在BeanDefinitionDocumentReader 接口的实现类DefaultBeanDefinitionDocumentReader 中registerBeanDefinitions(doc, createReaderContext(resource))方法实现
6.BeanDefinitionDocumentReader将载入工作交给代理类BeanDefinationParserDelegate
DefaultBeanDefinitionDocumentReader的registerBeanDefinitions(doc, createReaderContext(resource))方法
- public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
- this.readerContext = readerContext;
- logger.debug("Loading bean definitions");
- Element root = doc.getDocumentElement();
- BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);
- preProcessXml(root);
- parseBeanDefinitions(root, delegate);
- postProcessXml(root);
- }
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); BeanDefinitionParserDelegate delegate = createHelper(readerContext, root); preProcessXml(root); parseBeanDefinitions(root, delegate); postProcessXml(root); }
其中首先得到dom结构的根,然后由根进行分析
然后引入BeanDefinitionParserDelegate 代理类对dom结构进行分析,调用parseBeanDefinitions(root, delegate)方法
- protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
- if (delegate.isDefaultNamespace(delegate.getNamespaceURI(root))) {
- NodeList nl = root.getChildNodes();
- for (int i = 0; i < nl.getLength(); i++) {
- Node node = nl.item(i);
- if (node instanceof Element) {
- Element ele = (Element) node;
- String namespaceUri = delegate.getNamespaceURI(ele);
- if (delegate.isDefaultNamespace(namespaceUri)) {
- parseDefaultElement(ele, delegate);
- }
- else {
- delegate.parseCustomElement(ele);
- }
- }
- }
- }
- else {
- delegate.parseCustomElement(root);
- }
- }
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(delegate.getNamespaceURI(root))) { NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; String namespaceUri = delegate.getNamespaceURI(ele); if (delegate.isDefaultNamespace(namespaceUri)) { parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }
其中最主要的操作是在调用parseDefaultElement(ele, delegate)方法中进行
- private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
- if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
- importBeanDefinitionResource(ele);
- }
- else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
- processAliasRegistration(ele);
- }
- else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
- processBeanDefinition(ele, delegate);
- }
- }
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } }
从这个方法里面我们就能看出来底层元素的端倪了,首先判断Node是否为import节点,然后是alias节点,最后是bean节点,我们关心的是bean节点,processBeanDefinition(ele, delegate)方法
- protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
- BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
- if (bdHolder != null) {
- bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
- try {
- // Register the final decorated instance.
- BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
- }
- catch (BeanDefinitionStoreException ex) {
- getReaderContext().error("Failed to register bean definition with name '" +
- bdHolder.getBeanName() + "'", ele, ex);
- }
- // Send registration event.
- getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
- }
- }
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
这里首先由BeanDefinitionParserDelegate 生成BeanDefination的包装类BeanDefinitionHolder ,然后再进行一些修饰工作,这里把工作正式交给BeanDefinitionParserDelegate
7.BeanDefinitionParserDelegate 中的解析工作
BeanDefinition的解析主要在BeanDefinitionParserDelegate 的parseBeanDefinitionElement(ele)方法中进行,重载到
- public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
- String id = ele.getAttribute(ID_ATTRIBUTE);
- String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
- List<String> aliases = new ArrayList<String>();
- if (StringUtils.hasLength(nameAttr)) {
- String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, BEAN_NAME_DELIMITERS);
- aliases.addAll(Arrays.asList(nameArr));
- }
- String beanName = id;
- if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
- beanName = aliases.remove(0);
- if (logger.isDebugEnabled()) {
- logger.debug("No XML 'id' specified - using '" + beanName +
- "' as bean name and " + aliases + " as aliases");
- }
- }
- if (containingBean == null) {
- checkNameUniqueness(beanName, aliases, ele);
- }
- AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
- if (beanDefinition != null) {
- if (!StringUtils.hasText(beanName)) {
- try {
- if (containingBean != null) {
- beanName = BeanDefinitionReaderUtils.generateBeanName(
- beanDefinition, this.readerContext.getRegistry(), true);
- }
- else {
- beanName = this.readerContext.generateBeanName(beanDefinition);
- // Register an alias for the plain bean class name, if still possible,
- // if the generator returned the class name plus a suffix.
- // This is expected for Spring 1.2/2.0 backwards compatibility.
- String beanClassName = beanDefinition.getBeanClassName();
- if (beanClassName != null &&
- beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
- !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
- aliases.add(beanClassName);
- }
- }
- if (logger.isDebugEnabled()) {
- logger.debug("Neither XML 'id' nor 'name' specified - " +
- "using generated bean name [" + beanName + "]");
- }
- }
- catch (Exception ex) {
- error(ex.getMessage(), ele);
- return null;
- }
- }
- String[] aliasesArray = StringUtils.toStringArray(aliases);
- return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
- }
- return null;
- }
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); List<String> aliases = new ArrayList<String>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, BEAN_NAME_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } String beanName = id; if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { beanName = aliases.remove(0); if (logger.isDebugEnabled()) { logger.debug("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases"); } } if (containingBean == null) { checkNameUniqueness(beanName, aliases, ele); } AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { if (!StringUtils.hasText(beanName)) { try { if (containingBean != null) { beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry(), true); } else { beanName = this.readerContext.generateBeanName(beanDefinition); // Register an alias for the plain bean class name, if still possible, // if the generator returned the class name plus a suffix. // This is expected for Spring 1.2/2.0 backwards compatibility. String beanClassName = beanDefinition.getBeanClassName(); if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) { aliases.add(beanClassName); } } if (logger.isDebugEnabled()) { logger.debug("Neither XML 'id' nor 'name' specified - " + "using generated bean name [" + beanName + "]"); } } catch (Exception ex) { error(ex.getMessage(), ele); return null; } } String[] aliasesArray = StringUtils.toStringArray(aliases); return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; }
这个方法首先得到元素的name和id以及别名属性,然后再生成底层的AbstractBeanDefinition对象将它们包装生成BeanDefinitionHolder,其中包括bean的名称,别名,以及BeanDefinition,返回给上层方法
核心在于生成BeanDefinition的parseBeanDefinitionElement(ele, beanName, containingBean)方法
- public AbstractBeanDefinition parseBeanDefinitionElement(
- Element ele, String beanName, BeanDefinition containingBean) {
- this.parseState.push(new BeanEntry(beanName));
- String className = null;
- if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
- className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
- }
- try {
- String parent = null;
- if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
- parent = ele.getAttribute(PARENT_ATTRIBUTE);
- }
- AbstractBeanDefinition bd = createBeanDefinition(className, parent);
- parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
- bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
- parseMetaElements(ele, bd);
- parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
- parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
- parseConstructorArgElements(ele, bd);
- parsePropertyElements(ele, bd);
- parseQualifierElements(ele, bd);
- bd.setResource(this.readerContext.getResource());
- bd.setSource(extractSource(ele));
- return bd;
- }
- catch (ClassNotFoundException ex) {
- error("Bean class [" + className + "] not found", ele, ex);
- }
- catch (NoClassDefFoundError err) {
- error("Class that bean class [" + className + "] depends on not found", ele, err);
- }
- catch (Throwable ex) {
- error("Unexpected failure during bean definition parsing", ele, ex);
- }
- finally {
- this.parseState.pop();
- }
- return null;
- }
public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); String className = null; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } try { String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } AbstractBeanDefinition bd = createBeanDefinition(className, parent); parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); parseMetaElements(ele, bd); parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); parseConstructorArgElements(ele, bd); parsePropertyElements(ele, bd); parseQualifierElements(ele, bd); bd.setResource(this.readerContext.getResource()); bd.setSource(extractSource(ele)); return bd; } catch (ClassNotFoundException ex) { error("Bean class [" + className + "] not found", ele, ex); } catch (NoClassDefFoundError err) { error("Class that bean class [" + className + "] depends on not found", ele, err); } catch (Throwable ex) { error("Unexpected failure during bean definition parsing", ele, ex); } finally { this.parseState.pop(); } return null; }
这个方法我们看起来一目了然,全部都是bean节点中的配置信息
首先得到class的名字,然后得到继承的parent的名字,然后是meta节点,look-up节点,replaced-method节点,构造函数设置节点,最后是比较复杂的property节点,我们继续分析比较复杂的property节点的解析,parsePropertyElements(ele, bd)方法
- public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
- NodeList nl = beanEle.getChildNodes();
- for (int i = 0; i < nl.getLength(); i++) {
- Node node = nl.item(i);
- if (node instanceof Element && nodeNameEquals(node, PROPERTY_ELEMENT)) {
- parsePropertyElement((Element) node, bd);
- }
- }
- }
public void parsePropertyElements(Element beanEle, BeanDefinition bd) { NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element && nodeNameEquals(node, PROPERTY_ELEMENT)) { parsePropertyElement((Element) node, bd); } } }
将bean节点的子元素逐个取出判断是否为property节点,然后进行解析,parsePropertyElement((Element) node, bd)方法
- public void parsePropertyElement(Element ele, BeanDefinition bd) {
- String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
- if (!StringUtils.hasLength(propertyName)) {
- error("Tag 'property' must have a 'name' attribute", ele);
- return;
- }
- this.parseState.push(new PropertyEntry(propertyName));
- try {
- if (bd.getPropertyValues().contains(propertyName)) {
- error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
- return;
- }
- Object val = parsePropertyValue(ele, bd, propertyName);
- PropertyValue pv = new PropertyValue(propertyName, val);
- parseMetaElements(ele, pv);
- pv.setSource(extractSource(ele));
- bd.getPropertyValues().addPropertyValue(pv);
- }
- finally {
- this.parseState.pop();
- }
- }
public void parsePropertyElement(Element ele, BeanDefinition bd) { String propertyName = ele.getAttribute(NAME_ATTRIBUTE); if (!StringUtils.hasLength(propertyName)) { error("Tag 'property' must have a 'name' attribute", ele); return; } this.parseState.push(new PropertyEntry(propertyName)); try { if (bd.getPropertyValues().contains(propertyName)) { error("Multiple 'property' definitions for property '" + propertyName + "'", ele); return; } Object val = parsePropertyValue(ele, bd, propertyName); PropertyValue pv = new PropertyValue(propertyName, val); parseMetaElements(ele, pv); pv.setSource(extractSource(ele)); bd.getPropertyValues().addPropertyValue(pv); } finally { this.parseState.pop(); } }
解析的主要过程,首先判断是否重复,如果重复抛出异常,然后对property节点内部进行解析,最后加入到bean节点信息中,我们继续解析property节点内部,parsePropertyValue(ele, bd, propertyName)方法
- public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
- String elementName = (propertyName != null) ?
- "<property> element for property '" + propertyName + "'" :
- "<constructor-arg> element";
- // Should only have one child element: ref, value, list, etc.
- NodeList nl = ele.getChildNodes();
- Element subElement = null;
- for (int i = 0; i < nl.getLength(); i++) {
- Node node = nl.item(i);
- if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
- !nodeNameEquals(node, META_ELEMENT)) {
- // Child element is what we're looking for.
- if (subElement != null) {
- error(elementName + " must not contain more than one sub-element", ele);
- }
- else {
- subElement = (Element) node;
- }
- }
- }
- boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
- boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
- if ((hasRefAttribute && hasValueAttribute) ||
- ((hasRefAttribute || hasValueAttribute) && subElement != null)) {
- error(elementName +
- " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
- }
- if (hasRefAttribute) {
- String refName = ele.getAttribute(REF_ATTRIBUTE);
- if (!StringUtils.hasText(refName)) {
- error(elementName + " contains empty 'ref' attribute", ele);
- }
- RuntimeBeanReference ref = new RuntimeBeanReference(refName);
- ref.setSource(extractSource(ele));
- return ref;
- }
- else if (hasValueAttribute) {
- TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
- valueHolder.setSource(extractSource(ele));
- return valueHolder;
- }
- else if (subElement != null) {
- return parsePropertySubElement(subElement, bd);
- }
- else {
- // Neither child element nor "ref" or "value" attribute found.
- error(elementName + " must specify a ref or value", ele);
- return null;
- }
- }
public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) { String elementName = (propertyName != null) ? "<property> element for property '" + propertyName + "'" : "<constructor-arg> element"; // Should only have one child element: ref, value, list, etc. NodeList nl = ele.getChildNodes(); Element subElement = null; for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) && !nodeNameEquals(node, META_ELEMENT)) { // Child element is what we're looking for. if (subElement != null) { error(elementName + " must not contain more than one sub-element", ele); } else { subElement = (Element) node; } } } boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE); boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE); if ((hasRefAttribute && hasValueAttribute) || ((hasRefAttribute || hasValueAttribute) && subElement != null)) { error(elementName + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele); } if (hasRefAttribute) { String refName = ele.getAttribute(REF_ATTRIBUTE); if (!StringUtils.hasText(refName)) { error(elementName + " contains empty 'ref' attribute", ele); } RuntimeBeanReference ref = new RuntimeBeanReference(refName); ref.setSource(extractSource(ele)); return ref; } else if (hasValueAttribute) { TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE)); valueHolder.setSource(extractSource(ele)); return valueHolder; } else if (subElement != null) { return parsePropertySubElement(subElement, bd); } else { // Neither child element nor "ref" or "value" attribute found. error(elementName + " must specify a ref or value", ele); return null; } }
property节点主要是value和ref属性的配置,所以此方法首先是配置以上两个属性,然后是分析property节点的子元素,parsePropertySubElement(subElement, bd)方法,重载到
- public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
- if (!isDefaultNamespace(getNamespaceURI(ele))) {
- return parseNestedCustomElement(ele, bd);
- }
- else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
- BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
- if (nestedBd != null) {
- nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
- }
- return nestedBd;
- }
- else if (nodeNameEquals(ele, REF_ELEMENT)) {
- // A generic reference to any name of any bean.
- String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
- boolean toParent = false;
- if (!StringUtils.hasLength(refName)) {
- // A reference to the id of another bean in the same XML file.
- refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);
- if (!StringUtils.hasLength(refName)) {
- // A reference to the id of another bean in a parent context.
- refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
- toParent = true;
- if (!StringUtils.hasLength(refName)) {
- error("'bean', 'local' or 'parent' is required for <ref> element", ele);
- return null;
- }
- }
- }
- if (!StringUtils.hasText(refName)) {
- error("<ref> element contains empty target attribute", ele);
- return null;
- }
- RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
- ref.setSource(extractSource(ele));
- return ref;
- }
- else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
- return parseIdRefElement(ele);
- }
- else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
- return parseValueElement(ele, defaultValueType);
- }
- else if (nodeNameEquals(ele, NULL_ELEMENT)) {
- // It's a distinguished null value. Let's wrap it in a TypedStringValue
- // object in order to preserve the source location.
- TypedStringValue nullHolder = new TypedStringValue(null);
- nullHolder.setSource(extractSource(ele));
- return nullHolder;
- }
- else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
- return parseArrayElement(ele, bd);
- }
- else if (nodeNameEquals(ele, LIST_ELEMENT)) {
- return parseListElement(ele, bd);
- }
- else if (nodeNameEquals(ele, SET_ELEMENT)) {
- return parseSetElement(ele, bd);
- }
- else if (nodeNameEquals(ele, MAP_ELEMENT)) {
- return parseMapElement(ele, bd);
- }
- else if (nodeNameEquals(ele, PROPS_ELEMENT)) {
- return parsePropsElement(ele);
- }
- else {
- error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
- return null;
- }
- }
public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) { if (!isDefaultNamespace(getNamespaceURI(ele))) { return parseNestedCustomElement(ele, bd); } else if (nodeNameEquals(ele, BEAN_ELEMENT)) { BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd); if (nestedBd != null) { nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd); } return nestedBd; } else if (nodeNameEquals(ele, REF_ELEMENT)) { // A generic reference to any name of any bean. String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE); boolean toParent = false; if (!StringUtils.hasLength(refName)) { // A reference to the id of another bean in the same XML file. refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE); if (!StringUtils.hasLength(refName)) { // A reference to the id of another bean in a parent context. refName = ele.getAttribute(PARENT_REF_ATTRIBUTE); toParent = true; if (!StringUtils.hasLength(refName)) { error("'bean', 'local' or 'parent' is required for <ref> element", ele); return null; } } } if (!StringUtils.hasText(refName)) { error("<ref> element contains empty target attribute", ele); return null; } RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent); ref.setSource(extractSource(ele)); return ref; } else if (nodeNameEquals(ele, IDREF_ELEMENT)) { return parseIdRefElement(ele); } else if (nodeNameEquals(ele, VALUE_ELEMENT)) { return parseValueElement(ele, defaultValueType); } else if (nodeNameEquals(ele, NULL_ELEMENT)) { // It's a distinguished null value. Let's wrap it in a TypedStringValue // object in order to preserve the source location. TypedStringValue nullHolder = new TypedStringValue(null); nullHolder.setSource(extractSource(ele)); return nullHolder; } else if (nodeNameEquals(ele, ARRAY_ELEMENT)) { return parseArrayElement(ele, bd); } else if (nodeNameEquals(ele, LIST_ELEMENT)) { return parseListElement(ele, bd); } else if (nodeNameEquals(ele, SET_ELEMENT)) { return parseSetElement(ele, bd); } else if (nodeNameEquals(ele, MAP_ELEMENT)) { return parseMapElement(ele, bd); } else if (nodeNameEquals(ele, PROPS_ELEMENT)) { return parsePropsElement(ele); } else { error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele); return null; } }
这个方法内部也是一目了然,首先是配置property节点的内嵌bean,然后配置ref引用,然后是idref引用,接下来是内嵌的value元素,还有null元素,最后是一系列的复杂数据类型,array,list,set,map以及props。
到这里配置文件的载入基本上已经到底了,如果对以上元素的配置感兴趣的话,可以继续查看源代码。这里只是包含配置文件的载入过程,并不包括在Ioc容器中的注册,以及依赖注入的过程。
发表评论
-
Spring Security认识
2015-07-28 15:29 589先来谈一谈Acegi的基础知识,Acegi的架构比较复杂,但 ... -
acegi第一个实例
2015-07-28 14:30 385目前acegi(Spring Security)主要是针对简 ... -
Acegi (Spring Security)入门
2015-07-28 13:25 936一、Acegi Security 介绍 1 ... -
Spring JMS MessageListener实现类不能参与事务拦截
2015-06-04 11:29 1372Spring JMS MessageListener实现类不 ... -
spring配置定时器的时间设置
2014-01-10 16:26 543转自:http://blog.csdn.net/zhaoz ... -
Spring跨库事务JOTM
2012-08-18 22:16 660http://sprone.iteye.com/blog/89 ... -
spring+hibernate+jotm分布式事务配置总结
2012-03-10 17:44 868在前段开拓的体系 中 ... -
用Spring集成的JOTM配置分布式事务
2012-03-10 17:38 1226【藏自】http://boy00fly.iteye.com ... -
spring分布式事务实现
2012-03-10 17:27 1068藏自:http://log-cd.iteye.com/blog ... -
Spring声明式事务管理源码解读之事务提交
2012-03-04 22:43 763其实我的感觉就是事务提交要比事务开始复杂,看事务是否提交我们还 ... -
主题:解惑:在spring+hibernate中,只读事务是如何被优化的。
2011-08-28 11:00 1247出自:http://www.iteye.com/topic/9 ... -
【收藏】Spring TransactionManager和hibernate吐血经验谈
2011-08-22 20:45 1015http://lsk.iteye.com/blog/17879 ... -
【收藏】Spring事务王国架构
2011-08-20 10:12 644http://book.51cto.com/art/20090 ... -
【转载】TransactionSynchronizationManager理解
2011-08-19 21:25 908出自:http://blog.sina.com.cn/s/bl ... -
【收藏】主题:解惑 spring 嵌套事务
2011-08-18 23:08 697http://www.iteye.com/topic/3590 ... -
主题:Spring源代码解析(一):IOC容器
2011-07-31 08:45 775以下内容引自博客:http://jiwenke-spring. ... -
Spring MVC中的IoC容器初始化
2011-06-30 10:16 821http://blog.csdn.net/prince2270 ...
相关推荐
Spring集成MongoDB官方指定jar包:spring-data-mongodb-1.4.1.RELEASE.jar
1. **spring-mvc.xml**: 这是Spring MVC框架的核心配置文件,用于设置DispatcherServlet的行为,管理控制器(Controller)、视图解析器(View Resolver)、数据绑定器(DataBinder)等组件。例如,它会定义bean,如...
config.properties:数据库配置文件 log4j.properties:mybatis日志文件 spring-mvc.xml:spring-MVC配置文件 spring-mybatis.xml:mybatis的配置文件 spring.xml
主要用于spring和mybatis的整合,实现SSM架构的应用。
spring-boot-mybaits-xml:xml配置版本 spring-boot-mybatis-mulidatasource:springboot+mybatis多数据源最简解决方案 spring-boot-mybatis-annotation-mulidatasource:springboot+mybatis(注解版)多数据源最简...
首先,`mvc:annotation-driven`是一个XML配置元素,它简化了对Spring MVC应用中注解驱动功能的配置。通过添加这个元素,我们无需手动注册如`HandlerMapping`、`HandlerAdapter`、`ConversionService`、`Validator`等...
检查所有依赖是否已经正确导入,包括Spring Cloud的起步依赖(如`spring-cloud-starter-netflix-eureka-client`)和Spring Boot的起步依赖(如`spring-boot-starter-web`)。 2. **Maven仓库问题**:如果Maven无法...
1. **依赖添加**:在`pom.xml`文件中引入`druid-spring-boot-starter`依赖,如下: ```xml <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter 版本号 ``` 2. **配置数据源**:在`...
注意在spring-src-read模块下的build.gradle中添加compile(project(":spring-context")) 。 环境测试 工程目录如下: 新建配置类 @Configuration @ComponentScan ( " com.fchen " ) public class MyConfig { } 新建...
9. **XML与Java配置**:Spring支持XML配置和基于Java的配置,后者在5.x版本中逐渐成为首选。这两种配置方式各有优缺点,理解和掌握两者可以帮助开发者灵活选择合适的配置方式。 10. **Spring Expression Language ...
接下来是"spring-framework-4.3.23.RELEASE-schema.zip",这个文件包含Spring的XML配置模式,这些模式定义了Spring配置文件的结构和约束。通过分析这些模式,我们可以了解到Spring如何解析和验证配置文件,以及如何...
`spring-beans-3.0.xsd` 文件定义了 Spring 容器如何读取并解析 XML 配置文件,来实例化、装配和管理 beans。在这个文件中,你可以定义 bean 的 id、class、属性、依赖注入等。通过版本号 3.0,我们可以看出这是针对...
`spring-framework-5.1.4.RELEASE-schema.zip`包含了Spring的XML配置schema,这些schema定义了XML配置文件的结构和约束,使得配置更加规范,同时也支持IDE的自动补全功能,提升开发效率。 在5.1.4版本中,Spring对...
而`spring-framework-5.1.6.RELEASE-schema.zip`则包含了Spring配置文件的XML Schema定义,帮助我们理解和验证配置的正确性。 7. **模块化设计**:Spring Framework采用模块化设计,每个模块都有明确的职责,这在...
logback-spring.xml文件配置,1、异步日志,2、滚动日志,存放固定时长的日志,超过时间的自动删除,3、单个文件超过指定大小,分成多个,防止单个文件过大,查看不方便
这个源码包,"spring-boot-2.0.0.M7",是Spring Boot的2.0.0预发布版本,M7代表的是第七个Milestone版本,即在正式版发布前的阶段性版本,通常用于测试和完善功能。 Spring Boot的核心特点包括自动配置、起步依赖、...
4. **XML解析库**:如DOM4J、Xerces,用于解析XML配置文件。 5. **Servlet容器库**:如Tomcat、Jetty,Spring Web模块在此基础上运行。 四、使用指南 1. **环境搭建**:确保JDK、构建工具(如Maven或Gradle)、IDE...
这是一个springmvc-config.xml文件,<?xml version="1.0" encoding="UTF-8"?> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:...
《Spring Boot 2.7.0 源码解析与深度探索》 Spring Boot作为Java开发中的一个核心框架,以其便捷的起步配置、自动化配置和一站式的解决方案深受开发者喜爱。当我们深入研究Spring Boot 2.7.0的源码时,可以更深刻地...
在这个过程中,Spring AOP 使用 DefaultBeanDefinitionDocumentReader 来解析 XML 文件,并生成 Bean 定义对象。 2. 解析 AOP 配置:在解析 Bean 定义文件时,Spring AOP 也会解析 AOP 配置文件,例如 `<aop:config...