前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【小家Spring】Spring IOC容器启动流程 AbstractApplicationContext#refresh()方法源码分析(二),Spring容器启动/刷新的完整总结

【小家Spring】Spring IOC容器启动流程 AbstractApplicationContext#refresh()方法源码分析(二),Spring容器启动/刷新的完整总结

作者头像
YourBatman
发布2019-09-03 16:30:22
2.1K0
发布2019-09-03 16:30:22
举报
文章被收录于专栏:BAT的乌托邦

前言

在上一篇文章:【小家Spring】Spring IOC容器启动流程 AbstractApplicationContext#refresh()方法源码分析(一)中已经介绍了前五步,现在Spring IOC容器的工厂环境已经都准备好了。

Bean工厂可以简单理解为一个钩子容器,里面注册有众多的BeanFactoryPostProcessor以及BeanFactoryPostProcessor,接下来我们就前去学习钩子的细节~

Spring源码基于的Spring版本为:5.0.6.RELEASE(下同) Spring源码基于的Spring版本为:5.0.6.RELEASE(下同) Spring源码基于的Spring版本为:5.0.6.RELEASE(下同)

refresh() 第六步:registerBeanPostProcessors(beanFactory)

在讲解这个方法之前先看下什么是BeanPostProcessor,下面是BeanPostProcessor的代码:

代码语言:javascript
复制
public interface BeanPostProcessor {

	// 在Bean实例化/依赖注入完毕以及自定义的初始化方法之前调用。什么叫自定义初始化方法:比如init-method、比如@PostConstruct标、比如实现InitailztingBean接口的方法等等
	// bean:这个Bean实例  beanName:bean名称
	
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
	
	// 在上面基础上,初始化方法之后调用
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
}

接口中两个方法不能返回null,如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象 ,因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中

BeanFactory和ApplicationContext注册Bean的后置处理器不通点:

ApplicationContext直接使用@Bean注解,就能向容器注册一个后置处理器。

原因:它注册Bean的时候,会先检测是否实现了BeanPostProcessor接口,并自动把它们注册为后置处理器。所在在它这部署一个后置处理器和注册一个普通的Bean,是没有区别的

BeanFactory必须显示的调用:void addBeanPostProcessor(BeanPostProcessor beanPostProcessor才能注册进去。

Spring 可以注册多个Bean的后置处理器,是按照注册的顺序进行调用的。若想定制顺序,可以实现@Order或者实现Order接口~

源码解读

先说说:((DefaultListableBeanFactory) beanFactory).getBeanPostProcessors();这个方法:

代码语言:javascript
复制
	public List<BeanPostProcessor> getBeanPostProcessors() {
		return this.beanPostProcessors;
	}

它返回的是所有的通过BeanFactory#addBeanPostProcessor方法添加进去的后置处理器们,会存在这个List里面。

还有就是这个内部类:(一共4个,是容器启动时,用BeanFactory添加进去的Bean后置处理器)

而这个方法getBeanNamesForType是从Bean定义信息里面去找:主要是如下几个属性缓存上的:

(所以请注意和getBeanPostProcessors的结果区分开来,虽然都是BeanPostProcessor

代码语言:javascript
复制
	/** Map of bean definition objects, keyed by bean name */
	private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
	/** Map of singleton and non-singleton bean names, keyed by dependency type */
	private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);
	/** Map of singleton-only bean names, keyed by dependency type */
	private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64);
	/** List of bean definition names, in registration order */
	private volatile List<String> beanDefinitionNames = new ArrayList<>(256);

这些其实就是IOC容器的本质:一堆Map

具体源码:

代码语言:javascript
复制
	// 发现它又是委托给PostProcessorRegistrationDelegate 去做的
	protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
	}


	public static void registerBeanPostProcessors(
			ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
		
		// 从所与Bean定义中提取出BeanPostProcessor类型的Bean,显然,最初的6个bean,有三个是BeanPostProcessor:
		// AutowiredAnnotationBeanPostProcessor  RequiredAnnotationBeanPostProcessor  CommonAnnotationBeanPostProcessor
		String[] 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.
		// 此处有点意思了,向beanFactory又add了一个BeanPostProcessorChecker,并且此事后总数设置为了getBeanPostProcessorCount和addBeanPostProcessor的总和(+1表示自己)
		int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
		// 此处注意:第一个参数beanPostProcessorTargetCount表示的是处理器的总数,总数(包含两个位置离的,用于后面的校验)
		beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

		// Separate between BeanPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
		// 同样的 先按优先级,归类了BeanPostProcessor
		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 pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
				priorityOrderedPostProcessors.add(pp);
				// MergedBeanDefinitionPostProcessor则是在合并处理Bean定义的时候的回调。这个东东按我的理解也基本是框架内部使用的,用户不用管
				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<>();
		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<>();
		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).
		// 最后此处需要注意的是:Spring还给我们注册了一个Bean的后置处理器:ApplicationListenerDetector  它的作用:用来检查所有得ApplicationListener
		// 有的人就想问了:之前不是注册过了吗,怎么这里又注册一次呢?其实上面的doc里面说得很清楚:
		// Re-register重新注册这个后置处理器。把它移动到处理器连条的最后面,最后执行(小技巧是:先remove,然后执行add操作~~~ 自己可以点进addBeanPostProcessor源码可以看到这个小技巧)
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
	}

	// 把类型是BeanPostProcessor的Bean,注册到beanFactory里面去
	private static void registerBeanPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {

		for (BeanPostProcessor postProcessor : postProcessors) {
			beanFactory.addBeanPostProcessor(postProcessor);
		}
	}

这一步:我们从所有的@Bean定义中抽取出来了BeanPostProcessor然后都注册进去,等待后面的的顺序调用

refresh() 第七步:initMessageSource()

初始化消息源。

