SpringBoot启动流程分析之准备应用上下文refreshContext()(八)
文章目录
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);
// 注册BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// 注册DelegatingMessageSource
initMessageSource();
// 注册multicaster
initApplicationEventMulticaster();
// 创建内置的Servlet容器
onRefresh();
// 注册Listener
registerListeners();
// 完成BeanFactory初始化,初始化剩余单例bean
finishBeanFactoryInitialization(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;
}
@Override
protected boolean removeEldestEntry(Map.Entry<Resource, MetadataReader> eldest) {
return size() > this.cacheLimit;
}
}
1.2 父类prepareRefresh()方法
protected void prepareRefresh() {
//系统启动时间
this.startupDate = System.currentTimeMillis();
//是否关闭标识,false
this.closed.set(false);
//是否活跃标识,true
this.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");
//servletContextInitParams
String 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));
}
//servletConfigInitParams
name = 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));
}
}
注册了一个WebApplicationContextServletContextAwareProcessor。并将ServletContextAware添加到忽略的集合中。再注册web相关作用域bean。
org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#postProcessBeanFactory
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
beanFactory.addBeanPostProcessor(
new WebApplicationContextServletContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
registerWebApplicationScopes();
}
private void registerWebApplicationScopes() {
ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(
getBeanFactory());
WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory());
existingScopes.restore();
}
public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory,
@Nullable ServletContext sc) {
beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope());
if (sc != null) {
ServletContextScope appScope = new ServletContextScope(sc);
beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope);
// Register as ServletContext attribute, for ContextCleanupListener to detect it.
sc.setAttribute(ServletContextScope.class.getName(), appScope);
}
// 注册ServletRequest 的工厂bean
beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());
beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());
if (jsfPresent) {
FacesDependencyRegistrar.registerFacesDependencies(beanFactory);
}
}
标签:SpringBoot,beanFactory,refreshContext,void,refresh,bean,new,上下文,class
From: https://blog.csdn.net/lvyuanj/article/details/139466731