当前位置: 首页 > news >正文

spring揭秘00-ioc定义与ioc容器及集成工厂模式

文章目录

  • 【README】
  • 【1】IOC概述
    • 【1.1】ioc定义
    • 【1.2】IOC三种依赖注入方式
  • 【2】ioc服务提供者
    • 【2.1】 ioc服务提供者职责
    • 【2.2】ioc服务提供者如何管理对象间依赖关系
  • 【3】IOC容器
    • 【3.1】BeanFactory
  • 【4】集成工厂模式创建bean
    • 【4.1】静态工厂方法
    • 【4.2】非静态工厂方法
    • 【4.3】FactoryBean接口

【README】

本文总结自《spring揭秘》,作者王福强,非常棒的一本书,墙裂推荐;

本文内容包括ioc概述及ioc容器概述;


【1】IOC概述

【1.1】ioc定义

1.Ioc控制反转,别名是依赖注入DI;

  • (1)反转:就反转在让你从原来的事事必躬亲,转变为现在的享受服务(这是ioc提出的价值所在 );
  • (2)通常情况下: 被注入对象直接依赖于被依赖对象; 但是在IOC场景中,被注入对象与被依赖对象通过IOC服务提供者来打交道,所有的被注入对象和被依赖对象都由IOC服务提供者统一管理; 如ioc容器就是一个ioc服务提供者;
    • 【例】被注入对象与被依赖对象:如Student类声明了 Teacher属性,spring把Teacher对象注入到Student对象,则Student是被注入对象 ,Teacher是被依赖对象;(Teacher是被Student依赖的对象)
    • 其中, 被注入对象与被依赖对象都称为业务对象;

2.IOC作用: IOC是一种帮助我们解耦各业务对象间依赖关系的对象绑定方式;


【1.2】IOC三种依赖注入方式

1)构造方法注入;

  • 优点: 对象构造完成后,马上进入就绪状态,可以马上使用;
  • 缺点: 当依赖对象较多时, 构造器入参列表比较长;

2)Setter方法注入;

  • 优点: 方法可以命名, 允许设置默认值,有良好IDE支持;
  • 缺点:对象构造完成后,无法立即进入就绪状态;

3)实现接口注入;(不推荐,因为有侵入性


【2】ioc服务提供者

ioc服务提供者定义: 管理所有被注入对象和被依赖对象; 如spring ioc容器就是一个ioc服务提供者;

具体的, spring ioc容器有 BeanFactory , ApplicationContext; 其中BeanFactory是基础容器, ApplicationContext继承了 BeanFactory,是高级容器,功能更加丰富

【ApplicationContext】

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {@NullableString getId();String getApplicationName();String getDisplayName();long getStartupDate();@NullableApplicationContext getParent();AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}

【2.1】 ioc服务提供者职责

1)业务对象的构建管理(创建bean): 即业务对象无需关心所依赖的对象如何构建(bean如何创建),由IOC服务提供者来完成;

2)业务对象间的依赖绑定(绑定对象间依赖关系):IOC服务服务提供者通过结合之前构建和管理的所有业务对象,以及各个业务对象间可以识别的依赖关系,将这些对象所依赖的对象注入绑定;

【2.2】ioc服务提供者如何管理对象间依赖关系

1)直接编码方式; (不推荐
2)配置文件方式: 比较常见的依赖管理方式; 如使用普通文本文件,XML,properties文件,等都可以作为管理依赖关系的载体;
3)元数据方式:即通过注解实现; 直接在类中使用元数据信息(注解)来标注对象间的依赖关系;


【3】IOC容器

1)ioc 容器概述:

  • ioc容器是一个ioc服务提供者;
  • Spring的Ioc容器是一个提供ioc支持的轻量级容器;
  • spring提供了两种容器: BeanFactory ,ApplicationContext ; 其中 ApplicationContext 继承自 BeanFactory ;