代码语言:javascript
复制
	protected void initMessageSource() {
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();

		// 判断是否已经存在名为“messageSource”的Bean了(一般情况下,我们都是没有的)
		if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
			// 从容器里拿出这个messageSource 
			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());
				}
			}
		}
		else {
			// Use empty MessageSource to be able to accept getMessage calls.
			DelegatingMessageSource dms = new DelegatingMessageSource();

			// 其实就是获取到父容器的messageSource字段(否则就是getParent()上下文自己)
			dms.setParentMessageSource(getInternalParentMessageSource());
			// 给当前的messageSource赋值
			this.messageSource = dms;
			// 把messageSource作为一个单例的Bean注册进beanFactory工厂里面
			beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
		}
	}

这部分逻辑比较简单:向容器里注册一个一个事件源的单例Bean:MessageSource

refresh() 第八步:initApplicationEventMulticaster()

初始化Spring的事件多播器:ApplicationEventMulticaster

代码语言:javascript
复制
	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);
		} else {
			this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
			beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster); 
		}
	}

这个逻辑太简单了,一句话:若用户自己定义了这个Bean(备注:Bean名称必须是"applicationEventMulticaster"哦),就以用户的为准。否则注册一个系统默认的**SimpleApplicationEventMulticaster**

refresh() 第九步:onRefresh()

类似于第四步的postProcessBeanFactory,它也是个模版方法。本环境中的实现为:AbstractRefreshableWebApplicationContext#onRefresh方法:

代码语言:javascript
复制
	@Override
	protected void onRefresh() {
		this.themeSource = UiApplicationContextUtils.initThemeSource(this);
	}

web环境,所以去初始化了它的主题。

refresh() 第十步:registerListeners();

我们知道,上面我们已经把事件源、多播器都注册好了,这里就是注册监听器了:

代码语言:javascript
复制
	protected void registerListeners() {
		// 这一步和手动注册BeanDefinitionRegistryPostProcessor一样,可以自己通过set手动注册监听器  然后是最新执行的(显然此处我们无自己set)
		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!
		// 取到容器里面的所有的监听器的名称,绑定到广播器  后面会广播出去这些事件的
		// 同时提醒大伙注意:此处并没有说到ApplicationListenerDetector这个东东,下文会分解
		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...
		// 这一步需要注意了:如果存在早期应用事件,这里就直接发布了(同时就把earlyApplicationEvents该字段置为null)
		// 
		Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
		this.earlyApplicationEvents = null;
		if (earlyEventsToProcess != null) {
			for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
				getApplicationEventMulticaster().multicastEvent(earlyEvent);
			}
		}
	}
refresh() 第十一步:finishBeanFactoryInitialization(beanFactory)

这进行这一步之前,我这里截图看看,当前工厂里的Bean的的一个情况:

容器内所有的单例Bean们: 有的是提前经历过getBean()被提前实例化了,有的是直接addSingleton()方法直接添加的

容器内所有的Bean定义信息: 我们能够发现,我们自己@Bean进去的目前都仅仅存在于Bean定义信息内,还并没有真正的实例化。这就是我们这一步需要做的事

这里先建立一个快照,等执行完成这一步之后,再截图对比。


创建所有非懒加载的单例类(并invoke BeanPostProcessors)。这一步可谓和我们开发者打交道最多的,我们自定义的Bean绝大都是在这一步被初始化的,包括依赖注入等等~

因此了解这一步,能让我们更深入的了解Spring是怎么管理我们的Bean的声明周期,以及依赖关系的。

代码语言:javascript
复制
	protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
		// Initialize conversion service for this context.
		// 初始化上下文的转换服务,ConversionService是一个类型转换接口
		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.
		// 设置一个内置的值处理器(若没有的话),该处理器作用有点像一个PropertyPlaceholderConfigurer bean
		if (!beanFactory.hasEmbeddedValueResolver()) {
			beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
		}

		// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
		// 注意此处已经调用了getBean方法,初始化LoadTimeWeaverAware Bean
		// getBean()方法的详细,下面会详细分解
		// LoadTimeWeaverAware是类加载时织入的意思
		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
		for (String weaverAwareName : weaverAwareNames) {
			getBean(weaverAwareName);
		}

		// Stop using the temporary ClassLoader for type matching.
		// 停止使用临时的类加载器
		beanFactory.setTempClassLoader(null);

		// Allow for caching all bean definition metadata, not expecting further changes.
		// 缓存(冻结)所有的bean definition数据,不期望以后会改变
		beanFactory.freezeConfiguration();

		// Instantiate all remaining (non-lazy-init) singletons.
		// 这个就是最重要的方法:会把留下来的Bean们  不是lazy懒加载的bean都实例化掉
		//  bean真正实例化的时刻到了
		beanFactory.preInstantiateSingletons();
	}


	@Override
	public void freezeConfiguration() {
		this.configurationFrozen = true;
		this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames);
	}

接下来重点看看DefaultListableBeanFactory#preInstantiateSingletons:实例化所有剩余的单例Bean

