精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

SpringMVC 初始化流程分析

開發(fā) 前端
框架源碼是我們 Coding 晉級中的必修課,SSM 應(yīng)該算是小伙伴們?nèi)粘=佑|最多的框架了,這其中 SpringMVC 初始化流程相對來說要簡單一些,因此今天松哥就先來和大家分析一下 SpringMVC 初始化流程。

[[387214]]

框架源碼是我們 Coding 晉級中的必修課,SSM 應(yīng)該算是小伙伴們?nèi)粘=佑|最多的框架了,這其中 SpringMVC 初始化流程相對來說要簡單一些,因此今天松哥就先來和大家分析一下 SpringMVC 初始化流程。

即使你沒看過 SpringMVC 的源碼,估計也聽說過:DispatcherServlet 是 SpringMVC 的大腦,它負(fù)責(zé)整個 SpringMVC 的調(diào)度工作,是 SpringMVC 中最最核心的類,SpringMVC 整個頂層架構(gòu)設(shè)計都體現(xiàn)在這里,所以搞明白 DispatcherServlet 的源碼,基本上 SpringMVC 的工作原理也就了然于胸了。

然而 DispatcherServlet 繼承自 FrameworkServlet,F(xiàn)rameworkServlet 又繼承自 HttpServletBean,如下圖:

 

因此我們的分析就從 HttpServletBean 開始。

1.HttpServletBean

HttpServletBean繼承自 HttpServlet,它負(fù)責(zé)將 init-param 中的參數(shù)注入到當(dāng)前 Servlet 實例的屬性中,同時也為子類提供了增加 requiredProperties 的能力,需要注意的是 HttpServletBean 并不依賴于 Spring 容器。

大家知道,HttpServlet 的初始化是從 init 方法開始的,所以我們就先從 HttpServletBean 的 init 方法開始看起:

  1. @Override 
  2. public final void init() throws ServletException { 
  3.  // Set bean properties from init parameters. 
  4.  PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties); 
  5.  if (!pvs.isEmpty()) { 
  6.   try { 
  7.    BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); 
  8.    ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext()); 
  9.    bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment())); 
  10.    initBeanWrapper(bw); 
  11.    bw.setPropertyValues(pvs, true); 
  12.   } 
  13.   catch (BeansException ex) { 
  14.    if (logger.isErrorEnabled()) { 
  15.     logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex); 
  16.    } 
  17.    throw ex; 
  18.   } 
  19.  } 
  20.  // Let subclasses do whatever initialization they like
  21.  initServletBean(); 

