Spring中refresh分析之finishRefresh方法详解

简介: Spring中refresh分析之finishRefresh方法详解

接上文Spring中refresh分析之finishBeanFactoryInitialization方法详解我们分析过finishBeanFactoryInitialization后,本文分析finishRefres方法。


方法功能梳理:

清理前面记录的类资源(因为已经有了BeanDefinition);

初始化生命周期处理器,默认是DefaultLifecycleProcessor,并作为单例注册到容器;

触发DefaultLifecycleProcessor的onRefresh方法,简单来讲就是触发那些实现了Lifecycle的bean的start方法并将running状态设置为true。

发布事件ContextRefreshedEvent,这个玩意很重要标志着上下文刷新执行完毕

注册ApplicationContext到LiveBeansView内部的applicationContexts中。

启动webserver,处理webserver的service与connector,并触发connector的start方法;

发布ServletWebServerInitializedEvent事件,标志着WebServer启动完毕。ServletWebServerApplicationContext的finishRefresh方法

@Override
protected void finishRefresh() {
  //触发父类的方法
  super.finishRefresh();
  //启动WebServer,将WebServer的started置为true
  WebServer webServer = startWebServer();
  // 发布事件
  if (webServer != null) {
    publishEvent(new ServletWebServerInitializedEvent(webServer, this));
  }
}

如上所示其会首先触发父类的方法,然后启动WebServer,最后发布ServletWebServerInitializedEvent事件。

ServletWebServerInitializedEvent事件会被如下四个监听器捕捉:

0 = {RestartApplicationListener@9680} 
1 = {SpringApplicationAdminMXBeanRegistrar@9681} 
2 = {DelegatingApplicationListener@9682} 
3 = {ServerPortInfoApplicationContextInitializer@9683} 

其ServerPortInfoApplicationContextInitializer的onApplicationEvent方法将会为环境的PropertySources设置server.ports--new MapPropertySource("server.ports", new HashMap<>())


1389675e88a7462e84c905ee474eed63.png


【1】super.finishRefresh

AbstractApplicationContext的finishRefresh方法

protected void finishRefresh() {
  // Clear context-level resource caches (such as ASM metadata from scanning).
  clearResourceCaches();
  // Initialize lifecycle processor for this context.
  initLifecycleProcessor();
  // Propagate refresh to lifecycle processor first.
  getLifecycleProcessor().onRefresh();
  // Publish the final event.
  publishEvent(new ContextRefreshedEvent(this));
  // Participate in LiveBeansView MBean, if active.
  LiveBeansView.registerApplicationContext(this);
}

方法逻辑梳理如下

  • 清理前面记录的类资源(因为已经有了BeanDefinition);
  • 初始化生命周期处理器,默认是DefaultLifecycleProcessor,并作为单例注册到容器;
  • 触发DefaultLifecycleProcessor的onRefresh方法,简单来讲就是触发那些实现了Lifecycle的bean的start方法并将running状态设置为true。
  • 发布事件ContextRefreshedEvent,这个玩意很重要标志着上下文刷新执行完毕
  • 注册ApplicationContext到LiveBeansView内部的applicationContexts中。

① clearResourceCaches

DefaultResourceLoaderResourceLoader接口的默认实现,内部维护了一个ConcurrentHashMap用来缓存classresource。这里即清理前面记录的类资源(因为已经有了BeanDefinition)。

// DefaultResourceLoader
public void clearResourceCaches() {
  this.resourceCaches.clear();
}
private final Map<Class<?>, Map<Resource, ?>> resourceCaches = new ConcurrentHashMap<>(4);

本文这里的resourceCaches 如下所示:


② initLifecycleProcessor

顾名思义,初始化生命周期处理器。方法如下所示:

  • 获取BeanFactory,本文这里是DefaultListableBeanFactory。
  • 如果beanFactory有lifecycleProcessor,则触发getBean获取到bean实例赋予this.lifecycleProcessor

如果beanFactory没有lifecycleProcessor,则实例化DefaultLifecycleProcessor然后设置beanFactory

  • 将新创建的defaultProcessor 指向this.lifecycleProcessor
  • 作为单例注册到beanFactory中
protected void initLifecycleProcessor() {
  ConfigurableListableBeanFactory beanFactory = getBeanFactory();
   // lifecycleProcessor
  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() + "]");
    }
  }
}

③ getLifecycleProcessor().onRefresh()

其实就是调用前面我们实例化的DefaultLifecycleProcessor的onRefresh方法。简单来讲就是触发那些实现了Lifecycle的bean的start方法并将running状态设置为true。

// DefaultLifecycleProcessor
@Override
public void onRefresh() {
  startBeans(true);
  this.running = true;
}

这个startBeans是什么意思呢?就是触发那些实现了Lifecycle的bean的start方法。

