文章目录
- 源码入口
- 1、准备刷新
- 1.1、子类prepareRefresh()方法
- 1.2 父类prepareRefresh()方法
- 2、通知子类刷新内部bean工厂
- 3、准备bean工厂
- 4、允许上下文子类对bean工厂进行后置处理
源码入口
org.springframework.boot.SpringApplication#run(java.lang.String…)
public ConfigurableApplicationContext run(String... args) {.... try {//本篇内容从本行开始记录 refreshContext(context);//本篇内容记录到这,后续更新....}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, listeners);throw new IllegalStateException(ex);}
}
流程分析
private void refreshContext(ConfigurableApplicationContext context) {refresh(context);if (this.registerShutdownHook) {try {context.registerShutdownHook();}catch (AccessControlException ex) {// Not allowed in some environments.}}}
最终调用父类AbstractApplicationContext的refresh()方法。
protected void refresh(ApplicationContext applicationContext) {Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);((AbstractApplicationContext) applicationContext).refresh();}@Override
public final void refresh() throws BeansException, IllegalStateException { try {super.refresh();}catch (RuntimeException ex) {stopAndReleaseWebServer();throw ex;}
}
可以看到refresh中的步骤都是单个单个的方法
如果看过Spring源码的同学现在应该很熟悉了…
org.springframework.context.support.AbstractApplicationContext#refresh
@Override
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// 准备刷新prepareRefresh();// 通知子类刷新内部bean工厂ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// 准备bean工厂以便在此上下文中使用prepareBeanFactory(beanFactory);try {// 允许上下文子类中对bean工厂进行后处理postProcessBeanFactory(beanFactory);// 在bean创建之前调用BeanFactoryPostProcessors后置处理方法invokeBeanFactoryPostProcessors(beanFactory);// 注册BeanPostProcessorregisterBeanPostProcessors(beanFactory);// 注册DelegatingMessageSourceinitMessageSource();// 注册multicasterinitApplicationEventMulticaster();// 创建内置的Servlet容器onRefresh();// 注册ListenerregisterListeners();// 完成BeanFactory初始化,初始化剩余单例beanfinishBeanFactoryInitialization(beanFactory);// 发布对应事件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.destroyBeans();// Reset 'active' flag.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();}}
}
开始之前先把AnnotationConfigServletWebServerApplicationContext类图放这:
1、准备刷新
先调用子类重写的方法,再调用父类方法。还记得前面讲过在创建AnnotationConfigServletWebServerApplicationContext的时候构造方法中实例化了一个ClassPathBeanDefinitionScanner。
@Override
protected void prepareRefresh() {this.scanner.clearCache();super.prepareRefresh();
}
1.1、子类prepareRefresh()方法
在其父类ClassPathScanningCandidateComponentProvider中有一个MetadataReaderFactory(接口)工厂对象,判断该对象是否是CachingMetadataReaderFactory这个特定类或者是它的子类的一个实例,返回Boolean值,是就是true,则清除缓存。该类中有个Map,用来缓存每个Spring资源句柄(即每个“.class”文件)的MetadataReader实例。
@Nullable
private Map<Resource, MetadataReader> metadataReaderCache;/*** Clear the local MetadataReader cache, if any, removing all cached class metadata.*/
public void clearCache() {if (this.metadataReaderCache instanceof LocalResourceCache) {synchronized (this.metadataReaderCache) {this.metadataReaderCache.clear();}}else if (this.metadataReaderCache != null) {// Shared resource cache -> reset to local cache.setCacheLimit(DEFAULT_CACHE_LIMIT);}
}
缓存Map如果是LocalResourceCache(可以看到该类继承了LinkedHashMap),执行的就是LinkedHashMap的clear()方法了
else如果缓存不为空,就是重新new一个LocalResourceCache
* Specify the maximum number of entries for the MetadataReader cache.* <p>Default is 256 for a local cache, whereas a shared cache is* typically unbounded. This method enforces a local resource cache,* even if the {@link ResourceLoader} supports a shared resource cache.*/
public void setCacheLimit(int cacheLimit) {if (cacheLimit <= 0) {this.metadataReaderCache = null;}else if (this.metadataReaderCache instanceof LocalResourceCache) {((LocalResourceCache) this.metadataReaderCache).setCacheLimit(cacheLimit);}else {this.metadataReaderCache = new LocalResourceCache(cacheLimit);}
}/*** Clear the local MetadataReader cache, if any, removing all cached class metadata.*/
public void clearCache() {if (this.metadataReaderCache instanceof LocalResourceCache) {synchronized (this.metadataReaderCache) {this.metadataReaderCache.clear();}}else if (this.metadataReaderCache != null) {// Shared resource cache -> reset to local cache.setCacheLimit(DEFAULT_CACHE_LIMIT);}
}@SuppressWarnings("serial")
private static class LocalResourceCache extends LinkedHashMap<Resource, MetadataReader> {private volatile int cacheLimit;public LocalResourceCache(int cacheLimit) {super(cacheLimit, 0.75f, true);this.cacheLimit = cacheLimit;}public void setCacheLimit(int cacheLimit) {this.cacheLimit = cacheLimit;}public int getCacheLimit() {return this.cacheLimit;}@Overrideprotected boolean removeEldestEntry(Map.Entry<Resource, MetadataReader> eldest) {return size() > this.cacheLimit;}
}
1.2 父类prepareRefresh()方法
protected void prepareRefresh() {//系统启动时间this.startupDate = System.currentTimeMillis();//是否关闭标识,falsethis.closed.set(false);//是否活跃标识,truethis.active.set(true);if (logger.isDebugEnabled()) {if (logger.isTraceEnabled()) {logger.trace("Refreshing " + this);}else {logger.debug("Refreshing " + getDisplayName());}}// 调用子类GenericWebApplicationContext重写后的方法替换servlet相关属性源initPropertySources();// 这里是验证由ConfigurablePropertyResolver#setRequiredProperties()方法指定的属性,解析为非空值,如果没有设置的话这个方法就不会执行什么操作。getEnvironment().validateRequiredProperties();// Allow for the collection of early ApplicationEvents,// to be published once the multicaster is available...this.earlyApplicationEvents = new LinkedHashSet<>();
}
看下最后这个方法,initServlet属性源,方法注释是这么说的将基于Servlet的StubPropertySource替换为使用给定servletContext和servletConfig对象填充的实例。此方法可以被调用任意次数,但将用相应的实际属性源替换为StubPropertySource一次且仅一次。
看下if判断里的条件,servletContext不为空,source中存在指定name的的属性源,且该属性源要是StubPropertySource的类型或者是其子类。也就是当第一次调用以后,该属性源就被替换成了ServletContextPropertySource和ServletConfigPropertySource,所以之后的调用最后一个判断条件就不会成立了。
public static void initServletPropertySources(MutablePropertySources sources,@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {Assert.notNull(sources, "'propertySources' must not be null");//servletContextInitParamsString name = StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME;if (servletContext != null && sources.contains(name) && sources.get(name) instanceof StubPropertySource) {sources.replace(name, new ServletContextPropertySource(name, servletContext));}//servletConfigInitParamsname = StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME;if (servletConfig != null && sources.contains(name) && sources.get(name) instanceof StubPropertySource) {sources.replace(name, new ServletConfigPropertySource(name, servletConfig));}
}
看validateRequiredProperties()方法前,先看下Environment的类图。这里是验证由ConfigurablePropertyResolver#setRequiredProperties()方法指定的属性,解析为非空值,如果没有设置的话这个方法就不会执行什么操作,所以这里就略过了。
方法最后new了一个LinkedHashSet,收集早期事件,如果multicaster 有用就会广播事件。prepareRefresh()就执行完了。
2、通知子类刷新内部bean工厂
可以看到refreshBeanFactory()方法上的注释说的,什么都不做:我们拥有一个内部beanfactory,并依靠调用方通过我们的公共方法(或beanfactory)注册bean。
前面介绍GenericApplicationContext说了与每次刷新创建新的内部beanfactory实例的其他applicationContext实现不同,此上下文的内部beanfactory从一开始就可用,以便能够在其上注册bean定义。只能调用一次refresh()。
所以在该方法内只设置了SerializationId,该id是在准备应用上下文时调用ContextIdApplicationContextInitializer时设置的id,在setSerializationId方法中,使用id做key,new了一个弱引用对象为value,添加到了serializableFactories中,DefaultListableBeanFactory为被弱引用对象;如果需要,可以通过id得到引用对象,在通过get()方法得到DefaultListableBeanFactory对象。
@Override
protected final void refreshBeanFactory() throws IllegalStateException {if (!this.refreshed.compareAndSet(false, true)) {throw new IllegalStateException("GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");}this.beanFactory.setSerializationId(getId());
}/** Map from serialized id to factory instance. */
private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories = new ConcurrentHashMap<>(8);
public void setSerializationId(@Nullable String serializationId) {if (serializationId != null) {serializableFactories.put(serializationId, new WeakReference<>(this));}else if (this.serializationId != null) {serializableFactories.remove(this.serializationId);}this.serializationId = serializationId;
}
3、准备bean工厂
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {//通知内部bean工厂使用上下文的类加载器beanFactory.setBeanClassLoader(getClassLoader());//为bean定义值中的表达式指定解析策略,即解析el表达式,默认"#{"开头,"}"结尾beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));//在这里new了一个资源编辑注册器ResourceEditorRegistrar,该类实现了PropertyEditorRegistrar接口//作用是使用以下资源编辑器去填充给的的注册表:ResourceEditor、InputStreamEditor、InputSourceEditor、FileEditor、Urleditor、UriEditor、ClassEditor、ClassArrayEditor。//如果给的注册表是PropertyEditorRegistrySupport类型,编辑器交由该类管理beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));// 向BeanPostProcessor的List中添加一个ApplicationContextAwareProcessor,参数是上下文//该类作用是将上下文传递给实现environmentaware、embeddedValueResolveraware、resourceLoaderware、applicationEventPublisheraware、messageSourceAware或applicationContextaware接口的bean。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 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);// 该BeanPostProcessor检测那些实现了ApplicationListener接口的bean,在它们创建时初始化之后,将它们添加到应用上下文的事件多播器上//并在这些ApplicationListener bean销毁之前,将它们从应用上下文的事件多播器上移除。beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));// Detect a LoadTimeWeaver and prepare for weaving, if found.if (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()));}// Register default environment beans.//注册默认environment bean,如果beanfactory不存在environment if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());}//systemProperties 同上if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());}//systemEnvironment 同上if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());}
}
4、允许上下文子类对bean工厂进行后置处理
basePackages和annotatedClasses都为空。跳过
org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext#postProcessBeanFactory
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {super.postProcessBeanFactory(beanFactory);if (this.basePackages != null && this.basePackages.length > 0) {this.scanner.scan(this.basePackages);}if (!this.annotatedClasses.isEmpty()) {this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));}
}