Spring IoC源码学习:总览,java面试问项目的难点是什么

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

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

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

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

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

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

正文

如何将 Spring 源码导入到 IDE 中

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

1.以 IDEA 为例,首先到Git上下载某个 RELEASE 版本的 Spring 源码压缩包:Spring 源码地址,并解压到本地磁盘中。

2.New -> Project from Existing Sources

3.找到源码解压的地址,选中并点击 OK

4.选择 Import project from external model,并选中 Gradle,然后点击 Next,之后一路默认即可,如果有需要选择的,选择Yes。

5.导入之后需要一段时间来构建索引,最后完成之后如下。

关于学习源码的好处

=========

这边再聊个小事情。17年初,我当时正在准备跳槽,有一次面试的时候,一个面试官问我:你觉得学习源码有什么好处?对于当时的我来说,学习源码不过是为了应付面试。到现在,我对这个问题有了一些新的想法,我目前感觉到的主要好处有:

  • 深入学习过源码后,自己在使用的时候显得更游刃有余。

  • 可以学习到一些优秀的代码,无论是一些逻辑上的思路,还是仅仅是编码风格。

  • 许多中间件都会基于 Spring 的扩展功能来实现,阅读 Spring 源码,能帮助你更好的阅读中间件源码。

  • 最后还是应付面试。

如何高效的学习 Spring 源码

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

学习 Spring 源码不同于学习 JDK 源码,以前学习 JDK 源码基本就纯看源码,但是 Spring 源码太多了,你纯看的话可能会无法很好的理解。以下几个点,可以帮助你更好的学习 Spring 源码。

  1. 保持耐心,Spring 源码很多,想在短时间内就看透是很难的,需要保持持续性和耐心,一点点的去啃。

  2. 可以通过 Debug Spring 源码的方式来帮助自己更好的理解。这边可以新建一个只有基础框架的空项目,然后根据自己的需要增加一些测试类。

  3. 代码是最好的注释。Spring 作为最优秀的框架之一,其代码质量必然不用担心。因此,除了注释外,我们还可以通过类名、方法名、变量名、打印的日志来帮助我们理解。

  4. 由于逻辑比较复杂,因此在执行一个操作时可能会有一个很长的调用链,最终进行实际操作的方法,一般会以 do 为方法的前缀。例如:对于创建 bean 实例来说,最终执行创建的方法为:doCreateBean;对于加载 bean 定义,最终执行加载的方法为:doLoadBeanDefinitions。

  5. 如果某些代码看了很多遍还是无法很好的理解,可以到网上搜下别人的文章参考,如果没有合适的参考,可以先放着,先往后看,也许等你把后面的流程看了,你在回过头来看就理解了。因为有很多地方是前后相关联的,只看前面的是无法很好理解的。

  6. 最重要的一点:反复看,反复看。Spring 的源码是一个大工程,想要一遍两遍就吃透就基本不可能的,只有反复的看、反复的推敲才能逐渐的加深自己的理解。

关于 IoC

======

IoC 即 Inversion of Control,也就是控制反转。在传统的程序设计,我们直接在对象内部通过 new 来创建对象,是程序主动去创建依赖对象;而在 Spring 中有专门的一个容器来创建和管理这些对象,并将对象依赖的其他对象注入到该对象中,这个容器我们一般称为 IoC 容器。

所有的类的创建、销毁都由 Spring 来控制,也就是说控制对象生存周期的不再是引用它的对象,而是 Spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被 Spring 控制,所以这叫控制反转。

IoC 构建过程

========

Spring 初始化的入口在 ContextLoaderListener,如果你的项目用了 Spring,通常可以在 web.xml 中找到下面这行代码。

org.springframework.web.context.ContextLoaderListener

ContextLoaderListener 是实现了 javax.servlet.ServletContextListener 接口的服务器端程序,随 web 应用的启动而启动,只初始化一次,随 web 应用的停止而销毁。在web应用启动的时候会调用 contextInitialized 方法,停止的时候会调用 contextDestroyed 方法。

从 ContextLoaderListener 类为出发点,跟着下面的调用过程:

ContextLoaderListener.contextInitialized(ServletContextEvent event) ->

initWebApplicationContext(event.getServletContext());

ContextLoader.initWebApplicationContext(ServletContext servletContext) ->

configureAndRefreshWebApplicationContext(cwac, servletContext);

ContextLoader.configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) ->

wac.refresh();

AbstractApplicationContext.refresh()

我们最终来到了 AbstractApplicationContext.java 里的 refresh() 方法,这个方法就是构建整个 IoC 容器过程的完整代码,只要把这个方法里的每一行代码都了解了,基本上了解了大部分 Spring 的原理和功能。

@Override

public void refresh() throws BeansException, IllegalStateException {

synchronized (this.startupShutdownMonitor) {

// Prepare this context for refreshing.

prepareRefresh();

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

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

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

prepareBeanFactory(beanFactory);

try {

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

postProcessBeanFactory(beanFactory);

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

invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.

registerBeanPostProcessors(beanFactory);

// Initialize message source for this context.

initMessageSource();

// Initialize event multicaster for this context.

initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.

onRefresh();

// Check for listener beans and register them.

registerListeners();

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

finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.

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

}

}

}

