Java进阶-Spring-IOC

一、IOC

1.1 延迟查找

  SpringFramework 4.3 中引入了一个新的 API :ObjectProvider,可以实现延迟查找

ApplicationContext context = new ClassPathXmlApplicationContext("context/beanDefine.xml");
ObjectProvider<Person> dogProvider = context.getBeanProvider(Person.class);
Person person = dogProvider.getIfAvailable(Person::new);

https://www.jianshu.com/p/27ced9a9854d

  使用场景:

  • 可以让依赖的资源充分等到初始化完成之后再使用
  • 可以和@Lazy注解配合充分实现延迟初始化
  • 可用于解决构造器级别的循环依赖

1.2 @Autowired的注入原理

  先拿属性对应的类型,去 IOC 容器中找 Bean ,如果找到了一个,直接返回;如果找到多个类型一样的Bean,把属性名拿过去,跟这些 Bean 的 id 逐个对比,如果有一个相同的,直接返回;如果没有任何相同的 id 与要注入的属性名相同,则会抛出 NoUniqueBeanDefinitionException 异常。

1.3 @Autowired和@Resource区别

  • 构造器注入/setter注入

  • @Autowired 按类型注入, 可指定required=false来避免注入失败

  • @Resource 按名称注入,相当于@Autowired+@Qualifier

1.4 回调注入

  ApplicationContextAware、BeanNameAware 接口。

  • 当ApplicationContext创建了一个实现ApplicationContextAware接口的对象实例时,就为该实例提供了ApplicationContext引用
  • 当ApplicationContext创建实现BeanNameAware接口的类时,该类提供了在其关联对象定义中定义的名称的引用

https://www.cnblogs.com/springmorning/p/10355859.html

1.5 FactoryBean

  ApplicationContext初始化Bean的时机默认是容器加载时就已经创建,FactoryBean本身的加载是伴随 IOC 容器的初始化时机一起的。FactoryBean生产Bean的机制是延迟生产

  • BeanFactory :SpringFramework 中实现IOC的最底层容器(此处的回答可以从两种角度出发:从类的继承结构上看,它是最顶级的接口,也就是最顶层的容器实现;从类的组合结构上看,它则是最深层次的容器,ApplicationContext在最底层组合了BeanFactory)
  • FactoryBean :创建对象的工厂Bean,可以使用它来直接创建一些初始化流程比较复杂的对象。
  • FactoryBean的生命周期与IOC容器一致,而FactoryBean生产bean的时机是延迟创建的。

1.6 Bean生命周期

image.png

  在IOC容器初始化之前,默认情况下Bean已经创建好了,而且完成了初始化动作;容器调用销毁动作时,先销毁所有Bean,最后IOC容器全部销毁完成

  Bean的生命周期中,是先对属性赋值,后执行init-method标记的方法。

  • init-method & destroy-method
  • @PostConstruct & @PreDestroy
  • InitializingBean & DisposableBean
image.png
image.png

https://juejin.cn/post/7075168883744718856

1.7 BeanFactory

image.png
  • HierarchicalBeanFactory
  • ListableBeanFactory
image.png
  • AutowireCapableBeanFactory
  • ConfigurableBeanFactory
  • AbstractBeanFactory(getBeanDefinition/createBean)
  • AbstractAutowireCapableBeanFactory
  • DefaultListableBeanFactory

1.8 ApplicationContext

image.png
  • AbstractApplicationContext - refresh
image.png

1.9 模块装配

模块

  • 独立的
  • 功能高内聚
  • 可相互依赖
  • 目标明确

模块装配:把一个模块需要的核心功能组件都装配好
核心原则:自定义注解 + @Import 导入组件

@Import

  • 导入普通类
  • 导入ImportSelector接口实现类
  • 导入ImportBeanDefinitionRegistrar实现类

https://blog.csdn.net/Howinfun/article/details/118932670