2)Spring还在ioc容器基础上提供了AOP框架支持,企业级服务集成等服务,如下图所示。

在这里插入图片描述

【3.1】BeanFactory

**1)容器1-BeanFactory:**基础类型IOC容器(懒汉式初始化 ), 提供完整的IOC服务支持; 如果没有特殊指定,默认采用延迟初始化策略;

  • 适用场景: 适用于资源有限,功能要求不是很严格的场景;
  • 作为spring基本的IOC容器, BeanFactory职责包括业务对象注册和对象间依赖关系绑定;

2)容器2-ApplicationContext(饿汉式初始化: 在BeanFactory基础上构建,是比较高级的容器;ApplicationContext管理的对象,在ApplicationContext容器启动后,默认全部初始化并绑定完成;

补充: ApplicationContext 继承自 BeanFactory ;


【4】集成工厂模式创建bean

1)背景:在系统开发中 ,需要集成第三方库或实例化bean过程复杂(如创建bean的代理,添加上下文),需要通过工厂模式创建bean,以简化代码及解耦被注入对象与被依赖对象接口实现类, 如 使用第三方库 SimpleClientHttpRequestFactory 创建http连接对象, 就是通过工厂方法模式实例化bean ;

2)对于下图中的Foo与BarInterface及BarInterfaceImpl, 可以通过工厂模式解除 Foo 与 BarInterfaceImpl具体实现类 间的耦合关系; (依赖抽象而不应该依赖具体实现 BarInterfaceImpl , 否则实现类有改动,则被注入对象Foo也会改动,不灵活,且回归测试成本高
在这里插入图片描述

3)spring ioc容器提供了对3种工厂模式的集成支持,包括静态工厂方法,非静态工厂方法, FactoryBean接口 ;

  • 静态工厂(静态工厂方法模式): 简单,但从头到尾都有且只有一个工厂;即工厂不抽象(1个),产品可以抽象(多个);
  • 非静态工厂(工厂方法模式): 相对灵活,调用方依赖的产品和工厂都可以抽象;
  • FactoryBean: 是一个接口,Spring容器提供的一种可以扩展容器对象实例化的接口; 即业务工厂实现FactoryBean接口, 重写 getObject() 方法,扩展bean创建逻辑 ;

补充1: 静态工厂与非静态工厂, 其产品和工厂可以抽象也可以不抽象;

补充2:特例, 非静态工厂的特例是抽象工厂,其工厂必须抽象;

【4.1】静态工厂方法

【CarStaticFactoryMain】静态工厂入口main函数

public class CarStaticFactoryMain {public static void main(String[] args) {ApplicationContext container = new ClassPathXmlApplicationContext("beans0403factorymethod.xml");ICar electricCar = container.getBean("electricCar", ICar.class);ICar electricCar2 = container.getBean("electricCar", ICar.class);ICar electricCar3 = container.getBean("electricCar", ICar.class);electricCar.drive();electricCar2.drive();electricCar3.drive();}
}

【beans0403factorymethod.xml】

 <!-- 静态工厂实例化bean  --><bean id="electricCar" class="com.tom.springnote.chapter04.t0403xmlfactorymethod.CarStaticFactory"factory-method="getInstance" scope="prototype"/>

【CarStaticFactory】汽车静态工厂

public class CarStaticFactory {private static final AtomicInteger INCREMENTOR = new AtomicInteger(0);public static ICar getInstance() {return new ElectricCar("特斯拉汽车" + INCREMENTOR.getAndIncrement());}
}

【ICar】 抽象产品 (接口或抽象类都可以)

public abstract class ICar {private String name = "";public ICar() {}public ICar(String name) {this.name = name;}abstract void drive();public String getName() {return name;}
}

【ElectricCar】电动车,具体产品

public class ElectricCar extends ICar {public ElectricCar(String name) {super(name);}@Overridepublic void drive() {System.out.println("name=" + getName() + ", 电池驱动, 自动驾驶");}
}

