日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > php教程 > Spring 源碼解析之DispatcherServlet源碼解析(五)

Spring 源碼解析之DispatcherServlet源碼解析(五)

來源:程序員人生   發布時間:2016-06-14 09:25:50 閱讀次數:2926次

Spring 源碼解析之DispatcherServlet源碼解析(5)

前言

本文需要有前4篇文章的基礎,才能夠清晰易懂,有興趣可以先看看詳細的流程,這篇文章可以說是第1篇文章,也能夠說是前4篇文章的的匯總,Spring的全部要求流程都是圍繞著DispatcherServlet進行的

類結構圖

Renderings

根據類的結構來講DispatcherServlet本身也是繼承了HttpServlet的,所有的要求都是根據這1個Servlet來進行轉發的,同時解釋了為何需要在web.xml進行以下配置,由于Spring是基于1個Servlet來展開的,固然不需要Servlet也能夠使用Spring

<servlet> <servlet-name>appServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/spring-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>appServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>

1 DispatcherServlet初始化

1.1 DispatcherServlet初始化加載的幾個bean

protected void initStrategies(ApplicationContext context) { //初始化文件上傳處理類 initMultipartResolver(context); //初始化本地化Resolver initLocaleResolver(context); //初始化主題Resolver initThemeResolver(context); //初始化1些個與處理的HandlerMappings initHandlerMappings(context); // initHandlerAdapters(context); //初始化異常處理的handler initHandlerExceptionResolvers(context); //初始化要求路徑轉換為ViewName 的Translator initRequestToViewNameTranslator(context); //初始化ViewResolvers 這個就是針對視圖處理的Resolvers 比如jsp處理Resolvers 或freemarker處理Resolvers initViewResolvers(context); //初始化 主要管理flashmap,比如RedirectAttributes 的屬性會放到這個里面,默許使用的是SessionFlashMapManager initFlashMapManager(context); }

1.2 初始化流程圖

Renderings

1.2.1 HttpServletBean源碼解析

HttpServletBean本身來講是1個普通的servlet而已,主要做1些資源的初始化

public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware { protected final Log logger = LogFactory.getLog(getClass()); /** * Set of required properties (Strings) that must be supplied as * config parameters to this servlet. */ private final Set<String> requiredProperties = new HashSet<String>(); private ConfigurableEnvironment environment; /** * Subclasses can invoke this method to specify that this property * (which must match a JavaBean property they expose) is mandatory, * and must be supplied as a config parameter. This should be called * from the constructor of a subclass. * <p>This method is only relevant in case of traditional initialization * driven by a ServletConfig instance. * @param property name of the required property */ protected final void addRequiredProperty(String property) { this.requiredProperties.add(property); } /** * Map config parameters onto bean properties of this servlet, and * invoke subclass initialization. * @throws ServletException if bean properties are invalid (or required * properties are missing), or if subclass initialization fails. */ @Override public final void init() throws ServletException { if (logger.isDebugEnabled()) { logger.debug("Initializing servlet '" + getServletName() + "'"); } // Set bean properties from init parameters. try { //使用Servlet配置的初始化參數創建1個PropertyValues對象,PropertyValues對象是名值對的集合, 子類也能夠指定哪些屬性是必須的 PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties); //把當前的Servlet當作1個Bean, 把Bean的屬性和屬性的存取方法信息放入BeanWrapper對象 BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); //注冊1個可以在資源和路徑之間進行轉化的客戶化編輯器,這些資源是這個Web利用的內部資源,例如,1個文件,1個圖片等等 ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext()); bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment())); //提供給子類機會增加更多的客戶化的編輯器,或對BeanWrapper進行更多的初始化 initBeanWrapper(bw); //把初始化制定的參數值賦值到Servlet的屬性中,第2個參數true表明疏忽位置屬性 bw.setPropertyValues(pvs, true); } catch (BeansException ex) { logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex); throw ex; } // Let subclasses do whatever initialization they like. //提供給子類的的初始化方法 目前是FrameworkServlet 進行了實現 initServletBean(); if (logger.isDebugEnabled()) { logger.debug("Servlet '" + getServletName() + "' configured successfully"); } } /** * Initialize the BeanWrapper for this HttpServletBean, * possibly with custom editors. * <p>This default implementation is empty. * @param bw the BeanWrapper to initialize * @throws BeansException if thrown by BeanWrapper methods * @see org.springframework.beans.BeanWrapper#registerCustomEditor */ protected void initBeanWrapper(BeanWrapper bw) throws BeansException { } /** * Overridden method that simply returns {@code null} when no * ServletConfig set yet. * @see #getServletConfig() */ @Override public final String getServletName() { return (getServletConfig() != null ? getServletConfig().getServletName() : null); } /** * Overridden method that simply returns {@code null} when no * ServletConfig set yet. * @see #getServletConfig() */ @Override public final ServletContext getServletContext() { return (getServletConfig() != null ? getServletConfig().getServletContext() : null); } /** * Subclasses may override this to perform custom initialization. * All bean properties of this servlet will have been set before this * method is invoked. * <p>This default implementation is empty. * @throws ServletException if subclass initialization fails */ protected void initServletBean() throws ServletException { } /** * {@inheritDoc} * @throws IllegalArgumentException if environment is not assignable to * {@code ConfigurableEnvironment}. */ @Override public void setEnvironment(Environment environment) { Assert.isInstanceOf(ConfigurableEnvironment.class, environment); this.environment = (ConfigurableEnvironment) environment; } /** * {@inheritDoc} * <p>If {@code null}, a new environment will be initialized via * {@link #createEnvironment()}. */ @Override public ConfigurableEnvironment getEnvironment() { if (this.environment == null) { this.environment = this.createEnvironment(); } return this.environment; } /** * Create and return a new {@link StandardServletEnvironment}. Subclasses may override * in order to configure the environment or specialize the environment type returned. */ protected ConfigurableEnvironment createEnvironment() { return new StandardServletEnvironment(); } /** * PropertyValues implementation created from ServletConfig init parameters. */ //主要是用來添加初始化參數的 private static class ServletConfigPropertyValues extends MutablePropertyValues { /** * Create new ServletConfigPropertyValues. * @param config ServletConfig we'll use to take PropertyValues from * @param requiredProperties set of property names we need, where * we can't accept default values requiredProperties 這個參數主要是指定初始化時必須添加的參數 * @throws ServletException if any required properties are missing */ public ServletConfigPropertyValues(ServletConfig config, Set<String> requiredProperties) throws ServletException { Set<String> missingProps = (requiredProperties != null && !requiredProperties.isEmpty()) ? new HashSet<String>(requiredProperties) : null; Enumeration<String> en = config.getInitParameterNames(); while (en.hasMoreElements()) { String property = en.nextElement(); Object value = config.getInitParameter(property); addPropertyValue(new PropertyValue(property, value)); if (missingProps != null) { missingProps.remove(property); } } // Fail if we are still missing properties. if (missingProps != null && missingProps.size() > 0) { throw new ServletException( "Initialization from ServletConfig for servlet '" + config.getServletName() + "' failed; the following required properties were missing: " + StringUtils.collectionToDelimitedString(missingProps, ", ")); } } } }

1.2.1 FrameworkServlet源碼解析

這里只貼初始化的需要的部份代碼,根據上面的邏輯,子類實現了initServletBean()這個方法進行初始化

public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware { protected void initFrameworkServlet() throws ServletException { } //實現HttpServletBean 的初始化接口 @Override protected final void initServletBean() throws ServletException { getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'"); if (this.logger.isInfoEnabled()) { this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started"); } long startTime = System.currentTimeMillis(); try { //初始化webApplicationContext this.webApplicationContext = initWebApplicationContext(); //這個是留給子類去實現的方法,暫時來講沒有具體的實現,主要是留給開發人員自定義1些特性的時候 //這個時候WebApplicationContext已被初始化了,也就是1些個spring的配置文件已被初始化了 initFrameworkServlet(); } catch (ServletException ex) { this.logger.error("Context initialization failed", ex); throw ex; } catch (RuntimeException ex) { this.logger.error("Context initialization failed", ex); throw ex; } if (this.logger.isInfoEnabled()) { long elapsedTime = System.currentTimeMillis() - startTime; this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " + elapsedTime + " ms"); } } protected WebApplicationContext initWebApplicationContext() { //獲得根的Context對象,比如說我用了Spring boot或注解的方式進行初始化,那末這里的Context就是Spring boot或其他的context對象 WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContext wac = null; //如果當前的webApplicationContext 不等于null if (this.webApplicationContext != null) { // A context instance was injected at construction time -> use it wac = this.webApplicationContext; //如果context對象是ConfigurableWebApplicationContext if (wac instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac; //如果ConfigurableWebApplicationContext 不是存活狀態 if (!cwac.isActive()) { // The context has not yet been refreshed -> provide services such as // setting the parent context, setting the application context id, etc //如果沒有設置過parent if (cwac.getParent() == null) { // The context instance was injected without an explicit parent -> set // the root application context (if any; may be null) as the parent cwac.setParent(rootContext); } // configureAndRefreshWebApplicationContext(cwac); } } } if (wac == null) { // No context instance was injected at construction time -> see if one // has been registered in the servlet context. If one exists, it is assumed // that the parent context (if any) has already been set and that the // user has performed any initialization such as setting the context id //查詢當前的Context,下述有詳細講授 wac = findWebApplicationContext(); } //如果沒有找到那末就通過rootContext 去創建1個Context對象 if (wac == null) { // No context instance is defined for this servlet -> create a local one wac = createWebApplicationContext(rootContext); } //如果允許通過事件通知,那末就直接初始化。通過事件的通知可以反向的說明onRefresh()這個方法是可以被重復調用的,具體分析看下面 if (!this.refreshEventReceived) { // Either the context is not a ConfigurableApplicationContext with refresh // support or the context injected at construction time had already been // refreshed -> trigger initial onRefresh manually here. onRefresh(wac); } // Publish the context as a servlet context attribute. //如果允許publish Context的話那末就把spring context放入到spring的ServletContext中 if (this.publishContext) { String attrName = getServletContextAttributeName(); getServletContext().setAttribute(attrName, wac); if (this.logger.isDebugEnabled()) { this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() + "' as ServletContext attribute with name [" + attrName + "]"); } } return wac; } //創建and refresh WebApplicationContext protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) { //判斷id if (ObjectUtils.identityToString(wac).equals(wac.getId())) { // The application context id is still set to its original default value // -> assign a more useful id based on available information if (this.contextId != null) { wac.setId(this.contextId); } else { // Generate default id... wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(getServletContext().getContextPath()) + "/" + getServletName()); } } wac.setServletContext(getServletContext()); wac.setServletConfig(getServletConfig()); wac.setNamespace(getNamespace()); //添加針對ContextRefreshListener事件的監聽 //ApplicationListener decorator that filters events from a specified event source, invoking its delegate listener for matching ApplicationEvent objects only. //看了1下英文,大概是用了decorator(裝潢)模式,具體源碼里面,也只是做了1個簡單的裝潢模式,這個類接受所有的ApplicationEvent事件 wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener())); // The wac environment's #initPropertySources will be called in any case when the context // is refreshed; do it eagerly here to ensure servlet property sources are in place for // use in any post-processing or initialization that occurs below prior to #refresh ConfigurableEnvironment env = wac.getEnvironment(); if (env instanceof ConfigurableWebEnvironment) { ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig()); } //Post-process the given WebApplicationContext before it is refreshed //大概就是說,在初始化handlermapping和1些本地化等調用refresh方法之前處理WebApplicationContext,這個類沒有具體實現,開發者可以自己去處理 postProcessWebApplicationContext(wac); //spring dispatcherServlet初始化的時候可以指定初始化1些類 applyInitializers(wac); //這個是重點方法,這里采取了事件的模式進行通知,去調用refresh方法初始化配置 wac.refresh(); } //初始化spring context的時候 初始化1些指定需要初始化的類 這些類需要實現ApplicationContextInitializer 這個接口才能進行調用 protected void applyInitializers(ConfigurableApplicationContext wac) { //獲得到ServletContext中初始化的類數組參數 // String globalClassNames = getServletContext().getInitParameter(ContextLoader.GLOBAL_INITIALIZER_CLASSES_PARAM); if (globalClassNames != null) { //不斷的去初始化這個類數組 以,;\t\n等作為分隔符 for (String className : StringUtils.tokenizeToStringArray(globalClassNames, INIT_PARAM_DELIMITERS)) { this.contextInitializers.add(loadInitializer(className, wac)); } } if (this.contextInitializerClasses != null) { for (String className : StringUtils.tokenizeToStringArray(this.contextInitializerClasses, INIT_PARAM_DELIMITERS)) { this.contextInitializers.add(loadInitializer(className, wac)); } } //排序,可以指定這些類的初始化順序,通過@Order注解來實現排序 AnnotationAwareOrderComparator.sort(this.contextInitializers); //初始化 for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : this.contextInitializers) { initializer.initialize(wac); } } //初始化類, private ApplicationContextInitializer<ConfigurableApplicationContext> loadInitializer( String className, ConfigurableApplicationContext wac) { try { //加載這個類 Class<?> initializerClass = ClassUtils.forName(className, wac.getClassLoader()); //判斷是不是實現了接口ApplicationContextInitializer Class<?> initializerContextClass = GenericTypeResolver.resolveTypeArgument(initializerClass, ApplicationContextInitializer.class); if (initializerContextClass != null && !initializerContextClass.isInstance(wac)) { throw new ApplicationContextException(String.format( "Could not apply context initializer [%s] since its generic parameter [%s] " + "is not assignable from the type of application context used by this " + "framework servlet: [%s]", initializerClass.getName(), initializerContextClass.getName(), wac.getClass().getName())); } //初始化對象 return BeanUtils.instantiateClass(initializerClass, ApplicationContextInitializer.class); } catch (ClassNotFoundException ex) { throw new ApplicationContextException(String.format("Could not load class [%s] specified " + "via 'contextInitializerClasses' init-param", className), ex); } } }

上述代碼獲得root Context的時候可以通過以下代碼了解到獲得方式,webapp的Context對象的保存,其實不過就是把spring的context放到了ServletContext的1個屬性中而已

WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
public abstract class WebApplicationContextUtils { public static WebApplicationContext getWebApplicationContext(ServletContext sc) { return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); } /** * Find a custom {@code WebApplicationContext} for this web app. * @param sc ServletContext to find the web application context for * @param attrName the name of the ServletContext attribute to look for * @return the desired WebApplicationContext for this web app, or {@code null} if none */ public static WebApplicationContext getWebApplicationContext(ServletContext sc, String attrName) { Assert.notNull(sc, "ServletContext must not be null"); //通過從ServletContext 去獲得spring的context對象 Object attr = sc.getAttribute(attrName); if (attr == null) { return null; } if (attr instanceof RuntimeException) { throw (RuntimeException) attr; } if (attr instanceof Error) { throw (Error) attr; } if (attr instanceof Exception) { throw new IllegalStateException((Exception) attr); } if (!(attr instanceof WebApplicationContext)) { throw new IllegalStateException("Context attribute is not of type WebApplicationContext: " + attr); } return (WebApplicationContext) attr; } }

wac = findWebApplicationContext(); 上述這塊邏輯主要是通過獲得ContextAttribute的屬性名去ServletContext中獲得Context對象

protected WebApplicationContext findWebApplicationContext() { String attrName = getContextAttribute(); if (attrName == null) { return null; } WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName); if (wac == null) { throw new IllegalStateException("No WebApplicationContext found: initializer not registered?"); } return wac; }

1.2.2 FrameworkServlet 中refresh源碼解析

這里流程比較繁瑣,重點講述1下 wac.refresh(); 這個方法會調用AbstractApplicationContext這里類面的refresh去實現相應的邏輯,這個類具體的英文解釋(implements common context functionality. Uses the Template Method design pattern) 大概意思就是說實現了1些公有的方法,通過Template Method這類設計模式實現功能,其實也就是將邏輯放到了AbstractApplicationContext中,然后子類去實現各種方法。邏輯已由AbstractApplicationContext定好,子類不關心邏輯

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext, DisposableBean { //準備刷新之前調用 protected void prepareRefresh() { //記錄開始時間 this.startupDate = System.currentTimeMillis(); //改變狀態 this.closed.set(false); this.active.set(true); if (logger.isInfoEnabled()) { logger.info("Refreshing " + this); } // Initialize any placeholder property sources in the context environment //這個主要留給子類去實現 initPropertySources(); // Validate that all properties marked as required are resolvable // see ConfigurablePropertyResolver#setRequiredProperties //校驗必須初始化的參數 getEnvironment().validateRequiredProperties(); // Allow for the collection of early ApplicationEvents, // to be published once the multicaster is available... this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>(); } //初始化1些beanFactory參數 protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // Tell the internal bean factory to use the context's class loader etc. //設置classLoader beanFactory.setBeanClassLoader(getClassLoader()); //設置bean表達式解析器 spring 的el 表達式 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); //使用資源編輯器來填充指定的PropertyEditorRegistry。 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); // Configure the bean factory with context callbacks. //負責注入ResourceLoaderAware, ApplicationEventPublisherAware, MessageSourceAware, ApplicationContextAware ApplicationContext相干特性的Bean beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); beanFactory.ignoreDependencyInterface(EnvironmentAware.class); // BeanFactory interface not registered as resolvable type in a plain factory. // MessageSource registered (and found for autowiring) as a bean. //This is intended for factory/context references that are supposed to be autowirable but are not defined as beans in the factory: e.g. a dependency of type ApplicationContext resolved to the ApplicationContext instance that the bean is living in. //上述英文大概意思就是定義了1個特殊的bean,但是這個bean不通過 beanFactory進行管理生命周期,beanFactory本身就是1個bean,本身管理本身就有點奇怪,所以這個方法是注冊1些特殊的bean,并且可以進行注入 beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); // Detect a LoadTimeWeaver and prepare for weaving, if found. if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); // Set a temporary ClassLoader for type matching. beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } // Register default environment beans. if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); } if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); } if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); } } @Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. //preparecontext之前履行的操作 prepareRefresh(); //告知子類刷新bean工廠,spring boot能夠做到改變1個類進行熱部署,我猜可能就調用了這個刷新方法去刷新bean工廠,所以改變了1些靜態變量spring boot是不會動態刷新的 // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. //初始化1些bean工廠的參數 prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. // 增加處理servletContext的類 postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); //初始化消息源 // Initialize message source for this context. initMessageSource(); //初始化消息事件 // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); //發送refresh事件 // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } } }

AbstractApplicationContext這個類比較繁瑣,這里只大概描寫了1下大概的功能,后續文章會詳細進行講授,這里主要是講授初始化流程

Spring 整體流程圖

Renderings.png?dir=0&filepath=spring%2FsourceCode%2Fimg%2Fdipatcher+%281%29.png&oid=d32d3920eb9fa1afe65c08f70e5e3c3966ddd8e2&sha=de3a2aaf492d9bcacf82f1462d06bd50f6091186)

生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 久久久久久毛片免费看 | 国产激情久久久久影院小草 | 丁香五月网久久综合 | 国产精品久久久久久久av大片 | 久久精品不卡 | 久久99精品久久久久久园产越南 | 中文字幕成人av | 一区在线免费 | 精品毛片 | 亚洲精品国产精品国自产观看浪潮 | 99日韩| 欧美日韩国产色综合一二三四 | www.久久精品 | av资源在线免费观看 | 99精品99| 欧美性猛交xxxx黑人交 | 欧美精品国产一区二区 | 黄色三级在线观看 | 国产午夜精品一区二区 | 国产精选视频在线观看 | 欧美一区二 | 综合久久综合久久 | 尤物国产 | 日韩国产欧美一区二区 | 欧美 亚洲 视频 | 国产精品免费福利 | 欧美在线视频播放 | 日韩成人影院在线观看 | 欧美在线色 | 操操片 | 美女很黄很黄的网站 | 亚洲精品福利电影 | 午夜欧美一区二区三区在线播放 | 亚洲视频在线观看网址 | 亚洲精品不卡 | 久久久性 | 午夜精品一区二区三区在线播放 | 91先生在线观看 | 国产一区二区在线播放视频 | 亚洲色图15p | 亚洲一区二区欧美 |