Spring中refresh分析之finishRefresh方法详解

关联博文:
AbstractApplicationContext中refresh方法详解
Spring中refresh分析之prepareRefresh方法详解
Spring中refresh分析之obtainFreshBeanFactory方法详解
Spring中refresh分析之prepareBeanFactory方法详解
Spring中refresh分析之postProcessBeanFactory方法详解
Spring中refresh分析之invokeBeanFactoryPostProcessors方法详解
Spring中refresh分析之registerBeanPostProcessors方法详解
Spring中refresh分析之initMessageSource方法详解
Spring中refresh分析之initApplicationEventMulticaster方法详解
Spring中refresh分析之onRefresh方法详解
Spring中refresh分析之registerListeners方法详解
Spring中refresh分析之finishBeanFactoryInitialization方法详解
Spring中refresh分析之finishRefresh方法详解

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

方法功能梳理:

  • 清理前面记录的类资源(因为已经有了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<>())
在这里插入图片描述

关于事件发布与捕捉可以参考博文:Spring中事件监听(通知)机制详解与实践


【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();
		}
	}
}

在这里插入图片描述

④ 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<Integer, List<Wrapper>> grouped中的values以流的方式返回一个list。

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

在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流烟默

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值