1.10 条件装配

  • @Profile
      默认default
      基于环境的配置:根据当前项目的运行时环境不同,可以动态的注册当前运行环境匹配的组件。

  • @Conditional

  被@Conditional注解标注的组件,只有所有指定条件都匹配时,才有资格注册。条件是可以在要注册BeanDefinition之前以编程式确定的任何状态

  实现Condition接口-条件匹配规则类

https://blog.csdn.net/weixin_46535927/article/details/119387476

1.11 组件扫描

  include的过滤规则之间互相不受影响,且不会互相排除;排除型过滤器会排除掉其他过滤规则已经包含进来的Bean

1.12 资源管理

image.png
  • ProtocolResolver
  • DefaultResourceLoader
  • @PropertySource
  • PropertySourceFactory
  • DefaultPropertySourceFactory

1.13 Environment抽象

image.png
  • Environment中包含profiles和properties,这些配置信息会影响IOC容器中的bean的注册与创建;
  • Environment的创建是在ApplicationContext创建后才创建的,所以Environment应该是伴随着ApplicationContext的存在而存在
  • ApplicationContext中同时包含Environment和组件bean ,而且从BeanFactory的视角来看,Environment 也是一个Bean,只不过它的地位比较特殊。
image.png

1.14 BeanDefinition & BeanDefinitionRegistry

  BeanDefinition描述了一个bean的实例,该实例具有属性值,构造函数参数值以及具体实现所提供的更多信息。这只是一个最小的接口,它的主要目的是允许BeanFactoryPostProcessor(例如 PropertyPlaceholderConfigurer )内省和修改属性值和其他bean的元数据。

  BeanDefinition描述了SpringFramework中bean的元信息,它包含bean的类信息、属性、行为、依赖关系、配置信息等。BeanDefinition具有层次性,并且可以在IOC容器初始化阶段被BeanDefinitionRegistryPostProcessor构造和注册,被BeanFactoryPostProcessor拦截修改等。

image.png
  • BeanDefinition继承了AttributeAccessor 接口,具有配置bean属性的功能;

  BeanDefinitionRegistry是维护BeanDefinition的注册中心,它内部存放了 IOC 容器中bean的定义信息,同时BeanDefinitionRegistry也是支撑其它组件和动态注册Bean的重要组件。在SpringFramework中,BeanDefinitionRegistry的实现是DefaultListableBeanFactory。

  • BeanFactoryPostProcessor,可实现去除beanDefinition
  • BeanDefinition的合并

1.15 后置处理器

  BeanPostProcessor是一个回调机制的扩展点,它的核心工作点是在bean的初始化前后做一些额外的处理(预初始化bean的属性值、注入特定的依赖,甚至扩展生成代理对象等)。

  • BeanPostProcessor的执行可以指定先后顺序,实现Ordered接口;
  • BeanPostProcessor作用于bean对象的创建后,不同IOC容器中的BeanPostProcessor不会互相起作用
  • BeanPostProcessor提供了两个回调时机:bean的初始化之前和bean的初始化之后,它们分别适合做填充和代理的工作;
image.png
  • postProcessBeforeInitialization是用来填充的,而工厂就是做的这事。如果使用FactoryBean就是说用户已经把想填充的内容在工厂里做好了,spring不应该再插手,所以不会调用postProcessBeforeInitialization。
image.png
  • InstantiationAwareBeanPostProcessor
  • SmartInstantiationAwareBeanPostProcessor
  • DestructionAwareBeanPostProcessor
  • MergedBeanDefinitionPostProcessor

1.16 BeanFactoryPostProcessor

image.png

  BeanFactoryPostProcessor是容器的扩展点,它用于IOC容器的生命周期中,所有BeanDefinition都注册到BeanFactory后回调触发,用于访问/修改已经存在的BeanDefinition。与BeanPostProcessor相同,它们都是容器隔离的,不同容器中的BeanFactoryPostProcessor不会相互起作用。

image.png

1.17 BeanDefinitionRegistryPostProcessor

