这次就不啰嗦 直接上 (以下资料都是查互联网之后加上自己的理解整理出来的 纯粹作为笔记自己学习下 没有其他什么意思 )

Spring最重要的就是IOC和AOP 对于IOC来说在配置文件中你配置好了对象和对象之间的关系 但是你如何来读取这个配置文件呢

首先来看读取配置文件的XmlBeanFactory 在这里面需要指定Resource对象也就是xml文件

XmlBeanFactory继承自DefaultListableBeanFactory,扩展了从xml文档中读取bean definition的能力。

从本质上讲,XmlBeanFactory等同于
DefaultListableBeanFactory+XmlBeanDefinitionReader ,如果有更好的需求,可以考虑使用DefaultListableBeanFactory+XmlBeanDefinitionReader方案,因为该方案可以从多个xml文件读取资源,并且在解析xml上具有更灵活的可配置性。

public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory)  throws BeansException
{  super(parentBeanFactory);  reader = new XmlBeanDefinitionReader(this);  reader.loadBeanDefinitions(resource);
}

于是这样可以得到XmlBeanFactory 引用资源的方法

Resource resource = new ClassPathResource("appcontext.xml");
BeanFactory factory = new XmlBeanFactory(resource); 

其实在有的代码中也见过这么写的 不过这种方法要说到另外的东西 在后面的日记中会重新说明的

