[读书笔记]AbstractApplicationContext中refresh方法详解

关联博文:
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 IoC容器对Bean定义资源的载入是从refresh()函数开始的,refresh()是一个模板方法,refresh()方法的作用是在创建IoC容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh之后使用的是新建立起来的IoC容器。

refresh的作用类似于对IoC容器的重启,在新建立好的容器中对容器进行初始化,对Bean定义资源进行载入

refresh()方法主要为IoC容器Bean的生命周期管理提供条件,Spring IoC容器载入Bean定义资源文件从其子类容器的refreshBeanFactory()方法启动,所以整个refresh()中ConfigurableListableBeanFactory beanFactory =obtainFreshBeanFactory();”这句以后代码的都是注册容器的信息源和生命周期事件,载入过程就是从这句代码启动。

本文开始,我们将分析refresh的系列方法。

【1】方法概览

AbstractApplicationContext 的refresh方法如下所示:

@Override
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// Prepare this context for refreshing.
		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.
			//为了防止Bean资源占用,在异常处理中销毁已经在前面过程中生成的单件Bean
			destroyBeans();

			// Reset 'active' flag.
			//重置 active 标识
			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();
		}
	}
}

方法解释如下:

  • ① 准备刷新的上下文环境;
  • ② 获取到应用上下文维护的beanFactory,默认是DefaultListableBeanFactory。并设置刷新标志refreshed为true
  • ③ 对beanFactory做了一些基础设置的配置,比如BeanClassLoader、BeanExpressionResolver、ApplicationContextAwareProcessor、ApplicationListenerDetector监听器检测器以及默认的环境信息bean。并设置了哪些不需要自动注入以及哪些已经解析过可以直接使用。
  • ④ BeanFactory的后置处理;
  • ⑤ 注册并调用BeanFactoryPostProcessor,扫描获取BeanDefinition;
  • ⑥ 注册BeanPostProcessor到BeanFactory;
  • ⑦ 初始化MessageSource消息源;
  • ⑧ 初始化事件广播器;
  • ⑨ 初始化themeSource并创建WebServer;
  • ⑩ 检查监听bean并将这些bean向容器中注册
  • (11) 初始化所有non-lazy-init bean,比如我们的controller、service、mapper等;
  • (12) 发布容器事件,结束Refresh过程
  • (13) 重置Spring核心中的常见内省缓存,因为我们可能不再需要单例bean的元数据。。。

【2】异常捕捉中的两个方法

① destroyBeans

这是一个模板方法,销毁所有上下文管理的bean。默认实现是销毁上下文缓存的所有单例bean,通过触发DisposableBean.destroy()方法或者指定的具体destroy-method。可以重写以在标准单例销毁之前或之后添加特定于上下文的bean销毁步骤,如果上下文的BeanFactory仍处于活动状态。

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

DefaultListableBeanFactory的销毁实例方法如下所示,其首先触发父类DefaultSingletonBeanRegistry的销毁方法,然后清空Set<String> manualSingletonNames

@Override
public void destroySingletons() {
	super.destroySingletons();
	updateManualSingletonNames(Set::clear, set -> !set.isEmpty());
	clearByTypeCache();
}

DefaultSingletonBeanRegistry的destroySingletons方法。

public void destroySingletons() {
	if (logger.isTraceEnabled()) {
		logger.trace("Destroying singletons in " + this);
	}
	synchronized (this.singletonObjects) {
	//设置状态
		this.singletonsCurrentlyInDestruction = true;
	}

	String[] disposableBeanNames;
	synchronized (this.disposableBeans) {
		disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
	}
	// 循环遍历销毁每一个disposableBean
	for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
		destroySingleton(disposableBeanNames[i]);
	}
	//清空集合
	this.containedBeanMap.clear();
	this.dependentBeanMap.clear();
	this.dependenciesForBeanMap.clear();
	// 清空缓存 包括一级、二级、三级以及registeredSingletons
	clearSingletonCache();
}

② cancelRefresh

这个方法简单,就只重置标志:

  • 将beanFactory的SerializationId置为null
  • active设置为false

【3】resetCommonCaches

重置Spring核心中的常见内省缓存,因为我们可能不再需要单例bean的元数据。

// AbstractApplicationContext
protected void resetCommonCaches() {
	ReflectionUtils.clearCache();
	AnnotationUtils.clearCache();
	ResolvableType.clearCache();
	CachedIntrospectionResults.clearClassLoader(getClassLoader());
}

ReflectionUtils.clearCache如下所示:

public static void clearCache() {
	declaredMethodsCache.clear();
	declaredFieldsCache.clear();
}

AnnotationUtils.clearCache如下所示:

public static void clearCache() {
	AnnotationTypeMappings.clearCache();
	AnnotationsScanner.clearCache();
}

ResolvableType.clearCache如下所示:

public static void clearCache() {
	cache.clear();
	SerializableTypeWrapper.cache.clear();
}

private static final ConcurrentReferenceHashMap<ResolvableType, ResolvableType> cache =
new ConcurrentReferenceHashMap<>(256);
  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
`org.springframework.context.support.AbstractApplicationContext` 类的 `refresh()` 方法用于刷新应用程序上下文。 当调用 `refresh()` 方法时,它会执行一系列的操作来刷新应用程序上下文,包括加载或刷新配置文件、创建和初始化 Bean、解析依赖关系、自动装配等。 在 Spring 应用程序,通常会有一个特定的类继承自 `AbstractApplicationContext`,并在其 `main()` 方法调用 `refresh()` 方法来启动应用程序上下文。这个类可以是 `ClassPathXmlApplicationContext`、`AnnotationConfigApplicationContext` 或其他 Spring 提供的特定类型的应用程序上下文。 下面是一个使用 `ClassPathXmlApplicationContext` 的例子: ```java import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { // 创建并初始化应用程序上下文 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // 刷新应用程序上下文 context.refresh(); // 执行其他操作... // 关闭应用程序上下文 context.close(); } } ``` 在这个例子,我们使用 `ClassPathXmlApplicationContext` 创建了一个基于 XML 配置文件的应用程序上下文。然后,在 `main()` 方法调用了 `refresh()` 方法刷新应用程序上下文。之后可以执行其他操作,并在最后关闭应用程序上下文。 请注意,具体的配置和使用方式取决于你的项目结构和需求。你可以根据自己的情况选择合适的应用程序上下文类型,并在适当的时候调用 `refresh()` 方法刷新上下文。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

流烟默

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

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

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

打赏作者

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

抵扣说明:

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

余额充值