startupShutdownMonitor 属性


用于“刷新”和“销毁”的同步监视器,说白了就是一个锁。

prepareRefresh() 方法


为刷新准备新的上下文环境,设置其启动日期和活动标志以及执行一些属性的初始化。主要是一些准备工作,不是很重要的方法,可以先不关注。

obtainFreshBeanFactory() 方法


用于获得一个新的 BeanFactory。

该方法会解析所有 Spring 配置文件(通常我们会放在 resources 目录下),将所有 Spring 配置文件中的 bean 定义封装成 BeanDefinition,加载到 BeanFactory 中。常见的,如果解析到<context:component-scan base-package=“com.joonwhee.open” /> 注解时,会扫描 base-package 指定的目录,将该目录下使用指定注解(@Controller、@Service、@Component、@Repository)的 bean 定义也同样封装成 BeanDefinition,加载到 BeanFactory 中。

上面提到的“加载到 BeanFactory 中”的内容主要指的是以下3个缓存:

  • beanDefinitionNames缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 集合。

  • beanDefinitionMap缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 和 BeanDefinition 映射。

  • aliasMap缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 和别名映射。

prepareBeanFactory(beanFactory) 方法


配置 beanFactory 的标准上下文特征,例如上下文的 ClassLoader、后置处理器等。这个方法会注册3个默认环境 bean:environment、systemProperties 和 systemEnvironment,注册 2 个 bean 后置处理器:ApplicationContextAwareProcessor 和 ApplicationListenerDetector。

postProcessBeanFactory(beanFactory) 方法


允许子类对 BeanFactory 进行后续处理,默认实现为空,留给子类实现。

invokeBeanFactoryPostProcessors(beanFactory) 方法


实例化和调用所有 BeanFactoryPostProcessor,包括其子类 BeanDefinitionRegistryPostProcessor。

BeanFactoryPostProcessor 接口是 Spring 初始化 BeanFactory 时对外暴露的扩展点,Spring IoC 容器允许 BeanFactoryPostProcessor 在容器实例化任何 bean 之前读取 bean 的定义,并可以修改它。

BeanDefinitionRegistryPostProcessor 继承自 BeanFactoryPostProcessor,比 BeanFactoryPostProcessor 具有更高的优先级,主要用来在常规的 BeanFactoryPostProcessor 激活之前注册一些 bean 定义。特别是,你可以通过 BeanDefinitionRegistryPostProcessor 来注册一些常规的 BeanFactoryPostProcessor,因为此时所有常规的 BeanFactoryPostProcessor 都还没开始被处理。

注:这边的 “常规 BeanFactoryPostProcessor” 主要用来跟 BeanDefinitionRegistryPostProcessor 区分。

registerBeanPostProcessors(beanFactory) 方法


注册所有的 BeanPostProcessor,将所有实现了 BeanPostProcessor 接口的类加载到 BeanFactory 中。

BeanPostProcessor 接口是 Spring 初始化 bean 时对外暴露的扩展点,Spring IoC 容器允许 BeanPostProcessor 在容器初始化 bean 的前后,添加自己的逻辑处理。在这边只是注册到 BeanFactory 中,具体调用是在 bean 初始化的时候。

具体的:在所有 bean 实例化时,执行初始化方法前会调用所有 BeanPostProcessor 的 postProcessBeforeInitialization 方法,执行初始化方法后会调用所有 BeanPostProcessor 的 postProcessAfterInitialization 方法。

initMessageSource() 方法


初始化消息资源 MessageSource。

最后,附一张自己面试前准备的脑图:

image

面试前一定少不了刷题,为了方便大家复习,我分享一波个人整理的面试大全宝典

  • Java核心知识整理

image

  • Spring全家桶(实战系列)

image.png

Step3:刷题

既然是要面试,那么就少不了刷题,实际上春节回家后,哪儿也去不了,我自己是刷了不少面试题的,所以在面试过程中才能够做到心中有数,基本上会清楚面试过程中会问到哪些知识点,高频题又有哪些,所以刷题是面试前期准备过程中非常重要的一点。

以下是我私藏的面试题库:

image

很多人感叹“学习无用”,实际上之所以产生无用论,是因为自己想要的与自己所学的匹配不上,这也就意味着自己学得远远不够。无论是学习还是工作,都应该有主动性,所以如果拥有大厂梦,那么就要自己努力去实现它。

最后祝愿各位身体健康,顺利拿到心仪的offer!

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

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

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

以下是我私藏的面试题库:

[外链图片转存中…(img-QEWDvlys-1713426612475)]

很多人感叹“学习无用”,实际上之所以产生无用论,是因为自己想要的与自己所学的匹配不上,这也就意味着自己学得远远不够。无论是学习还是工作,都应该有主动性,所以如果拥有大厂梦,那么就要自己努力去实现它。

最后祝愿各位身体健康,顺利拿到心仪的offer!

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

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

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

  • 43
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值