ClassPathResource res = new ClassPathResource("beans.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(res); 

同时在上述XmlBeanFactory源码中 reader是XmlBeanDefinitionReader的实例,XmlBeanDefinitionReader类继承自AbstractBeanDefinitionReader类

瞧一眼XmlBeanDefinitionReader类的源码

public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader

同样的把AbstractBeanDefinitionReader类的源码818

public abstract class AbstractBeanDefinitionReader  implements BeanDefinitionReader 

是不是感觉很像传销呢 = 。 =

public interface BeanDefinitionReader 

到头了 那么来看下接口的方法 重要的就是loadBeanDefinitions方法

public abstract int loadBeanDefinitions(Resource resource)  throws BeanDefinitionStoreException;  public abstract int loadBeanDefinitions(Resource aresource[])  throws BeanDefinitionStoreException;  public abstract int loadBeanDefinitions(String s)  throws BeanDefinitionStoreException;  public abstract int loadBeanDefinitions(String as[])  throws BeanDefinitionStoreException;  

所以可以简单的总结一下 在XmlBeanFactory 实例化XmlBeanDefinitionReader 之后,同时调用一系列七大姑八大姨的关系在XmlBeanDefinitionReader 中实现的loadBeanDefinitions 方法 来加载 bean 配置并把 bean 配置注册到 XmlBeanFactory 中

当然读取到XmlBeanFactory中并不代表结束了 在Spring框架中有的时候会遇到个这么一个错误

at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions........

看在XmlBeanDefinitionReader似乎还有一个这么东西 这个从哪来的呢 这个不急 先把那个do去掉不就是LoadBeanDefinitions方法了吗 那么把LoadBeanDefinitions方法拆开会怎么样呢?

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 (this.logger.isInfoEnabled()) {  this.logger.info("Loading XML bean definitions from " + encodedResource.getResource());  }  Set currentResources = (Set)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  {  //这里得到XML文件,并得到IO的InputSource准备进行读取。  InputStream inputStream = encodedResource.getResource().getInputStream();  try {  InputSource inputSource = new InputSource(inputStream);  if (encodedResource.getEncoding() != null) {  inputSource.setEncoding(encodedResource.getEncoding());  }  //在这里发现其实在LoadBeanDefinitions方法中调用了doLoadBeanDefinitions方法int i = doLoadBeanDefinitions(inputSource, encodedResource.getResource());  inputStream.close();  currentResources.remove(encodedResource);  if (currentResources.isEmpty())  this.resourcesCurrentlyBeingLoaded.remove();  return i;  }  finally  {  InputStream inputStream;  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();  }  throw localObject2;  }  

那么接下来去doLoadBeanDefinitions方法中查一下水表吧

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)  throws BeanDefinitionStoreException  {  try  {  int validationMode = getValidationModeForResource(resource);  //这里取得XML文件的Document对象,这个解析过程是由 documentLoader完成的,这个documentLoader是DefaultDocumentLoader,在定义documentLoader的地方创建     Document doc = this.documentLoader.loadDocument(  inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());  //这里启动的是对BeanDefinition解析的详细过程,这个解析会使用到Spring的Bean配置规则。     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);  }  //调用这个方法  public int registerBeanDefinitions(Document doc, Resource resource)  throws BeanDefinitionStoreException  {  BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();  int countBefore = getRegistry().getBeanDefinitionCount();  documentReader.registerBeanDefinitions(doc, createReaderContext(resource));  return getRegistry().getBeanDefinitionCount() - countBefore;  }

如此是否一目了然了呢 当然饭要一口一口吃 不过因为本喵自己学的也是懵懵然 所以大概捋一下顺序吧

Document doc = documentLoader.loadDocument(inputSource, getEntityResolver(), errorHandler, validationMode, isNamespaceAware());

可以看出通过一个叫documentLoader的东西的loadDocument方法来加载配置文件形成DOM, 来看看documentLoader

...
private DocumentLoader documentLoader
...
documentLoader = new DefaultDocumentLoader();
...

那么接着来看DefaultDocumentLoader

public class DefaultDocumentLoader  implements DocumentLoader
...  public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware)  throws Exception  {  DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);  if(logger.isDebugEnabled())  logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");  DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);  return builder.parse(inputSource);  }  

于是至此 已完成了从配置文件读取到Domcument. 接着要开始解析Dom了

自然是通过sax解析得到Dom的 至于怎么解析 这个太高深了 稍微的818吧 其实我也不是很懂 T.T 以下是为大神的文章 copy过来大家一起膜拜下 其实这些对于初学者来说可以有空的研究下 如果持续纠结在这里面有时觉得得不偿失 毕竟理解还是要跟经验走的

关于具体的Spring BeanDefinition的解析 是在BeanDefinitionParserDelegate中完成的 这个类里包含了各种Spring Bean定义规则的处理

我们举一个例子来分析这个处理过程 比如我们最熟悉的对Bean元素的处理怎样完成的,也就是我们在XML定义文件中出现的<bean></bean>这个最常见的元素信息是怎样被处理的。在这里,我们会看到那些熟悉的BeanDefinition定义的处理,比如id、name、aliase等属性元素。把这些元素的值从XML文件相应的元素的属性中读取出来以后,会被设置到生成的BeanDefinitionHolder中去。这些属性的解析还是比较简单的。对于其他元素配置的解析,比如各种Bean的属性配置,通过一个较为复杂的解析过程,这个过程是由parseBeanDefinitionElement来完成的。解析完成以后,会把解析结果放到BeanDefinition对象中并设置到BeanDefinitionHolder中去。

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean)  {  String id = ele.getAttribute("id");  String nameAttr = ele.getAttribute("name");  List aliases = new ArrayList();  if (StringUtils.hasLength(nameAttr)) {  String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; ");  aliases.addAll((Collection)Arrays.asList(nameArr));  }  String beanName = id;  if ((!StringUtils.hasText(beanName)) && (!aliases.isEmpty())) {  beanName = (String)aliases.remove(0);  if (this.logger.isDebugEnabled()) {  this.logger.debug("No XML 'id' specified - using '" + beanName +   "' as bean name and " + aliases + " as aliases");  }  }  if (containingBean == null) {  checkNameUniqueness(beanName, aliases, ele);  }  //这个方法会引发对bean元素的详细解析  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);  String beanClassName = beanDefinition.getBeanClassName();  if ((beanClassName != null) &&   (beanName.startsWith(beanClassName)) && (beanName.length() > beanClassName.length()) &&   (!this.readerContext.getRegistry().isBeanNameInUse(beanClassName))) {  aliases.add(beanClassName);  }  }  if (this.logger.isDebugEnabled())  this.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;  }  

在具体生成BeanDefinition以后。我们举一个对property进行解析的例子来完成对整个BeanDefinition载入过程的分析,还是在类BeanDefinitionParserDelegate的代码中,它对BeanDefinition中的定义一层一层地进行解析,比如从属性元素集合到具体的每一个属性元素,然后才是对具体的属性值的处理。根据解析结果,对这些属性值的处理会封装成PropertyValue对象并设置到BeanDefinition对象中去,如以下代码清单所示。

public void parsePropertyElements(Element beanEle, BeanDefinition bd)  {  //遍历所有bean元素下定义的property元素    NodeList nl = beanEle.getChildNodes();  for (int i = 0; i < nl.getLength(); i++) {  Node node = nl.item(i);  if ((isCandidateElement(node)) && (nodeNameEquals(node, "property")))  //在判断是property元素后进入parsePropertyElement解析  parsePropertyElement((Element)node, bd);  }  }  

进入parsePropertyElement解析

public void parsePropertyElement(Element ele, BeanDefinition bd)  {  //这里取得property的名字    String propertyName = ele.getAttribute("name");  if (!StringUtils.hasLength(propertyName)) {  error("Tag 'property' must have a 'name' attribute", ele);  return;  }  this.parseState.push(new PropertyEntry(propertyName));  try {  //如果同一个bean中已经有同名的存在,则不进行解析,直接返回。也就是说,如果在同一个bean中有同名的property设置,那么起作用的只是第一个。     if (bd.getPropertyValues().contains(propertyName)) { error("Multiple 'property' definitions for property '" + propertyName + "'", ele);  return; }  //这里是解析property值的地方,返回的对象对应对Bean定义的property属性设置的解析结果,这个解析结果会封装到PropertyValue对象中,然后设置到BeanDefinitionHolder中去  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(); } this.parseState.pop();  }  

parsePropertyValue方法具体代码

public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName)  {  String elementName = propertyName != null ?   "<property> element for property '" + propertyName + "'" :   "<constructor-arg> element";  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")) ||   (nodeNameEquals(node, "meta")))  continue;  if (subElement != null) {  error(elementName + " must not contain more than one sub-element", ele);  }  else {  subElement = (Element)node;  }  }  boolean hasRefAttribute = ele.hasAttribute("ref");  boolean hasValueAttribute = ele.hasAttribute("value");  //这里判断property的属性,是ref还是value,不允许同时是ref和value。  if (((hasRefAttribute) && (hasValueAttribute)) || (  ((hasRefAttribute) || (hasValueAttribute)) && (subElement != null))) {  error(elementName +   " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);  }  //如果是ref,创建一个ref的数据对象RuntimeBeanReference,这个对象封装了ref的信息。  if (hasRefAttribute) {  String refName = ele.getAttribute("ref");  if (!StringUtils.hasText(refName)) {  error(elementName + " contains empty 'ref' attribute", ele);  }  RuntimeBeanReference ref = new RuntimeBeanReference(refName);  ref.setSource(extractSource(ele));  return ref;  }  //如果是value,创建一个value的数据对象TypedStringValue ,这个对象封装了value的信息。   if (hasValueAttribute) {  TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute("value"));  valueHolder.setSource(extractSource(ele));  return valueHolder;  }  //如果还有子元素,触发对子元素的解析     if (subElement != null) {  return parsePropertySubElement(subElement, bd);  }  error(elementName + " must specify a ref or value", ele);  return null;  }  

经过这样一层一层的解析,我们在XML文件中定义的BeanDefinition就被整个给载入到了IoC容器中,并在容器中建立了数据映射。在IoC容器中建立了对应的数据结构,或者说可以看成是POJO对象在IoC容器中的映像,这些数据结构可以以AbstractBeanDefinition为入口,让IoC容器执行索引、查询和操作。

写的有些跑题了 那么回归正题 继续来818 doLoadBeanDefinitions这个方法

有的时候在部署spring时还会遇到这个问题

at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions 

其实就是在doLoadBeanDefinitions()方法中的调用的registerBeanDefinitions 这个方法
如下

return registerBeanDefinitions(doc, resource);  

来看看registerBeanDefinitions的实现

...
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
...  

于是找到一个BeanDefinitionDocumentReader接口 实际上Spring对它有一个默认的实现类叫DefaultBeanDefinitionDocumentReader 我们来算一下这个软妹子(不要问我为什么!捂脸) 的生辰八字

public class DefaultBeanDefinitionDocumentReader  Implement BeanDefinitionDocumentReader
public interface BeanDefinitionDocumentReader

在这个接口中我们找到了唯一的一个方法

public abstract void registerBeanDefinitions(Document document, XmlReaderContext xmlreadercontext)  throws BeanDefinitionStoreException;  

对于上述方法所带的两个参数 一个是Document模型 这个应该是我们读取配置文件获取到的 另一个是XmlReaderContext对象 我们在上面方法中看到是通过createReaderContext(resource)得到的

那么接着瞧一瞧怎么实现的

protected XmlReaderContext createReaderContext(Resource resource)
{  if(namespaceHandlerResolver == null)  namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();  return new XmlReaderContext(resource, problemReporter, eventListener, sourceExtractor, this, namespaceHandlerResolver);
}  

于是知道是通过构造函数new出来的 并且自带一个参数resource 再继续来看DefaultBeanDefinitionDocumentReader对BeanDefinitionDocumentReader的registerBeanDefinitions方法实现

 public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext)  {  ...
BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);
...  parseBeanDefinitions(root, delegate);  ...  }  

于是开始解析了 主要是通过parseBeanDefinitions方法

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
{  if(delegate.isDefaultNamespace(root.getNamespaceURI()))  {  NodeList nl = root.getChildNodes();  for(int i = 0; i < nl.getLength(); i++)  {  org.w3c.dom.Node node = nl.item(i);  if(node instanceof Element)  {  Element ele = (Element)node;  String namespaceUri = ele.getNamespaceURI();  if(delegate.isDefaultNamespace(namespaceUri))  parseDefaultElement(ele, delegate);  else  delegate.parseCustomElement(ele);  }  }  } else  {  delegate.parseCustomElement(root);  }
}  

循环解析Domcument节点
parseDefaultElement方法和delegate的parseCustomElement方法
先来看parseDefaultElement方法

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)
{  if(DomUtils.nodeNameEquals(ele, "import"))  importBeanDefinitionResource(ele);  else  if(DomUtils.nodeNameEquals(ele, "alias"))  processAliasRegistration(ele);  else  if(DomUtils.nodeNameEquals(ele, "bean"))  processBeanDefinition(ele, delegate);
}  

