• Spring应用上下文启动准备阶段
  • `BeanFactory`创建阶段
  • `BeanFactory`准备阶段
  • `BeanFactory`后置处理阶段
    • `AnnotationConfigServletWebApplicationContext#postProcessBeanFactory`
    • `AbstractApplicationContext#invokeBeanFactoryPostProcessors`
  • `BeanFactory`注册`BeanPostProcessor`阶段
  • 初始化内建Bean: `MessageSource`
  • 初始化内建Bean : Spring事件广播器
  • Spring应用上下文刷新阶段
  • Spring事件监听器注册阶段
    • `getApplicationEventMulticaster`
    • `AbstractApplicationEventMulticaster#addApplicationListener`
  • `BeanFactory`初始化完成阶段

    • 冻结配置
    • 初始化非延迟单例 Bean
  • Spring应用上下文刷新完成阶段

    • 清除ResourceLoader缓存
    • 初始化LifecycleProcessor对象
    • 调用LifecycleProcessor#onRefresh方法
    • 发布Spring应用上下文已刷新事件
    • 向MBeanServer 托管Live Beans(JMX)
  • Spring应用上下文启动阶段
  • Spring应用上下文停止阶段
  • Spring应用上下文关闭阶段
    • `AbstractApplicationContext#doClose`
    • `removeShutdownHook`
  • 面试题

    • Spring应用上下文生命周期有哪些阶段
    • Environment完整的生命周期
    • Spring应用上下文生命周期执行动作

Spring应用上下文生命周期

AbstractApplicationContext#refresh是Spring应用上下文生命周期的入口方法

    @Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.// Spring应用上下文启动准备阶段prepareRefresh();// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.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);// 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();}}}

Spring应用上下文启动准备阶段

AbstractApplicationContext#prepareRefresh
/**
* Prepare this context for refreshing, setting its startup date and
* active flag as well as performing any initialization of property sources.
*/
protected void prepareRefresh() {
// Switch to active.
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
}
else {
logger.debug("Refreshing " + getDisplayName());
}
}
// Initialize any placeholder property sources in the context environment.
// 默认是空实现,供子类实现
initPropertySources();
// Validate that all properties marked as required are resolvable:
// see ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties();
// Store pre-refresh ApplicationListeners...
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<>();
}

  • 启动时间 startupDate
  • 状态标识
    this.closed.set(false); this.active.set(true);
  • 初始化PropertySources
    空方法,供子类实现,通常会提早创建Environment
  • 检验Environment中必须属性
  • 初始化事件监听器集合
  • 初始化早期Spring事件集合

BeanFactory创建阶段

AbstractApplicationContext#obtainFreshBeanFactory

