【设计模式精讲】开源实战之剖析Spring框架:Spring中工厂模式的应用

文章目录

  • 第七章 开源实战
    • 7.1 剖析Spring框架中用到的经典设计模式
      • 7.1.1 Spring中工厂模式的应用
        • 7.1.1.1 Spring中的Bean组件
        • 7.1.1.2 Spring中的BeanFactory
        • 7.1.1.3 Spring中的FactoryBean

在这里插入图片描述
个人主页:道友老李
欢迎加入社区:道友老李的学习社区

第七章 开源实战

7.1 剖析Spring框架中用到的经典设计模式

7.1.1 Spring中工厂模式的应用

Spring的设计理念

  • Spring是面向Bean的编程(BOP:Bean Oriented Programming),Bean在Spring中才是真正的主角。Bean在Spring中作用就像Object对OOP的意义一样,没有对象的概念就像没有面向对象编程,Spring中没有Bean也就没有Spring存在的意义。Spring提供了IoC 容器通过配置文件或者注解的方式来管理对象之间的依赖关系。
  • 控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。
7.1.1.1 Spring中的Bean组件

Bean组件定义在Spring的org.springframework.beans包下,解决了以下几个问题:

这个包下的所有类主要解决了三件事:

  • Bean的定义
  • Bean的创建
  • Bean的解析

Spring Bean的创建是典型的工厂模式,它的顶级接口是BeanFactory。

在这里插入图片描述

BeanFactory有三个子类:ListableBeanFactory、HierarchicalBeanFactory和AutowireCapableBeanFactory。目的是为了区分Spring内部对象处理和转化的数据限制

但是从图中可以发现最终的默认实现类是DefaultListableBeanFactory,它实现了所有的接口

7.1.1.2 Spring中的BeanFactory

Spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象

BeanFactory,以Factory结尾,表示它是一个工厂(接口), 它负责生产和管理bean的一个工厂。在Spring中,BeanFactory是工厂的顶层接口,也是IOC容器的核心接口,因此BeanFactory中定义了管理Bean的通用方法,如 getBeancontainsBean 等.

它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。

在这里插入图片描述

BeanFactory只是个接口,并不是IOC容器的具体实现,所以Spring容器给出了很多种实现,如 DefaultListableBeanFactoryXmlBeanFactoryApplicationContext等,其中XmlBeanFactory就是常用的一个,该实现将以XML方式描述组成应用的对象及对象间的依赖关系。

1) BeanFactory源码解析

public interface BeanFactory {/**对FactoryBean的转移定义,因为如果使用bean的名字来检索FactoryBean得到的是对象是工厂生成的对象,如果想得到工厂本身就需要转移*/String FACTORY_BEAN_PREFIX = "&";//根据Bean的名字 获取IOC容器中对应的实例Object getBean(String var1) throws BeansException;//根据Bean的名字和class类型得到bean实例,增加了类型安全验证机制<T> T getBean(String var1, Class<T> var2) throws BeansException;Object getBean(String var1, Object... var2) throws BeansException;<T> T getBean(Class<T> var1) throws BeansException;<T> T getBean(Class<T> var1, Object... var2) throws BeansException;<T> ObjectProvider<T> getBeanProvider(Class<T> var1);<T> ObjectProvider<T> getBeanProvider(ResolvableType var1);//查看Bean容器中是否存在对应的实例,存在返回true 否则返回falseboolean containsBean(String var1);//根据Bean的名字 判断这个bean是不是单例boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;//得到bean实例的class类型@NullableClass<?> getType(String var1) throws NoSuchBeanDefinitionException;@NullableClass<?> getType(String var1, boolean var2) throws NoSuchBeanDefinitionException;//得到bean的别名String[] getAliases(String var1);
}

BeanFactory的使用场景

  1. 从IOC容器中获取Bean(Name or Type)
  2. 检索IOC容器中是否包含了指定的对象
  3. 判断Bean是否为单例

2) BeanFactory的使用

public class User {private int id;private String name;private Friends friends;public User() {}public User(Friends friends) {this.friends = friends;}//get set......
}public class Friends {private List<String> names;public Friends() {}public List<String> getNames() {return names;}public void setNames(List<String> names) {this.names = names;}
}

配置文件

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:task="http://www.springframework.org/schema/task"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.2.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.2.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-4.2.xsdhttp://www.springframework.org/schema/taskhttp://www.springframework.org/schema/task/spring-task-4.2.xsd"><bean id="User" class="com.example.factory.User"><property name="friends" ref="UserFriends" /></bean><bean id="UserFriends" class="com.example.factory.Friends"><property name="names"><list><value>"LiLi"</value><value>"LuLu"</value></list></property></bean>
</beans>

