小白也看得懂的 Spring IoC 核心流程介绍,350道Java面试真题分享

ApplicationContextInitializer {

@Override

public void initialize(ConfigurableApplicationContext applicationContext) {

// 自己的逻辑实现

// 例子1:通过硬编码的方式添加监听器

EarlyListener earlyListener = new EarlyListener();

applicationContext.addApplicationListener(earlyListener);

// 例子2:通过硬编码的方式添加BeanFactoryPostProcessor

MyBeanFactoryPostProcessor myBeanFactoryPostProcessor = new MyBeanFactoryPostProcessor();

applicationContext.addBeanFactoryPostProcessor(myBeanFactoryPostProcessor);

}

}

2)在web.xml中,定义 contextInitializerClasses 或 globalInitializerClasses 参数,参数值为 SpringApplicationContextInitializer 的全路径。

三、初始化 BeanFactory、加载 Bean 定义


1、创建一个新的 BeanFactory,默认为 DefaultListableBeanFactory。

2、根据 web.xml 中 contextConfigLocation 配置的路径,读取 Spring 配置文件,并封装成 Resource。

3、根据 Resource 加载 XML 配置文件,并解析成 Document 对象 。

4、从根节点开始,遍历解析 Document 中的节点。

4.1、对于默认命名空间的节点:先将 bean 节点内容解析封装成 BeanDefinition,然后将 beanName、BeanDefinition 放到 BeanFactory 的缓存中,用于后续创建 bean 实例时使用。

默认命名空间:http://www.springframework.org/schema/beans,可能存在的节点如下:

4.2、对于自定义命名空间的节点:会拿到自定义命名空间对应的解析器,对节点进行解析处理。

例如:<context:component-scan base-package=“com.joonwhee” /> ,该节点对应的解析器会扫描 base-package 指定路径下的所有类,将使用了 @Component(@Controller、@Service、@Repository)注解的类封装成 BeanDefinition,然后将 beanName、BeanDefinition 放到 BeanFactory 的缓存中,用于后续创建 Bean 实例时使用。

四、触发 BeanFactoryPostProcessor


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

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

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

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

例子:BeanFactoryPostProcessor 扩展使用

1)创建一个 BeanFactoryPostProcessor 接口的实现类,例如下面的 MyBeanFactoryPostProcessor,并在 postProcessBeanFactory 方法中进行自己的逻辑操作。例如:扫描某个包路径,将该包路径下使用了某个注解的类全部注册到 Spring 中。

2)将该实现类注册到 Spring 容器中,例如使用 @Component 注解

package com.joonwhee.open.demo.spring;

import org.springframework.beans.BeansException;

import org.springframework.beans.factory.config.BeanFactoryPostProcessor;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

import org.springframework.stereotype.Component;

/**

  • @author joonwhee

  • @date 2019/2/18

*/

@Component

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

@Override

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

System.out.println(“MyBeanFactoryPostProcessor#postProcessBeanFactory”);

// 自己的逻辑处理

}

}

另外,Mybatis 中的 MapperScannerConfigurer 是一个典型的 BeanDefinitionRegistryPostProcessor 的扩展使用,有兴趣的可以看看这个类的源码。

五、注册 BeanPostProcessor


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

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

例子:BeanPostProcessor 扩展使用

1)创建一个 BeanPostProcessor 接口的实现类,例如下面的 MyBeanPostProcessor,并在方法中进行自己的逻辑操作。

2)将该实现类注册到 Spring 容器中,例如使用 @Component 注解。

package com.joonwhee.open.processor;

import org.springframework.beans.BeansException;

import org.springframework.beans.factory.config.BeanPostProcessor;

import org.springframework.stereotype.Component;

/**

  • @author joonwhee

  • @date 2019/2/23

*/

@Component

public class MyBeanPostProcessor implements BeanPostProcessor {

@Override

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

System.out.println(“MyBeanPostProcessor#postProcessBeforeInitialization”);

// 自己的逻辑

return bean;

}

@Override

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

System.out.println(“MyBeanPostProcessor#postProcessAfterInitialization”);

// 自己的逻辑

return bean;

}

}

六、实例化所有剩余的非懒加载单例 bean


1、遍历所有被加载到缓存中的 beanName,触发所有剩余的非懒加载单例 bean 的实例化。

2、首先通过 beanName 尝试从缓存中获取,如果存在则跳过实例化过程;否则,进行 bean 的实例化。

3、根据 BeanDefinition,使用构造函数创建 bean 实例。

4、根据 BeanDefinition,进行 bean 实例属性填充。

5、执行 bean 实例的初始化。

5.1、触发 Aware 方法。

5.2、触发 BeanPostProcessor 的 postProcessBeforeInitialization 方法。

5.3、如果 bean 实现了 InitializingBean 接口,则触发 afterPropertiesSet() 方法。

5.4、如果 bean 设置了 init-method 属性,则触发 init-method 指定的方法。

5.5、触发 BeanPostProcessor 的 postProcessAfterInitialization 方法。

6、将创建好的 bean 实例放到缓存中,用于之后使用。

七、完成上下文的刷新


使用应用事件广播器推送上下文刷新完毕事件(ContextRefreshedEvent )到相应的监听器。

例子:监听器扩展使用

1)创建一个自定义监听器,实现 ApplicationListener 接口,监听 ContextRefreshedEvent(上下文刷新完毕事件)。

2)将该监听器注册到 Spring IoC 容器即可。

import org.springframework.context.ApplicationListener;

import org.springframework.context.event.ContextRefreshedEvent;

import org.springframework.stereotype.Component;

/**

  • @author joonwhee

  • @date 2019/6/22

*/

@Component

public class MyRefreshedListener implements ApplicationListener {

@Override

public void onApplicationEvent(ContextRefreshedEvent event) {

// 自己的逻辑处理

}

}

至此,整个 IoC 的核心流程介绍完毕。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

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

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

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

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

写在最后

为了这次面试,也收集了很多的面试题!

以下是部分面试题截图

Java程序员秋招三面蚂蚁金服,我总结了所有面试题,也不过如此
025038720)]
[外链图片转存中…(img-WYqKFNiV-1712025038720)]

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

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

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-SSt1ptAP-1712025038721)]

写在最后

为了这次面试,也收集了很多的面试题!

以下是部分面试题截图

[外链图片转存中…(img-pMhf12uN-1712025038721)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值