/*** Tell the subclass to refresh the internal bean factory.* @return the fresh BeanFactory instance* @see #refreshBeanFactory()* @see #getBeanFactory()*/protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {refreshBeanFactory();// 返回BeanFactoryreturn getBeanFactory();}

AbstractRefreshableApplicationContext#refreshBeanFactory

/*** This implementation performs an actual refresh of this context's underlying* bean factory, shutting down the previous bean factory (if any) and* initializing a fresh bean factory for the next phase of the context's lifecycle.*/@Overrideprotected final void refreshBeanFactory() throws BeansException {// 判断是否创建了BeanFactory ,是的话 销毁Bean,关闭BeanFactoryif (hasBeanFactory()) {destroyBeans();closeBeanFactory();}try {// 创建BeanFactoryDefaultListableBeanFactory beanFactory = createBeanFactory();// 设置idbeanFactory.setSerializationId(getId());// 设置是否允许BeanDefinition 重复定义 , 设置是否允许循环依赖customizeBeanFactory(beanFactory);// 加载beanDefinitionloadBeanDefinitions(beanFactory);synchronized (this.beanFactoryMonitor) {this.beanFactory = beanFactory;}}catch (IOException ex) {throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);}}

  • AbstractApplicationContext#obtainFreshBeanFactory

    • AbstractRefreshableApplicationContext#refreshBeanFactory

      • 如果BeanFactory已经创建好了,就关闭或销毁BeanFactory
      • createBeanFactory()
      • beanFactory.setSerializationId
      • customizeBeanFactory(beanFactory)
        protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
        // 设置是否允许BeanDefinition 重复定义
        if (this.allowBeanDefinitionOverriding != null) {
        beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
        // 设置是否允许循环依赖
        if (this.allowCircularReferences != null) {
        beanFactory.setAllowCircularReferences(this.allowCircularReferences);
        }
        }
      • loadBeanDefinitions(beanFactory)
        xml 、注解驱动上下文 的具体实现不同
    • getBeanFactory();

BeanFactory准备阶段

/*** Configure the factory's standard context characteristics,* such as the context's ClassLoader and post-processors.* @param beanFactory the BeanFactory to configure*/protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {// Tell the internal bean factory to use the context's class loader etc.// 关联ClassLoader (给予xml的上下文之前没有加载到bean class)beanFactory.setBeanClassLoader(getClassLoader());// 设置Bean表达式处理器beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));// 添加PropertyEditorRegistrar(类型转换)实现: ResourceEditorRegistrarbeanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));// Configure the bean factory with context callbacks.// 添加Aware回调接口 BeanPostProcessor实现 :ApplicationContextAwareProcessorbeanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));// 忽略Aware接口作为依赖注入接口beanFactory.ignoreDependencyInterface(EnvironmentAware.class);beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);beanFactory.ignoreDependencyInterface(MessageSourceAware.class);beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);// BeanFactory interface not registered as resolvable type in a plain factory.// MessageSource registered (and found for autowiring) as a bean.// 注册ResolvableDependency对象beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);beanFactory.registerResolvableDependency(ResourceLoader.class, this);beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);beanFactory.registerResolvableDependency(ApplicationContext.class, this);// Register early post-processor for detecting inner beans as ApplicationListeners.beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(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.// 注册单例对象 (environment相关)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());}}

BeanFactory后置处理阶段

 // Allows post-processing of the bean factory in context subclasses.
// 由子类实现postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);

AbstractApplicationContext#refresh

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {}/*** Instantiate and invoke all registered BeanFactoryPostProcessor beans,* respecting explicit order if given.* <p>Must be called before singleton instantiation.*/protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));}}

AnnotationConfigServletWebApplicationContext#postProcessBeanFactory

Servlet Web 注解驱动上下文的实现

@Overrideprotected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { // 调用父类super.postProcessBeanFactory(beanFactory);if (!ObjectUtils.isEmpty(this.basePackages)) {this.scanner.scan(this.basePackages);}if (!this.annotatedClasses.isEmpty()) {this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));}}

1.GenericWebApplicationContext#postProcessBeanFactory

/*** Register ServletContextAwareProcessor.* @see ServletContextAwareProcessor*/@Overrideprotected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {if (this.servletContext != null) {beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext));beanFactory.ignoreDependencyInterface(ServletContextAware.class);}WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext);}

WebApplicationContextUtils#registerWebApplicationScopes(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, javax.servlet.ServletContext)

