Spring注解版执行流程 refresh

Spring注解版执行流程 refresh

之前的文章已经将刷新前的前置操作说完了,进入refresh方法,refresh方法是在AbstractApplicationContext容器中定义的。再说一次注解容器的继承关系
注解容器继承自GenericApplicationContext。
GenericApplicationContext继承自AbstractApplicationContext。
第一步就是使用重锁synchronized保证同一时间只能有一个线程执行此方法。
在这里插入图片描述

1.prepareRefresh()

protected void prepareRefresh() {
		// 设置环境启动时间
		// Switch to active.
		this.startupDate = System.currentTimeMillis();
		// 设置状态,当前处于活跃状态
		this.closed.set(false);
		this.active.set(true);
		// 初始化上下文环境中的任何占位符属性源
		// Initialize any placeholder property sources in the context environment.
		initPropertySources();
		// 保证加载的配置文件都是可以解析的
		// Validate that all properties marked as required are resolvable:
		// see ConfigurablePropertyResolver#setRequiredProperties
		getEnvironment().validateRequiredProperties();
		// 设置预刷新的监听器。这里其实applicationListeners也是空的
		// 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);
		}
		// 这里指如果时间多播器如果还没创建,先把事件添加到earlyApplicationEvents 集合中,等创建事件多播器后再发布事件
		// Allow for the collection of early ApplicationEvents,
		// to be published once the multicaster is available...
		this.earlyApplicationEvents = new LinkedHashSet<>();
	}

前面设置启动事件,活跃状态。initPropertySources方法是加载配置文件,但是我们这里并没有配置文件,并且AnnotationConfigApplicationContext也没有实现这个方法,所有简单来说initPropertySources()和getEnvironment().validateRequiredProperties()方法并没有做什么。后续换一个实现了这个配置的容器。后面设置监听器和早期事件也可以不用看了,都是一些初始值。prepareRefresh并没有做什么事情。

2.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory()

获取工厂对象。refreshBeanFactory方法在AbstractApplicationContext中并没有实现,但是子类GenericApplicationContext实现了。this.refreshed成员变量也是GenericApplicationContext中的。在对象创建时赋值了原子类 AtomicBoolean refreshed = new AtomicBoolean();这个类保证多线程安全。如果不显示赋值默认为false。getBeanFactory就是返回GenericApplicationContext容器中的工厂对象。这一系列操作,就是保证获取的这个工厂对象是单线程在操作的。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		refreshBeanFactory();
		return getBeanFactory();
	}

	@Override
	protected final void refreshBeanFactory() throws IllegalStateException {
		/**
		 *  compareAndSet(boolean expect, boolean update)
		 * 1.比较AtomicBoolean和expect的值,如果一致,执行方法内的语句。其实就是一个if语句
		 * 2.把AtomicBoolean的值设成update比较最要的是这两件事是一气呵成的,这连个动作之间不会被打断,任何内部或者外部的语句都不可能在两个动作之间运行。为多线程的控制提供了解决的方案。
		    this.refreshed.compareAndSet(false, true)
		    如果refreshed是false,返回true,并且把refreshed更新为true
		 */ 
		if (!this.refreshed.compareAndSet(false, true)) {
			throw new IllegalStateException(
					"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
		}
		// 这是工厂的序列号id
		this.beanFactory.setSerializationId(getId());
	}
	
@Override
	public final ConfigurableListableBeanFactory getBeanFactory() {
		return this.beanFactory;
	}

3.prepareBeanFactory(beanFactory)

进入prepareBeanFactory方法,第一步设置bean工厂的类加载器,实际上是应用类加载器。
shouldIgnoreSpel表示是否需要忽略spel表达式,默认是false指不忽略。给bean工厂设置一个标准的spel表达式解析器和ResourceEditorRegistrar资源编辑器。(这两个也不是一两句话能讲完的,打个标记)。ignoredDependencyInterface方法是忽略该接口的实现类中和接口setter方法入参类型相同的依赖。这个简单解释一下就是忽略接口实现类中相关属性的注入(这个也要单独解释,两句话说不清)。

	protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		// Tell the internal bean factory to use the context's class loader etc.
		beanFactory.setBeanClassLoader(getClassLoader());
		if (!shouldIgnoreSpel) {
			beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
		}
		// 添加一个对bean的属性等设置管理工具,它和资源、数据转换有关
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
        // 添加AwareProcessor后置处理器,这个和Aware知识相关。
		// Configure the bean factory with context callbacks.
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
		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.ignoreDependencyInterface(ApplicationStartupAware.class);

registerResolvableDependency方法的作用就是指定该类型接口,如果外部要注入该类型接口的对象,则会注入我们指定的对象,而不会去管其他接口实现类。为什么呢?如果在自动注入的时候,我们指定的是接口,但是容器中有许多实现类,那么容器可能会不知道注入哪一个。registerResolvableDependency方法就算告诉容器指定注入哪个对象。(老规矩,打标记先。

		// BeanFactory interface not registered as resolvable type in a plain factory.
		// MessageSource registered (and found for autowiring) as a bean.
		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
		beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
		beanFactory.registerResolvableDependency(ApplicationContext.class, this);

ApplicationListenerDetector的主要作用:

1、在Bean初始化完成之后:如果Bean是单例的则并且bean instanceof ApplicationListener。加入到this.applicationListeners中。
2、在Bean销毁之前搞事情: 如果Bean是一个ApplicationListener,则会从ApplicationEventMulticaster(事件广播器)中提前删除了。
		// Register early post-processor for detecting inner beans as ApplicationListeners.
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

LoadTimeWeaverAwareProcessor和AOP作用相关的一种,但是这里逻辑判断并没有进去,因为Beanfactory这个时候还是空的。准确的说 singletonObjects集合和beanDefinitionMap集合中都没有LoadTimeWeaverAwareProcessor相关信息。

		if (!NativeDetector.inNativeImage() && 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()));
		}

下面方法往容器中添加单例对象。这个时候我们的容器中就会有4个对象了。

		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());
		}
		if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
			beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
		}

分别是applicationStartup、environment环境对象、systemProperties(指的是我们的java程序中的jvm环境变量)、systemEnvironment(操作系统中的环境变量)
在这里插入图片描述

在添加之前先做判断,容器中是否有此类对象。判断逻辑是查看ingletonObjects集合和beanDefinitionMap集合中都没有相关信息。同时要求bean对象不能是工厂对象,这里又区别了普通对象和工厂对象的关系。(普通对象和工厂对象
在这里插入图片描述
prepareBeanFactory方法暂时先就这样了,大致可以理解成为为我们的bean工厂对象“升级”,崭新出厂的beanFactory对象经过这一步拥有了许多的能力。

之前看别人博客的时候看到普遍都说spring源码复杂。自己动手写觉得还真是那么回事,哈哈哈。一篇文章留下的全是等着填的坑,解释的也不是很清晰。
有点怀疑自己了,初生牛犊不怕虎,哈哈哈哈哈哈!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值