这就很清楚了, 就是根据节点的名称作不同解析, 如我们Spring配置文件中常有以下几种配置

<import resource="classpath:xxx" />
<bean id="xxx" class="xxx.xxx.xxx" />
<alias name="xxxx" alias="yyyyy"/>  

对节点, 调用importBeanDefinitionResource方法解析, 此方法中, 又回到第一步读取配置文件并解析. 如此递归循环.

...
Resource relativeResource = getReaderContext().getResource().createRelative(location);
int importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
...  

<alias>节点, 调用processAliasRegistration进行别名解析
我们主要看对节点调用processBeanDefinition进行解析

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)
{  BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);  if(bdHolder != null)  {  bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);  try  {  BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());  }  catch(BeanDefinitionStoreException ex)  {  getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex);  }  getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));  }
}  

嘿嘿, 又用到delegate对象了, 且调用它的BeanDefinitionHolder方法, 返回一个BeanDefinitionHolder, 进去看它的parseBeanDefinitionElement方法

public class BeanDefinitionParserDelegate
{     private final Set usedNames = new HashSet();  ...  public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean)  {  ... 解析id, name等属性, 并验证name是否唯一, 并将name保存在usedNames中  AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);  ...   return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);  }  ...
}  

可以看到, 在BeanDefinitionHolder中保存了BeanDefinition的定义
OK, 重头戏开始, 最经典的部分出现了, 请看parseBeanDefinitionElement方法