public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory,@Nullable ServletContext sc) {// 注册Scope// requestbeanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());// sessionbeanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope());if (sc != null) {// applicationServletContextScope appScope = new ServletContextScope(sc);beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope);// Register as ServletContext attribute, for ContextCleanupListener to detect it. // 设置ServletContext Attributesc.setAttribute(ServletContextScope.class.getName(), appScope);}// 注册ResolvableDependencybeanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());if (jsfPresent) {FacesDependencyRegistrar.registerFacesDependencies(beanFactory);}}

WebApplicationContextUtils.registerEnvironmentBeans

注册Servlet相关的Bean

/*** Register web-specific environment beans ("contextParameters", "contextAttributes")* with the given BeanFactory, as used by the WebApplicationContext.* @param bf the BeanFactory to configure* @param sc the ServletContext that we're running within*/public static void registerEnvironmentBeans(ConfigurableListableBeanFactory bf, @Nullable ServletContext sc) {registerEnvironmentBeans(bf, sc, null);}public static void registerEnvironmentBeans(ConfigurableListableBeanFactory bf,@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {if (servletContext != null && !bf.containsBean(WebApplicationContext.SERVLET_CONTEXT_BEAN_NAME)) {bf.registerSingleton(WebApplicationContext.SERVLET_CONTEXT_BEAN_NAME, servletContext);}// servletConfig=nullif (servletConfig != null && !bf.containsBean(ConfigurableWebApplicationContext.SERVLET_CONFIG_BEAN_NAME)) {bf.registerSingleton(ConfigurableWebApplicationContext.SERVLET_CONFIG_BEAN_NAME, servletConfig);}if (!bf.containsBean(WebApplicationContext.CONTEXT_PARAMETERS_BEAN_NAME)) {Map<String, String> parameterMap = new HashMap<>();if (servletContext != null) {Enumeration<?> paramNameEnum = servletContext.getInitParameterNames();while (paramNameEnum.hasMoreElements()) {String paramName = (String) paramNameEnum.nextElement();parameterMap.put(paramName, servletContext.getInitParameter(paramName));}}if (servletConfig != null) {Enumeration<?> paramNameEnum = servletConfig.getInitParameterNames();while (paramNameEnum.hasMoreElements()) {String paramName = (String) paramNameEnum.nextElement();parameterMap.put(paramName, servletConfig.getInitParameter(paramName));}}bf.registerSingleton(WebApplicationContext.CONTEXT_PARAMETERS_BEAN_NAME,Collections.unmodifiableMap(parameterMap));}if (!bf.containsBean(WebApplicationContext.CONTEXT_ATTRIBUTES_BEAN_NAME)) {Map<String, Object> attributeMap = new HashMap<>();if (servletContext != null) {Enumeration<?> attrNameEnum = servletContext.getAttributeNames();while (attrNameEnum.hasMoreElements()) {String attrName = (String) attrNameEnum.nextElement();attributeMap.put(attrName, servletContext.getAttribute(attrName));}}bf.registerSingleton(WebApplicationContext.CONTEXT_ATTRIBUTES_BEAN_NAME,Collections.unmodifiableMap(attributeMap));}}

2.ClassPathBeanDefinitionScanner#scan

根据basePackages的内容加载、注册BeanDefinition

public int scan(String... basePackages) {int beanCountAtScanStart = this.registry.getBeanDefinitionCount();doScan(basePackages);// Register annotation config processors, if necessary.if (this.includeAnnotationConfig) {AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);}return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}

AbstractApplicationContext#invokeBeanFactoryPostProcessors

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));}}

PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors())

BeanFactoryPostProcessor回调

