Spring源码剖析-IOC启动流程(二)(1),2024年最新华为在线面试

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
img

正文

/**

  • Create a new ClassPathXmlApplicationContext with the given parent,

  • loading the definitions from the given XML files.

  • @param configLocations array of resource locations

  • @param refresh whether to automatically refresh the context,

  • loading all bean definitions and creating all singletons.

  • Alternatively, call refresh manually after further configuring the context.

  • @param parent the parent context

  • @throws BeansException if context creation failed

  • @see #refresh()

*/

public ClassPathXmlApplicationContext(

String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)

throws BeansException {

//调用父类的构造器

super(parent);

//设置位置文件地址

setConfigLocations(configLocations);

if (refresh) {

//刷新容器【重点】

refresh();

}

}

在ClasspathXmlApplication的构造器中做了如下事情:

  • 调用了父容器的构造器方法,目的是加载设置Bean的资源加载器 ResourcePatternResolver

  • 然后通过setConfigLocations方法保存好配置文件地址,

  • 最后调用refresh()刷新容器

ResourcePatternResolver 资源加载器


ResourcePatternResolver是Bean的资源加载器 ,通过父容器 AbstractApplicationContext 中的构造方法创建:

public abstract class AbstractApplicationContext extends DefaultResourceLoader

implements ConfigurableApplicationContext

public AbstractApplicationContext(@Nullable ApplicationContext parent) {

//加载 resourcePatternResolver

this();

//

setParent(parent);

}

/**

  • Create a new AbstractApplicationContext with no parent.

*/

//创建一个AbstractApplicationContext容器工厂,并构建一个ResourcePatternResolver

public AbstractApplicationContext() {

this.resourcePatternResolver = getResourcePatternResolver();

}

//获取 PathMatchingResourcePatternResolver

protected ResourcePatternResolver getResourcePatternResolver() {

return new PathMatchingResourcePatternResolver(this);

}

public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) {

Assert.notNull(resourceLoader, “ResourceLoader must not be null”);

//资源加载器

this.resourceLoader = resourceLoader;

}

父容器AbstractApplicationContext 继承了 DefaultResourceLoader ,拥有资源加载的能力,在构造器中中创建了ResourcePatternResolver,使用的是PathMatchingResourcePatternResolver作为实现,它能够将指定的资源位置路径解析为一个或多个匹配的资源。

在这里插入图片描述

下面是ResourceLoader 源码:

public interface ResourceLoader {

//默认从classpath中加载资源文件

/** Pseudo URL prefix for loading from the class path: “classpath:”. */

String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;

//把资源文件转换成Resource

Resource getResource(String location);

ClassLoader getClassLoader();

}

public interface ResourcePatternResolver extends ResourceLoader {

//从classpath加载资源

String CLASSPATH_ALL_URL_PREFIX = “classpath*:”;

//把文件转换成Resource[] ,对ResourceLoader做了扩展

Resource[] getResources(String locationPattern) throws IOException;

}

setConfigLocations 保存配置地址


然后就是保存配置地址 ,从源码可以看出,我们是可以传入多个配置文件给容器的。

public abstract class AbstractRefreshableConfigApplicationContext extends AbstractRefreshableApplicationContext