public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean)
{  ...  代码太长, 请参考具体代码  AbstractBeanDefinition bd = BeanDefinitionReaderUtils.createBeanDefinition(parent, className, readerContext.getBeanClassLoader());  ...  return abstractbeandefinition;  ...
}

在这个方法中, 解析了bean的所有属性, 有最常用的class, scope, lazy-init等等. 并返回一个AbstractBeanDefinition实例. 至于具体怎么解析, 就只能进一步跟踪了, 不过既然到了这一步, 已经明白了它的基本原理, 具体实现就不作介绍

这一步将节点解析成BeanDefinitionHolder对象, 再看看如何注册, 回到DefaultBeanDefinitionDocumentReader的processBeanDefinition方法

看到对解析到的bdHolder对象又做了decorateBeanDefinitionIfRequired操作 接着调用了BeanDefinitionReaderUtils的registerBeanDefinition方法注册bdHolder, 来看看如何实现的

public class BeanDefinitionReaderUtils
{  public static void registerBeanDefinition(BeanDefinitionHolder bdHolder, BeanDefinitionRegistry beanFactory)  throws BeanDefinitionStoreException  {  String beanName = bdHolder.getBeanName();  beanFactory.registerBeanDefinition(beanName, bdHolder.getBeanDefinition());  String aliases[] = bdHolder.getAliases();  if(aliases != null)  {  for(int i = 0; i < aliases.length; i++)  beanFactory.registerAlias(beanName, aliases[i]);  }  }
}  