image.png

  BeanDefinitionRegistryPostProcessor是容器的扩展点,它用于 IOC 容器的生命周期中,所有BeanDefinition都准备好,即将加载到BeanFactory时回调触发,用于给BeanFactory中添加新的BeanDefinition。BeanDefinitionRegistryPostProcessor也是容器隔离的,不同容器中的BeanDefinitionRegistryPostProcessor不会相互起作用。

  BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry执行完毕后,会先执行它们的postProcessBeanFactory,然后才能轮到普通的BeanFactoryPostProcessor执行。

image.png

spring-BeanDefinitionRegistryPostProcessor、BeanFactoryPostProcessor、BeanPostProcessor三者区别

1.18 编程式驱动IOC

  refresh方法的执行,会触发非延迟加载的单实例bean的实例化和初始化。

  使用模块装配,通过标注一个@EnableJdbc的注解,能够根据当前工程中导入的数据库连接驱动,注册对应的数据源到IOC容器。

  SPI:通过一种服务寻找的机制,动态的加载接口/抽象类对应的具体实现类。它把接口具体实现类的定义和声明权交给了外部化的配置文件中。SpringFramework 中的SPI相比较于jdk原生的,不仅仅局限于接口/抽象类,它可以是任何一个类、接口、注解。

https://github.com/just-right/spring-study

1.19 事件&监听器

  子容器的事件会向上传播到父容器,父容器的事件不会向下传播

  • ApplicationEvent/ApplicationListener/PayloadApplicationEvent/

  ApplicationEventPublisher和ApplicationEventMulticaster,它们分别代表事件发布器和事件广播器。事件发布器是用来接受事件,并交给事件广播器处理;事件广播器拿到事件发布器的事件,并广播给监听器

1.20 Bean生命周期-补充

  • BeanDefinition部分
    • BeanDefinition的解析
    • BeanDefinition的注册
  • bean实例部分
    • bean的实例化
    • bean的属性赋值+依赖注入
    • bean的初始化流程
    • bean的启动与停止
    • bean的销毁
image.png

  BeanPostProcessor的扩展InstantiationAwareBeanPostProcessor可以在bean的实例化之后、初始化之前执行postProcessAfterInstantiation方法,以及postProcessProperties( postProcessPropertyValues) 方法完成属性赋值。BeanPostProcessor的回调包含bean的初始化之前和初始化之后,但DestructionAwareBeanPostProcessor只包含bean销毁回调之前的动作,没有之后。

  首先ClassPathXmlApplicationContext在refresh之前,会指定传入的xml配置文件的路径,执行refresh方法时,会初始化BeanFactory,触发xml配置文件的读取、加载和解析。其中xml的读取需要借助XmlBeanDefinitionReader ,解析xml配置文件则使用 DefaultBeanDefinitionDocumentReader ,最终解析xml中的元素,封装出BeanDefinition,最后注册到 BeanDefinitionRegistry。

  注解配置类的解析发生在BeanDefinitionRegistryPostProcessor的执行阶段,它对应的核心后置处理器是ConfigurationClassPostProcessor ,它主要负责两个步骤三件事情:解析配置类、注册BeanDefinition。三件事情包括:1) 解析@ComponentScan 并进行包扫描,实际进行包扫描的组件是ClassPathBeanDefinitionScanner ;2) 解析配置类中的注解(如 @Import 、@ImportResource 、@PropertySource 等)并处理,工作的核心组件是ConfigurationClassParser ;3) 解析配置类中的 @Bean并封装BeanDefinition,实际解析的组件是ConfigurationClassBeanDefinitionReader。

image.png
image.png
image.png

1.21 参考链接

https://www.jianshu.com/p/1dec08d290c1
https://juejin.cn/book/6857911863016390663/section/6867492434910117902
https://juejin.cn/post/6956814839729618957

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,997评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,603评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,359评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,309评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,346评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,258评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,122评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,970评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,403评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,596评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,769评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,464评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,075评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,705评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,848评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,831评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,678评论 2 354

推荐阅读更多精彩内容