亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

Spring IOC 源碼閱讀資源加載和注冊

2019-11-11 05:24:33
字體:
來源:轉載
供稿:網友

   上面講到,sPRing在查找到資源以后,在BeanDefinitionReader的loadBeanDefinitions(String location)方法中,接著就調用了int loadCount = loadBeanDefinitions(resources);

   這個方法間接的調用了子類xmlBeanDifinitionReader的loadBeanDefinitions(EncodedResource encodedResource)方法:

[java] view plain copy <span style="font-size:12px;">/**      * Load bean definitions from the specified XML file.      * @param encodedResource the resource descriptor for the XML file,      * allowing to specify an encoding to use for parsing the file      * @return the number of bean definitions found      * @throws BeanDefinitionStoreException in case of loading or parsing errors      */      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 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());                  }                  <span style="color:#ff0000;">return doLoadBeanDefinitions(inputSource, encodedResource.getResource());</span>              }              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();              }          }      }</span>  

上述方法調用了doLoadBeanDefinitions(InputSource inputSource, Resource resource)方法:

 

[java] view plain copy /**      * Actually load bean definitions from the specified XML file.      * @param inputSource the SAX InputSource to read from      * @param resource the resource descriptor for the XML file      * @return the number of bean definitions found      * @throws BeanDefinitionStoreException in case of loading or parsing errors      */      protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)              throws BeanDefinitionStoreException {          try {              int validationMode = getValidationModeForResource(resource);              <span style="color:#ff0000;">Document doc = this.documentLoader.loadDocument(                      inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());              return registerBeanDefinitions(doc, resource);  </span>     }          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);          }      }  

在上面的方法中將xml人間解析成了document對象,然后調用了registerBeanDefinitions(Document doc, Resource resource)方法:

[java] view plain copy     /**      * Register the bean definitions contained in the given DOM document.      * Called by <code>loadBeanDefinitions</code>.      * <p>Creates a new instance of the parser class and invokes      * <code>registerBeanDefinitions</code> on it.      * @param doc the DOM document      * @param resource the resource descriptor (for context information)      * @return the number of bean definitions found      * @throws BeanDefinitionStoreException in case of parsing errors      * @see #loadBeanDefinitions      * @see #setDocumentReaderClass      * @see BeanDefinitionDocumentReader#registerBeanDefinitions      */      public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {          BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();          documentReader.setEnvironment(this.getEnvironment());          int countBefore = getRegistry().getBeanDefinitionCount();          <span style="color:#ff0000;">documentReader.registerBeanDefinitions(doc, createReaderContext(resource));  </span>     return getRegistry().getBeanDefinitionCount() - countBefore;      }  

在上面的方法中先創建了一個DocumentReader對象,然后調用DefaultBeanDifinitionDocumentReader的registerBeanDefinitions(Document doc, XmlReaderContext readerContext)方法,此方法調用了下面的方法

[java] view plain copy /**  * Register each bean definition within the given root {@code <beans/>} element.  * @throws IllegalStateException if {@code <beans profile="..."} attribute is present  * and Environment property has not been set  * @see #setEnvironment  */  protected void doRegisterBeanDefinitions(Element root) {      String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);      if (StringUtils.hasText(profileSpec)) {          Assert.state(this.environment != null, "environment property must not be null");          String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);          if (!this.environment.acceptsProfiles(specifiedProfiles)) {              return;          }      }        // any nested <beans> elements will cause recursion in this method. In      // order to propagate and preserve <beans> default-* attributes correctly,      // keep track of the current (parent) delegate, which may be null. Create      // the new (child) delegate with a reference to the parent for fallback purposes,      // then ultimately reset this.delegate back to its original (parent) reference.      // this behavior emulates a stack of delegates without actually necessitating one.      BeanDefinitionParserDelegate parent = this.delegate;      this.delegate = createHelper(readerContext, root, parent);        preProcessXml(root);      <span style="color:#ff0000;">parseBeanDefinitions(root, this.delegate);  /span>      postProcessXml(root);        this.delegate = parent;  }  