【打印日志】

name=特斯拉汽车0, 电池驱动, 自动驾驶
name=特斯拉汽车1, 电池驱动, 自动驾驶
name=特斯拉汽车2, 电池驱动, 自动驾驶

补充: 本文的静态工厂代码,对产品做了抽象,依赖ICar,而不是 ElectricCar 这个具体car;

在实际开发过程中, 静态工厂可以抽象也可以不抽象产品;

  • 工厂与产品是同一个类,这又是静态工厂的特例,叫简单工厂, 如 Integer.valueOf ;
  • 工厂不抽象,但产品抽象;如 List.of(…)

【Integer.valueOf】

public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}

【List.of()】

static <E> List<E> of(E e1, E e2) {return new ImmutableCollections.List12<>(e1, e2);}

【4.2】非静态工厂方法

非静态工厂方法对工厂和产品都做了抽象;

【CarNonStaticFactoryMain】非静态工厂方法入口main

public class CarNonStaticFactoryMain {public static void main(String[] args) {ApplicationContext container = new ClassPathXmlApplicationContext("beans0403factorymethod.xml");ICar car = container.getBean("petrolCar", ICar.class);ICar car2 = container.getBean("petrolCar", ICar.class);ICar car3 = container.getBean("petrolCar", ICar.class);car.drive();car2.drive();car3.drive();}
}

【beans0403factorymethod.xml】

<!-- 02 非静态工厂实例化bean  -->
<bean id="carNonStaticFactory" class="com.tom.springnote.chapter04.t0403xmlfactorymethod.CarNonStaticFactoryImpl" />
<bean id="petrolCar" factory-bean="carNonStaticFactory" factory-method="getInstance" scope="prototype" />

【CarNonStaticFactoryImpl】非静态工厂,具体工厂

public class CarNonStaticFactoryImpl implements ICarFactory {private static final AtomicInteger INCREMENTOR = new AtomicInteger(0);@Overridepublic ICar getInstance() {return new PetrolCar("奔驰汽车" + INCREMENTOR.getAndIncrement());}
}

【PetrolCar】继承ICar抽象类,具体产品

public class PetrolCar extends ICar {public PetrolCar(String name) {super(name);}@Overridepublic void drive() {System.out.println("name=" + getName() + ", 汽油驱动,人工驾驶");}
}

【打印日志】

name=奔驰汽车0, 汽油驱动,人工驾驶
name=奔驰汽车1, 汽油驱动,人工驾驶
name=奔驰汽车2, 汽油驱动,人工驾驶

【4.3】FactoryBean接口

factoryBean是一个接口, Spring容器提供的一种可以扩展容器对象实例化逻辑的接口; 定义如下:

【FactoryBean接口】

public interface FactoryBean<T> {String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";@NullableT getObject() throws Exception;@NullableClass<?> getObjectType();default boolean isSingleton() {return true;}
}

spring容器内部很多地方使用到了FactoryBean接口实例化bean

  • JndiObjectFactoryBean
  • LocalSessionFactoryBean
  • SqlMapClientFactoryBean
  • ProxyFactoryBean

使用FactoryBean创建bean代码示例:

【CarFactoryBeanImplMain】FactoryBean入口main

public class CarFactoryBeanImplMain {public static void main(String[] args) {ApplicationContext container = new ClassPathXmlApplicationContext("beans0403factorymethod.xml");ICar car = container.getBean("electricCarFactoryBean", ICar.class);ICar car2 = container.getBean("electricCarFactoryBean", ICar.class);ICar car3 = container.getBean("electricCarFactoryBean", ICar.class);car.drive();car2.drive();car3.drive();}
}

【beans0403factorymethod.xml】

<!-- 03 实现factorybean接口实例化bean  --><bean id="electricCarFactoryBean" class="com.tom.springnote.chapter04.t0403xmlfactorymethod.CarFactoryBeanImpl"scope="prototype" />