测试

public class SpringFactoryTest {public static void main(String[] args) {ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");User user = ctx.getBean("User", User.class);List<String> names = user.getFriends().getNames();for (String name : names) {System.out.println("FriendName: " + name);}ctx.close();}
}
7.1.1.3 Spring中的FactoryBean

首先FactoryBean是一个Bean,但又不仅仅是一个Bean,这样听起来矛盾,但为啥又这样说呢?其实在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。但对FactoryBean而言,这个FactoryBean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂方法模式和修饰器模式类似

1) 为什么需要FactoryBean?

  1. 在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。FactoryBean接口对于Spring框架来说占用重要的地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂Bean的细节,给上层应用带来了便利。
  2. 由于第三方库不能直接注册到spring容器,于是可以实现org.springframework.bean.factory.FactoryBean接口,然后给出自己对象的实例化代码即可。

2 ) FactoryBean的使用特点

  1. 当用户使用容器本身时,可以使用转义字符"&"来得到FactoryBean本身,以区别通过FactoryBean产生的实例对象和FactoryBean对象本身。

  2. 在BeanFactory中通过如下代码定义了该转义字符:

     StringFACTORY_BEAN_PREFIX = "&";
    
  3. 举例

    如果MyObject是一个FactoryBean,则使用&MyObject得到的是MyObject对象,而不是MyObject产生出来的对象。
    

3) FactoryBean的代码示例

@Configuration
@ComponentScan("com.example.factory_bean")
public class AppConfig {
}@Component("studentBean")
public class StudentBean implements FactoryBean {//返回工厂中的实例@Overridepublic Object getObject() throws Exception {//这里并不一定要返回MyBean自身的实例,可以是其他任何对象的实例。return new TeacherBean();}//该方法返回的类型是在IOC容器中getBean所匹配的类型@Overridepublic Class<?> getObjectType() {return StudentBean.class;}public void study(){System.out.println("学生学习......");}
}public class TeacherBean {public void teach(){System.out.println("老师教书......");}
}public class Test01 {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);//StudentBean studentBean = (StudentBean)context.getBean("studentBean");//加上&符号,返回工厂中的实例
//        StudentBean studentBean = (StudentBean)context.getBean("&studentBean");
//        studentBean.study();TeacherBean teacherBean = (TeacherBean) context.getBean("studentBean");teacherBean.teach();}
}

3) FactoryBean源码分析

public interface FactoryBean<T> {String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";/**getObject()方法: 会返回该FactoryBean生产的对象实例,我们需要实现该方法,以给出自己的对象实例化逻辑这个方法也是FactoryBean的核心.*/@NullableT getObject() throws Exception;/**getObjectType()方法: 仅返回getObject() 方法所返回的对象类型,如果预先无法确定,返回NULL,这个方法返回类型是在IOC容器中getBean所匹配的类型*/@NullableClass<?> getObjectType();//该方法的结果用于表明 工厂方法getObject() 所生产的 对象是否要以单例形式存储在容器中如果以单例存在就返回true,否则返回falsedefault boolean isSingleton() {return true;}
}

FactoryBean表现的是一个工厂的职责,如果一个BeanA 是实现FactoryBean接口,那么A就是变成了一个工厂,根据A的名称获取到的实际上是工厂调用getObject()方法返回的对象,而不是对象本身,如果想获取工厂对象本身,需要在名称前面加上 '&'符号

  • getObject(‘name’) 返回的是工厂中工厂方法生产的实例
  • getObject(‘&name’) 返回的是工厂本身实例

使用场景

  • FactoryBean的最为经典的使用场景,就是用来创建AOP代理对象,这个对象在Spring中就是 ProxyFactoryBean

BeanFactory与FactoryBean区别

  • 他们两个都是工厂,但是FactoryBean本质还是一个Bean,也归BeanFactory管理
  • BeanFactory是Spring容器的顶层接口,FactoryBean更类似于用户自定义的工厂接口