代码语言:javascript
复制
	@Override
	public void preInstantiateSingletons() throws BeansException {

		// 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.
		// 此处目的,把所有的bean定义信息名称,赋值到一个新的集合中
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// Trigger initialization of all non-lazy singleton beans...
		for (String beanName : beanNames) {
			//getMergedLocalBeanDefinition:见下~
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
	
			// 不是抽象类&&是单例&&不是懒加载
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {

				// 这是Spring提供的对工程bean模式的支持:比如第三方框架的继承经常采用这种方式
				// 如果是工厂Bean,那就会此工厂Bean放进去
				if (isFactoryBean(beanName)) {
					// 拿到工厂Bean本省,注意有前缀为:FACTORY_BEAN_PREFIX 
					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());
						}

						// true:表示渴望马上被初始化的,那就拿上执行初始化~
						if (isEagerInit) {
							getBean(beanName);
						}
					}
				} else { // 这里,就是普通单例Bean正式初始化了~  核心逻辑在方法:doGetBean 
					// 关于doGetBean方法的详解:下面有贴出博文,专文讲解
					getBean(beanName);
				}
			}
		}

		// Trigger post-initialization callback for all applicable beans...
		// SmartInitializingSingleton:所有非lazy单例Bean实例化完成后的回调方法 Spring4.1才提供
		//SmartInitializingSingleton的afterSingletonsInstantiated方法是在所有单例bean都已经被创建后执行的
		//InitializingBean#afterPropertiesSet 是在仅仅自己被创建好了执行的
		// 比如EventListenerMethodProcessor它在afterSingletonsInstantiated方法里就去处理所有的Bean的方法
		// 看看哪些被标注了@EventListener注解,提取处理也作为一个Listener放到容器addApplicationListener里面去
		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 {
					// 比如:ScheduledAnnotationBeanPostProcessor CacheAspectSupport  MBeanExporter等等
					smartSingleton.afterSingletonsInstantiated();
				}
			}
		}
	}

此处必须说明:此处绝大部分的单例Bean定义信息都会被实例化,但是如果是通过FactoryBean定义的,它是懒加载的(如果没人使用,就先不会实例化。只会到使用的时候才实例化~)。如下例子:

代码语言:javascript
复制
@Configuration
public class RootConfig {

    @Bean
    public Person person() {
        System.out.println("this is from @Bean person");
        return new Person();
    }

    @Bean("personFactoryBean")
    public FactoryBean<Person> personFactoryBean() {
        return new FactoryBean<Person>() {
            @Override
            public Person getObject() throws Exception {
                System.out.println("this is from personFactoryBean");
                return new Person();
            }

            @Override
            public Class<?> getObjectType() {
                return Person.class;
            }
        };
    }

}

默认情况下,person()会被启动时候,实例化,但是personFactoryBean()不会。

此时通过applicationContext.getBeanDefinitionNames()能找到personFactoryBean这个Bean定义。并且通过.beanFactory.getSingletonNames()也能找到personFactoryBean这个单例Bean,所以其实此时容器内的Bean是FactoryBean而不是真正的Bean,只有在真正使用的时候,才会create一个真正的Bean出来~

比如我只需要在某个组件内注入一下:

代码语言:javascript
复制
    @Autowired
    @Qualifier("personFactoryBean")
    private Person person;

这个FactoryBean#getObject就会立马执行了~


getMergedLocalBeanDefinition方法分解:

这里先解释一下getMergedLocalBeanDefinition方法的含义,因为这个方法会常常看到。

Bean定义公共的抽象类是AbstractBeanDefinition,普通的Bean在Spring加载Bean定义的时候,实例化出来的是GenericBeanDefinition,而Spring上下文包括实例化所有Bean用的AbstractBeanDefinition是RootBeanDefinition,这时候就使用getMergedLocalBeanDefinition方法做了一次转化,将非RootBeanDefinition转换为RootBeanDefinition以供后续操作。

代码语言:javascript
复制
	// 该方法功能说明:在map缓存中把Bean的定义拿出来。交给getMergedLocalBeanDefinition处理。最终转换成了RootBeanDefinition类型
	//在转换的过程中如果BeanDefinition的父类不为空,则把父类的属性也合并到RootBeanDefinition中,
	//所以getMergedLocalBeanDefinition方法的作用就是获取缓存的BeanDefinition对象并合并其父类和本身的属性
	//注意如果当前BeanDefinition存在父BeanDefinition,会基于父BeanDefinition生成一个RootBeanDefinition,然后再将调用OverrideFrom子BeanDefinition的相关属性覆写进去
	protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
		// Quick check on the concurrent map first, with minimal locking.
		RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
		if (mbd != null) {
			return mbd;
		}
		return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
	}

getBeanDefinition(beanName):方法如下

	// 这一步说白了:就是把前面已经保存在IOC容器里的BeanDefinition定义信息
	@Override
	public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
		BeanDefinition bd = this.beanDefinitionMap.get(beanName);
		if (bd == null) {
			if (this.logger.isTraceEnabled()) {
				this.logger.trace("No bean named '" + beanName + "' found in " + this);
			}
			throw new NoSuchBeanDefinitionException(beanName);
		}
		return bd;
	}
getBean():创建Bean的核心方法

getBean()方法为创建Bean,包括初始化剩余的单实例Bean时候的核心方法,专门写了一篇博文来介绍它,请移步此处:【小家Spring】AbstractBeanFactory#getBean()、doGetBean完成Bean的初始化、实例化,以及BeanPostProcessor后置处理器源码级详细分析

至此,finishBeanFactoryInitialization这一步完成,所有的单例Bean已经创建完成并放置容器里。

refresh() 第十二步:finishRefresh()

refresh做完之后需要做的其他事情。

代码语言:javascript
复制
	protected void finishRefresh() {
		// Clear context-level resource caches (such as ASM metadata from scanning).
		// 这个是Spring5.0之后才有的方法
		// 表示清除一些resourceCaches,如doc说的  清楚context级别的资源缓存,比如ASM的元数据
		clearResourceCaches();

		// Initialize lifecycle processor for this context.
		// 初始化所有的LifecycleProcessor  详见下面
		initLifecycleProcessor();

		// Propagate refresh to lifecycle processor first.
		// 上面注册好的处理器,这里就拿出来,调用它的onRefresh方法了
		getLifecycleProcessor().onRefresh();

		// Publish the final event.
		// 发布容器刷新的事件:
		publishEvent(new ContextRefreshedEvent(this));

		// Participate in LiveBeansView MBean, if active.
		// 和MBeanServer和MBean有关的。相当于把当前容器上下文,注册到MBeanServer里面去。
		// 这样子,MBeanServer持久了容器的引用,就可以拿到容器的所有内容了,也就让Spring支持到了MBean的相关功能
		LiveBeansView.registerApplicationContext(this);
	}

