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

首頁 > 開發 > Java > 正文

深入講解spring boot中servlet的啟動過程與原理

2024-07-14 08:41:25
字體:
來源:轉載
供稿:網友

前言

本文主要介紹了關于spring boot中servlet啟動過程與原理的相關內容,下面話不多說了,來一起看看詳細的介紹吧

啟動過程與原理:

1 spring boot 應用啟動運行run方法

StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; FailureAnalyzers analyzers = null; configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try {  ApplicationArguments applicationArguments = new DefaultApplicationArguments(   args);  ConfigurableEnvironment environment = prepareEnvironment(listeners,   applicationArguments);  Banner printedBanner = printBanner(environment);   //創建一個ApplicationContext容器  context = createApplicationContext();  analyzers = new FailureAnalyzers(context);  prepareContext(context, environment, listeners, applicationArguments,   printedBanner);   //刷新IOC容器  refreshContext(context);  afterRefresh(context, applicationArguments);  listeners.finished(context, null);  stopWatch.stop();  if (this.logStartupInfo) {  new StartupInfoLogger(this.mainApplicationClass)   .logStarted(getApplicationLog(), stopWatch);  }  return context; } catch (Throwable ex) {  handleRunFailure(context, listeners, analyzers, ex);  throw new IllegalStateException(ex); }

2  createApplicationContext():創建IOC容器,如果是web應用則創建AnnotationConfigEmbeddedWebApplacation的IOC容器,如果不是,則創建AnnotationConfigApplication的IOC容器

public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."  + "annotation.AnnotationConfigApplicationContext"; /** * The class name of application context that will be used by default for web * environments. */ public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework."  + "boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext";protected ConfigurableApplicationContext createApplicationContext() { Class<?> contextClass = this.applicationContextClass; if (contextClass == null) {  try {          //根據應用環境,創建不同的IOC容器  contextClass = Class.forName(this.webEnvironment   ? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);  }  catch (ClassNotFoundException ex) {  throw new IllegalStateException(   "Unable create a default ApplicationContext, "    + "please specify an ApplicationContextClass",   ex);  } } return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass); }

3    refreshContext(context) spring boot刷新IOC容器(創建容器對象,并初始化容器,創建容器每一個組件)

private void refreshContext(ConfigurableApplicationContext context) { refresh(context); if (this.registerShutdownHook) {  try {  context.registerShutdownHook();  }  catch (AccessControlException ex) {  // Not allowed in some environments.  } } }

4 refresh(context);刷新剛才創建的IOC容器

protected void refresh(ApplicationContext applicationContext) { Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext); ((AbstractApplicationContext) applicationContext).refresh(); }

5 調用父類的refresh()的方法

public void refresh() throws BeansException, IllegalStateException { Object var1 = this.startupShutdownMonitor; synchronized(this.startupShutdownMonitor) {  this.prepareRefresh();  ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();  this.prepareBeanFactory(beanFactory);  try {  this.postProcessBeanFactory(beanFactory);  this.invokeBeanFactoryPostProcessors(beanFactory);  this.registerBeanPostProcessors(beanFactory);  this.initMessageSource();  this.initApplicationEventMulticaster();  this.onRefresh();  this.registerListeners();  this.finishBeanFactoryInitialization(beanFactory);  this.finishRefresh();  } catch (BeansException var9) {  if (this.logger.isWarnEnabled()) {   this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);  }  this.destroyBeans();  this.cancelRefresh(var9);  throw var9;  } finally {  this.resetCommonCaches();  } } }

6  抽象父類AbstractApplicationContext類的子類EmbeddedWebApplicationContext的onRefresh方法

@Override protected void onRefresh() { super.onRefresh(); try {  createEmbeddedServletContainer(); } catch (Throwable ex) {  throw new ApplicationContextException("Unable to start embedded container",   ex); } }

7  在createEmbeddedServletContainer放啊發中會獲取嵌入式Servlet容器工廠,由容器工廠創建Servlet

private void createEmbeddedServletContainer() { EmbeddedServletContainer localContainer = this.embeddedServletContainer; ServletContext localServletContext = getServletContext(); if (localContainer == null && localServletContext == null) {                //獲取嵌入式Servlet容器工廠  EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();          //根據容器工廠獲取對應嵌入式Servlet容器  this.embeddedServletContainer = containerFactory   .getEmbeddedServletContainer(getSelfInitializer()); } else if (localServletContext != null) {  try {  getSelfInitializer().onStartup(localServletContext);  }  catch (ServletException ex) {  throw new ApplicationContextException("Cannot initialize servlet context",   ex);  } } initPropertySources(); }

8  從IOC容器中獲取Servlet容器工廠

//EmbeddedWebApplicationContext#getEmbeddedServletContainerFactory protected EmbeddedServletContainerFactory getEmbeddedServletContainerFactory() {  // Use bean names so that we don't consider the hierarchy  String[] beanNames = getBeanFactory()  .getBeanNamesForType(EmbeddedServletContainerFactory.class);  if (beanNames.length == 0) {  throw new ApplicationContextException(   "Unable to start EmbeddedWebApplicationContext due to missing "   + "EmbeddedServletContainerFactory bean.");  }  if (beanNames.length > 1) {  throw new ApplicationContextException(   "Unable to start EmbeddedWebApplicationContext due to multiple "   + "EmbeddedServletContainerFactory beans : "   + StringUtils.arrayToCommaDelimitedString(beanNames));  }  return getBeanFactory().getBean(beanNames[0],      EmbeddedServletContainerFactory.class); }

9  使用Servlet容器工廠獲取嵌入式Servlet容器,具體使用哪一個容器工廠看配置環境依賴

this.embeddedServletContainer = containerFactory   .getEmbeddedServletContainer(getSelfInitializer()); 

10  上述創建過程  首先啟動IOC容器,接著啟動嵌入式Servlet容器,接著將IOC容器中剩下沒有創建的對象獲取出來,比如自己創建的controller

// Instantiate all remaining (non-lazy-init) singletons.  finishBeanFactoryInitialization(beanFactory);
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { // Initialize conversion service for this context. if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&  beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {  beanFactory.setConversionService(   beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); } // Register a default embedded value resolver if no bean post-processor // (such as a PropertyPlaceholderConfigurer bean) registered any before: // at this point, primarily for resolution in annotation attribute values. if (!beanFactory.hasEmbeddedValueResolver()) {  beanFactory.addEmbeddedValueResolver(new StringValueResolver() {  @Override  public String resolveStringValue(String strVal) {   return getEnvironment().resolvePlaceholders(strVal);  }  }); } // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early. String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); for (String weaverAwareName : weaverAwareNames) {  getBean(weaverAwareName); } // Stop using the temporary ClassLoader for type matching. beanFactory.setTempClassLoader(null); // Allow for caching all bean definition metadata, not expecting further changes. beanFactory.freezeConfiguration(); // Instantiate all remaining (non-lazy-init) singletons. beanFactory.preInstantiateSingletons(); }

看看 preInstantiateSingletons方法

public void preInstantiateSingletons() throws BeansException {  if (this.logger.isDebugEnabled()) {   this.logger.debug("Pre-instantiating singletons in " + this);  }  List<String> beanNames = new ArrayList(this.beanDefinitionNames);  Iterator var2 = beanNames.iterator();  while(true) {   while(true) {    String beanName;    RootBeanDefinition bd;    do {     do {      do {       if (!var2.hasNext()) {        var2 = beanNames.iterator();        while(var2.hasNext()) {         beanName = (String)var2.next();         Object singletonInstance = this.getSingleton(beanName);         if (singletonInstance instanceof SmartInitializingSingleton) {          final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton)singletonInstance;          if (System.getSecurityManager() != null) {           AccessController.doPrivileged(new PrivilegedAction<Object>() {            public Object run() {             smartSingleton.afterSingletonsInstantiated();             return null;            }           }, this.getAccessControlContext());          } else {           smartSingleton.afterSingletonsInstantiated();          }         }        }        return;       }       beanName = (String)var2.next();       bd = this.getMergedLocalBeanDefinition(beanName);      } while(bd.isAbstract());     } while(!bd.isSingleton());    } while(bd.isLazyInit());    if (this.isFactoryBean(beanName)) {     final FactoryBean<?> factory = (FactoryBean)this.getBean("&" + beanName);     boolean isEagerInit;     if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {      isEagerInit = ((Boolean)AccessController.doPrivileged(new PrivilegedAction<Boolean>() {       public Boolean run() {        return ((SmartFactoryBean)factory).isEagerInit();       }      }, this.getAccessControlContext())).booleanValue();     } else {      isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean)factory).isEagerInit();     }     if (isEagerInit) {      this.getBean(beanName);     }    } else {            //注冊bean     this.getBean(beanName);    }   }  } }

是使用getBean方法來通過反射將所有未創建的實例創建出來

  使用嵌入式Servlet容器:

     優點:   簡單,便攜

     缺點:   默認不支持jsp,優化定制比較復雜

使用外置Servlet容器的步驟:

  1  必須創建war項目,需要劍豪web項目的目錄結構

  2  嵌入式Tomcat依賴scope指定provided

  3  編寫SpringBootServletInitializer類子類,并重寫configure方法

public class ServletInitializer extends SpringBootServletInitializer {   @Override  protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {   return application.sources(SpringBoot04WebJspApplication.class);  } }

        4  啟動服務器

jar包和war包啟動區別

    jar包:執行SpringBootApplication的run方法,啟動IOC容器,然后創建嵌入式Servlet容器

 war包:  先是啟動Servlet服務器,服務器啟動Springboot應用(springBootServletInitizer),然后啟動IOC容器

Servlet 3.0+規則

    1  服務器啟動(web應用啟動),會創建當前web應用里面所有jar包里面的ServletContainerlnitializer實例

     2 ServletContainerInitializer的實現放在jar包的META-INF/services文件夾下

   3  還可以使用@HandlesTypes注解,在應用啟動的時候加載指定的類。

外部Tomcat流程以及原理

 ?、?nbsp; 啟動Tomcat

  ②  根據上述描述的Servlet3.0+規則,可以在Spring的web模塊里面找到有個文件名為javax.servlet.ServletContainerInitializer的文件,而文件的內容為org.springframework.web.SpringServletContainerInitializer,用于加載SpringServletContainerInitializer類

 ?、劭纯碨pringServletContainerInitializer定義

@HandlesTypes(WebApplicationInitializer.class)public class SpringServletContainerInitializer implements ServletContainerInitializer { /**  * Delegate the {@code ServletContext} to any {@link WebApplicationInitializer}  * implementations present on the application classpath.  * <p>Because this class declares @{@code HandlesTypes(WebApplicationInitializer.class)},  * Servlet 3.0+ containers will automatically scan the classpath for implementations  * of Spring's {@code WebApplicationInitializer} interface and provide the set of all  * such types to the {@code webAppInitializerClasses} parameter of this method.  * <p>If no {@code WebApplicationInitializer} implementations are found on the classpath,  * this method is effectively a no-op. An INFO-level log message will be issued notifying  * the user that the {@code ServletContainerInitializer} has indeed been invoked but that  * no {@code WebApplicationInitializer} implementations were found.  * <p>Assuming that one or more {@code WebApplicationInitializer} types are detected,  * they will be instantiated (and <em>sorted</em> if the @{@link  * org.springframework.core.annotation.Order @Order} annotation is present or  * the {@link org.springframework.core.Ordered Ordered} interface has been  * implemented). Then the {@link WebApplicationInitializer#onStartup(ServletContext)}  * method will be invoked on each instance, delegating the {@code ServletContext} such  * that each instance may register and configure servlets such as Spring's  * {@code DispatcherServlet}, listeners such as Spring's {@code ContextLoaderListener},  * or any other Servlet API componentry such as filters.  * @param webAppInitializerClasses all implementations of  * {@link WebApplicationInitializer} found on the application classpath  * @param servletContext the servlet context to be initialized  * @see WebApplicationInitializer#onStartup(ServletContext)  * @see AnnotationAwareOrderComparator  */ @Override public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)   throws ServletException {  List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>();  if (webAppInitializerClasses != null) {   for (Class<?> waiClass : webAppInitializerClasses) {    // Be defensive: Some servlet containers provide us with invalid classes,    // no matter what @HandlesTypes says...    if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&      WebApplicationInitializer.class.isAssignableFrom(waiClass)) {     try {                //為所有的WebApplicationInitializer類型創建實例,并加入集合中      initializers.add((WebApplicationInitializer) waiClass.newInstance());     }     catch (Throwable ex) {      throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);     }    }   }  }  if (initializers.isEmpty()) {   servletContext.log("No Spring WebApplicationInitializer types detected on classpath");   return;  }  servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");  AnnotationAwareOrderComparator.sort(initializers);      //調用每一個WebApplicationInitializer實例的onstartup方法  for (WebApplicationInitializer initializer : initializers) {   initializer.onStartup(servletContext);  } }}

 在上面一段長長的注釋中可以看到,SpringServletContainerInitializer將@HandlesTypes(WebApplicationInitializer.class)標注的所有WebApplicationInitializer這個類型的類都傳入到onStartup方法的Set參數中,并通過反射為這些WebApplicationInitializer類型的類創建實例;

  ④  方法最后,每一個WebApplicationInitilizer實現調用自己onstartup方法

 ?、?nbsp; 而WebApplicationInitializer有個抽象實現類SpringBootServletInitializer(記住我們繼承了該抽象類),則會調用每一個WebApplicationInitializer實例(包括SpringBootServletInitializer)的onStartup方法:

public abstract class SpringBootServletInitializer implements WebApplicationInitializer {    //other code...      @Override   public void onStartup(ServletContext servletContext) throws ServletException {     // Logger initialization is deferred in case a ordered     // LogServletContextInitializer is being used     this.logger = LogFactory.getLog(getClass());     //創建IOC容器     WebApplicationContext rootAppContext = createRootApplicationContext(         servletContext);     if (rootAppContext != null) {       servletContext.addListener(new ContextLoaderListener(rootAppContext) {         @Override         public void contextInitialized(ServletContextEvent event) {           // no-op because the application context is already initialized         }       });     }     else {       this.logger.debug("No ContextLoaderListener registered, as "           + "createRootApplicationContext() did not "           + "return an application context");     }   }    protected WebApplicationContext createRootApplicationContext(       ServletContext servletContext) {     //創建Spring應用構建器,并進行相關屬性設置     SpringApplicationBuilder builder = createSpringApplicationBuilder();     StandardServletEnvironment environment = new StandardServletEnvironment();     environment.initPropertySources(servletContext, null);     builder.environment(environment);     builder.main(getClass());     ApplicationContext parent = getExistingRootWebApplicationContext(servletContext);     if (parent != null) {       this.logger.info("Root context already created (using as parent).");       servletContext.setAttribute(           WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, null);       builder.initializers(new ParentContextApplicationContextInitializer(parent));     }     builder.initializers(         new ServletContextApplicationContextInitializer(servletContext));     builder.contextClass(AnnotationConfigEmbeddedWebApplicationContext.class);          //調用configure方法,創建war類型的web項目后,由于編寫SpringBootServletInitializer的子類重寫configure方法,所以此處調用的是我們定義的子類重寫的configure方法     builder = configure(builder);          //通過構建器構建了一個Spring應用     SpringApplication application = builder.build();     if (application.getSources().isEmpty() && AnnotationUtils         .findAnnotation(getClass(), Configuration.class) != null) {       application.getSources().add(getClass());     }     Assert.state(!application.getSources().isEmpty(),         "No SpringApplication sources have been defined. Either override the "             + "configure method or add an @Configuration annotation");     // Ensure error pages are registered     if (this.registerErrorPageFilter) {       application.getSources().add(ErrorPageFilterConfiguration.class);     }     //啟動Spring應用     return run(application);   }      //Spring應用啟動,創建并返回IOC容器   protected WebApplicationContext run(SpringApplication application) {     return (WebApplicationContext) application.run();   }   }

SpringBootServletInitializer實例執行onStartup方法的時候會通過createRootApplicationContext方法來執行run方法,接下來的過程就同以jar包形式啟動的應用的run過程一樣了,在內部會創建IOC容器并返回,只是以war包形式的應用在創建IOC容器過程中,不再創建Servlet容器了。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VeVb武林網的支持。


注:相關教程知識閱讀請移步到JAVA教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品视频大全| 国产在线精品一区免费香蕉| 亚洲日韩欧美视频一区| 91精品国产乱码久久久久久蜜臀| 97人洗澡人人免费公开视频碰碰碰| 日本久久久久久久久| 欧美精品videos性欧美| 成人动漫网站在线观看| 成人欧美一区二区三区在线湿哒哒| 欧美天天综合色影久久精品| 国产欧美日韩免费| 亚洲欧美国产另类| 91精品视频观看| 青草成人免费视频| 96精品视频在线| 国产精品一区二区女厕厕| 国产精品久久久久av免费| 成人精品福利视频| 国产精品丝袜一区二区三区| 欧美电影在线观看| 日韩av电影在线网| 成人欧美一区二区三区在线湿哒哒| 国产精品美女在线| 欧美成人黄色小视频| 亚洲人成电影在线播放| 成人黄色av免费在线观看| 欧美在线观看视频| 欧美裸体男粗大视频在线观看| 日韩成人中文字幕在线观看| 欧美一级成年大片在线观看| 欧美午夜片欧美片在线观看| 8090成年在线看片午夜| 久久成人这里只有精品| 成人免费午夜电影| 亚洲激情久久久| 亚洲福利视频久久| 亚洲欧洲中文天堂| 日韩av免费看| 亚洲第一视频网站| 日韩在线观看免费网站| 欧美黄色小视频| 精品一区精品二区| 97在线精品视频| 国产精品视频26uuu| 国产成人aa精品一区在线播放| 久久91亚洲精品中文字幕| 成人精品一区二区三区电影黑人| 久久亚洲精品成人| 国产日本欧美在线观看| 欧美与黑人午夜性猛交久久久| 日韩国产欧美区| 韩国日本不卡在线| 国产成人精品免费久久久久| 欧美日韩福利视频| 国产主播精品在线| www.国产一区| 久久久久久91香蕉国产| 精品国产老师黑色丝袜高跟鞋| 亚洲qvod图片区电影| 国产亚洲欧美日韩精品| 亚洲精品久久7777777| 亚洲免费视频一区二区| 日本久久亚洲电影| 2019中文字幕全在线观看| 欧美极品少妇xxxxⅹ裸体艺术| 国产精品丝袜久久久久久高清| 亚洲视频在线观看免费| 欧美特级www| 国外成人免费在线播放| 欧美在线视频免费播放| 亚洲va久久久噜噜噜| 亚洲天堂成人在线| 尤物九九久久国产精品的特点| 欧美一区三区三区高中清蜜桃| 狠狠躁夜夜躁人人爽天天天天97| 8x拔播拔播x8国产精品| 在线观看精品自拍私拍| 亚洲精品xxx| 亚洲热线99精品视频| 91啪国产在线| 亚洲福利在线视频| 日韩中文字幕在线观看| 欧美裸身视频免费观看| 亚洲一区二区自拍| 亚洲2020天天堂在线观看| 深夜福利日韩在线看| 国产精品人成电影在线观看| 国产自摸综合网| 在线观看日韩视频| 亚洲国产精品人人爽夜夜爽| 欧美另类69精品久久久久9999| 97av在线播放| 欧美一级大片在线免费观看| 国内精品视频在线| 成人免费在线视频网站| 国产精品久久久久7777婷婷| 91久久久亚洲精品| 国产精品吊钟奶在线| 日韩在线观看网站| 国产美女久久久| 久久婷婷国产麻豆91天堂| 欧美日韩精品在线| 日韩电影中文字幕av| 国产精品露脸av在线| 国语自产精品视频在线看抢先版图片| 国产精品久久久久久av福利软件| 欧美日韩第一视频| 国产精品久久久| 亚洲成人av在线播放| 91系列在线观看| 亚洲一区亚洲二区| 欧美色xxxx| 久久av在线播放| 国产a∨精品一区二区三区不卡| 亚洲第一免费网站| 久久久国产精品视频| 中文字幕欧美视频在线| 日本欧美一级片| 高清一区二区三区日本久| 欧美乱大交xxxxx另类电影| 日韩高清中文字幕| 狠狠做深爱婷婷久久综合一区| 日韩高清a**址| 久久综合88中文色鬼| 日韩电影网在线| 亚洲欧美变态国产另类| 久久噜噜噜精品国产亚洲综合| 亚洲欧美色图片| 97超级碰碰人国产在线观看| 亚洲一区二区三区成人在线视频精品| 欧美日本国产在线| 欧美成人免费全部观看天天性色| 色综合影院在线| 欧美福利视频网站| 欧美限制级电影在线观看| 啪一啪鲁一鲁2019在线视频| 日韩av理论片| www.欧美精品一二三区| 亚洲成人网久久久| 亚洲国产精品小视频| 韩国v欧美v日本v亚洲| 欧美性一区二区三区| 欧美日韩亚洲精品一区二区三区| 亚洲第一精品电影| 91视频国产一区| 亚洲精品久久久一区二区三区| 日韩高清免费在线| 亚洲天堂视频在线观看| 国产成人精品久久二区二区| 国产精品久久久久免费a∨| 这里只有精品在线观看| 国产欧美在线看| 日韩视频第一页| 欧美大片在线影院| 91精品国产91久久久久久久久| 欧美高清理论片| 成人久久精品视频| 欧美成人剧情片在线观看| 国产欧美精品一区二区三区介绍| 欧美有码在线观看视频| 亚洲第一福利网站| 国产成人精品免高潮在线观看| 国产乱肥老妇国产一区二| 久久国产精品久久国产精品|