在這個方法中創建了解析beandefinition的委托對象,實際上所有的解析都是在這個委托對象中完成的。

再看上面的方法間接調用了下面的DefaultBeanDifinitionDocumentReader方法:

[java] view plain copy /**  * Process the given bean element, parsing the bean definition  * and registering it with the registry.  */  protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {      <span style="color:#ff0000;">BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);</span>      if (bdHolder != null) {          bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);          try {              // Register the final decorated instance.              <span style="color:#ff0000;">BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());  /span>          }          catch (BeanDefinitionStoreException ex) {              getReaderContext().error("Failed to register bean definition with name '" +                      bdHolder.getBeanName() + "'", ele, ex);          }          // Send registration event.          getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));      }  }  

上面紅色的的兩個方法一個是解析得到BeanDefinitionHolder對象,此對象持有BeanDefinition對象和bean的別名,id等信息。一個方法是注冊解析得到的BeanDefinition。

 下面看看在BeanDefinitionParserDeleget類中的解析方法,

[html] view plain copy /**   * Parses the supplied <code><bean></code> element. May return <code>null</code>   * if there were errors during parse. Errors are reported to the   * {@link org.springframework.beans.factory.parsing.ProblemReporter}.   */  public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {      return parseBeanDefinitionElement(ele, null);  }    /**   * Parses the supplied <code><bean></code> element. May return <code>null</code>   * if there were errors during parse. Errors are reported to the   * {@link org.springframework.beans.factory.parsing.ProblemReporter}.   */  public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {      //這里取得<bean>中定義的 id name和 aliase的值  [html] view plain copy String id = ele.getAttribute(ID_ATTRIBUTE);  = ele.getAttribute(NAME_ATTRIBUTE);  [html] view plain copy         List<String> aliases = new ArrayList<String>();          if (StringUtils.hasLength(nameAttr)) {              String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_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);          }                    //這個方法是對bean元素的詳細解析          <span style="color:#ff0000;">AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);  </span>     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;      }  看看詳細的解析方法: parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean)[html] view plain copy /**   * Parse the bean definition itself, without regard to name or aliases. May return   * <code>null</code> if problems occurred during the parsing of the bean definition.   */  public AbstractBeanDefinition parseBeanDefinitionElement(          Element ele, String beanName, BeanDefinition containingBean) {        this.parseState.push(new BeanEntry(beanName));                   //取得class name的定義,這里指讀取<bean>中設置的class的名字,記錄到BeanDefinition中,并不涉及對象的實例化過程,實例化實際上是在以來注入的時候完成的      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);          }          <span style="color:#ff0000;">AbstractBeanDefinition bd = createBeanDefinition(className, parent);                            //對當前的Bean元素進行屬性解析,并設置description的信息  /span>          parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);          bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));                            //從名字可以看出。這里是對各種<bean>元素的信息進行解析的地方          parseMetaElements(ele, bd);          parseLookupOverrideSubElements(ele, bd.getMethodOverrides());          parseReplacedMethodSubElements(ele, bd.getMethodOverrides());                            //解析<bean>的構造函數          parseConstructorArgElements(ele, bd);          //解析bean的property設置  [html] view plain copy                          <span style="color:#ff0000;">parsePropertyElements(ele, bd);  span>           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;  

上面主要關注紅色的兩個方法,一個是創建了BeanDefinition,一個是解析詳細的bean的屬性設置。

創建BeanDefinition是在調用了類BeanDefinitionReaderUtils.createBeanDefinition(parentName, className, this.readerContext.getBeanClassLoader());方法

[java] view plain copy /**  * Create a new GenericBeanDefinition for the given parent name and class name,  * eagerly loading the bean class if a ClassLoader has been specified.  * @param parentName the name of the parent bean, if any  * @param className the name of the bean class, if any  * @param classLoader the ClassLoader to use for loading bean classes  * (can be <code>null</code> to just register bean classes by name)  * @return the bean definition  * @throws ClassNotFoundException if the bean class could not be loaded  */  public static AbstractBeanDefinition createBeanDefinition(          String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException {        GenericBeanDefinition bd = new GenericBeanDefinition();      bd.setParentName(parentName);      if (className != null) {          if (classLoader != null) {              bd.setBeanClass(ClassUtils.forName(className, classLoader));          }          else {              bd.setBeanClassName(className);          }      }      return bd;  }  

再看詳細解析bean的屬性定義的方法:

 

[html] view plain copy /**   * Parse property sub-elements of the given bean element.   */  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 (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {              <span style="color:#ff0000;">parsePropertyElement((Element) node, bd);  /span>          }      }  }  

 

[java] view plain copy /**  * Parse a property element.  */  public void parsePropertyElement(Element ele, BeanDefinition bd) {      //取得property的名字  [java] view plain copy                 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 {        //如果在同一個Bean中已經有同名的property存在,則不進行解析,直接返回,也就是說,在同一個bean中的相同property設置,只有第一個起作用  [java] view plain copy                       if (bd.getPropertyValues().contains(propertyName)) {  error("Multiple 'property' definitions for property '" + propertyName + "'", ele);  return;                           //這里是解析property的地方,返回的對象對應對bean定義的property屬性設置的解析結果,這個解析結果會被封裝到PropertyValue中  [java] view plain copy     <span style="color:#ff0000;">Object val = parsePropertyValue(ele, bd, propertyName);  span>           <span style="color:#009900;">PropertyValue pv = new PropertyValue(propertyName, val);      parseMetaElements(ele, pv);      pv.setSource(extractSource(ele));      bd.getPropertyValues().addPropertyValue(pv);  span>       }  finally {      this.parseState.pop();  }  [java] view plain copy    [java] view plain copy 下面這個方法是去的Property元素的值,也許是MAP,LIST SET或者其他ref對象  [python] view plain copy /**   * Get the value of a property element. May be a list etc.   * Also used for constructor arguments, "propertyName" being null in this case.   */  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;              }          }      }                   //這里判斷property的屬性是ref還是value,不允許同時是ref和value      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);      }                   //如果是ref,創建一個ref的數據對象RuntimeBeanReference 這個對象封裝 了ref的信息      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;      }                   //如果是value,創建一個value的數據對象TypeStringValue,這個對象封裝了value信息  [python] view plain copy else if (hasValueAttribute) {      TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));      valueHolder.setSource(extractSource(ele));      return valueHolder;  }  //如果有子元素,對子元素解析,這里是對Map、List、Set、Property等元素解析  [python] view plain copy                 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;      }  }  

上述解析過程可簡單的看成是

1、XmlBeanDefinitionReader讀取資源,

2、交給DefaultBeanDefinitionDocumentReader對象解析成Document對象,

3、然后DefaultBeanDefinitionDocumentReader對象委托給BeanDefinitionParserDelegate對象解析成BeanDefinitionHoler對象。

4、得到返回的BeanDefunitionHolder對象后調用BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());方法進行注冊。

getReaderContext().getRegistry()這里得到的是DefaultListableBeanFactory。在AbstarctXmlapplicationContext的創建XmlBeandefinitionReader的地方可以看到:

[java] view plain copy XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);  

 

DefaultListableBeanFactory中注冊的地方

 

[java] view plain copy public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)          throws BeanDefinitionStoreException {        Assert.hasText(beanName, "Bean name must not be empty");      Assert.notNull(beanDefinition, "BeanDefinition must not be null");        if (beanDefinition instanceof AbstractBeanDefinition) {          try {              ((AbstractBeanDefinition) beanDefinition).validate();          }          catch (BeanDefinitionValidationException ex) {              throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,                      "Validation of bean definition failed", ex);          }      }                    注冊的地方需要同步,保持一致性      synchronized (this.beanDefinitionMap) {                            //這里檢查是不是有相同名字的BeanDefinition已經存在于IOC容器了,如果有相同的名字的BeanDefinition,但又不允許覆蓋,會拋出異常  [java] view plain copy Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);  if (oldBeanDefinition != null) {      if (!this.allowBeanDefinitionOverriding) {          throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,                  "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +                  "': There is already [" + oldBeanDefinition + "] bound.");      }      else {          if (this.logger.isInfoEnabled()) {              this.logger.info("Overriding bean definition for bean '" + beanName +                      "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");          }      }  }  else {      //這是正常的注冊BeanDefinition的過程,把Bean的名字存入到BeanDefinitionNames的同時,beanName作為Map的Key,吧BeanDefinition作為value存入到IOC容器的BeanDefinitionMap中  [java] view plain copy                                      this.beanDefinitionNames.add(beanName);                  this.frozenBeanDefinitionNames = null;              }              <span style="color:#ff0000;">this.beanDefinitionMap.put(beanName, beanDefinition);  </span>     }            resetBeanDefinition(beanName);      }  

上面的代碼可以看出IOC容器是作為一個Map實現的??纯碊efaultListableBeanFactory中有關容器定義

 

 /** Map from dependency type to corresponding autowired value */ private final Map<Class<?>, Object> resolvableDependencies = new HashMap<Class<?>, Object>();

 /** 這個就是存放BeanDefinition的容器MAP */ private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();

 /** 存放單例的類的名字 */ private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>();

 /** Map of non-singleton bean names keyed by bean class */ private final Map<Class<?>, String[]> nonSingletonBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>();

 /** 容器中的beanName集合 */ private final List<String> beanDefinitionNames = new ArrayList<String>();

容器啟動時候完成的事情就已經全部分析完成了,類的實例化是在依賴注入或根據配置在容器啟動的時候完成的。容器啟動加載完成后,就可以再getBean方法調用的時候去使用了。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美一级淫片播放口| 精品国偷自产在线| 日韩av电影手机在线| 大量国产精品视频| 精品国产一区二区三区久久久| 欧美激情二区三区| 欧美性猛交xxxx富婆弯腰| 国产精品免费看久久久香蕉| xxxxxxxxx欧美| 亚洲最大的成人网| 亚洲人成在线免费观看| 久久免费视频在线观看| 尤物精品国产第一福利三区| 亚洲一区二区三区sesese| 亚洲xxxx视频| 国产亚洲a∨片在线观看| 免费97视频在线精品国自产拍| 日韩电影免费观看中文字幕| 欧洲成人性视频| 国产成人+综合亚洲+天堂| 一区二区三区视频免费| 久久久久久高潮国产精品视| 91视频国产高清| 国内精品免费午夜毛片| 精品国产一区二区三区久久狼黑人| 亚洲国产日韩欧美综合久久| 欧美性黄网官网| 成人xxxxx| 国产精品欧美日韩久久| 色噜噜国产精品视频一区二区| 久久久在线视频| 亚洲娇小xxxx欧美娇小| 亚洲精品国精品久久99热| 国产亚洲精品久久久久动| 成人a免费视频| 91影视免费在线观看| 韩日欧美一区二区| 亚洲另类激情图| 欧美久久精品午夜青青大伊人| 中文字幕亚洲一区二区三区五十路| 中文字幕亚洲在线| 日本道色综合久久影院| 日韩精品日韩在线观看| 91精品久久久久久久久不口人| 欧美激情中文字幕在线| 91久久综合亚洲鲁鲁五月天| 亚洲欧美一区二区三区在线| 日韩精品视频在线播放| 91在线免费视频| 色www亚洲国产张柏芝| 亚洲人成电影在线播放| 久久久久久久久综合| 亚洲成人久久久久| 91久热免费在线视频| 国产午夜精品视频免费不卡69堂| 久久亚洲私人国产精品va| 欧美国产日韩二区| 欧美日韩中文字幕综合视频| 亚洲欧美综合区自拍另类| 国产精品久久久久9999| 亚洲久久久久久久久久久| 日韩欧美在线字幕| 国产精品久久久久久久久久| 日日噜噜噜夜夜爽亚洲精品| 8090成年在线看片午夜| 亚洲精品一区二区三区婷婷月| 日韩动漫免费观看电视剧高清| 日韩视频第一页| 日韩一区二区精品视频| 啊v视频在线一区二区三区| 国产精品91久久久| 91精品国产综合久久香蕉最新版| 日本久久精品视频| 一区二区三区在线播放欧美| 色中色综合影院手机版在线观看| 日韩精品在线免费观看| 欧美午夜电影在线| 日韩av电影在线免费播放| 青青久久aⅴ北条麻妃| 日韩有码视频在线| 亚洲精品国产精品国自产在线| 精品国产乱码久久久久酒店| 久久久噜噜噜久噜久久| 久久久久久久一| 97婷婷涩涩精品一区| 国产精品美女www爽爽爽视频| 日韩av快播网址| 欧美一区三区三区高中清蜜桃| 国产精品情侣自拍| 亚洲欧美在线看| 国产精品电影在线观看| 精品久久久久久亚洲国产300| www日韩中文字幕在线看| 国产在线观看一区二区三区| 欧美日韩一区二区免费在线观看| 亚洲视频欧洲视频| 日韩欧美极品在线观看| 美女撒尿一区二区三区| 欧美精品情趣视频| 97欧美精品一区二区三区| 国模私拍视频一区| 久久精品久久久久久国产 免费| 日韩一区二区三区xxxx| 北条麻妃久久精品| 亚洲欧美日韩天堂| 久久精品一本久久99精品| 国产成人精品久久久| 成人有码在线播放| 国产亚洲精品高潮| 色偷偷av一区二区三区乱| 庆余年2免费日韩剧观看大牛| 精品国产精品三级精品av网址| 亚洲人午夜色婷婷| 中文字幕亚洲一区二区三区五十路| 欧美最猛性xxxxx免费| 中文字幕日韩精品在线| 国产视频久久久久| 国产精品久久久久免费a∨大胸| 欧美视频精品一区| 中文字幕av一区二区三区谷原希美| 亚洲视频精品在线| 欧美天天综合色影久久精品| 中文字幕亚洲欧美一区二区三区| 国产精品久久久久久久电影| 国产精品稀缺呦系列在线| 成人激情电影一区二区| 一区二区三区视频观看| 中文字幕自拍vr一区二区三区| 亚洲成人性视频| 美女国内精品自产拍在线播放| 日本精品久久中文字幕佐佐木| 国产精品av免费在线观看| 久久精品精品电影网| 深夜福利亚洲导航| 国产精品美腿一区在线看| 伊人成人开心激情综合网| 超碰日本道色综合久久综合| 欧美中在线观看| 精品国产91久久久久久老师| 亚洲精品av在线播放| 国产成人欧美在线观看| 中文字幕欧美精品在线| 亚洲大胆美女视频| 国产精品久久久久久搜索| 一本大道亚洲视频| 亚洲综合色激情五月| 日韩中文字幕在线视频播放| 亚洲欧美国产另类| 精品久久久香蕉免费精品视频| 久久伊人91精品综合网站| 亚洲精品国产拍免费91在线| 97国产suv精品一区二区62| 欧美日韩在线视频一区| 欧美日韩亚洲精品内裤| 在线观看久久久久久| 一区二区亚洲欧洲国产日韩| 在线视频欧美日韩| 国产精品ⅴa在线观看h| 国产精品一区二区三区久久久| 久久久久免费精品国产| 国产精品亚发布| 精品国内亚洲在观看18黄| 奇米影视亚洲狠狠色| 538国产精品视频一区二区|