initLifecycleProcessor()

在 Spring 中还提供了 Lifecycle 接口, Lifecycle 中包含start/stop方法,实现此接口后Spring会保证在启动的时候调用其start方法开始生命周期,并在Spring关闭的时候调用 stop方法来结束生命周期,通常用来配置后台程序,在启动后一直运行(如对 MQ 进行轮询等)。而ApplicationContext的初始化最后正是保证了这一功能的实现。

当ApplicationContext启动或停止时,它会通过LifecycleProcessor来与所有声明的bean的周期做状态更新,而在LifecycleProcessor的使用前首先需要初始化。

代码语言:javascript
复制
	// 这个初始化逻辑比较简单
	protected void initLifecycleProcessor() {
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	
		// 如果工厂里已经存在LifecycleProcessor,那就拿出来,把值放上去this.lifecycleProcessor
		if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
			this.lifecycleProcessor = beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
		}
		// 一般情况下,都会注册上这个默认的处理器DefaultLifecycleProcessor
		else {
			DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
			defaultProcessor.setBeanFactory(beanFactory);
			this.lifecycleProcessor = defaultProcessor;
			// 直接注册成单例Bean进去容器里
			beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
		}
	}

初始化生命周期处理器,并设置到Spring容器中(LifecycleProcessor)

调用生命周期处理器的onRefresh方法,这个方法会找出Spring容器中实现了SmartLifecycle接口的类并进行start方法的调用

发布ContextRefreshedEvent事件告知对应的ApplicationListener进行响应的操作

调用LiveBeansView的registerApplicationContext方法:如果设置了JMX相关的属性,则就调用该方法

发布EmbeddedServletContainerInitializedEvent事件告知对应的ApplicationListener进行响应的操作


getLifecycleProcessor().onRefresh()**:DefaultLifecycleProcessor讲解**

备注:LifecycleProcessor作为一个Bean,它自己也实现了Lifecycle这个接口。LifecycleProcessor和DefaultLifecycleProcessor都是Spring3.0提供的,Lifecycle在Spring2.0就有了,但子接口SmartLifecycle是Spring3.0后提供的

代码语言:javascript
复制
public interface LifecycleProcessor extends Lifecycle {}

public interface SmartLifecycle extends Lifecycle, Phased {
	// 是否伴随这容器的启动而启动  true表示容器refreshed它就会启动了
	// false:必须显示的执行了它的start()才行
	boolean isAutoStartup();
	// 相比于Lifecycle 的stop,增加了回调函数
	void stop(Runnable callback);
}

public interface Phased {
	// 权重值
	int getPhase();
}

这里的处理器(只能有一个),就是我们上面注册好了的DefaultLifecycleProcessor,我们看看它的主要方法:

  • 启动和关闭调用的顺序是很重要的。如果两个对象之间存在依赖关系,依赖类要在其依赖类后启动,依赖类也要在其依赖类前停止。
代码语言:javascript
复制
// Lifecycle的方法
	@Override
	public void start() {
		// 传false,表示Bean一定会启动
		startBeans(false);
		this.running = true;
	}
	@Override
	public void stop() {
		stopBeans();
		this.running = false;
	}
	@Override
	public boolean isRunning() {
		return this.running;
	}

// LifecycleProcessor的方法

	//getLifecycleProcessor().onRefresh(); 这个方法才是容器启动时候自动会调用的,其余都不是
	// 显然它默认只会执行实现了SmartLifecycle接口并且isAutoStartup = true的Bean的start方法
	@Override
	public void onRefresh() {
		startBeans(true);
		this.running = true;
	}
	
	// 容器关闭的时候自动会调的
	@Override
	public void onClose() {
		stopBeans();
		this.running = false;
	}
// 而到底bean实现的Lifecyle的start()、stop()方法是否会调用呢? 请看下文

//======================startBeans和stopBeans  LifecycleGroup#start======================
	// autoStartupOnly:是否仅支持自动启动   
	// true:只支持伴随容器启动 (bean必须实现了`SmartLifecycle`接口且isAutoStartup为true才行)
	// false:表示无所谓。都会执行bean的start方法=======
	private void startBeans(boolean autoStartupOnly) {
		//拿到所有的实现了Lifecycle/SmartLifecycle的  已经在IOC容器里面的单例Bean们(备注:不包括自己this,也就是说处理器自己不包含进去)
		// 这里若我们自己没有定义过实现Lifecycle的Bean,这里就是空的
		Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
		
		// phases 这个Map,表示按照phase 值,吧这个Bean进行分组,最后分组执行
		Map<Integer, LifecycleGroup> phases = new HashMap<>();
		lifecycleBeans.forEach((beanName, bean) -> {
			
			// 若Bean实现了SmartLifecycle 接口并且标注是AutoStartup  或者  强制要求自动自行的autoStartupOnly = true
			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);
				}
				// 添加到phase 值相同的组  分组嘛
				group.add(beanName, bean);
			}
		});
		if (!phases.isEmpty()) {
			List<Integer> keys = new ArrayList<>(phases.keySet());
			// 此处有个根据key从小到大的排序,然后一个个的调用他们的start方法
			Collections.sort(keys);
			for (Integer key : keys) {
			
				// 这里调用LifecycleGroup#start() 如下
				phases.get(key).start();
			}
		}
	}
	
//LifecycleGroup#start()
		public void start() {
			if (this.members.isEmpty()) {
				return;
			}
			if (logger.isInfoEnabled()) {
				logger.info("Starting beans in phase " + this.phase);
			}
			// 按照权重值进行排序  若没有实现Smart接口的  权重值都为0
			Collections.sort(this.members);
			
			for (LifecycleGroupMember member : this.members) {
				if (this.lifecycleBeans.containsKey(member.name)) {
					// 一次执行这些Bean的start方法(这里面逻辑就没啥好看的,只有一个考虑到getBeanFactory().dependenciesForBean控制Bean的依赖关系的)
					doStart(this.lifecycleBeans, member.name, this.autoStartupOnly);
				}
			}
		}