看吧, 又调用了BeanDefinitionRegistry的registerBeanDefinition方法, 跟踪之 (这个要看DefaultListableBeanFactory的实现)

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory  implements ConfigurableListableBeanFactory, BeanDefinitionRegistry
{  private final Map beanDefinitionMap;  private final List beanDefinitionNames;  ...  public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)  throws BeanDefinitionStoreException  {  ...  Object oldBeanDefinition = beanDefinitionMap.get(beanName);  ...  beanDefinitionMap.put(beanName, beanDefinition);  ...  }
}  

这里, 看到了一个最最重要的对象就是beanDefinitionMap, 这个map存放了所有的bean对象, 和我们通常讲的容器概念最为接近, getBean时实际是也是从这里辚取对象, 相同的还有一个beanDefinitionNames, 但这个只保存bean的名称
完成上面之后, 还有一步操作beanFactory.registerAlias(beanName, aliases[i]);
这个实现实际是上AbstractBeanFactory抽象类所定义的

于是从定义 -> 定位 -> 装载 -> 注册 就完成只是在Spring3.1中已经将XmlBeanFactory 设置成不赞成使用了 推荐是DefaultListableBeanFactory和XmlBeanDefinitionReader来进行替换 不过今天就写到这吧 我要回家玩刺客信条呢 明天来公司加班再说其他的吧!