private void startBeans(boolean autoStartupOnly) {
// 获取实现了Lifecycle的bean
  Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
  Map<Integer, LifecycleGroup> phases = new HashMap<>();
  // 
  lifecycleBeans.forEach((beanName, bean) -> {
    if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
    // 确定给定bean的生命周期阶段
      int phase = getPhase(bean);
      //获取其所属的生命周期组
      LifecycleGroup group = phases.get(phase);
      if (group == null) {
      // 如果group为null则初始化一个LifecycleGroup 并 放入phases中
        group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
        phases.put(phase, group);
      }
      //将当前bean添加到生命周期组中 List<LifecycleGroupMember> members 
      group.add(beanName, bean);
    }
  });
  // 如果不为空,则按照生命周期阶段,触发每个生命周期组中bean的start方法
  if (!phases.isEmpty()) {
    List<Integer> keys = new ArrayList<>(phases.keySet());
    Collections.sort(keys);
    for (Integer key : keys) {
      phases.get(key).start();
    }
  }
}

338c0f53e8e44350851958cbb7f940d3.png

④ registerApplicationContext

// LiveBeansView
static void registerApplicationContext(ConfigurableApplicationContext applicationContext) {
// spring.liveBeansView.mbeanDomain  本文这里mbeanDomain是""
  String mbeanDomain = applicationContext.getEnvironment().getProperty(MBEAN_DOMAIN_PROPERTY_NAME);
  if (mbeanDomain != null) {
    synchronized (applicationContexts) {
      if (applicationContexts.isEmpty()) {
        try {
        // JmxMBeanServer
          MBeanServer server = ManagementFactory.getPlatformMBeanServer();
          // 本文这里是""
          applicationName = applicationContext.getApplicationName();
          server.registerMBean(new LiveBeansView(),
          // application
              new ObjectName(mbeanDomain, MBEAN_APPLICATION_KEY, applicationName));
        }
        catch (Throwable ex) {
          throw new ApplicationContextException("Failed to register LiveBeansView MBean", ex);
        }
      }
      // 将上下文放到applicationContexts中
      applicationContexts.add(applicationContext);
    }
  }
}
// applicationContexts如下
private static final Set<ConfigurableApplicationContext> applicationContexts = new LinkedHashSet<>();

【2】startWebServer

ServletWebServerApplicationContext的startWebServer方法如下所示,其是关于tomcat中service与connector的处理。

  • 会将connector放到StandardService的 protected Connector connectors[] = new Connector[0];
  • 为connector绑定service;
  • 触发connector的start方法
  • 检测connector的状态是否为LifecycleState.FAILED
// ServletWebServerApplicationContext
private WebServer startWebServer() {
  WebServer webServer = this.webServer;
  if (webServer != null) {
    webServer.start();
  }
  return webServer;
}
// TomcatWebServer
@Override
public void start() throws WebServerException {
  synchronized (this.monitor) {
    if (this.started) {
      return;
    }
    try {
      addPreviouslyRemovedConnectors();
      Connector connector = this.tomcat.getConnector();
      if (connector != null && this.autoStart) {
        performDeferredLoadOnStartup();
      }
      // 检测connector的状态是否为LifecycleState.FAILED
      checkThatConnectorsHaveStarted();
      this.started = true;
      logger.info("Tomcat started on port(s): " + getPortsDescription(true) + " with context path '"
          + getContextPath() + "'");
    }
    catch (ConnectorStartFailedException ex) {
      stopSilently();
      throw ex;
    }
    catch (Exception ex) {
      if (findBindException(ex) != null) {
        throw new PortInUseException(this.tomcat.getConnector().getPort());
      }
      throw new WebServerException("Unable to start embedded Tomcat server", ex);
    }
    finally {
    //StandardEngine[Tomcat].StandardHost[localhost].TomcatEmbeddedContext[]
      Context context = findContext();
      ContextBindings.unbindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
    }
  }
}

addPreviouslyRemovedConnectors

获取tomcat server的service,及connectors ,然后逐个为connector绑定service并触发connector的start方法。

private void addPreviouslyRemovedConnectors() {
  Service[] services = this.tomcat.getServer().findServices();
  for (Service service : services) {
  // serviceConnectors只是一个HashMap
    Connector[] connectors = this.serviceConnectors.get(service);
    if (connectors != null) {
      for (Connector connector : connectors) {
      //添加到service
        service.addConnector(connector);
        if (!this.autoStart) {
          stopProtocolHandler(connector);
        }
      }
      //从map中移除
      this.serviceConnectors.remove(service);
    }
  }
}
// Add a new Connector to the set of defined Connectors, and associate it 
//with this Service's Container
public void addConnector(Connector connector) {
       synchronized (connectorsLock) {
           connector.setService(this);
           Connector results[] = new Connector[connectors.length + 1];
           System.arraycopy(connectors, 0, results, 0, connectors.length);
           results[connectors.length] = connector;
           connectors = results;
       }
       try {
           if (getState().isAvailable()) {
               connector.start();
           }
       } catch (LifecycleException e) {
           throw new IllegalArgumentException(
                   sm.getString("standardService.connector.startFailed", connector), e);
       }
       // Report this property change to interested listeners
       support.firePropertyChange("connector", null, connector);
   }