在這個方法里,首先獲取到 Servlet 的所有配置并轉(zhuǎn)為 PropertyValues,然后通過 BeanWrapper 修改目標(biāo) Servlet 的相關(guān)屬性。BeanWrapper 是 Spring 中提供一個工具,使用它可以修改一個對象的屬性,像下面這樣:

  1. public class Main { 
  2.     public static void main(String[] args) { 
  3.         User user = new User(); 
  4.         BeanWrapper beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(user); 
  5.         beanWrapper.setPropertyValue("username""itboyhub"); 
  6.         PropertyValue pv = new PropertyValue("address""www.itboyhub.com"); 
  7.         beanWrapper.setPropertyValue(pv); 
  8.         System.out.println("user = " + user); 
  9.     } 

最終輸出:

  1. user = User{username='itboyhub', address='www.itboyhub.com'

所以前面的 bw 實際上就代表當(dāng)前 DispatcherServlet 對象。

通過 BeanWrapper 修改目標(biāo) Servlet 的相關(guān)屬性時,有一個 initBeanWrapper 方法是空方法,開發(fā)者如有需要可以在子類中實現(xiàn)該方法,并且完成一些初始化操作。

屬性配置完成后,最終調(diào)用 initServletBean 方法進(jìn)行 Servlet 初始化,然而該方法也是一個空方法,在子類中實現(xiàn)。

這就是 HttpServletBean 所做的事情,比較簡單,加載 Servlet 相關(guān)屬性并設(shè)置給當(dāng)前 Servlet 對象,然后調(diào)用 initServletBean 方法繼續(xù)完成 Servlet 的初始化操作。

2.FrameworkServlet

從前面的介紹可知,F(xiàn)rameworkServlet 初始化的入口方法就是 initServletBean,因此我們就從 FrameworkServlet#initServletBean 方法開始看起:

  1. @Override 
  2. protected final void initServletBean() throws ServletException { 
  3.  //省略... 
  4.  try { 
  5.   this.webApplicationContext = initWebApplicationContext(); 
  6.   initFrameworkServlet(); 
  7.  } 
  8.  catch (ServletException | RuntimeException ex) { 
  9.   //省略... 
  10.  } 

這個方法原本挺長的,但是拋開日志打印異常拋出,剩下的核心代碼其實就兩行:

initWebApplicationContext 方法用來初始化 WebApplicationContext。

initFrameworkServlet 方法用來初始化 FrameworkServlet,但是這個方法是一個空方法,沒有具體的實現(xiàn)。本來子類可以重寫該方法做一些初始化操作,但是實際上子類并沒有重寫該方法,所以這個方法我們就暫且忽略之,不去分析了。

那么這里最為重要的其實就是 initWebApplicationContext 方法了,我們一起來看下:

  1. protected WebApplicationContext initWebApplicationContext() { 
  2.  WebApplicationContext rootContext = 
  3.    WebApplicationContextUtils.getWebApplicationContext(getServletContext()); 
  4.  WebApplicationContext wac = null
  5.  if (this.webApplicationContext != null) { 
  6.   wac = this.webApplicationContext; 
  7.   if (wac instanceof ConfigurableWebApplicationContext) { 
  8.    ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac; 
  9.    if (!cwac.isActive()) { 
  10.     if (cwac.getParent() == null) { 
  11.      cwac.setParent(rootContext); 
  12.     } 
  13.     configureAndRefreshWebApplicationContext(cwac); 
  14.    } 
  15.   } 
  16.  } 
  17.  if (wac == null) { 
  18.   wac = findWebApplicationContext(); 
  19.  } 
  20.  if (wac == null) { 
  21.   wac = createWebApplicationContext(rootContext); 
  22.  } 
  23.  if (!this.refreshEventReceived) { 
  24.   synchronized (this.onRefreshMonitor) { 
  25.    onRefresh(wac); 
  26.   } 
  27.  } 
  28.  if (this.publishContext) { 
  29.   String attrName = getServletContextAttributeName(); 
  30.   getServletContext().setAttribute(attrName, wac); 
  31.  } 
  32.  return wac; 

這里的邏輯也比較清晰:

1.首先獲取 rootContext。在默認(rèn)情況下,Spring 會將容器設(shè)置為 ServletContext 的一個屬性,屬性的 key 為 org.springframework.web.context.WebApplicationContext.ROOT,所以根據(jù)這個 key 就可以調(diào)用 ServletContext#getAttribute 方法獲取到 rootContext 了。

2.獲取 WebApplicationContext 實例,也就是給 wac 變量賦值的過程,這里存在三種可能性:1.如果已經(jīng)通過構(gòu)造方法給 webApplicationContext 賦值了,則直接將其賦給 wac 變量,同時,如果需要設(shè)置 parent 就設(shè)置,需要刷新就刷新。這種方式適用于 Servlet3.0 以后的環(huán)境,因為從 Servlet3.0 開始,才支持直接調(diào)用 ServletContext.addServlet 方法去注冊 Servlet,手動注冊的時候就可以使用自己提前準(zhǔn)備好的 WebApplicationContext 了,這塊松哥在我錄制的 Spring Boot 視頻中也講過,感興趣的小伙伴可以在公眾號后臺回復(fù) vhr 查看視頻詳情;2.如果第一步?jīng)]能成功給 wac 賦值,那么調(diào)用 findWebApplicationContext 方法嘗試去 ServletContext 中查找 WebApplicationContext 對象,找到了就賦值給 wac;3.如果第二步?jīng)]能成功給 wac 賦值,那么調(diào)用 createWebApplicationContext 方法創(chuàng)建一個 WebApplicationContext 對象并賦值給 wac,一般來說都是通過這種方式創(chuàng)建的 WebApplicationContext。這三套組合拳下來,wac 肯定是有值了。

3.當(dāng) ContextRefreshedEvent 事件沒有觸發(fā)時,調(diào)用 onRefresh 方法完成容器刷新(由于第一種和第三種獲取 WebApplicationContext 的方式最終都會調(diào)用 configureAndRefreshWebApplicationContext 方法,然后發(fā)布事件,再將 refreshEventReceived 變量標(biāo)記為 true,所以實際上只有第二種方式獲取 wac 實例的時候,這里才會刷新,具體可以看下文分析)。

4.最后將 wac 保存到到 ServletContext 中。保存的時候會根據(jù) publishContext 變量的值來決定是否保存,publishContext 可以在 web.xml 中配置 Servlet 時通過 init-param 進(jìn)行配置,保存的目的是為了方便獲取。