//stopBeans原理基本同startBeans,只是顺序是倒序的,此处省略

就这样,实现了Lifecycle接口的Bean start方法什么时候调用就有门路了。

从上面的源码中,我们能够读出什么异常的地方呢?我们发现**Lifecycle**这个接口并不能直接使用

因为DefaultLifecycleProcessoronRefresh方法传值为autoStartupOnly=true:表示只有实现了SmartLifecycle的Bean才会调用start方法,因为实现了SmartLifecycle接口会有一个phase值,根据上面源码会根据此值分组执行。

autoStartupOnly=false则只要是Lifecycle 的实现既可以被调用,我们会给其默认的phase。

所以,我们要想要这个功能,请实现SmartLifecycle,而不是Lifecycle接口

结论:

  • Spring的IoC容器启动过程中,默认只会执行实现了SmartLifecycle接口且isAutoStartup()=true的Bean的start()方法的。(所以你要想容器启动后就执行,请实现SmartLifecycle吧
  • AbstractApplicationContext#start() 手动调用触发。常见的一般这么做的:
代码语言:javascript
复制
 context = new ClassPathXmlApplicationContext(configPath.split("[,\\s]+"));
 context.start();

调用container这个方法后,则会将启动信号扩散至该容器内部的所有组件。会调用【所有】的实现了Lifecycle的组件的start()方法~~~

当然,我们稍作处理,也能让Lifecycle生效。当然,我并不建议这么去做~

代码语言:javascript
复制
// 注意,此处的名称必须,必须是lifecycleProcessor  否则没有效果的
// 名称也可以用这个常量AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME
@Component("lifecycleProcessor") 
public class MinivisionDefaultLifecycleProcessor extends DefaultLifecycleProcessor {

    /**
     * 这边重写了onRefresh方法 让其去调用start()方法,而start方法上面我们能看得见,它传的false
     */
    @Override
    public void onRefresh() {
        super.start();
    }
}

还有一个方式就是我们获取到容器后显示的调用start方法。但是这两种方式,我个人都不推荐这么去做~~~

publishEvent(new ContextRefreshedEvent(this)):发布容器刷新的事件

代码语言:javascript
复制
	//由此我们可以看到,ApplicationContext容器也是有发布事件的能力的(事件为:ApplicationEvent或其子类)
	@Override
	public void publishEvent(ApplicationEvent event) {
		publishEvent(event, null);
	}
	
	// 本方法Spring4.2之后才有  属于发布事件的方法
	// 这个方法更强:它能发布所有的事件,事件源是Object嘛
	protected void publishEvent(Object event, @Nullable ResolvableType eventType) {

		// Decorate event as an ApplicationEvent if necessary
		ApplicationEvent applicationEvent;
		if (event instanceof ApplicationEvent) {
			applicationEvent = (ApplicationEvent) event;
		}
		// 最终也会被包装成applicationEvent的事件类型,带有一个Payload而已
		else {
			applicationEvent = new PayloadApplicationEvent<>(this, event);
			if (eventType == null) {
				eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();
			}
		}

		// Multicast right now if possible - or lazily once the multicaster is initialized
		// 如果早期事件已经被初始化了,那就先放进早期事件里,否则esle那里,就直接发送事件了
		if (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);
			}
		}
	}

完成了这一步骤后,Spring IOC容器正式启动成功了。

至于catch和finally里的方法,都特别简单,就不再做介绍了~




优雅的关闭Spring容器

关于关闭容器,是讨论得比较少的话题。确实,平时开发中,我们也可以不用太关心容器的关闭,暴力解决就行,因此这里也只简单的说一下,优雅的关闭Spring容器的方式。

先聊聊Runtime类

每个Java应用都有一个属于自己的Runtime类实例,使应用程序能够与其运行的环境相连接,可以通过 getRuntime 方法获取/销毁当前运行状态中的一些内容或者进行内存清理。应用程序不能创建自己Runtime 类实例。

它有一个API如下:Runtime.getRuntime().addShutdownHook(shutdownHook)

在Java应用程序中可以通过添加关闭钩子,实现在程序退出时关闭资源的功能。 使用Runtime.addShutdownHook(Thread hook)JVM添加关闭钩子

这句代码可以书写在任何地方,总之就是JVM退出的时候才会去调用这个钩子Thread~

