回顾

Spring 容器初始化流程(中)中我们分析了bean工厂的后置处理器注册调用、Bean后置处理器的注册、国际化、事件广播器等 ,在最后的篇幅中,我们将会分析上下文的监听器注册,及容器生命周期等相关源码。在最后还会附上一张较为完整的容器初始化流程图哦~

开始吧~

10. registerListeners

在所有 beanDefinition 中查找 listener bean,然后注册到广播器中

// AbstractApplicationContext.java

protected void registerListeners() {
    // 首先注册静态指定的侦听器。
    for (ApplicationListener<?> listener : getApplicationListeners()) {
        getApplicationEventMulticaster().addApplicationListener(listener);
    }

    // Do not initialize FactoryBeans here: We need to leave all regular beans
    // uninitialized to let post-processors apply to them!
    // 不要在这里初始化 FactoryBean:需要将所有常规 bean 保持未初始化状态,以便后处理器适用于它们!
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, truefalse);
    for (String listenerBeanName : listenerBeanNames) {
        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    }

    // 至此,已经完成将监听器注册到ApplicationEventMulticaster中,下面将发布前期的事件给监听器。
    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    this.earlyApplicationEvents = null;
    if (earlyEventsToProcess != null) {
        for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
            getApplicationEventMulticaster().multicastEvent(earlyEvent);
        }
    }
}
11. finishBeanFactoryInitialization

初始化剩下的单例Bean(非延迟加载的)

流程如下:

然后来看看源码:

// AbstractApplicationContext.java

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // 初始化转换器
    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));
    }

    // 如果之前没有注册 bean 后置处理器(例如PropertyPlaceholderConfigurer),则注册默认的解析器
    if (!beanFactory.hasEmbeddedValueResolver()) {
        beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
    }

    // 初始化LoadTimeWeaverAware类型的bean LoadTimeWeaverAware是类加载时进行织入
    String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, falsefalse);
    for (String weaverAwareName : weaverAwareNames) {
        getBean(weaverAwareName);
    }

    // 停止使用临时类加载器进行类型匹配。
    beanFactory.setTempClassLoader(null);

    // 冻结之前beandifinition的配置,留作后面的缓存用
    beanFactory.freezeConfiguration();

    // 初始化所有剩余的单例(非延迟初始化)
    beanFactory.preInstantiateSingletons();
}
11.1 `LoadTimeWeaverAware`

Spring使用LoadTimeWeaver在将类加载到Java虚拟机(JVM)时动态转换类。

11.2 `freezeConfiguration`

只是更新容器的配置状态和BeanDefinitionNames缓存

// DefaultListableBeanFactory.java

/** 是否可以缓存所有bean的bean定义元数据。 */
private volatile boolean configurationFrozen = false;

/** 缓存的bean定义名数组。 */
@Nullable
private volatile String[] frozenBeanDefinitionNames;

@Override
public void freezeConfiguration() {
    this.configurationFrozen = true;
    this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames);
}
11.3 `preInstantiateSingletons`

初始化所有剩余的单例(非延迟初始化),结合上面的流程图和注释

// DefaultListableBeanFactory.java

@Override
public void preInstantiateSingletons() throws BeansException {
    if (logger.isTraceEnabled()) {
        logger.trace("Pre-instantiating singletons in " + this);
    }

    // 迭代副本以允许 init 方法,这些方法反过来注册新的 Bean 定义。
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

    // 初始化所有非lazy init的bean
    for (String beanName : beanNames) {
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            // 非抽象的单例类,且lazy init为false
            if (isFactoryBean(beanName)) {
                // 工厂bean
                Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                if (bean instanceof FactoryBean) {
                    final FactoryBean<?> factory = (FactoryBean<?>) bean;
                    boolean isEagerInit;
                    // 判断工厂bean是否需要优先初始化
                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                        isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
                                        ((SmartFactoryBean<?>) factory)::isEagerInit,
                                getAccessControlContext());
                    }
                    else {
                        isEagerInit = (factory instanceof SmartFactoryBean &&
                                ((SmartFactoryBean<?>) factory).isEagerInit());
                    }
                    if (isEagerInit) {
                        // 初始化工厂bean
                        getBean(beanName);
                    }
                }
            }
            else {
                // 非工厂bean,直接初始化
                getBean(beanName);
            }
        }
    }

    // 为所有适用的bean触发初始化后的回调…
    for (String beanName : beanNames) {
        // 获取单例实例
        Object singletonInstance = getSingleton(beanName);
        if (singletonInstance instanceof SmartInitializingSingleton) {
            // 如果是 SmartInitializingSingleton 类型的实例,则调用其单例初始化后的回调方法
            final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                    smartSingleton.afterSingletonsInstantiated();
                    return null;
                }, getAccessControlContext());
            }
            else {
                smartSingleton.afterSingletonsInstantiated();
            }
        }
    }
}