public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {// Invoke BeanDefinitionRegistryPostProcessors first, if any.Set<String> processedBeans = new HashSet<>();if (beanFactory instanceof BeanDefinitionRegistry) {BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {// 先处理BeanDefinitionRegistryPostProcessorif (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {BeanDefinitionRegistryPostProcessor registryProcessor =(BeanDefinitionRegistryPostProcessor) postProcessor;// 回调   registryProcessor.postProcessBeanDefinitionRegistry(registry);registryProcessors.add(registryProcessor);}else {regularPostProcessors.add(postProcessor);}}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!// Separate between BeanDefinitionRegistryPostProcessors that implement// PriorityOrdered, Ordered, and the rest.List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {// BeanDefinitionRegistryPostProcessor  PriorityOrderedif (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.boolean reiterate = true;while (reiterate) {reiterate = false;postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);reiterate = true;}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);currentRegistryProcessors.clear();}// Now, invoke the postProcessBeanFactory callback of all processors handled so far.invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);}else {// Invoke factory processors registered with the context instance.invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,// Ordered, and the rest.List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();List<String> orderedPostProcessorNames = new ArrayList<>();List<String> nonOrderedPostProcessorNames = new ArrayList<>();for (String ppName : postProcessorNames) {if (processedBeans.contains(ppName)) {// skip - already processed in first phase above}else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));}else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {orderedPostProcessorNames.add(ppName);}else {nonOrderedPostProcessorNames.add(ppName);}}// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.sortPostProcessors(priorityOrderedPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);// Next, invoke the BeanFactoryPostProcessors that implement Ordered.List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());for (String postProcessorName : orderedPostProcessorNames) {orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}sortPostProcessors(orderedPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);// Finally, invoke all other BeanFactoryPostProcessors.List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());for (String postProcessorName : nonOrderedPostProcessorNames) {nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));}invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);// Clear cached merged bean definitions since the post-processors might have// modified the original metadata, e.g. replacing placeholders in values...beanFactory.clearMetadataCache();}

BeanFactory注册BeanPostProcessor阶段

AbstractApplicationContext#registerBeanPostProcessors
主要涉及如下逻辑:

  1. 注册PriorityOrdered类型的BeanPostProcessorBeans
  2. 注册Ordered类型的BeanPostProcessorBeans
  3. 注册普通的BeanPostProcessor Beans
  4. 注册MergedBeanDefinitionPostProcessor Beanss
  5. 注册ApplicationListenerDetector对象
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);}public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {// 获取BeanPostProcessor Bean Name ListString[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);// Register BeanPostProcessorChecker that logs an info message when// a bean is created during BeanPostProcessor instantiation, i.e. when// a bean is not eligible for getting processed by all BeanPostProcessors.int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));// Separate between BeanPostProcessors that implement PriorityOrdered,// Ordered, and the rest.List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();List<String> orderedPostProcessorNames = new ArrayList<>();List<String> nonOrderedPostProcessorNames = new ArrayList<>();for (String ppName : postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {// 提前初始化BeanPostProcessor BeanBeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);priorityOrderedPostProcessors.add(pp);if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}}else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {orderedPostProcessorNames.add(ppName);}else {nonOrderedPostProcessorNames.add(ppName);}}// First, register the BeanPostProcessors that implement PriorityOrdered.sortPostProcessors(priorityOrderedPostProcessors, beanFactory);registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);// Next, register the BeanPostProcessors that implement Ordered.List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());for (String ppName : orderedPostProcessorNames) {BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);orderedPostProcessors.add(pp);if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}}sortPostProcessors(orderedPostProcessors, beanFactory);registerBeanPostProcessors(beanFactory, orderedPostProcessors);// Now, register all regular BeanPostProcessors.List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());for (String ppName : nonOrderedPostProcessorNames) {BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);nonOrderedPostProcessors.add(pp);if (pp instanceof MergedBeanDefinitionPostProcessor) {internalPostProcessors.add(pp);}}registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);// Finally, re-register all internal BeanPostProcessors.sortPostProcessors(internalPostProcessors, beanFactory);registerBeanPostProcessors(beanFactory, internalPostProcessors);// Re-register post-processor for detecting inner beans as ApplicationListeners,// moving it to the end of the processor chain (for picking up proxies etc).beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));}

初始化内建Bean: MessageSource

AbstractApplicationContext#initMessageSource

 protected void initMessageSource() {ConfigurableListableBeanFactory beanFactory = getBeanFactory();if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);// Make MessageSource aware of parent MessageSource.if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;if (hms.getParentMessageSource() == null) {// Only set parent context as parent MessageSource if no parent MessageSource// registered already.hms.setParentMessageSource(getInternalParentMessageSource());}}if (logger.isTraceEnabled()) {logger.trace("Using MessageSource [" + this.messageSource + "]");}}else {// Use empty MessageSource to be able to accept getMessage calls.DelegatingMessageSource dms = new DelegatingMessageSource();dms.setParentMessageSource(getInternalParentMessageSource());this.messageSource = dms;beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);if (logger.isTraceEnabled()) {logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");}}}

默认情况下会注册一个DelegatingMessageSource 类型的MessageSource(国际化) singleton Bean

初始化内建Bean : Spring事件广播器

ApplicationEventMulticaster在Spring应用上下文中必须存在

protected void initApplicationEventMulticaster() {ConfigurableListableBeanFactory beanFactory = getBeanFactory();if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {this.applicationEventMulticaster =beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);if (logger.isTraceEnabled()) {logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");}}else {// 默认注册SimpleApplicationEventMulticaster Beanthis.applicationEventMulticaster = new SimpleApplicationEventMulticaster Bean(beanFactory);beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);if (logger.isTraceEnabled()) {logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");}}}