关于service、connector如下图所示:

performDeferredLoadOnStartup

如下所示,触发TomcatEmbeddedContext的deferredLoadOnStartup方法。

// TomcatWebServer
private void performDeferredLoadOnStartup() {
  try {
    for (Container child : this.tomcat.getHost().findChildren()) {
      if (child instanceof TomcatEmbeddedContext) {
        ((TomcatEmbeddedContext) child).TomcatEmbeddedContext();
      }
    }
  }
  catch (Exception ex) {
    if (ex instanceof WebServerException) {
      throw (WebServerException) ex;
    }
    throw new WebServerException("Unable to start embedded Tomcat connectors", ex);
  }
}

TomcatEmbeddedContextdeferredLoadOnStartup方法如下所示,其会获取到容器关联的children。对children进行遍历获取其loadOnStartup值,如果大于0则有选择性的放到grouped中。

void deferredLoadOnStartup() throws LifecycleException {
  doWithThreadContextClassLoader(getLoader().getClassLoader(),
      () -> getLoadOnStartupWrappers(findChildren()).forEach(this::load));
}
//这里会触发Runnable 的 run方法
private void doWithThreadContextClassLoader(ClassLoader classLoader, Runnable code) {
  ClassLoader existingLoader = (classLoader != null) ? ClassUtils.overrideThreadContextClassLoader(classLoader)
      : null;
  try {
    code.run();
  }
  finally {
    if (existingLoader != null) {
      ClassUtils.overrideThreadContextClassLoader(existingLoader);
    }
  }
}
private Stream<Wrapper> getLoadOnStartupWrappers(Container[] children) {
  Map<Integer, List<Wrapper>> grouped = new TreeMap<>();
  for (Container child : children) {
    Wrapper wrapper = (Wrapper) child;
    // 获取其loadOnStartup值
    int order = wrapper.getLoadOnStartup();
    if (order >= 0) {
      grouped.computeIfAbsent(order, (o) -> new ArrayList<>()).add(wrapper);
    }
  }
  return grouped.values().stream().flatMap(List::stream);
}

本文这里获取到的tomcat container的children如下所示:

0 = {StandardWrapper@9088} "StandardEngine[Tomcat].StandardHost[localhost].TomcatEmbeddedContext[].StandardWrapper[default]"
1 = {StandardWrapper@9090} "StandardEngine[Tomcat].StandardHost[localhost].TomcatEmbeddedContext[].StandardWrapper[dispatcherServlet]"

最后把Map> grouped中的values以流的方式返回一个list。

flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流

690f776e4a2640eca82d5b4cdfb15ef6.png


目录
相关文章
|
2月前
|
Java Spring
【Spring】方法注解@Bean,配置类扫描路径
@Bean方法注解,如何在同一个类下面定义多个Bean对象,配置扫描路径
178 73
|
2月前
|
XML Java 数据格式
Spring Core核心类库的功能与应用实践分析
【12月更文挑战第1天】大家好,今天我们来聊聊Spring Core这个强大的核心类库。Spring Core作为Spring框架的基础,提供了控制反转(IOC)和依赖注入(DI)等核心功能,以及企业级功能,如JNDI和定时任务等。通过本文,我们将从概述、功能点、背景、业务点、底层原理等多个方面深入剖析Spring Core,并通过多个Java示例展示其应用实践,同时指出对应实践的优缺点。
71 14
|
3月前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
53 1
|
4月前
|
存储 安全 Java
|
3月前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
46 1
|
4月前
|
Java BI API
spring boot 整合 itextpdf 导出 PDF,写入大文本,写入HTML代码,分析当下导出PDF的几个工具
这篇文章介绍了如何在Spring Boot项目中整合iTextPDF库来导出PDF文件,包括写入大文本和HTML代码,并分析了几种常用的Java PDF导出工具。
870 0
spring boot 整合 itextpdf 导出 PDF,写入大文本,写入HTML代码,分析当下导出PDF的几个工具
|
4月前
|
XML Java 应用服务中间件
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
312 2
|
3月前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
47 0
|
5月前
|
消息中间件 设计模式 缓存
spring源码设计模式分析(四)-观察者模式
spring源码设计模式分析(四)-观察者模式
|
5月前
|
负载均衡 Java 网络架构
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
243 5