11.3.1 getSingleton

这里是真正初始化的逻辑:

// DefaultListableBeanFactory.java

@Override
@Nullable
public Object getSingleton(String beanName) {
    return getSingleton(beanName, true);
}

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 先从单例缓存中取,取到就直接返回
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        // 如果取不到,且单例正在初始化中
        synchronized (this.singletonObjects) {
            // 从早期初始化的缓存中取(在loadBeanDefinition的时候可能触发了并完成了实例化)
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                // 如果没取到,并且允许从早期引用中获取(在loadBeanDefinition时触发但未完成实例化)
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    // 如果能获取到早期的对象工厂,就调用对象工厂的getObject方法获取单例实例
                    singletonObject = singletonFactory.getObject();
                    // 设置到早期单例缓存对象中,以便其他依赖bean获取
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    // 移除早期的单例对象工厂
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

结合注释,比较清楚的逻辑

12. finishRefresh

完成刷新过程,通知生命周期处理器 lifecycleProcessor 刷新过程,同时发出 ContextRefreshEvent 通知别人

主要是调用 LifecycleProcessor#onRefresh() ,并且发布事件(ContextRefreshedEvent)。

// AbstractApplicationContext.java

protected void finishRefresh() {
    // 清除上下文级资源缓存(如扫描中的 ASM 元数据)。
    clearResourceCaches();

    // 初始化上下文的生命周期处理器。
    initLifecycleProcessor();

    // 通知实现了Lifecycle的bean容器已经完成刷新
    getLifecycleProcessor().onRefresh();

    // 发布刷新完成事件。
    publishEvent(new ContextRefreshedEvent(this));

    // 如果配置了pring.liveBeansView.mbeanDomain属性,就尝试注册到JVM平台的MBeanServer中
    // 以便通过JXM来实时查看上下文中注册了哪些bean
    LiveBeansView.registerApplicationContext(this);
}
12.1 `clearResourceCaches`
// AbstractApplicationContext.java

public void clearResourceCaches() {
    this.resourceCaches.clear();
}
12.2 `initLifecycleProcessor`
// AbstractApplicationContext.java

protected void initLifecycleProcessor() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
        // 如果有配置了生命周期处理器,则实例化并注册到容器中
        this.lifecycleProcessor =
                beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
        if (logger.isTraceEnabled()) {
            logger.trace("Using LifecycleProcessor [" + this.lifecycleProcessor + "]");
        }
    }
    else {
        // 如果没有指定,则实例化默认的生命周期处理器,并注册到容器和bean工厂中(注册为单例bean)
        DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
        defaultProcessor.setBeanFactory(beanFactory);
        this.lifecycleProcessor = defaultProcessor;
        beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
        if (logger.isTraceEnabled()) {
            logger.trace("No '" + LIFECYCLE_PROCESSOR_BEAN_NAME + "' bean, using " +
                    "[" + this.lifecycleProcessor.getClass().getSimpleName() + "]");
        }
    }
}

12.3 getLifecycleProcessor#onRefresh

已默认的生命周期处理器来示例

// DefaultLifecycleProcessor.java

@Override
public void onRefresh() {
    // 调用所有生命周期的start方法
    startBeans(true);
    // 设置订单的running状态为true
    this.running = true;
}

12.3.1 startBeans方法

对生命周期分组并排序后,调用其start方法

// DefaultLifecycleProcessor.java

private void startBeans(boolean autoStartupOnly) {
    // 获取所有Lifecycle类型的bean
    Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
    Map<Integer, LifecycleGroup> phases = new HashMap<>();
    // 对不同阶段的bean进行遍历分组
    lifecycleBeans.forEach((beanName, bean) -> {
        if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
            int phase = getPhase(bean);
            LifecycleGroup group = phases.get(phase);
            if (group == null) {
                group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
                phases.put(phase, group);
            }
            group.add(beanName, bean);
        }
    });
    // 如果有则调用生命周期组的start方法
    if (!phases.isEmpty()) {
        List<Integer> keys = new ArrayList<>(phases.keySet());
        Collections.sort(keys);
        for (Integer key : keys) {
            phases.get(key).start();
        }
    }
}
  • getLifecycleBeans

获取所有Lifecycle类型的bean

// DefaultLifecycleProcessor.java

