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源码复杂。自己动手写觉得还真是那么回事,哈哈哈。一篇文章留下的全是等着填的坑,解释的也不是很清晰。
有点怀疑自己了,初生牛犊不怕虎,哈哈哈哈哈哈!!!