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

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

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

2019-11-11 05:22:56
字體:
來源:轉載
供稿:網友

   上面講到,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方法調用的時候去使用了。


上一篇:Regression

下一篇:mysql 2003以及10061錯誤

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
91亚洲国产成人久久精品网站| 久久久中精品2020中文| 色婷婷成人综合| 色综合久久久久久中文网| 国产在线一区二区三区| 亚洲成**性毛茸茸| 欧美中文字幕在线| 国产精品白嫩初高中害羞小美女| 最新日韩中文字幕| 91精品国产高清久久久久久| 美女视频黄免费的亚洲男人天堂| 中文字幕亚洲一区二区三区五十路| 美日韩精品免费视频| 午夜精品久久久久久99热软件| 欧美第一黄网免费网站| 精品国产网站地址| 国产成人自拍视频在线观看| 国产日韩在线看片| 最近2019中文免费高清视频观看www99| 中文字幕欧美国内| 成人97在线观看视频| 欧美激情视频免费观看| 亚洲欧美中文字幕| 91极品女神在线| 国产欧美精品一区二区三区-老狼| 久久精品电影网站| 亲子乱一区二区三区电影| 国产精品成人av在线| 国产三级精品网站| 精品久久久久国产| 亚洲国产精品专区久久| 久久久日本电影| 午夜精品视频网站| 久久久久久免费精品| 亚洲在线免费观看| 色婷婷亚洲mv天堂mv在影片| 91免费福利视频| 成人美女免费网站视频| 中文字幕在线日韩| 日本国产一区二区三区| 亚洲精品一二区| 亚洲伊人第一页| 在线午夜精品自拍| 国产成人亚洲精品| 在线观看亚洲区| 欧洲午夜精品久久久| 欧美怡红院视频一区二区三区| 97视频在线观看免费高清完整版在线观看| 欧美成人在线影院| 国产日韩精品一区二区| 精品动漫一区二区三区| 欧美怡红院视频一区二区三区| 精品美女国产在线| 欧美丰满片xxx777| 亚洲精品久久久久中文字幕二区| 91久久国产精品91久久性色| 国产日韩亚洲欧美| 91精品视频免费看| 欧美怡红院视频一区二区三区| 91精品国产综合久久久久久蜜臀| 国产亚洲欧美aaaa| 97人人做人人爱| 欧美成人高清视频| 国产区精品在线观看| 奇米四色中文综合久久| 久久欧美在线电影| 亚洲精品在线视频| 国产精品久久色| 日韩欧美精品网址| 亚洲欧美日韩精品久久奇米色影视| 一区二区亚洲精品国产| 92福利视频午夜1000合集在线观看| 日韩在线视频观看正片免费网站| 午夜精品福利在线观看| 国产精品视频地址| 亚洲成人激情在线观看| 成人黄色激情网| 在线看欧美日韩| 国产亚洲一区二区在线| 91精品啪在线观看麻豆免费| 精品久久久久久电影| 亚州精品天堂中文字幕| 热re99久久精品国产66热| 欧美激情欧美狂野欧美精品| 亚洲色图50p| 最新中文字幕亚洲| 欧美与黑人午夜性猛交久久久| 亚洲精品有码在线| 国产精品美女在线观看| 久久精品亚洲一区| 色在人av网站天堂精品| 亚洲毛片在线看| 亚洲伦理中文字幕| 欧美高清不卡在线| 日韩中文在线观看| 日韩免费观看在线观看| 庆余年2免费日韩剧观看大牛| 精品美女国产在线| 一区二区三区视频在线| 中文字幕av一区二区三区谷原希美| 国产精品日韩专区| 一区二区在线视频播放| 久久国产精品99国产精| 裸体女人亚洲精品一区| 国产精品高清网站| 国产精品啪视频| 久久97精品久久久久久久不卡| 国产精品久久不能| 久久综合免费视频| 中文字幕精品www乱入免费视频| 岛国av在线不卡| 一区二区三区高清国产| 国产97在线|亚洲| 日本道色综合久久影院| 欧美日韩一区二区在线播放| 欧美在线国产精品| 3344国产精品免费看| 欧美高清不卡在线| 日韩av在线天堂网| 欧美性猛交xxxx乱大交蜜桃| www.久久色.com| 欧美一区三区三区高中清蜜桃| 国产极品精品在线观看| 欧美激情乱人伦| 久久影视电视剧免费网站| 久久伊人91精品综合网站| 国外成人性视频| 国产视频欧美视频| 国产欧美日韩中文字幕| 国产视频久久久久| 中文字幕日韩免费视频| 欧美性猛交99久久久久99按摩| 欧美美最猛性xxxxxx| 欧美日韩在线观看视频| 国产综合在线观看视频| 欧美电影在线观看| 欧美精品免费播放| 综合136福利视频在线| 中文字幕国内精品| 日韩欧美亚洲范冰冰与中字| 国语自产偷拍精品视频偷| 久久久久久噜噜噜久久久精品| 亚洲性生活视频在线观看| 国产精品久久久久久久久免费看| 成人久久精品视频| 久久欧美在线电影| 欧美激情精品久久久久| 国产亚洲欧美日韩美女| 国产亚洲精品高潮| 国产精品成av人在线视午夜片| 欧美一区二粉嫩精品国产一线天| 日韩av在线网站| 欧美日韩国产丝袜美女| 国产美女精品免费电影| 1769国内精品视频在线播放| 91国在线精品国内播放| 国产欧美日韩高清| 日韩精品视频在线| 日韩va亚洲va欧洲va国产| 色悠久久久久综合先锋影音下载| 国产有码在线一区二区视频| 国产香蕉97碰碰久久人人| 色综合久久精品亚洲国产| 中文字幕在线国产精品|