protected Map<String, Lifecycle> getLifecycleBeans() {
    // 获取bean工厂
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    Map<String, Lifecycle> beans = new LinkedHashMap<>();
    // 获取 Lifecycle 类型的beanName
    String[] beanNames = beanFactory.getBeanNamesForType(Lifecycle.class, falsefalse);
    for (String beanName : beanNames) {
        // 获取真实的beanName(可能传入的是工厂bean或者alias)
        String beanNameToRegister = BeanFactoryUtils.transformedBeanName(beanName);
        boolean isFactoryBean = beanFactory.isFactoryBean(beanNameToRegister);
        String beanNameToCheck = (isFactoryBean ? BeanFactory.FACTORY_BEAN_PREFIX + beanName : beanName);
        if ((beanFactory.containsSingleton(beanNameToRegister) &&
                (!isFactoryBean || matchesBeanType(Lifecycle.class, beanNameToCheck, beanFactory))) ||
                matchesBeanType(SmartLifecycle.class, beanNameToCheck, beanFactory)) {
            // 如果是已注册的单例bean,或者符合指定类型的bean,则进行初始化并放到Map中返回
            Object bean = beanFactory.getBean(beanNameToCheck);
            if (bean != this && bean instanceof Lifecycle) {
                beans.put(beanNameToRegister, (Lifecycle) bean);
            }
        }
    }
    return beans;
}
  • LifecycleGroup#start

    // DefaultLifecycleProcessor.java

    public void start() {
      // members就是上面通过group.add方法添加进来的
      if (this.members.isEmpty()) {
          return;
      }
      if (logger.isDebugEnabled()) {
          logger.debug("Starting beans in phase " + this.phase);
      }
      Collections.sort(this.members);
      for (LifecycleGroupMember member : this.members) {
          doStart(this.lifecycleBeans, member.name, this.autoStartupOnly);
      }
    }

    实际上就是调用成员的start方法,先来看看LifecycleGroupMember的结构

    // DefaultLifecycleProcessor.java

    private class LifecycleGroupMember implements Comparable<LifecycleGroupMember{

      private final String name;

      private final Lifecycle bean;
    }
  • 只是简单的beanName及生命周期bean实例

    再看看doStart方法

    // DefaultLifecycleProcessor.java

    private void doStart(Map<String, ? extends Lifecycle> lifecycleBeans, String beanName, boolean autoStartupOnly) {
      Lifecycle bean = lifecycleBeans.remove(beanName);
      if (bean != null && bean != this) {
          // 当前bean不是自己
          // 获取bean的依赖,并递归调用doStart方法
          String[] dependenciesForBean = getBeanFactory().getDependenciesForBean(beanName);
          for (String dependency : dependenciesForBean) {
              doStart(lifecycleBeans, dependency, autoStartupOnly);
          }
          if (!bean.isRunning() &&
                  (!autoStartupOnly || !(bean instanceof SmartLifecycle) || ((SmartLifecycle) bean).isAutoStartup())) {
              if (logger.isTraceEnabled()) {
                  logger.trace("Starting bean '" + beanName + "' of type [" + bean.getClass().getName() + "]");
              }
              try {
                  // 启动生命周期
                  bean.start();
              }
              catch (Throwable ex) {
                  throw new ApplicationContextException("Failed to start bean '" + beanName + "'", ex);
              }
              if (logger.isDebugEnabled()) {
                  logger.debug("Successfully started bean '" + beanName + "'");
              }
          }
      }
    }

    都是比较简单的逻辑,先调用依赖的start方法(如果依赖符合的话),然后再调用当前bean的start方法。

至此,Spring容器的初始化过程就算结束了,最后放一张全局的流程图(有点长):

关于BeanDefinition的载入与Bean的实例化(doGetBean),会有新的篇幅来详细解析,敬请期待~


49 条评论

clenbuterol acheter · 2023年6月21日 下午11:21

… [Trackback]

[…] Find More on on that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

where to buy dmt vape​ · 2023年6月23日 上午7:01

… [Trackback]

[…] There you can find 92378 more Information on that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

เว็บ หวยยี่กี มีต้นกำเนิดมาจากไหน · 2023年7月6日 上午6:47

… [Trackback]

[…] Find More Info here to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

แอร์ ยี่ห้อไหนดี · 2023年7月6日 上午7:45

… [Trackback]

[…] Read More on that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

pic5678 · 2023年7月7日 上午6:19

… [Trackback]

[…] Read More Information here on that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

rajabandarq · 2023年7月13日 下午4:04

… [Trackback]

[…] Info to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

ทำกล่องขนมกล่องเค้กราคาถูก · 2023年7月19日 上午6:54

… [Trackback]

[…] Information to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

woolworths dried mushrooms · 2023年7月21日 上午9:55

… [Trackback]

[…] Info on that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

บาคาร่า · 2023年7月22日 上午7:48

… [Trackback]

[…] There you will find 70192 additional Info on that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