BeanFactory和ApplicationContext的区别

  • BeanFactory是Spring容器的顶层接口,而ApplicationContext应用上下文类 他是BeanFactory的子类,他是Spring中更高级的容器,提供了更多的功能
    • 国际化
    • 访问资源
    • 载入多个上下文
    • 消息发送 响应机制
  • 两者的装载bean的时机不同
    • BeanFactory: 在系统启动的时候不会去实例化bean,只有从容器中拿bean的时候才会去实例化(懒加载)
      • 优点: 应用启动的时候占用的资源比较少,对资源的使用要求比较高的应用 ,比较有优势
    • ApplicationContext:在启动的时候就把所有的Bean全部实例化.
      • lazy-init= true 可以使bean延时实例化
      • 优点: 所有的Bean在启动的时候就加载,系统运行的速度快,还可以及时的发现系统中配置的问题.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/72013.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[数据结构]用栈实现队列

思路分析 代码实现&#xff1a; typedef int STDataType; typedef struct Stack {int* a;int top;//下标int capacity; }ST; //栈的初始化 void STInit(ST* ps); //栈的插入 void STPush(ST* ps, STDataType x); //栈的删除 void STPop(ST* ps); // int STSize(ST* ps); //判断…

C++ 17 允许在 for 循环,if 语句,switch 语句中初始化变量

看到 c 有这个特性&#xff0c;python 和 java 似乎都没有&#xff0c;根据 AI 的回答进行了一些整理总结。 文章目录 **1. 在 for 循环中初始化变量****特点****多个变量初始化** **2. 在 if 语句中初始化变量&#xff08;C17 及以上&#xff09;****示例****特点** **3. 在 s…

【云原生之kubernetes实战】在k8s环境中高效部署Vikunja任务管理工具(含数据库配置)

【【云原生之kubernetes实战】在k8s环境中高效部署Vikunja任务管理工具(含数据库配置) 前言一、Vikunja介绍1.1 Vikunja简介1.2 Vikunja主要特点1.3 使用场景二、相关知识介绍2.1 本次实践存储介绍2.2 k8s存储介绍三、本次实践介绍3.1 本次实践简介3.2 本次环境规划3.3 部署前…

分享一个常用的命名规则和Spring的命名风格

目录 Spring 命名风格规范总结表 常用代码命名单词&#xff08;通用且专业&#xff09; 命名技巧 一、返回布尔值的方法 二、条件执行方法 三、异步处理方法 四、回调方法 五、集合操作方法 六、状态校验方法 七、对象生命周期方法 八、数据操作方法 Spring 命名风格规…

【Golang学习之旅】Go-zero + Gen:如何使用 Gen 提升 Go 开发效率

文章目录 前言一、Go-zero简介二、Gen工具简介2.1 Gen的功能与特点2.2 Gen的工作原理 三、Go-zero Gen&#xff1a;结合的优势3.1为什么选择Go-zero与Gen3.2 Gen的代码生成与Go-zero的结合点 四、实际案例&#xff1a;Go-zero Gen的应用4.1 构建一个用户管理系统4.2 定义Gen配…

软件工程----统一过程模型RUP

统一过程RUP是一种以用例驱动、以体系结构为核心、迭代和增量的软件开发过程&#xff0c;由UML方法和工具支持&#xff0c;广泛应用于各类面向对象项目。 RUP本身支持可裁剪性&#xff0c;可应付给类领域软件和不同的项目规模 RUP蕴含了大量优秀的实践方法&#xff0c;如&…

48V电气架构全面科普和解析:下一代智能电动汽车核心驱动

48V电气架构&#xff1a;下一代智能电动汽车核心驱动 随着全球汽车产业迈入电动化、智能化的新时代&#xff0c;传统12V电气系统逐渐暴露出其无法满足现代高功率需求的不足。在此背景下&#xff0c;48V电气架构应运而生&#xff0c;成为现代电动汽车&#xff08;EV&#xff09…

图数据库 | 24、如何进行正确性验证?

图数据库计算和查询结果的正确性&#xff0c;这个重要性当然是不言而喻的&#xff01; 老夫之前也写文章讲过&#xff0c;今天再手书一篇&#xff0c;旨在向大家系统地介绍一下图数据库查询与计算到底如何进行正确性验证&#xff01;&#xff01;&#xff01; 图数据库中的操…

Rust ~ Vec<u8>和[u8]

Vec<u8> 和 &[u8] 是两种不同的数据类型&#xff0c;它们都与字节序列相关&#xff0c;但在所有权、内存管理、使用场景等方面存在明显区别 类型本质 Vec<u8>&#xff1a;Rust 中的动态数组类型&#xff0c;即向量&#xff08;vector&#xff09;。它是一个拥…