上面的這些步驟中,通過 createWebApplicationContext 方法創(chuàng)建 WebApplicationContext 對象需要和大家細(xì)說下,因為一般情況下就是通過這種方式創(chuàng)建的 WebApplicationContext。我們來看一下相關(guān)的方法:

  1. protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) { 
  2.  Class<?> contextClass = getContextClass(); 
  3.  if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) { 
  4.   throw new ApplicationContextException( 
  5.     "Fatal initialization error in servlet with name '" + getServletName() + 
  6.     "': custom WebApplicationContext class [" + contextClass.getName() + 
  7.     "] is not of type ConfigurableWebApplicationContext"); 
  8.  } 
  9.  ConfigurableWebApplicationContext wac = 
  10.    (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); 
  11.  wac.setEnvironment(getEnvironment()); 
  12.  wac.setParent(parent); 
  13.  String configLocation = getContextConfigLocation(); 
  14.  if (configLocation != null) { 
  15.   wac.setConfigLocation(configLocation); 
  16.  } 
  17.  configureAndRefreshWebApplicationContext(wac); 
  18.  return wac; 
  19. protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) { 
  20.  if (ObjectUtils.identityToString(wac).equals(wac.getId())) { 
  21.   // The application context id is still set to its original default value 
  22.   // -> assign a more useful id based on available information 
  23.   if (this.contextId != null) { 
  24.    wac.setId(this.contextId); 
  25.   } 
  26.   else { 
  27.    // Generate default id... 
  28.    wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + 
  29.      ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName()); 
  30.   } 
  31.  } 
  32.  wac.setServletContext(getServletContext()); 
  33.  wac.setServletConfig(getServletConfig()); 
  34.  wac.setNamespace(getNamespace()); 
  35.  wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener())); 
  36.  // The wac environment's #initPropertySources will be called in any case when the context 
  37.  // is refreshed; do it eagerly here to ensure servlet property sources are in place for 
  38.  // use in any post-processing or initialization that occurs below prior to #refresh 
  39.  ConfigurableEnvironment env = wac.getEnvironment(); 
  40.  if (env instanceof ConfigurableWebEnvironment) { 
  41.   ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig()); 
  42.  } 
  43.  postProcessWebApplicationContext(wac); 
  44.  applyInitializers(wac); 
  45.  wac.refresh(); 

這里一共涉及到兩個方法:

createWebApplicationContext

首先獲取到創(chuàng)建類型,并檢查創(chuàng)建類型,沒問題的話調(diào)用 instantiateClass 方法完成創(chuàng)建工作,然后給創(chuàng)建好的 wac 對象配置各種屬性,配置的 configLocation 就是我們在 web.xml 文件中配置的 SpringMVC 配置文件路徑,默認(rèn)的文件路徑是/WEB-INF/[servletName]-servlet.xml。

configureAndRefreshWebApplicationContext