พรมดักฝุ่นรถยนต์ · 2023年8月1日 上午7:03

… [Trackback]

[…] Find More here to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

Buy pounds of weed online · 2023年8月3日 上午2:39

… [Trackback]

[…] Read More on that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

find more · 2023年8月4日 上午7:09

… [Trackback]

[…] Find More Information here to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

รับทำ SEO · 2023年8月4日 上午7:36

… [Trackback]

[…] Info to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

ป้ายโฆษณา · 2023年8月5日 上午7:17

… [Trackback]

[…] Information to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

พนันบอล true money · 2023年8月6日 上午10:18

… [Trackback]

[…] There you can find 7962 additional Information on that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

หวย24 · 2023年8月6日 上午10:44

… [Trackback]

[…] Info on that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

เครื่องกรองน้ำ coway · 2023年8月7日 上午6:34

… [Trackback]

[…] Find More on to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

Payday Loans Cantley QC · 2023年8月7日 下午6:19

… [Trackback]

[…] Info on that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

ผลิตภัณ์ Relx · 2023年8月8日 上午7:16

… [Trackback]

[…] Find More here on that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

togel singapore · 2023年8月14日 下午7:35

… [Trackback]

[…] Find More on to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

sudoku · 2023年8月16日 上午12:31

… [Trackback]

[…] Read More here to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

สล็อต ฝากถอน true wallet เว็บตรง 888pg · 2023年8月24日 上午6:34

… [Trackback]

[…] Info on that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

รีวิว vivo v29 5G · 2023年8月26日 上午6:31

… [Trackback]

[…] Find More here to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

หวยฮานอย · 2023年8月30日 上午6:21

… [Trackback]

[…] Find More on that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

สล็อต pg เว็บตรง แตกหนัก · 2023年8月30日 上午7:53

… [Trackback]

[…] Info to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

เว็บพนันบอล วอ ล เล็ ตเว็บพนันบอล sbobet · 2023年8月31日 上午7:20

… [Trackback]

[…] Find More to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

slot online · 2023年9月1日 下午7:06

… [Trackback]

[…] Find More to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

สล็อตออนไลน์ · 2023年9月2日 上午6:18

… [Trackback]

[…] Info to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

สล็อตเบทฟิก · 2023年9月3日 上午6:57

… [Trackback]

[…] Find More Info here to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

condo for sale pattaya · 2023年9月3日 上午7:17

… [Trackback]

[…] There you will find 65035 more Information on that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

เว็บตรงไม่ผ่านเอเย่นต์ · 2023年9月6日 上午6:31

… [Trackback]

[…] Read More Info here to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

skaties te · 2023年9月6日 下午6:05

… [Trackback]

[…] There you can find 85174 more Information on that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

counseling long island · 2023年9月7日 上午6:08

… [Trackback]

[…] Read More Info here to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

luxury pool villas in phuket · 2023年9月7日 上午6:16

… [Trackback]

[…] There you can find 18530 additional Info to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

เขียนโปรแกรม · 2023年9月7日 上午7:09

… [Trackback]

[…] Find More Information here to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

naga qq · 2023年9月9日 上午1:51

… [Trackback]

[…] Read More Information here to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

สมัครyehyeh · 2023年9月9日 上午7:41

… [Trackback]

[…] Read More Information here to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

Data singapore · 2023年9月10日 上午1:16

… [Trackback]

[…] Find More on on that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

เพิ่มยอดไลค์ · 2023年9月10日 上午6:32

… [Trackback]

[…] Info to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

openlims.org · 2023年9月10日 下午11:58

… [Trackback]

[…] Information on that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

Data HK · 2023年9月11日 下午11:21

… [Trackback]

[…] Read More on on that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

relax massage · 2023年9月12日 上午6:44

… [Trackback]

[…] Here you will find 36661 more Information on that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

รปภ เชียงใหม่ · 2023年9月12日 上午7:00

… [Trackback]

[…] Here you can find 70507 more Info to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

เค้กวันเกิดบางแค · 2023年9月12日 上午7:02

… [Trackback]

[…] Find More Information here to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

Vape carts USA · 2023年9月14日 上午1:41

… [Trackback]

[…] Read More to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

คาสิโนสด AE Group · 2023年9月14日 上午6:32

… [Trackback]

[…] Find More Info here to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

Recommended Reading · 2023年9月14日 下午10:44

… [Trackback]

[…] Info on that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

Toyota Alphard 2024 ราคา · 2023年9月15日 上午6:57

… [Trackback]

[…] Read More to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

คอนโดใหม่ · 2023年9月15日 上午7:06

… [Trackback]

[…] Information to that Topic: hugr.cn/2019/12/12/spring-容器初始化流程(下)/ […]

评论已关闭。