Spring应用上下文刷新阶段

AbstractApplicationContext#onRefresh默认是空方法,供具体的上下文(Web应用)进行自定义扩展

 protected void onRefresh() throws BeansException {// For subclasses: do nothing by default.}

Spring事件监听器注册阶段

protected void registerListeners() {// Register statically specified listeners first.// 1.添加当前Spring应用上下文关联的ApplicationListener对象集合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!// 2. 添加 BeanFactory所注册的ApplicationListener Beans// 这里不初始化Bean,延迟初始化String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);for (String listenerBeanName : listenerBeanNames) {getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);}// Publish early application events now that we finally have a multicaster...// 广播早期Spring事件Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;this.earlyApplicationEvents = null;if (earlyEventsToProcess != null) {for (ApplicationEvent earlyEvent : earlyEventsToProcess) {getApplicationEventMulticaster().multicastEvent(earlyEvent);}}}

getApplicationEventMulticaster

/*** Return the internal ApplicationEventMulticaster used by the context.* @return the internal ApplicationEventMulticaster (never {@code null})* @throws IllegalStateException if the context has not been initialized yet*/ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException {if (this.applicationEventMulticaster == null) {throw new IllegalStateException("ApplicationEventMulticaster not initialized - " +"call 'refresh' before multicasting events via the context: " + this);}return this.applicationEventMulticaster;}

AbstractApplicationEventMulticaster#addApplicationListener

@Overridepublic void addApplicationListener(ApplicationListener<?> listener) {// 加锁 保证多线程操作的原子性synchronized (this.retrievalMutex) {// Explicitly remove target for a proxy, if registered already,// in order to avoid double invocations of the same listener.Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);if (singletonTarget instanceof ApplicationListener) {this.defaultRetriever.applicationListeners.remove(singletonTarget);}this.defaultRetriever.applicationListeners.add(listener);this.retrieverCache.clear();}}

BeanFactory初始化完成阶段

/*** Finish the initialization of this context's bean factory,* initializing all remaining singleton beans.*/protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {// Initialize conversion service for this context.// BeanFactory 关联 ConversionService Bean(如果存在)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.// BeanFactory添加StringValueResolver对象if (!beanFactory.hasEmbeddedValueResolver()) {beanFactory.addEmbeddedValueResolver(strVal -> 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) {// 依赖查找LoadTimeWeaverAware BeangetBean(weaverAwareName);}// Stop using the temporary ClassLoader for type matching.// 将BeanFactory的临时ClassLoader置为空beanFactory.setTempClassLoader(null);// Allow for caching all bean definition metadata, not expecting further changes.// BeanFactory冻结配置beanFactory.freezeConfiguration();// Instantiate all remaining (non-lazy-init) singletons.// 初始化非延迟单例 BeanbeanFactory.preInstantiateSingletons();}

冻结配置

DefaultListableBeanFactory

@Overridepublic void freezeConfiguration() {this.configurationFrozen = true;// 冻结 不让修改的beanDefinition 名称this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames);}

初始化非延迟单例 Bean

@Overridepublic void preInstantiateSingletons() throws BeansException {if (logger.isTraceEnabled()) {logger.trace("Pre-instantiating singletons in " + this);}// Iterate over a copy to allow for init methods which in turn register new bean definitions.// While this may not be part of the regular factory bootstrap, it does otherwise work fine.List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);// Trigger initialization of all non-lazy singleton beans...for (String beanName : beanNames) {// merged BeanDefinitonRootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {if (isFactoryBean(beanName)) {Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);if (bean instanceof FactoryBean) {final FactoryBean<?> factory = (FactoryBean<?>) bean;boolean isEagerInit;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) {getBean(beanName);}}}else {getBean(beanName);}}}// Trigger post-initialization callback for all applicable beans...for (String beanName : beanNames) {Object singletonInstance = getSingleton(beanName);if (singletonInstance instanceof SmartInitializingSingleton) {final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {smartSingleton.afterSingletonsInstantiated();return null;}, getAccessControlContext());}else {smartSingleton.afterSingletonsInstantiated();}}}}

SmartInitializingSingleton#afterSingletonsInstantiated

回调

Spring应用上下文刷新完成阶段

finishorg.springframework.context.support.AbstractApplicationContext#finishRefresh

/*** Finish the refresh of this context, invoking the LifecycleProcessor's* onRefresh() method and publishing the* {@link org.springframework.context.event.ContextRefreshedEvent}.*/protected void finishRefresh() {// Clear context-level resource caches (such as ASM metadata from scanning).// 清除ResourceLoader缓存clearResourceCaches();// Initialize lifecycle processor for this context.// 初始化LifecycleProcessor对象initLifecycleProcessor();// Propagate refresh to lifecycle processor first.// 调用LifecycleProcessor.onrefresh方法getLifecycleProcessor().onRefresh();// Publish the final event.// 发布Spring应用上下文已刷新事件publishEvent(new ContextRefreshedEvent(this));// Participate in LiveBeansView MBean, if active.// 向MBeanServer 托管Live BeansLiveBeansView.registerApplicationContext(this);}

清除ResourceLoader缓存

private final Map<Class<?>, Map<Resource, ?>> resourceCaches = new ConcurrentHashMap<>(4);

/*** Clear all resource caches in this resource loader.* @since 5.0* @see #getResourceCache*/public void clearResourceCaches() {this.resourceCaches.clear();}

初始化LifecycleProcessor对象

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 {// 默认实现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() + "]");}}}

调用LifecycleProcessor#onRefresh方法

DefaultLifecycleProcessor#onRefresh

@Overridepublic void onRefresh() {startBeans(true);this.running = true;}
private void startBeans(boolean autoStartupOnly) {// 获取Lifecycle BeansMap<String, Lifecycle> lifecycleBeans = getLifecycleBeans();Map<Integer, LifecycleGroup> phases = new HashMap<>();// 遍历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);}});if (!phases.isEmpty()) {List<Integer> keys = new ArrayList<>(phases.keySet());Collections.sort(keys);for (Integer key : keys) {phases.get(key).start();}}}

发布Spring应用上下文已刷新事件

广播ContextRefreshedEvent事件AbstractApplicationContext#publishEvent
下面的源码就是之前说的ApplicationEventMulticasterApplicationEventPublisher(一般为Spring应用上下文)打工的故事

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {Assert.notNull(event, "Event must not be null");// Decorate event as an ApplicationEvent if necessaryApplicationEvent applicationEvent;if (event instanceof ApplicationEvent) {applicationEvent = (ApplicationEvent) event;}else {applicationEvent = new PayloadApplicationEvent<>(this, event);if (eventType == null) {eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();}}// Multicast right now if possible - or lazily once the multicaster is initializedif (this.earlyApplicationEvents != null) {this.earlyApplicationEvents.add(applicationEvent);}else {getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);}// Publish event via parent context as well...if (this.parent != null) {if (this.parent instanceof AbstractApplicationContext) {((AbstractApplicationContext) this.parent).publishEvent(event, eventType);}else {this.parent.publishEvent(event);}}}

向MBeanServer 托管Live Beans(JMX)

// LiveBeansView.registerApplicationContext
static void registerApplicationContext(ConfigurableApplicationContext applicationContext) {// 获取配置的mbeanDomainString mbeanDomain = applicationContext.getEnvironment().getProperty(MBEAN_DOMAIN_PROPERTY_NAME);if (mbeanDomain != null) {synchronized (applicationContexts) {if (applicationContexts.isEmpty()) {try {// MBeanServerMBeanServer server = ManagementFactory.getPlatformMBeanServer();applicationName = applicationContext.getApplicationName();server.registerMBean(new LiveBeansView(),new ObjectName(mbeanDomain, MBEAN_APPLICATION_KEY, applicationName));}catch (Throwable ex) {throw new ApplicationContextException("Failed to register LiveBeansView MBean", ex);}}applicationContexts.add(applicationContext);}}}

Spring应用上下文启动阶段

start 手动触发

 @Overridepublic void start() {getLifecycleProcessor().start();// 发布ContextStartedEvent事件publishEvent(new ContextStartedEvent
ContextStartedEvent(this));}

Spring应用上下文停止阶段

stop 手动触发

@Overridepublic void stop() {getLifecycleProcessor().stop();publishEvent(new ContextStoppedEvent(this));}

当我们的Bean实现了LifeCycle接口时,调用Spring应用上下文的start/stop方法,Bean 的start方法和stop方法会随之调用,这是对Spring上下文生命周期的补充,定义了一种全新的生命周期。

public interface Lifecycle {void start();void stop();boolean isRunning();
}

Spring应用上下文关闭阶段

close

    /** Synchronization monitor for the "refresh" and "destroy". */private final Object startupShutdownMonitor = new Object();@Overridepublic void close() {synchronized (this.startupShutdownMonitor) {doClose();// If we registered a JVM shutdown hook, we don't need it anymore now:// We've already explicitly closed the context.if (this.shutdownHook != null) {try {Runtime.getRuntime().removeShutdownHook(this.shutdownHook);}catch (IllegalStateException ex) {// ignore - VM is already shutting down}}}}

AbstractApplicationContext#doClose

/** Flag that indicates whether this context is currently active. */
private final AtomicBoolean active = new AtomicBoolean();/** Flag that indicates whether this context has been closed already. */
private final AtomicBoolean closed = new AtomicBoolean();protected void doClose() {// Check whether an actual close attempt is necessary...if (this.active.get() && this.closed.compareAndSet(false, true)) {// 撤销JMX对Spring Bean的托管LiveBeansView.unregisterApplicationContext(this);try {// Publish shutdown event.// 发布ContextClosedEvent事件publishEvent(new ContextClosedEvent(this));}catch (Throwable ex) {...}// Stop all Lifecycle beans, to avoid delays during individual destruction.if (this.lifecycleProcessor != null) {try {this.lifecycleProcessor.onClose();}catch (Throwable ex) {...}}// Destroy all cached singletons in the context's BeanFactory.destroyBeans();// Close the state of this context itself.closeBeanFactory();// Let subclasses do some final clean-up if they wish...onClose();// Reset local application listeners to pre-refresh state.if (this.earlyApplicationListeners != null) {this.applicationListeners.clear();this.applicationListeners.addAll(this.earlyApplicationListeners);}// Switch to inactive.this.active.set(false);}}

destroyBeans

protected void destroyBeans() {getBeanFactory().destroySingletons();
}

closeBeanFactory

removeShutdownHook

优雅宕机

spring生命周期_理解Spring应用上下文生命周期相关推荐

  1. ioc spring 上机案例_抛开Spring去理解IOC思想 - 原来IOC容器这么简单

    很多小伙伴们看到标题可能就会想到抛开Spring就不会存在IOC思想了,其实不然在接下来的文章中就会讲述到. 很多小伙伴在理解IOC的时候通常会和Spring放到一起去学习,首先呢Spring设计的非 ...

  2. spring 扫描所有_从Spring的几个阶段理解其工作过程

    首发于博客园,https://www.cnblogs.com/ibigboy/p/11150237.html Spring框架非常强大,想要彻底弄懂Spring是非常困难的. 为了便于初学者了解Spr ...

  3. spring mysql 注解_【Spring】SpringMVC之基于注解的实现SpringMVC+MySQL

    目录结构: contents structure [-] SpringMVC是什么 MVC的全称是Model View Controller,通过实现MVC框架可以很好的数据.视图.业务逻辑进行分离. ...

  4. spring boot测试_测试Spring Boot有条件的合理方式

    spring boot测试 如果您或多或少有经验的Spring Boot用户,那么很幸运,在某些时候您可能需要遇到必须有条件地注入特定bean或配置的情况 . 它的机制是很好理解的 ,但有时这样的测试 ...

  5. 页面生命周期_微信小程序的生命周期学习笔记-应用篇

    在我们学习微信小程序的过程当中,我们会参考很多资料.在这些资料中,我们经常能够看到"生命周期"四个字,在前面的课程中也提到过.在这里做一个说明. 生命周期是一类函数的统称,这些函数 ...

  6. spring 事务 会话_测试Spring的“会话”范围

    spring 事务 会话 在基于Spring的Web应用程序中,bean的作用域可以是用户"会话". 从本质上讲,这意味着对会话范围Bean的状态更改仅在用户会话范围内可见. 本条 ...

  7. java spring 条件注解_【Spring】Spring高级话题-条件注解-@Condition

    进行本示例的演示,需要先配置好Maven和Spring哦. 见: [Spring]基于IntelliJ IDEA搭建Maven 分析 通过profile,我们可以获得不同的profile,我们可以获得 ...

  8. java 实例的生命周期_[Java教程]Vue实例生命周期

    [Java教程]Vue实例生命周期 0 2017-08-15 19:00:09 前面的话 Vue实例在创建时有一系列的初始化步骤,例如建立数据观察,编译模板,创建数据绑定等.在此过程中,我们可以通过一 ...

  9. stm32for循环几个机械周期_波浪理论之五:循环周期理论

    循环周期理论是分析股市涨跌的一种方法.与其他研究分析股市方法的区别是循环周期理论着重于时间的分析,从周期的长短去研究推测循环高点或循环低点可能出现的日期,从而制定操作策略. 循环周期理论,实际上并非神 ...

最新文章

  1. pemicro识别不了驱动_usb驱动无法识别怎么办-usb驱动无法识别通常解决办法 - 河东软件园...
  2. 替换字符串中指定的字符--随手源码
  3. 自由自在带你品尝一种能长出果蔬的冰淇淋
  4. linux查看并发连接数
  5. yarn.lock 文件和 yarn install
  6. 洛谷 P2389 电脑班的裁员 解题报告
  7. NLTK学习笔记(八):文法--词关系研究的工具
  8. vSwitch报文转发分析
  9. 5.HTTP 常见状态码
  10. Unity3d程序必备的几种设计模式
  11. 码破苍穹:空指针的传说
  12. docker学习1--docker基础学习
  13. Floyd-Warshall算法详解(转)
  14. Zabbix5.0监控Nginx
  15. 上海旅游-徐家汇教堂
  16. regsvr32 注册.dll的用法
  17. GIF 89a图像格式解析
  18. jQuery 清除div内容
  19. 机器学习在分子模拟中的应用
  20. Commvault Complete™ Backup Recovery v11 SP18 OVF 下载

热门文章

  1. 查看dataloader的大小_一文弄懂Pytorch的DataLoader, DataSet, Sampler之间的关系
  2. SAP Spartacus 里的 .release-it.json 文件
  3. SAP Spartacus 捕捉 PageEvent 的方式
  4. ubuntu 21.04 版本上 安装 sqlcmd
  5. SAP Fiori Elements 学习笔记 - 2021年4月19日
  6. ng-template和对应生成的注释
  7. SAP Fiori Elements list report filter - implemented by framework
  8. Hybris service layer和SAP CRM WebClient UI架构的横向比较
  9. ABAP如何调用OCX
  10. hybris backoffice和产品主数据相关的一些sample data