configureAndRefreshWebApplicationContext 方法主要也是配置&刷新 WebApplicationContext,在這個方法里會調(diào)用 addApplicationListener 為 wac 添加一個監(jiān)聽器,監(jiān)聽的是 ContextRefreshedEvent 事件,當(dāng)收到該事件后,會調(diào)用 FrameworkServlet 的 onApplicationEvent 方法,并在該方法中調(diào)用 onRefresh 方法完成刷新,刷新之后,會將 refreshEventReceived 變量標(biāo)記為 true。

  1. public void onApplicationEvent(ContextRefreshedEvent event) { 
  2.  this.refreshEventReceived = true
  3.  synchronized (this.onRefreshMonitor) { 
  4.   onRefresh(event.getApplicationContext()); 
  5.  } 

這就是 FrameworkServlet#initServletBean 方法的大致工作邏輯。這里涉及到了 onRefresh 方法,但是這是一個空方法,在子類 DispatcherServlet 中實現(xiàn)了,所以接下來我們就來看 DispatcherServlet。

3.DispatcherServlet

這里我們就不廢話了,直接來看 onRefresh 方法,如下:

  1. @Override 
  2. protected void onRefresh(ApplicationContext context) { 
  3.  initStrategies(context); 
  4. protected void initStrategies(ApplicationContext context) { 
  5.  initMultipartResolver(context); 
  6.  initLocaleResolver(context); 
  7.  initThemeResolver(context); 
  8.  initHandlerMappings(context); 
  9.  initHandlerAdapters(context); 
  10.  initHandlerExceptionResolvers(context); 
  11.  initRequestToViewNameTranslator(context); 
  12.  initViewResolvers(context); 
  13.  initFlashMapManager(context); 

在 onRefresh 方法中調(diào)用了 initStrategies 進(jìn)行初始化操作。initStrategies 的內(nèi)容其實很簡單,就是九個組件的初始化。九個的初始化流程比較類似,這里我們以常見的視圖解析器的初始化方法 initViewResolvers 為例,來一起看看初始化流程:

  1. private void initViewResolvers(ApplicationContext context) { 
  2.  this.viewResolvers = null
  3.  if (this.detectAllViewResolvers) { 
  4.   // Find all ViewResolvers in the ApplicationContext, including ancestor contexts. 
  5.   Map<String, ViewResolver> matchingBeans = 
  6.     BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, truefalse); 
  7.   if (!matchingBeans.isEmpty()) { 
  8.    this.viewResolvers = new ArrayList<>(matchingBeans.values()); 
  9.    // We keep ViewResolvers in sorted order
  10.    AnnotationAwareOrderComparator.sort(this.viewResolvers); 
  11.   } 
  12.  } 
  13.  else { 
  14.   try { 
  15.    ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class); 
  16.    this.viewResolvers = Collections.singletonList(vr); 
  17.   } 
  18.   catch (NoSuchBeanDefinitionException ex) { 
  19.    // Ignore, we'll add a default ViewResolver later. 
  20.   } 
  21.  } 
  22.  // Ensure we have at least one ViewResolver, by registering 
  23.  // a default ViewResolver if no other resolvers are found. 
  24.  if (this.viewResolvers == null) { 
  25.   this.viewResolvers = getDefaultStrategies(context, ViewResolver.class); 
  26.   if (logger.isTraceEnabled()) { 
  27.    logger.trace("No ViewResolvers declared for servlet '" + getServletName() + 
  28.      "': using default strategies from DispatcherServlet.properties"); 
  29.   } 
  30.  } 

一開始的 viewResolvers 變量是一個集合,解析出來的視圖解析器對象都將放入這個集合中。

首先判斷 detectAllViewResolvers 變量是否為 true,如果為 true,則直接去查找 Spring 容器中的所有視圖解析器,將查找結(jié)果賦值給 viewResolvers,然后進(jìn)行排序。默認(rèn)情況下 detectAllViewResolvers 變量的值為 true,如果有需要,可以在 web.xml 中進(jìn)行配置,像下面這樣:

  1. <servlet> 
  2.     <servlet-name>springmvc</servlet-name
  3.     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
  4.     <init-param> 
  5.         <param-name>contextConfigLocation</param-name
  6.         <param-value>classpath:spring-servlet.xml</param-value> 
  7.     </init-param> 
  8.     <init-param> 
  9.         <param-name>detectAllViewResolvers</param-name
  10.         <param-value>false</param-value> 
  11.     </init-param> 
  12.     <load-on-startup>1</load-on-startup> 
  13. </servlet> 
  14. <servlet-mapping> 
  15.     <servlet-name>springmvc</servlet-name
  16.     <url-pattern>/</url-pattern> 
  17. </servlet-mapping> 

如果 detectAllViewResolvers 的值為 false,那么接下來就會去 Spring 容器中查找一個名為 viewResolver 的視圖解析器,此時查找到的就是一個單獨的視圖解析器。

一般來說,我們并不需要在 web.xml 中去配置 detectAllViewResolvers 的值,視圖解析器有多少個就加載多少個。

舉個簡單例子,我們在 SpringMVC 的配置文件中可能像下面這樣配置視圖解析器:

  1. <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="viewResolver"
  2.     <property name="prefix" value="/WEB-INF/jsp/"/> 
  3.     <property name="suffix" value=".jsp"/> 
  4. </bean> 

默認(rèn)情況下,這個 bean 的 id 有沒有都行,如果有,取什么值都可以,反正最終都是通過類型而不是 id 去查找的視圖解析器。但是如果你在 web.xml 中將 detectAllViewResolvers 修改為 false,那么這個 bean 的 id 取值就比較重要了,就一定要是 viewResolver。

如果在 Spring 容器中通過這兩種方式(通過類型查找或通過 id 查找)都沒有找到 ViewResolver 實例,那么會調(diào)用 getDefaultStrategies 方法去獲取一個默認(rèn)的 ViewResolver 實例。默認(rèn)實例的獲取方式如下:

 

  1. protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) { 
  2.  if (defaultStrategies == null) { 
  3.   try { 
  4.    // Load default strategy implementations from properties file. 
  5.    // This is currently strictly internal and not meant to be customized 
  6.    // by application developers. 
  7.    ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class); 
  8.    defaultStrategies = PropertiesLoaderUtils.loadProperties(resource); 
  9.   } 
  10.   catch (IOException ex) { 
  11.    throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage()); 
  12.   } 
  13.  } 
  14.  String key = strategyInterface.getName(); 
  15.  String value = defaultStrategies.getProperty(key); 
  16.  if (value != null) { 
  17.   String[] classNames = StringUtils.commaDelimitedListToStringArray(value); 
  18.   List<T> strategies = new ArrayList<>(classNames.length); 
  19.   for (String className : classNames) { 
  20.    try { 
  21.     Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader()); 
  22.     Object strategy = createDefaultStrategy(context, clazz); 
  23.     strategies.add((T) strategy); 
  24.    } 
  25.    catch (ClassNotFoundException ex) { 
  26.     throw new BeanInitializationException( 
  27.       "Could not find DispatcherServlet's default strategy class [" + className + 
  28.       "] for interface [" + key + "]", ex); 
  29.    } 
  30.    catch (LinkageError err) { 
  31.     throw new BeanInitializationException( 
  32.       "Unresolvable class definition for DispatcherServlet's default strategy class [" + 
  33.       className + "] for interface [" + key + "]", err); 
  34.    } 
  35.   } 
  36.   return strategies; 
  37.  } 
  38.  else { 
  39.   return Collections.emptyList(); 
  40.  } 