触发场景:

  1. 程序正常退出
  2. 使用System.exit()
  3. 终端使用Ctrl+C触发的中断
  4. 系统关闭
  5. 使用Kill pid命令干掉进程(kill -9除外

以下场景不会触发:

  1. 在Eclipse/idea中直接点击Terminate关闭程序时不会触发关闭钩子的;
  2. 在Linux下使用kill -9也是不会触发钩子的;

知道了这个钩子后,我们就可以在关闭线程里,做一些优雅的释放资源事情了。


有了以上知识,我们再看看Spring场景下怎么优雅的关闭:

Web应用

如果我们正常的关闭Tomcat,是能够正常的关闭web容器的同时,关闭Spring容器的。因此内部细节,我们此处不关心了

非web应用(比如纯dubbo应用)

我们看看AbstractApplicationContext类里其实提供了实现方法:

代码语言:javascript
复制
	@Override
	public void registerShutdownHook() {
		if (this.shutdownHook == null) {
			// No shutdown hook registered yet.
			this.shutdownHook = new Thread() {
				@Override
				public void run() {
					synchronized (startupShutdownMonitor) {
						// 具体的容器管理逻辑
						doClose();
					}
				}
			};
			Runtime.getRuntime().addShutdownHook(this.shutdownHook);
		}
	}

因此当我们启动容器的时候,自己调用registerShutdownHook这个方法便可,非常的方便。比如Dubbo框架,其实他就是这么优雅的去关闭容器的。

Spring Boot环境优雅的关闭容器

当把打包好的jar包发布到服务器,并通过java -jar运行,一般要把springboot项目关闭大多数都是先找到项目的pid,然后直接kill pid,不过这种方法在特殊需求场景下不太合适(不安全),同时也不优雅。

备注:我们本地启动,比如在idea一般直接点红色按钮就行,但是在本地嘛,无所谓啦,如果在服务器端,最好还是能够优雅点。

方案一:使用actuator

开启端点:

代码语言:javascript
复制
# 启用shutdown
management.endpoint.shutdown.enabled=true
# 公开所有的端点
management.endpoints.web.exposure.include=*

然后模拟发送一个POST请求:curl -X POST http://host:port/actuator/shutdown 即可优雅的关闭容器了。但是显然,这个危险系数太高了,万一ip和端口被别人知道了呢?线上哎,风险极高有木有

方案二:加固Endpoints

配置参考如下:

代码语言:javascript
复制
endpoints:
  shutdown:
    enabled: true
    path: /xxx
management:
  security:
    enabled: true
  port: 9001
  address: 127.0.0.1
  context-path: /admin
security:
  basic:
    enabled: true
    path: /admin
  user:
    name: root
    password: 123456

配置完成后,最终的停服命令为: (有了用户名、密码加持,可以说是能够达到生产级别的安全性了)

代码语言:javascript
复制
curl -X POST -u root:123456 http://127.0.0.1:9001/admin/xxx

方案三:注册为Linux系统服务

可以轻松地用 init.d 或 systemd 注册成 Linux/Unix 系统服务,这使得在生产环境中,安装和管理 SpringBoot 应用程序变得非常简单。

怎么把一个Spring Boot服务注册成服务,此处省略



Spring容器的refresh()【创建、刷新】完整总结

代码语言:javascript
复制
1、prepareRefresh()刷新前的预处理;
	0)、this.closed.set(false),this.active.set(true)  设置一些标记位
	1)、initPropertySources()初始化一些属性设置;(交由子类去实现,比如web容器中的 AbstractRefreshableWebApplicationContext 就去初始化了servlet的一些init参数等等)
	2)、getEnvironment().validateRequiredProperties();检验属性的合法等
	3)、earlyApplicationEvents= new LinkedHashSet<ApplicationEvent>();初始化容器,保存一些早期的事件;
	
2、obtainFreshBeanFactory();获取BeanFactory;
	1)、refreshBeanFactory();抽象方法,子类【AbstractRefreshableApplicationContext】唯一实现的:
			①、若已经存在beanFactory了,那就做一些清理工作(销毁单例Bean、关闭工厂)
			②、创建了一个this.beanFactory = new DefaultListableBeanFactory();并且设置id
			③、把旧的工厂的属性赋值给新创建的工厂:customizeBeanFactory(beanFactory)
			④、loadBeanDefinitions(beanFactory):加载Bean定义。抽象方法,由子类去决定从哪儿去把Bean定义加载进来,实现有比如:
					XmlWebApplicationContext:专为web设计的从xml文件里加载Bean定义(借助XmlBeanDefinitionReader)
					ClassPathXmlApplicationContext/FileSystemXmlApplicationContext:均由父类AbstractXmlApplicationContext去实现这个方法的,也是借助XmlBeanDefinitionReader
					AnnotationConfigWebApplicationContext:基于注解驱动的容器。(也是当下最流行、最重要的一个实现,前面一篇博文对此有重点分析),借助了AnnotatedBeanDefinitionReader.register()方法加载Bean定义
						(这里面需要注意的是:.register()只是把当前这一个Class对象registry.registerBeanDefinition()了,至于内部的@Bean、@ComponentScan扫描到的,都不是在此处注册的)
						
					有必要说一句:AnnotationConfigApplicationContext是在非web环境下的容器。它虽然没有实现实现loadBeanDefinitions()抽象方法,是因为它在new对象的时候,已经调用了.register()完成配置Bean定义信息的注册了
	2)、getBeanFactory();返回刚才GenericApplicationContext创建的BeanFactory对象;
	3)、将创建的BeanFactory【DefaultListableBeanFactory】返回;
	=======到这一步截止,BeanFactory已经创建好了(只不过都还是默认配置而已),配置Bean的定义信息也注册好了=======
	
3、prepareBeanFactory(beanFactory);BeanFactory的预准备工作(对BeanFactory进行一些设置);
	1)、设置BeanFactory的类加载器、StandardBeanExpressionResolver、ResourceEditorRegistrar
	2)、添加感知后置处理器BeanPostProcessor【ApplicationContextAwareProcessor】,并设置一些忽略EnvironmentAware、EmbeddedValueResolverAware、xxxxx(因为这个处理器都一把抓了)
	3)、注册【可以解析的(表示虽然不在容器里,但还是可以直接 @Auwowired)】自动装配;我们能直接在任何组件中自动注入(@Autowired):
			BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext
	5)、添加BeanPostProcessor【ApplicationListenerDetector】 检测注入进来的Bean是否是监听器
	6)、Detect a LoadTimeWeaver and prepare for weaving, if found.添加编译时的AspectJ支持:LoadTimeWeaverAwareProcessor
		(添加的支持的条件是:beanFactory.containsBean("loadTimeWeaver"))
	7)、给BeanFactory中注册一些能用的组件;
		environment-->【ConfigurableEnvironment】、
		systemProperties-->【Map<String, Object>】、
		systemEnvironment-->【Map<String, Object>】