Spring 学习日记 (1)配置文件的装载相关推荐

  1. spring学习笔记之配置文件applicationContext.xml

    1:spring中,用配置文件时 <bean>的<scope>属性是singleton时在创建容器时创建对象,创建一个容器在,对象在: <bean>的<sco ...

  2. Spring 学习日记 (四) Spring 整合Mybaits 和 struts2 框架的配置文件

    其实也是挺无奈的  这东西永远这一棒子那一锤子的  太不系统了 哎 没办法 跟着项目走吧 首先准备的JAR包 需要配置的几个配置文件 配置spring applicationContext.xml   ...

  3. SpringMVC学习日记 1.Spring框架

    SpringMVC学习日记 1.Spring框架 Spring简介 Spring框架是一个开源框架,由Rod Johnson组织和开发,生产目的在于简化企业级应用的开发. 主要特性 非侵入(no-in ...

  4. spring学习笔记03-spring-DI-依赖注入详解(通过xml配置文件来配置依赖注入)

    spring学习笔记03-spring-DI-依赖注入详解 1.概念 2.构造函数注入 3.set方法注入 4.集合的注入 需要被注入的实体对象 package com.itheima.service ...

  5. 【Spring Boot学习笔记】——配置文件

    两种类型的配置文件 properties和yml 作为全局配置文件,配置文件名是固定的: application.properties application.yml 配置文件的作用:修改Spring ...

  6. Spring学习总结一

    Spring框架IoC与DI思想及应用 Spring学习总结一 1.Spring是什么 2.Spring的优点 2.1.关键概念 2.2.Spring的优点 3.Spring的架构图 3.1.核心容器 ...

  7. Spring学习(五)bean装配详解之 【XML方式配置】

    本文借鉴:Spring学习(特此感谢!) 一.配置Bean的方式及选择 配置方式 在 XML 文件中显式配置 在 Java 的接口和类中实现配置 隐式 Bean 的发现机制和自动装配原则 方式选择的原 ...

  8. Spring 学习总结笔记【七、AOP面向切面编程】

    往期文章: Spring 学习总结笔记[一.快速入门] Spring 学习总结笔记[二.IoC-控制反转] Spring 学习总结笔记[三.注解开发] Spring 学习总结笔记[四.整合Junit] ...

  9. spring学习12 -Spring 框架模块以及面试常见问题注解等

    以下为spring常见面试问题: 1.Spring 框架中都用到了哪些设计模式? Spring框架中使用到了大量的设计模式,下面列举了比较有代表性的: 代理模式-在AOP和remoting中被用的比较 ...

最新文章

  1. mysql删除数据后不释放空间问题
  2. TensorFlow Wide And Deep 模型详解与应用 TensorFlow Wide-And-Deep 阅读344 作者简介:汪剑,现在在出门问问负责推荐与个性化。曾在微软雅虎工作,
  3. 10000 字讲清楚 Spring Boot 注解原理
  4. 基本权限管理框架,开通淘宝支付
  5. LeetCode 1552. 两球之间的磁力(极小极大化 二分查找)
  6. 设置中文linux输入ubuntu,Linux_ubuntu怎么设置成中文?ubuntu中文设置图文方法,  很多朋友安装ubuntu后,发 - phpStudy...
  7. image 微信小程序flex_微信小程序进阶-flex布局
  8. Java基础0308
  9. 还原二叉树--根据后序中序输出先序
  10. LeetCode刷题-四因数
  11. 关于打卡值班制度---一个excel开发工具小函数
  12. 老男孩教育 | 从小白进军IT,他仅用了四个月的时间!
  13. 2015.2,对任意正整数n,求xn,要求运算时间复杂度为o(logn).例如x30=x15*x15.
  14. 由113号元素鉨114号元素夫115号元素镆元素汞银金等元素构成的超导体
  15. 音视频开发系列1:音视频开发基本概念
  16. [内核内存] [arm64] 内存回收2---快速内存回收和直接内存回收
  17. gunicorn、uwsgi、uvicorn认识
  18. 【ssd】M.2的SATA,PCI-x2(Socket 2 ),PCI-x4(Socket 3)了解一下,老程序员都快被新硬件搞蒙圈了
  19. Python 之 列表推导式
  20. 辅流式沉淀池固体负荷计算方法_辐流式沉淀池设计计算

热门文章

  1. 提高Tomcat并发量的几种方法
  2. 一周看点 | Docker创始人再创业;谷歌Fuchsia OS负责人离职;淘宝小范围内测微信支付;蒋凡卸任淘宝董事长...
  3. 可以跟踪军事和情报人员的啤酒点评应用程序
  4. 使用Spring AOP自定义注解方式实现用户操作日志记录
  5. GYP(Generate Your Project)介绍
  6. python中的import指的是什么?
  7. SQL的交集并集差集
  8. cmd安装mysql时出现:计算机中丢失MSVCP120.dll 的解决办法
  9. 关于Segmentation fault(段错误)探究
  10. 神经网络算法可以解决什么问题