這段代碼其實也比較簡單,就是通過反射去獲取默認(rèn)的視圖解析器。

首先給 defaultStrategies 賦值,defaultStrategies 的值實際上就是從 DispatcherServlet.properties 文件中加載到的,我們來看下這個文件內(nèi)容:

 

可以看到,這里一共定義了 8 個默認(rèn)的鍵值對,有的值是一個,有的值是多個。前面 initStrategies 方法中一共要初始化九個組件,這里默認(rèn)只定義了 8 個,少了一個 MultipartResolver,這也好理解,并非所有的項目都有文件上傳,而且即使有文件上傳,用哪一個具體的 MultipartResolver 也不好確定,還是要開發(fā)者自己決定。

defaultStrategies 其實加載到的就是這 8 個鍵值對,其中視圖解析器對應(yīng)的是 org.springframework.web.servlet.view.InternalResourceViewResolver,通過反射創(chuàng)建該類的實例,當(dāng) Spring 容器中不存在任何視圖解析器的時候,默認(rèn)的視圖解析器即此。

這就是 initViewResolvers 的工作流程,另外 8 個也和它差不多,唯一不同的是 initMultipartResolver,如下:

  1. private void initMultipartResolver(ApplicationContext context) { 
  2.  try { 
  3.   this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class); 
  4.  } 
  5.  catch (NoSuchBeanDefinitionException ex) { 
  6.   this.multipartResolver = null
  7.  } 

可以看到,它只是根據(jù) bean 的名字去查找 bean 實例,沒有去查找默認(rèn)的 MultipartResolver。

說到這里,松哥和大家多說一句 SpringMVC 配置中的小細(xì)節(jié),

  1. <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="viewResolver"
  2.     <property name="prefix" value="/WEB-INF/jsp/"/> 
  3.     <property name="suffix" value=".jsp"/> 
  4. </bean> 
  5. <bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver"
  6. </bean> 

上面這個關(guān)于視圖解析器和文件上傳解析器的配置,不知道小伙伴們有沒有注意過,視圖解析器的 id 可有可無,而文件上傳解析器的 id 必須是 multipartResolver,回顧我們上面的源碼分析,你就知道為啥了!

4.小結(jié)

好啦,這就是松哥和小伙伴們分享的 SpringMVC 的初始化流程,主要涉及到了 HttpServletBean、FrameworkServlet 以及 DispatcherServlet 三個實例,HttpServletBean 主要是加載 Servlet 配置的各種屬性并設(shè)置到 Servlet 上;FrameworkServlet 則主要是初始化了 WebApplicationContext;DispatcherServlet 則主要是初始化了自身的九個組件。

這只是初始化的流程,那么當(dāng)請求到來之后,請求的流程又是怎么樣的呢?這個松哥下篇文章來和大家分享~好啦,今天就先和小伙伴們聊這么多。

本文轉(zhuǎn)載自微信公眾號「江南一點雨」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系江南一點雨公眾號。

 

責(zé)任編輯:武曉燕 來源: 江南一點雨
相關(guān)推薦

2022-07-06 10:37:45

SpringServlet初始化

2023-05-03 23:48:24

Spring容器初始化

2009-09-17 16:06:22

C#數(shù)組初始化