4、postProcessBeanFactory(beanFactory);BeanFactory准备工作完成后进行的后置处理工作;(由子类完成)
	一般web容器都会对应的实现此方法,比如 AbstractRefreshableWebApplicationContext:
		1)、添加感知BeanPostProcessor【ServletContextAwareProcessor】,支持到了ServletContextAware、ServletConfigAware
		2)、注册scopse:beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());当然还有SCOPE_SESSION、SCOPE_APPLICATION
		3)、向上线一样,注册【可以解析的】自动注入依赖:ServletRequest/ServletResponse/HttpSession/WebRequest
			(备注:此处放进容器的都是xxxObjectFactory类型,所以这是为何@Autowired没有线程安全问题的重要一步)
		4)、registerEnvironmentBeans:注册环境相关的Bean(使用的registerSingleton,是直接以单例Bean放到容器里面了)
			servletContext-->【ServletContext】
			servletConfig-->【ServletConfig】
			contextParameters-->【Map<String, String>】 保存有所有的init初始化参数(getInitParameter)
			contextAttributes-->【Map<String, Object>】 servletContext的所有属性(ServletContext#getAttribute(String))
			
========以上是BeanFactory的创建及预准备工作,至此准备工作完成了,那么接下来就得利用工厂干点正事了========

5、invokeBeanFactoryPostProcessors(beanFactory);执行BeanFactoryPostProcessor的方法;
	BeanFactoryPostProcessor:BeanFactory的后置处理器。此处调用,现在就表示在BeanFactory标准初始化之后执行的;
	两个接口:BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor(子接口)
	1)、执行BeanFactoryPostProcessor们的方法;
	
		===先执行BeanDefinitionRegistryPostProcessor===
		1)、获取所有的BeanDefinitionRegistryPostProcessor;(当然会最先执行我们手动set进去的Processor,但是这个一般都不会有)
		2)、先执行实现了PriorityOrdered优先级接口的BeanDefinitionRegistryPostProcessor、
			postProcessor.postProcessBeanDefinitionRegistry(registry)
		3)、在执行实现了Ordered顺序接口的BeanDefinitionRegistryPostProcessor
		4)、最后执行没有实现任何优先级或者是顺序接口的BeanDefinitionRegistryPostProcessors
		(小细节:都会调用getBean(“name”,BeanDefinitionRegistryPostProcessor.class)方法,所以都会先实例化,才去执行的)
		
		**这里面需要特别的介绍一个处理器:`ConfigurationClassPostProcessor`,它是一个BeanDefinitionRegistryPostProcessor**
		**它会解析完成所有的@Configuration配置类,然后所有@Bean、@ComponentScan等等Bean定义都会搜集进来了,所以这一步是非常的重要的**
	
		===再执行BeanFactoryPostProcessor的方法(顺序逻辑同上,略)===
	2)、再次检测一次添加对AspectJ的支持。为何还要检测呢?through an @Bean method registered by ConfigurationClassPostProcessor,这样我们注入了一个切面Bean,就符合条件了嘛
		
6、registerBeanPostProcessors(beanFactory);注册BeanPostProcessor(Bean的后置处理器)【 intercept bean creation】
		**不同接口类型的BeanPostProcessor;在Bean创建前后的执行时机是不一样的**
		BeanPostProcessor:BeanPostProcessor是一个工厂钩子,允许Spring框架在新创建Bean实例时对其进行定制化修改,比如填充Bean、创建代理、解析Bean内部的注解等等。。。
		DestructionAwareBeanPostProcessor:Bean销毁时候
		InstantiationAwareBeanPostProcessor:Bean初始化的时候
		SmartInstantiationAwareBeanPostProcessor:初始化增强版本:增加了一个对Bean类型预测的回调(一般是Spring内部使用,调用者还是使用InstantiationAwareBeanPostProcessor就好)
		MergedBeanDefinitionPostProcessor:合并处理Bean定义的时候的回调【该类型的处理器保存在名为internalPostProcessors的List中】、
		
		1)、获取所有的 BeanPostProcessor;后置处理器都默认可以通过PriorityOrdered、Ordered接口来执行优先级
		2)、先注册PriorityOrdered优先级接口的BeanPostProcessor;
			把每一个BeanPostProcessor;添加到BeanFactory中
			beanFactory.addBeanPostProcessor(postProcessor);
		3)、再注册Ordered接口的、最后注册没有实现任何优先级接口的、最终注册MergedBeanDefinitionPostProcessor
			(此处细节:BeanPostProcessor本身也是一个Bean,其注册之前一定先实例化,而且是分批实例化和注册。
			另外还有一个非常非常重要的一点就是阶段顺序问题:
			我们可以把BeanPostProcessor的实例化与注册分为四个阶段:
					第一阶段applicationContext内置阶段、
					第二阶段priorityOrdered阶段、
					第三阶段Ordered阶段、
					第四阶段nonOrdered阶段
			因为是分批注册,所以我们同阶段是不能拦截到同阶段的BeanPostProcessor的实例化的。举例子:
			PriorityOrdered的只能被内置阶段的比如:ApplicationContextAwareProcessor(可以注入啦)/ApplicationListenerDetector(可以接受事件啦)这种拦截
			而:Ordered就可以被	内置的、PriorityOrdered都拦截到了
			。。。 以此类推。。。
			
			所以我们的BeanPostProcessor是可以@Autowired 比如Service、Dao来做一些事的。单思,但是一定要【注意避免BeanPostProcessor启动时的“误伤”陷阱】,什么意思?大概解释一下如下:
				可能由于你的Processor依赖于某个@Bean,从而让它提前实例化了,然后就很可能错过了后面一些BeanPostProcessor的处理,造成“误伤”
				(SpringBoot中使用Shiro、Spring-Cache的时候,使用不当会出现这样的问题)
	
		6)、这一步非常有意思:moving it to the end of the processor chain。它的又注册了一次,作用是把这个探测器移动到处理器的底部,最后一个(显然,最后一个是为了不要放过任何Bean)
			(小细节:可能有小伙伴疑问,这里也是new出来,这这样容器内不就有两个探测器对象了吗?气其实不然,ApplicationListenerDetector它重写了hashCode方法,且只和应用applicationContext有关)
			return ObjectUtils.nullSafeHashCode(this.applicationContext);所以对它执行remove的时候,会被当作同一个对象处理,能把老的移除成功添加新的的