MYSQL学习笔记(十):约束介绍(如:非空、唯一、主键、外键、级联、默认、检查约束)

前言&#xff1a; 学习和使用数据库可以说是程序员必须具备能力&#xff0c;这里将更新关于MYSQL的使用讲解&#xff0c;大概应该会更新30篇&#xff0c;涵盖入门、进阶、高级(一些原理分析);这一篇讲解“约束”&#xff0c;如&#xff1a;非空、唯一、主键、外键、级联、默认…

树莓百度百科更新!宜宾园区业务再添新篇

树莓集团宜宾园区业务不断拓展&#xff0c;主要体现在以下几个方面&#xff1a; 产业布局 -聚焦数字经济核心领域&#xff1a;涵盖软件开发、人工智能、大数据等&#xff0c;吸引众多上下游企业入驻&#xff0c;形成从芯片研发、软件开发到系统集成的完整产业链条。 -推进“双…

Halcon 学习之路 set_grayval 算子

gen_imag_const 创建灰度图像 gen_image_const(Image&#xff0c;Type&#xff0c;Width&#xff0c;Height) 算子gen_image_const创建指定大小的图像&#xff0c;图像的宽度和高度由Width和Height决定 Type 像素类型 byte :每像素1字节&#xff0c;无符号&#xff08;0-255&…

03_pyqt5 + vlc 实现视频播放器

1.功能需求如图 按钮: 播放/暂停, 前进/后退, 视频上一个/下一个, 打开视频进度条: 视频进度条显示, 进度条拖拽, 音量控制按键控制: 1,2,3,4缩放画面大小, 2.方案选择 开发语言: python UI界面: pyqt5 qt_designed 设计ui布局 视频编码: python-vlc 方案说明: 视频解码可…

使用vscode导出Markdown的PDF无法显示数学公式的问题

我的硬件环境是M2的MacBook air&#xff0c;在vscode中使用了Markdown PDF来导出md文件对应的PDF。但不管导出html还是PDF文件&#xff0c;数学公式都是显示的源代码。 我看了许多教程&#xff0c;给的是这个方法&#xff1a;在md文件对应的html文件中加上以下代码&#xff1a…

Java 网络编程(二)—— TCP流套接字编程

TCP 和 UDP 的区别 在传输层&#xff0c;TCP 协议是有连接的&#xff0c;可靠传输&#xff0c;面向字节流&#xff0c;全双工 而UDP 协议是无连接的&#xff0c;不可靠传输&#xff0c;面向数据报&#xff0c;全双工 有连接和无连接的区别是在进行网络通信的时候&#xff0c;…

MySQL 事务笔记

MySQL 事务笔记 目录 事务简介事务操作事务四大特性并发事务问题事务隔离级别总结 事务简介 事务&#xff08;Transaction&#xff09;是数据库操作的逻辑单元&#xff0c;由一组不可分割的SQL操作组成。主要用于保证&#xff1a; 多个操作的原子性&#xff08;要么全部成功…

GPT1 与 GPT2 的异同

1.什么是GPT1&#xff1a; GPT1介绍了一种通过生成式预训练&#xff08;Generative Pre-Training&#xff09;来提升语言理解能力的方法。这种方法首先在一个大型的未标注文本语料库上进行语言模型的预训练&#xff0c;然后针对具体的任务进行判别式微调&#xff08;discrimin…

Android Audio其他——数字音频接口(附)

数字音频接口 DAI,即 Digital Audio Interfaces,顾名思义,DAI 表示在板级或板间传输数字音频信号的方式。相比于模拟接口,数字音频接口抗干扰能力更强,硬件设计简单,DAI 在音频电路设计中得到越来越广泛的应用。 一、音频链路 1、模拟音频信号 可以看到在传统的…

kafka-leader -1问题解决

一. 问题&#xff1a; 在 Kafka 中&#xff0c;leader -1 通常表示分区的领导者副本尚未被选举出来&#xff0c;或者在获取领导者信息时出现了问题。以下是可能导致出现 kafka leader -1 的一些常见原因及相关分析&#xff1a; 1. 副本同步问题&#xff1a; 在 Kafka 集群中&…

DeepSeek基础之机器学习

文章目录 一、核心概念总结&#xff08;一&#xff09;机器学习基本定义&#xff08;二&#xff09;基本术语&#xff08;三&#xff09;假设空间&#xff08;四&#xff09;归纳偏好&#xff08;五&#xff09;“没有免费的午餐”定理&#xff08;NFL 定理&#xff09; 二、重…