implements BeanNameAware, InitializingBean {

//地址保存到这里

@Nullable

private String[] configLocations;

/**

  • Set the config locations for this application context.

  • If not set, the implementation may use a default as appropriate.

*/

//可以传入多个配置

public void setConfigLocations(@Nullable String… locations) {

if (locations != null) {

Assert.noNullElements(locations, “Config locations must not be null”);

this.configLocations = new String[locations.length];

for (int i = 0; i < locations.length; i++) {

this.configLocations[i] = resolvePath(locations[i]).trim();

}

}

else {

this.configLocations = null;

}

}

Refresh() 刷新容器


ClasspathXmlApplication调用 AbstractApplicationContext#refresh 方法刷新容器,该方法中实现了IOC容器的整个初始化过程。

@Override

public void refresh() throws BeansException, IllegalStateException {

synchronized (this.startupShutdownMonitor) {

// Prepare this context for refreshing.

//准备刷新工作 ,记录开始时间,初始化属性,校验配置文件,准备事件的存储Set

prepareRefresh();

// Tell the subclass to refresh the internal bean factory.

//告诉子类,刷新Bean工厂,销毁旧beanFactory,创建新beanFactory,默认DefaultListableBeanFactory

//从子容器的refreshBeanFactory方法中载入Bean的资源文件

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context.

//准备工厂,配置工厂的下文特性, 例如上下文的 ClassLoader 和后处理器。Bean表达式解析器,

//BeanPostProcessor和 Aware类的自动装配等

prepareBeanFactory(beanFactory);

try {

// Allows post-processing of the bean factory in context subclasses.

//BeanFactory初始化完成的后置工作,这是一个空方法,留给三方框架或者自己配置,作用是允许对beanFoctory进行扩展处理

postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context.

//调用BeanFactory的后置处理器BeanFactoryPostProcessor,在 bean定义注册之后bean实例化之前调用

invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.

//注册Bean的后置处理器BeanPostProcessor,在Bean初始化前,后执行

registerBeanPostProcessors(beanFactory);

// Initialize message source for this context.

//初始化信息源,国际化相关

initMessageSource();

// Initialize event multicaster for this context.

//初始化容器事件传播器

initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.

//空方法,该方法子类实现,在容器刷新的时候可以自定义逻辑;如创建Tomcat,Jetty等WEB服务器

onRefresh();

// Check for listener beans and register them.

//注册事件监听器,注册实现了ApplicationListener接口的监听器bean,

//这些监听器是注册到ApplicationEventMulticaster中的

registerListeners();

// Instantiate all remaining (non-lazy-init) singletons.

//实例化所有剩余的(非延迟初始化)单例的Bean

finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.

//完成context的刷新。主要是调用LifecycleProcessor的onRefresh()方法,并且发布事件(ContextRefreshedEvent)

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.

//销毁已经创建的单例Bean。

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();

}

}

}

refresh()方法主要是通过子类 refreshBeanFactory()方法加载Bean信息,然后就是一些列的容器生命周期事件。这里其实是用到了模板设计模式,在refresh()方法中指定容器刷新流程,很多的细节步骤由子类去实现。

工厂的创建:obtainFreshBeanFactory

==========================================================================================

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {

//刷新工厂,有子类实现

refreshBeanFactory();

//通过子类返回工厂,默认 DefaultListableBeanFactory

return getBeanFactory();

}

这里只是定义了抽象方法,refreshBeanFactory由子类实现,见:AbstractRefreshableApplicationContext#refreshBeanFactory

AbstractRefreshableApplicationContext#refreshBeanFactory


@Override

protected final void refreshBeanFactory() throws BeansException {

if (hasBeanFactory()) {

//如果已经有BeanFactory,销毁Bean,关闭容器

destroyBeans();

closeBeanFactory();

}

try {

//创建IOC容器

DefaultListableBeanFactory beanFactory = createBeanFactory();

beanFactory.setSerializationId(getId());

//定制BeanFactory,如设置启动参数,开启注解的自动装配等

customizeBeanFactory(beanFactory);

//载入Bean,由子类实现

loadBeanDefinitions(beanFactory);

this.beanFactory = beanFactory;

}

catch (IOException ex) {

throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);

}

}

该方法中先判断如果已经存在BeanFactory就销毁掉重新创建,默认使用的是DefaultListableBeanFactory作为BeanFactory,并loadBeanDefinitions方法加载Bean,方法由子类 AbstractXmlApplicationContext#loadBeanDefinitions实现。

加载Bean:AbstractXmlApplicationContext#loadBeanDefinitions

======================================================================================================================

@Override

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {

// Create a new XmlBeanDefinitionReader for the given BeanFactory.

//创建 XmlBeanDefinitionReader ,用来从XML中读取Bean

XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

// Configure the bean definition reader with this context’s

// resource loading environment.

//把Environment 和 ResourceLoader 设置给beanDefinitionReader

beanDefinitionReader.setEnvironment(this.getEnvironment());

beanDefinitionReader.setResourceLoader(this);

//设置Sax解析器

beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

// Allow a subclass to provide custom initialization of the reader,

// then proceed with actually loading the bean definitions.

//初始化Bean的读取器,启用 Xml 的校验机制 , 允许子类自定义初始化读取器

initBeanDefinitionReader(beanDefinitionReader);

//加载Bean, XmlBeanDefinitionReader真正实现加载逻辑

loadBeanDefinitions(beanDefinitionReader);

最后

整理的这些资料希望对Java开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

image

image

其实面试这一块早在第一个说的25大面试专题就全都有的。以上提及的这些全部的面试+学习的各种笔记资料,我这差不多来回搞了三个多月,收集整理真的很不容易,其中还有很多自己的一些知识总结。正是因为很麻烦,所以对以上这些学习复习资料感兴趣

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

eader真正实现加载逻辑

loadBeanDefinitions(beanDefinitionReader);

最后

整理的这些资料希望对Java开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

[外链图片转存中…(img-Lq4b382u-1713654705929)]

[外链图片转存中…(img-mn5yjDqv-1713654705929)]

其实面试这一块早在第一个说的25大面试专题就全都有的。以上提及的这些全部的面试+学习的各种笔记资料,我这差不多来回搞了三个多月,收集整理真的很不容易,其中还有很多自己的一些知识总结。正是因为很麻烦,所以对以上这些学习复习资料感兴趣

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-omVSaM2A-1713654705930)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值