7、initMessageSource();初始化MessageSource组件(做国际化功能;消息绑定,消息解析)
		1)、看容器中是否有id为messageSource的,类型是MessageSource的组件
			如果有赋值给messageSource,如果没有自己创建一个DelegatingMessageSource;
				MessageSource:取出国际化配置文件中的某个key的值;能按照区域信息获取;
		2)、把创建好的MessageSource注册在容器中,以后获取国际化配置文件的值的时候,可以自动注入MessageSource
		beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource)
		
8、initApplicationEventMulticaster();初始化事件派发器;
		1)、从BeanFactory中获取applicationEventMulticaster的ApplicationEventMulticaster;
		2)、如果上一步没有配置;创建一个SimpleApplicationEventMulticaster,将创建的ApplicationEventMulticaster添加到BeanFactory中
		
9、onRefresh();留给子容器(子类) 容器刷新的时候做些事
		AbstractRefreshableWebApplicationContext:this.themeSource = UiApplicationContextUtils.initThemeSource(this);
		
10、registerListeners();把容器中将所有项目里面的ApplicationListener注册进来;
		1、拿到容器里所有的Bean定义的名字,类型为ApplicationListener,然后添加进来
			getApplicationEventMulticaster().addApplicationListener(listener);
		2、派发之前步骤产生的事件(早期事件)
		(细节:此处只是把Bean的名字放进去,Bean还没有实例化哦~~~~)

11、finishBeanFactoryInitialization(beanFactory);初始化所有剩下的单实例bean;这应该是最核心的一步了
	1)、为容器初始化ConversionService(容器若没有就不用初始化了,依然采用getBean()初始化的) 提供转换服务
	2)、若没有设置值解析器,那就注册一个默认的值解析器(lambda表示的匿名处理)
	3)、实例化LoadTimeWeaverAware(若存在)
	4)、清空临时类加载器:beanFactory.setTempClassLoader(null)
	5)、缓存(快照)下当前所有的Bean定义信息 beanFactory.freezeConfiguration();
	==== 更精确的是说是根据Bean的定义信息:beanDefinitionNames来实例化、初始化剩余的Bean ====
	6)、beanFactory.preInstantiateSingletons();初始化后剩下的单实例bean(过程这里就不详说了)
	
12、finishRefresh();完成BeanFactory的初始化创建工作;IOC容器就创建完成
		0)、clearResourceCaches(); (Spring5.0才有)
		1)、initLifecycleProcessor();初始化和生命周期有关的后置处理器;从容器中找是否有lifecycleProcessor的组件【LifecycleProcessor】;如果没有new DefaultLifecycleProcessor();
			关于Lifecycle接口的使用,也专门讲解过,这里不聊了
		2)、getLifecycleProcessor().onRefresh();  相当于上面刚注册,下面就调用了
		3)、publishEvent(new ContextRefreshedEvent(this));发布容器刷新完成事件;
		4)、liveBeansView.registerApplicationContext(this); 和MBean相关,略
	
	======总结===========
	1)、Spring容器在启动的时候,先会保存所有注册进来的Bean的定义信息(可以有N种方式);
		1)、xml注册bean;<bean>
		2)、注解注册Bean;@Service、@Component、@Bean、xxx
	2)、Spring容器会合适的时机创建这些Bean
		1)、用到这个bean的时候;利用getBean创建bean;创建好以后保存在容器中;
		2)、统一创建剩下所有的bean的时候;finishBeanFactoryInitialization();
	3)、后置处理器;BeanPostProcessor
		1)、每一个bean创建完成,都会使用各种后置处理器进行处理;来增强bean的功能;
			AutowiredAnnotationBeanPostProcessor:处理自动注入
			AnnotationAwareAspectJAutoProxyCreator:来做AOP功能;
			xxx....
			增强的功能注解:
			AsyncAnnotationBeanPostProcessor
			....
	4)、事件驱动模型;
		ApplicationListener;事件监听;
		ApplicationEventMulticaster;事件派发:

有了这份完整的总结描述,能让自己抽出来(不用太关心细节)从外层(更宏观的)看Spring 容器的初始化过程。希望能帮助到大家更好的理解~



总结

IoC的启动包括BeanDefinition的Resource定位、注入和注册三个基本过程。

第一个过程是Resource定位过程。这个Resource定位指的是BeanDefinition的资源定位,它由ResourceLoader通过统一的Resource接口来完成。

第二个过程是BeanDefinition的载入。这个载入过程是把用户定义好的Bean表示成IoC容器内部的数据结构,而这个容器内部的数据结构就是BeanDefinition。

第三个过程是向IoC容器注册这些BeanDefinition的过程。在IoC容器内部将BeanDefinition注入到一个HashMap中去,IoC容器就是通过这个HashMap来持有这些BeanDefinition数据的。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019年03月16日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • refresh() 第六步:registerBeanPostProcessors(beanFactory)
  • refresh() 第七步:initMessageSource()
  • refresh() 第八步:initApplicationEventMulticaster()
  • refresh() 第九步:onRefresh()
  • refresh() 第十步:registerListeners();
  • refresh() 第十一步:finishBeanFactoryInitialization(beanFactory)
  • refresh() 第十二步:finishRefresh()
  • 优雅的关闭Spring容器
  • Spring容器的refresh()【创建、刷新】完整总结
    • 总结
      相关产品与服务
      容器服务
      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档