【CarFactoryBeanImpl】 FactoryBean接口实现类

public class CarFactoryBeanImpl implements FactoryBean<ICar> {private static final AtomicInteger start = new AtomicInteger(0);@Overridepublic ICar getObject() throws Exception {return new ElectricCar("FactoryBean特斯拉" + start.getAndIncrement());}@Overridepublic Class<?> getObjectType() {return ICar.class;}@Overridepublic boolean isSingleton() {return false;}
}

【打印日志】

name=FactoryBean特斯拉0, 电池驱动, 自动驾驶
name=FactoryBean特斯拉1, 电池驱动, 自动驾驶
name=FactoryBean特斯拉2, 电池驱动, 自动驾驶

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 韩国服务器的性能如何提升
  • 系统数据库介绍及实践
  • springboot+vue生成word文件下载(最简单教程)
  • web前端之实现一只可爱的小杰尼乌龟、伪元素、动画
  • 什么是回滚
  • Java爬虫中的数据清洗:去除无效信息的技巧
  • 高德地图SDK Android版开发 3 显示定位
  • 网络通信要素
  • 在 MacOS 系统下设置终端命令别名的方法
  • 安全基础学习-SHA-256
  • 物流快递外卖管理平台系统-计算机毕设Java|springboot实战项目
  • 【面试宝典】Java面向对象面试题总结(上)
  • 【Spark】算子实现delete SQL语句
  • C语言整数溢出的问题
  • Linux学习之路 -- 进程 -- 进程间通信 -- 管道通信
  • (ckeditor+ckfinder用法)Jquery,js获取ckeditor值
  • [Vue CLI 3] 配置解析之 css.extract
  • canvas 五子棋游戏
  • const let
  • ES10 特性的完整指南
  • export和import的用法总结
  • Idea+maven+scala构建包并在spark on yarn 运行
  • Java小白进阶笔记(3)-初级面向对象
  • Lucene解析 - 基本概念
  • Median of Two Sorted Arrays
  • OSS Web直传 (文件图片)
  • seaborn 安装成功 + ImportError: DLL load failed: 找不到指定的模块 问题解决
  • Sublime Text 2/3 绑定Eclipse快捷键
  • 闭包--闭包作用之保存(一)
  • 二维平面内的碰撞检测【一】
  • 翻译 | 老司机带你秒懂内存管理 - 第一部(共三部)
  • 给自己的博客网站加上酷炫的初音未来音乐游戏?
  • 计算机在识别图像时“看到”了什么?
  • 前端技术周刊 2019-02-11 Serverless
  • 物联网链路协议
  • 小试R空间处理新库sf
  • 源码安装memcached和php memcache扩展
  • ​插件化DPI在商用WIFI中的价值
  • # 手柄编程_北通阿修罗3动手评:一款兼具功能、操控性的电竞手柄
  • #Datawhale AI夏令营第4期#AIGC文生图方向复盘
  • #FPGA(基础知识)
  • #includecmath
  • (31)对象的克隆
  • (三)SvelteKit教程:layout 文件
  • (一)SpringBoot3---尚硅谷总结
  • (已解决)报错:Could not load the Qt platform plugin “xcb“
  • (转)创业的注意事项
  • ******IT公司面试题汇总+优秀技术博客汇总
  • ******之网络***——物理***
  • *算法训练(leetcode)第四十天 | 647. 回文子串、516. 最长回文子序列
  • .NET Core IdentityServer4实战-开篇介绍与规划
  • .NET Core MongoDB数据仓储和工作单元模式封装
  • .NET 快速重构概要1
  • .NET/ASP.NETMVC 深入剖析 Model元数据、HtmlHelper、自定义模板、模板的装饰者模式(二)...
  • .NET_WebForm_layui控件使用及与webform联合使用