2010-06-04 15:47:46

MySQL初始化roo

2023-11-12 23:08:17

C++初始化

2025-05-21 10:09:09

Spring 5.xIOC編程

2025-03-14 10:37:24

SpringSpring IOC容器

2022-05-10 10:06:03

Kafka

2009-09-08 09:48:34

LINQ初始化數(shù)組

2009-11-11 15:29:15

ADO初始化

2019-11-04 13:50:36

Java數(shù)組編程語言

2010-07-28 10:22:33

FlexApplica

2020-12-03 09:50:52

容器IoC流程

2011-06-17 15:29:44

C#對象初始化器集合初始化器

2024-01-15 06:34:09

Gin鏡像容器

2009-09-18 11:15:52

C#數(shù)組初始化

2009-09-25 16:55:08

Hibernate初始

2011-03-16 10:52:20

2009-12-16 14:04:04

Ruby對象初始化

2021-12-26 00:08:35

C++初始化列表
點贊
收藏

51CTO技術(shù)棧公眾號

国产精品一区二区三区av麻| 无遮挡爽大片在线观看视频| 国内久久婷婷综合| 九九热最新视频//这里只有精品| 日本50路肥熟bbw| 美女av在线免费看| 欧美国产精品一区| 欧美tickling挠脚心丨vk| 日韩欧美猛交xxxxx无码| 天天射天天操天天干| 日本女优在线视频一区二区| 久久69精品久久久久久久电影好| 色噜噜在线观看| 色婷婷成人网| 亚洲sss视频在线视频| 亚洲不卡一卡2卡三卡4卡5卡精品| 亚洲一区二区影视| 99国产精品久久久久久久成人热| 中文字幕日韩精品在线| 亚洲午夜久久久久久久久| 在线成人视屏 | 88国产精品视频一区二区三区| 精品国产伦一区二区三区免费| 免费看污黄网站| 97在线超碰| 亚洲欧美综合另类在线卡通| 免费久久99精品国产自| www.热久久| 久久激情综合网| 国产亚洲欧洲在线| 丰满人妻中伦妇伦精品app| 色影院视频在线| 成人天堂资源www在线| 91精品美女在线| 国产伦精品一区二区三区视频网站| 你懂的亚洲视频| 中文字幕在线亚洲| www.中文字幕av| 久久资源综合| 精品日韩在线观看| 日本特黄在线观看| 伦理在线一区| 国产精品视频免费| 日本一区二区精品视频| 黄色aaa大片| 国产v日产∨综合v精品视频| 成人精品一区二区三区| 中文字幕在线观看精品| 日韩经典中文字幕一区| 日本高清不卡在线| 成年人免费看毛片| 亚洲欧洲一区二区天堂久久| 欧美精品福利在线| 2021亚洲天堂| 最新国产精品| 欧美日韩国产成人| 久一视频在线观看| 黄色一区二区三区四区| 久久久久国产精品免费网站| 无码人妻精品一区二区三区夜夜嗨 | 欧美在线你懂得| 国产情侣av自拍| 精品亚洲美女网站| 欧洲精品在线观看| 亚洲三级视频网站| 97成人超碰| 欧美久久久久久蜜桃| 国内av一区二区| 欧美日韩黄色| 亚洲风情亚aⅴ在线发布| 性农村xxxxx小树林| 麻豆成人入口| 亚洲美女免费精品视频在线观看| 法国伦理少妇愉情| 激情五月色综合国产精品| 自拍视频国产精品| 精品一区在线观看视频| 黄色精品免费| 日本成熟性欧美| 影音先锋国产资源| 国产精品白丝jk白祙喷水网站 | 人妻夜夜爽天天爽| 91一区二区在线观看| 日本一区二区三区www| 黄色网址免费在线观看| 亚洲伊人伊色伊影伊综合网| 国产青青在线视频| 99精品在免费线偷拍| 91精品国产日韩91久久久久久| 制服下的诱惑暮生| 亚洲品质自拍| 久久亚洲精品小早川怜子66| 免费一级全黄少妇性色生活片| 国产亚洲精品自拍| 国产欧美精品va在线观看| 亚洲精品一区二区三区区别 | 亚洲综合一区在线| 欧美亚洲另类色图| 欧美xxxx做受欧美88bbw| 亚洲丰满少妇videoshd| 中文精品一区二区三区| 麻豆av在线免费观看| 欧美亚洲综合一区| 超碰人人cao| 精品国产精品久久一区免费式| 另类色图亚洲色图| 色av性av丰满av| 国产乱妇无码大片在线观看| 欧美在线一区二区三区四区| 宅男网站在线免费观看| 在线一区二区三区四区五区| 乱码一区二区三区| 日韩欧美中文| 欧美在线视频一区二区| 国产高清不卡视频| 亚洲国产精品成人综合| 欧美亚洲精品一区二区| 丁香花在线电影小说观看| 色婷婷综合久久久| 看av免费毛片手机播放| 成人综合日日夜夜| 亚洲人成网站免费播放| 亚洲熟妇无码av| 女同性一区二区三区人了人一| 国产999在线观看| 亚洲精选一区二区三区| 国产精品久久久久aaaa| 欧美a在线视频| 96sao在线精品免费视频| 欧美不卡在线视频| 男人av资源站| 日韩精品一区第一页| 激情一区二区三区| 视频在线观看入口黄最新永久免费国产| 欧日韩精品视频| 欧美做受喷浆在线观看| 精品99视频| 亚洲综合国产精品| 黄网站视频在线观看| 欧美网站一区二区| 法国空姐电影在线观看| 免费中文字幕日韩欧美| 久久久久久久久一区| ****av在线网毛片| 亚洲成人精品视频在线观看| 精品无码一区二区三区电影桃花| 国产一区二区三区av电影 | 亚洲在线观看视频| 麻豆最新免费在线视频| 欧美日韩国产首页在线观看| 亚洲av毛片在线观看| 99精品电影| 成人欧美一区二区三区黑人孕妇| 永久av在线| 欧美午夜电影在线播放| 来吧亚洲综合网| 国产综合久久久久久久久久久久| 91制片厂免费观看| 国产99在线观看| 亚洲国产欧美在线成人app| 精品人妻一区二区三区视频| 午夜在线精品| 品久久久久久久久久96高清| 国产成人免费9x9x人网站视频| 国产亚洲美女久久| 91在线视频国产| 成人国产精品免费观看| 先锋影音亚洲资源| 成人在线免费电影网站| 精品国产一区二区三区在线观看| 久久久久久久麻豆| 狠狠v欧美v日韩v亚洲ⅴ| 日本道在线视频| 国产欧美自拍一区| 青草热久免费精品视频| 在线观看黄色av| 91精品免费在线观看| 欧美一区二区三区成人精品| 久热国产精品| 自拍偷拍视频在线| 成人动漫视频| 国产不卡av在线免费观看| av资源网在线观看| 日韩三级.com| √资源天堂中文在线| 久久66热偷产精品| 毛片在线视频观看| 亚洲免费成人av在线| 国产精品视频久久久| 婷婷色在线资源| 亚洲免费av网址| 国产美女自慰在线观看| 无码av中文一区二区三区桃花岛| 亚洲精品国产一区黑色丝袜| 精品一二三四区| 欧美在线一区视频| 日韩电影免费在线观看| 国产区欧美区日韩区| 国产乱子精品一区二区在线观看| 欧美国产视频日韩| 搞黄视频在线观看| 精品国产成人系列| 91国产精品一区| 精品色蜜蜜精品视频在线观看| 99国产精品免费视频| 久久久久久黄| 97免费视频观看| 欧美大黑bbbbbbbbb在线| 国产在线欧美日韩| 国产一区二区视频在线看| 热草久综合在线| 在线电影福利片| 在线视频欧美日韩精品| 少妇高潮久久久| 9191国产精品| а中文在线天堂| 精品久久久久久电影| 日韩成人毛片视频| 日本一区二区免费在线| 午夜久久久久久久| 国产精品综合视频| 久久综合久久美利坚合众国| 精品国产一区久久| 美女av免费看| 91丨九色丨黑人外教| 不卡的一区二区| 久久爱另类一区二区小说| 免费观看精品视频| 精品福利av| 久久久天堂国产精品| 日韩综合一区| 日韩精品久久久毛片一区二区| 国产一区二区在线视频你懂的| 成人在线中文字幕| 不卡亚洲精品| 日韩免费精品视频| 色偷偷色偷偷色偷偷在线视频| 欧美贵妇videos办公室| a级在线观看| 久久久www成人免费精品| 浮生影视网在线观看免费| 亚洲欧美日本另类| 男同在线观看| 亚洲欧美成人网| 欧美xxx.com| 亚洲人成亚洲人成在线观看| 青青草观看免费视频在线| 日韩av影片在线观看| 蜜桃视频在线观看www| 欧美va亚洲va国产综合| 亚洲黄色片视频| 亚洲成av人乱码色午夜| 六月丁香综合网| 亚洲成av人影院在线观看| 黄频在线免费观看| 亚洲精品国精品久久99热| 少妇人妻一区二区| 日韩毛片在线看| 十九岁完整版在线观看好看云免费| 夜色激情一区二区| 免费在线视频观看| 亚洲国产精品精华液网站| 日本少妇bbwbbw精品| 精品久久久久国产| www.久久久久久久| 日韩毛片精品高清免费| 波多野结衣家庭教师| 一区二区三区欧美日韩| 99免费在线观看| 日韩欧美中文免费| 中文字幕在线观看1| 欧美一区二区三区在线视频| 亚洲黄色精品视频| 亚洲人成电影网站| 日本视频不卡| 久久久人成影片一区二区三区| 亚洲涩涩在线| 国产精品自拍偷拍视频| 嫩呦国产一区二区三区av| 国产美女精品久久久| 美女毛片一区二区三区四区| 91九色蝌蚪成人| 农村少妇一区二区三区四区五区| 欧美激情视频一区二区三区| 四虎成人精品永久免费av九九| 男女爱爱视频网站| 亚洲深夜激情| 亚洲精品手机在线观看| 成人精品视频一区二区三区 | 在线观看免费观看在线| 日韩你懂的电影在线观看| 欧洲视频在线免费观看| 日韩亚洲欧美中文在线| 岛国毛片av在线| 国产精品日韩欧美大师| 日韩一二三区在线观看| 女同一区二区| 女生裸体视频一区二区三区| 国模杨依粉嫩蝴蝶150p| 国产精品99久久久| 中文字幕在线观看免费高清| 一区二区三区加勒比av| 久草热在线观看| 亚洲精品wwww| 国产三级在线播放| 国产va免费精品高清在线观看| 日韩高清在线观看一区二区| 你懂的视频在线一区二区| 欧美一区二区三区久久精品茉莉花| 日本精品免费在线观看| 国产精品99精品久久免费| 欧美18—19性高清hd4k| 午夜伦理一区二区| 国产一区二区女内射| 亚洲欧美另类中文字幕| segui88久久综合9999| 91久久久在线| 日韩在线不卡| 久章草在线视频| av成人老司机| 麻豆91精品91久久久| 欧美美女直播网站| 黄网在线免费| 在线播放国产精品| 爱啪啪综合导航| 亚洲综合在线播放| 久久免费av| 国产理论在线播放| 91色porny在线视频| 久久久久久久伊人| 欧美一区二区三区日韩视频| 在线播放毛片| 国产精品爱啪在线线免费观看| 亚洲免费专区| 欧美精品99久久| 99这里都是精品| 日本中文字幕免费| 亚洲成人网在线观看| 少女频道在线观看高清 | 国产精品久久久网站| 国产 欧美 日本| 国产成人精品午夜视频免费| 黄色片在线观看网站| 91精品国产免费| www.久久久久.com| 69174成人网| 欧美在线三级| 俄罗斯女人裸体性做爰| 一区二区三区波多野结衣在线观看 | 日韩视频一区二区三区在线播放| 免费av在线播放| 91精品视频在线免费观看| 91tv官网精品成人亚洲| aaa一级黄色片| 亚洲欧美欧美一区二区三区| 国产高清免费在线观看| 久久久久女教师免费一区| 成人搞黄视频| 精品无码一区二区三区在线| 91在线你懂得| 五月天婷婷导航| 日韩一级裸体免费视频| 999色成人| 美女黄色免费看| 久久综合久久综合久久| 亚洲中文字幕无码爆乳av| 中文字幕日韩综合av| 成人激情久久| 老太脱裤让老头玩ⅹxxxx| 久久久久一区二区三区四区| 姑娘第5集在线观看免费好剧| 久久精品国产亚洲精品| 中文字幕一区二区三区中文字幕| 国产黄页在线观看| 久久精品亚洲乱码伦伦中文| 在线视频播放大全| 欧美人成在线视频| 亚洲国产国产| 欧美视频亚洲图片| 午夜精品福利一区二区三区蜜桃| 美国成人毛片| 91中文字幕在线| 国产一区二区三区久久久久久久久| 免费看黄色av| 日韩欧美高清dvd碟片| 性感女国产在线| 中文字幕一区二区三区最新| 国产99久久久国产精品潘金| 91久久国产综合久久91| 久久精品人人爽| 群体交乱之放荡娇妻一区二区| 污污网站免费看| 午夜精品久久久久久久久| av在线电影网| 国产伦精品一区| 蜜桃视频第一区免费观看| 日本免费一二三区| 日韩性xxxx爱| 久久91成人| 日本精品一二三区|