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

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

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

2019-11-11 04:49:43
字體:
來源:轉載
供稿:網友

   上面講到,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實現的。看看DefaultListableBeanFactory中有關容器定義

 

 /** 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
欧美精品在线免费观看| 国产欧美欧洲在线观看| 精品国产自在精品国产浪潮| 午夜欧美大片免费观看| 国产97色在线|日韩| 在线看国产精品| 青青在线视频一区二区三区| 亚洲精品动漫久久久久| 久久综合色88| 一区三区二区视频| 国产成人亚洲综合青青| 亚洲欧美日韩在线高清直播| 亚洲美女中文字幕| 欧美在线国产精品| 777777777亚洲妇女| 亚洲天堂av在线免费观看| 欧美中文字幕在线观看| 欧美日韩国产专区| 亚洲精品电影网| 国产精品美女久久久久av超清| 国产一区二区三区日韩欧美| 日本免费久久高清视频| 欧美性猛交xxxx富婆| 日韩精品www| 中文字幕日韩精品在线| 精品国产乱码久久久久久天美| 日韩中文字幕免费看| 7777精品视频| 综合av色偷偷网| 欧美综合国产精品久久丁香| 欧美日在线观看| 欧美成人久久久| 亚洲成年人在线播放| 国产精品欧美日韩一区二区| 日本一区二区三区在线播放| 国产视频在线一区二区| 成人欧美一区二区三区在线湿哒哒| 国内精品久久久久影院优| 欧美国产亚洲精品久久久8v| 国产一区二区三区三区在线观看| 欧美孕妇孕交黑巨大网站| 欧美有码在线观看视频| 亚洲黄色www| 欧美中文在线字幕| 日韩av片电影专区| 日韩成人小视频| 欧洲午夜精品久久久| 久久伊人91精品综合网站| 一区二区三区亚洲| 精品美女永久免费视频| 日本一区二区在线播放| 欧美中文字幕第一页| 久久久精品免费视频| 中文字幕在线看视频国产欧美| 日韩在线观看免费高清完整版| 久久久久久午夜| 国内伊人久久久久久网站视频| 热久久99这里有精品| 亚洲人成77777在线观看网| 亚洲欧美自拍一区| 久久国产加勒比精品无码| 亚洲国产精久久久久久久| 久久精品在线视频| 欧美日韩激情视频| 日韩免费在线观看视频| 国产成人午夜视频网址| 岛国av在线不卡| 69av在线播放| 久久人体大胆视频| 欧美大荫蒂xxx| 久精品免费视频| 精品国产欧美成人夜夜嗨| 自拍偷拍亚洲精品| 色综合91久久精品中文字幕| 深夜精品寂寞黄网站在线观看| 亚洲欧美日韩一区二区在线| 一道本无吗dⅴd在线播放一区| 久久久亚洲成人| 欧美激情视频一区二区三区不卡| 亚洲精品999| 久久偷看各类女兵18女厕嘘嘘| 欧美高清视频在线| 成人激情春色网| 欧美日韩国产va另类| 国产精品日韩专区| 亚洲欧美激情四射在线日| 亚洲欧美日韩一区二区在线| 亚洲精品日韩在线| 亚洲综合色av| 色噜噜狠狠狠综合曰曰曰88av| 欧美亚洲第一页| 97在线视频一区| 国产69精品99久久久久久宅男| 97超级碰在线看视频免费在线看| 这里只有视频精品| 精品国偷自产在线视频99| 久久精品视频亚洲| 8x海外华人永久免费日韩内陆视频| 日韩中文字幕免费| 久久久久久久久久久人体| 亚洲91精品在线| 久久久在线观看| 精品视频一区在线视频| 日韩av电影在线免费播放| 国产日韩综合一区二区性色av| 欧美成人精品激情在线观看| 欧美韩国理论所午夜片917电影| 亚洲人永久免费| 亚洲欧美日韩在线一区| 亚洲人成网站999久久久综合| 精品国产一区av| 97视频人免费观看| 亚洲视频在线观看视频| 91超碰中文字幕久久精品| 亚洲黄色在线看| 国产成人精品免费视频| 精品国产999| 国产精品国模在线| 精品人伦一区二区三区蜜桃免费| 精品久久久久久中文字幕| 欧美一级大片在线免费观看| 亚洲欧美激情四射在线日| 国产精品视频网址| 欧美日韩一区二区在线播放| 国产精品久久久久久久久久久新郎| 尤物九九久久国产精品的特点| 国产精品久久久久久久久久免费| 日韩电影在线观看免费| 91网站在线免费观看| 亚洲精品久久久久中文字幕欢迎你| 欧美黑人xxxⅹ高潮交| 欧美大片免费看| 欧美成人激情视频| 久久影视电视剧免费网站| 国产精品免费观看在线| 成人精品视频99在线观看免费| 97精品一区二区视频在线观看| 亚洲一级片在线看| 欧美性xxxxx极品| 国产精品白丝jk喷水视频一区| 久久天天躁日日躁| 国产亚洲欧洲黄色| 成人a免费视频| 亚洲午夜未满十八勿入免费观看全集| 国产午夜精品免费一区二区三区| 国内精品美女av在线播放| 国产一区二区黑人欧美xxxx| 国产精品电影在线观看| 久久久国产精彩视频美女艺术照福利| 日韩欧美国产网站| 亚洲国产一区自拍| 欧美激情一区二区三级高清视频| 欧美成人小视频| 久久91超碰青草是什么| 欧美日韩中文在线观看| 亚洲xxxx妇黄裸体| 国产精品免费一区| 午夜精品久久久久久久99热| 欧美电影免费观看大全| 久久精品国产精品亚洲| 国产精品无码专区在线观看| 久久噜噜噜精品国产亚洲综合| 国产在线播放不卡| 在线激情影院一区|