SSM框架学习——工厂模式、Spring核心容器与Bean

工厂模式、核心容器与Spring Bean

工厂模式

工厂模式是Java中常用的一种设计模式,这种类型的设计模式属于创建型模式。说白了在代码层面就是取消了new的使用。

工厂模式有三种:

  • 简单工厂模式
  • 工厂方法模式
  • 抽象工厂模式

举个例子,我们去买手机,假设手机品牌有两种,分别是Xphone和Luwei,你显然不用关心手机是怎么生产的,手机零件怎么组装的,这都是工厂干的活。下面我们以这个例子来讲解三种工厂模式。

简单工厂模式

简单工厂模式示意图如下:

简单工厂模式示意图

我们用Java代码来表示,首先需要定义一个接口,来表示手机(Phone),不妨声明一个方法,用来获取品牌名称。

public interface Phone{
    String getBrand();
}

接下来我们该写这两种品牌的手机类,它们都实现Phone这个接口。

Xphone手机类如下

public class Xphone implements Phone{
    @Override
    public String getBrand(){
        return "Xphone";
    }
}

同理Luwei手机类如下

public class Luwei implements Phone{
    @Override
    public String getBrand(){
        return "Luwei";
    }
}

我们需要一个手机工厂PhoneFactory

public class PhoneFactory{
    public static Phone getPhone(String phoneBrand){
        if(phoneBrand.equals("Xphone")){
            return new Xphone();
        }

        if(phoneBrand.equals("Luwei")){
            return new Luwei();
        }
    }
}

作为消费者的你,想要获取手机只需要通过工厂即可

public class Customer{
    public static void main(String[] args){
        //获取手机实例对象
        Phone xphone = PhoneFactory.getPhone("Xphone");
        System.out.println(xphone.getBrand());
    }
}

但是细心观察你可能会发现,我们目前只有两个手机品牌,但是当品牌增多的时候,工厂内部的代码也需要修改,我们不得不面临一个麻烦——内部代码也会增加。这违反了设计模式的一个原则,即对扩展开放,对修改关闭

工厂方法模式

为了解决简单工厂模式的问题,聪明的你可能会想到,干脆将工厂也变为抽象的接口,我们让每个手机厂商去实现它们各自的工厂不久行啦!没错,这正是工厂方法模式

工厂方法模式示意图

我们在上文的基础上将PhoneFactory从类变为接口

public interface PhoneFactory{
    Phone getPhone();
}

然后为Xphone类实现它的工厂XphoneFactory

public class XphoneFactory implements PhoneFactory{
    @Override
    public Phone getPhone(){
        return new Xphone();
    }
}

同理为Luwei手机类也实现它的工厂

public class LuweiFactory implements PhoneFactory{
    @Override
    public Phone getPhone(){
        return new Luwei();
    }
}

而对于消费者我们可以这样调用

public class Customer{
    public static void main(String[] args){
        Phone xphone = (new XphoneFactory).getPhone();
        System.out.println(xphone.getBrand());
    }
}

这样我们就不必去更改Factory的代码就能增加品牌了,但工厂方法模式会带来另外一个问题,当我们增加品牌的时候就需要增加工厂,而且我们如果新增一款产品,那么每个工厂就必须增加相应的方法,这大大降低了代码的可维护性。

抽象工厂模式

抽象工厂模式相对来讲比较复杂,在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

假设我们前面提到的两个品牌都新增了一样产品——个人电脑。

我们来定义手机接口和电脑接口。

public interface Phone{
    String getBrand();
}
public interface Pc{
    String getBrand();
}

然后两家供应商都各自实现这两个产品

对于Luwei品牌

public class LuweiPhone implements Phone{
    @Override
    public String getBrand(){
        return "Phone_Luwei";
    }
}
public class LuweiPc implements Pc{
    @Override
    public String getBrand(){
        return "PC_Luwei";
    }
}

对于Xphone品牌

public class Xphone implements Phone{
    @Override
    public String getBrand(){
        return "Phone_Xphone";
    }
}
public class XphonePc implements Pc{
    @Override
    public String getBrand(){
        return "PC_Xphone";
    }
}

接下来就是工厂了,这两个品牌必须提供工厂来实现这两个产品。

我们定义抽象的工厂,即工厂接口IFactory

public interface IFactory{
    Phone getPhone();
    Pc getPc();
}

各自实现这个接口

public class LuweiFactory implements IFactory{
    @Override
    public Phone getPhone(){
        return new LuweiPhone();
    }

    @Override
    public Pc getPc(){
        return new LuweiPc();
    }
}
public class XphoneFactory implements IFactory{
    @Override
    public Phone getPhone(){
        return new Xphone();
    }

    @Override
    public Pc getPc(){
        return new XphonePc();
    }
}

我们为了统一它们的工厂,还需要一个超级工厂,即工厂的工厂,者有些类似于供应商与代理商之间的关系,供应商有自己的品牌和工厂生产自己的产品,然后交给代理商售卖给客户,同时代理商可以代理多家供应商的产品。

为了方便,我们直接在工厂接口里定义一个静态方法来完成这个“代理商”

public interface IFactory{
    public static IFactory createFactory(String factoryName){
        if(factoryName.equals("Xphone")){
            return new XphoneFactory();
        }

        if(factoryName.equals("Luwei")){
            return new LuweiFactory();
        }
    }

    Phone getPhone();
    Pc getPc();
}

这样我们就完成了多个品牌多个产品统一对客户的供应。

当然这个模型还可以更复杂一些,比如每个品牌每个商品都有自己的工厂,然后这些品牌创建自己商品工厂的工厂来对外,与客户之间还有一个超级工厂来创建大工厂,不过我们仅是演示原理没必要这么麻烦。

Spring核心容器

Spring容器会负责控制程序之间的关系,而不是由程序代码直接控制。

我们在上一节中,我们提到了IoC,而Spring的Ioc依赖于Spring的核心容器。

框架为我们提供了两种核心容器——BeanFactoryApplicationContext

前者位于spring-beans模块中,后者位于spring-context模块。(我们曾在pom.xml里引入过后者)

BeanFactoryBean都是懒加载的方式,也就是说只有你去调用的时候才被实例化,而ApplicationContext容器启动时Bean就被实例化了。如果不是性能要求特别苛刻或者有其它限制,一般会用后者。

BeanFactory与FactoryBean

看到BeanFactoryFactoryBean,你是不是就明白我们刚才为什么要花这么大的篇幅来讲解工厂模式了。

BeanFactory的重要程度我们用框架源代码中的一句话来讲——IoC的根接口!!!

但是我们只是个简单版本的教程,BeanFactory创建Bean的流程以及生命周期非常复杂,我们篇幅有限,而且并非是框架的文档,所以这里仅会简单描述一下它。

对于BeanFactory的主要作用就是:处理的BeanDefinition经过BeanFactory来生成Bean

BeanFactory作用

BeanFactory是一个大工厂,IoC的根基,可以生产各种Bean;而FactoryBean是一个小工厂,自己也是一个Bean,可以生产其它Bean

看不懂没关系,我们来了解下BeanFactory怎么用。

还记得我们前两章创建的top.cairbin.test1项目吗,现在打开它的App.java文件,就是主类所在的文件,我们目前内容如下:

package top.cairbin.test1;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


public class App 
{
    public static void main( String[] args )
    {
    	ApplicationContext applicationContext = new ClassPathXmlApplicationContext("AppCtx.xml");
        User user = (User)applicationContext.getBean("user");
        user.testSay();
    }
}

可以看到我们是用的ApplicationContext来加载的AppCtx.xml文件,现在我们可以使用BeanFactory来加载它(不过我们一般不这么做),不要忘记导入相应的包。

BeanFactory beanFactory = new BeanFactory(new FileSystemResource("这里写AppCtx.xml的绝对路径"));

ApplicationContext

BeanFactory相对ApplicationContext比较低层,后者是前者的一个子接口,在开发中我们经常用后者。

获取ApplicationContext的方法这里举两个例子,分别是ClassPathXmlApplicationContext创建和FileSystemXmlApplicationContext创建。

前者形式如下

ApplicationContext app = new ClassPathXmlApplicationContext(String configLocation);

也就是说ClassPathXmlApplicationContext是从类路径来找XML的配置文件。

如果你想要使用绝对路径来寻找可以使用FileSystemXmlApplicationContext

ApplicationContext app = new FileSystemXmlApplicationContext(String configLocation);

什么,你问我啥是相对路径绝对路径?前者是相对于你当前位置的;后者是目标文件在文件系统下真实路径,比如Windows中以盘符开始(例如C:\\),在Mac/Linux下以/开始。

Spring Bean

Bean是被实例化的、组装的以及被Spring容器接管的Java对象。听起来很费解,但是没关系我们往下看。

我们在编写AppCtx.xml文件的时候就注意到,根元素为<beans></beans>,其中又包含了若干个子元素<bean>,这些子元素通常携带一些属性来帮助Spring实现依赖注入。

Bean的实例化

Bean的实例化方法大致有三种:

  • 构造器实例化(最常用)
  • 静态工厂实例化
  • 实例工厂实例化
构造器实例化

构造器实例化需要类中拥有一个默认构造方法来实例化Bean,实际上你如果不写构造方法也会有一个默认的构造方法。

你只要创建符合条件的类,然后在AppCtx.xml文件里配置下就行了。我们之前章节就是使用构造器实例化的,所以这里不给出代码。

静态工厂实例化

我们要自己创建一个工厂,并实现一个用于实例化的静态方法,假设我们的Bean对应类名为MyBean

public class MyBeanStaticFactory{
    public static MyBean createBean(){
        return new MyBean();
    }
}

我们需要在AppCtx.xml<beans></beans>里添加

<bean id="myBean" class="top.cairbin.test1.MyBean" factory-method="createBean"/>

这个标签的factory-method属性指定了工厂实例化Bean的静态方法。

实例工厂实例化

实例工厂实例化Bean使用的是非静态方法,即没有static关键字修饰的方法。

public class MyBeanFactory{
    public MyBean createBean(){
        return new MyBean();
    }
}

只不过这种情况下,配置文件的标签要配置两个属性,除了指定工厂的方法外还要通过factory-bean指定实例化后的工厂。

<bean id="myBean" class="top.cairbin.test1.MyBean" factory-bean="myBeanFactory" factory-method="createBean"/>

Bean的属性

我们来介绍下之前涉及的几个属性:

  • id:Bean的唯一标识符。
  • name:该属性可以为Bean指定多个名称,用英文逗号,隔开。
  • class:指定Bean对应的类,它必须是一个完整的类名,从包名一直到类。
  • scope:用来设置Bean的作用域,至于作用域有哪些我们之后讲。

Bean的作用域与生命周期

Bean的作用域用下图来描述

Bean的作用域

至于Bean的生命周期,可讲解的点太多了,这里仅放一张部分的示意图

Bean声明周期

Bean的装配方式

Bean的装配方式对应我们前面的Spring实现DI的几种方式。Spring Bean的方式有以下几种:

  • 基于XML装配
  • 基于注解装配
  • 自动装配

看完这里你就应该明白IoC、DI、工厂、Bean以及Bean的装配它们之间的关系了。

基于XML装配

基于XML装配主要常用于两种注入方式——Setter注入构造器注入

Setter注入要求有Setter和一个无参的构造方法,在XML配置文件中用<property>来为每个属性注入值。

构造器注入必须提供有参数的构造方法,在XML配置文件中使用<constructor-arg>来为参数注入值。

基于注解的装配

用于装配的注解主要有以下几种

自动装配

自动装配要求属性有对应的Setter方法,在XML文件里进行属性设置,实际上是在<bean>元素标签上添加属性autowire,其值可以如下。

@Autowired注解与@Resource注解

@Resource的作用相当于@Autowired,只不过@AutowiredbyType自动注入,而@Resource默认按 byName自动注入。

Spring将@Resourcename属性解析为bean的名字,而type属性则解析为bean的类型。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。

另外需要注意@Resource这个注解不属于Spring,它是属于J2EE的。

自动扫描与装配的关系

自动扫描主要用到了后面两种装配方式,按照基于注解的装配方式将相应的注解转换成Bean纳入Spring容器后,会继续扫描@Resource@Autowired注解,然后按自动装配的方式进行关系建立。

然而后两种装配方式本身就是对XML的一种自动化处理,可能借助了Java的某些机制,例如反射,但实际上这几种装配方式在根本上还是一样的,不要将它们割裂来看。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

无缝投屏技巧:怎样将Windows电脑屏幕共享到安卓手机?

使用屏幕共享技术的好处是多方面的。首先&#xff0c;它为远程协助提供了极大的便利。当用户遇到电脑操作难题时&#xff0c;技术支持人员可以远程查看用户的屏幕&#xff0c;实时指导解决问题&#xff0c;就像他们身临其境一样。其次&#xff0c;这种技术也为教育和培训带来了…

时序预测 | Python实现VMD-CNN-LSTM时间序列预测

时序预测 | Python实现VMD-CNN-LSTM时间序列预测 目录 时序预测 | Python实现VMD-CNN-LSTM时间序列预测预测效果基本介绍模型描述代码设计预测效果 基本介绍 VMD-CNN-LSTM 是一种混合深度学习模型,结合了变分模态分解(VMD)、卷积神经网络(CNN)和长短期记忆网络(LSTM)的…

C#中值类型与引用类型的存储

目录 值对象与引用对象的存储 引用对象的成员存储 值对象与引用对象的存储 数据项的类型定义了存储数据需要的内存大小及组成该类型的数据成员。类型还决定了对象在内存中的存储位置——栈或堆。 C#中类型分为两种&#xff1a;值类型和引用类型&#xff0c;这两种类型的对象…

“省钱有道”的太平鸟,如何真正“高飞”?

衣食住行产业中&#xff0c;服装品类消费弹性较大、可选属性较强&#xff0c;其发展可以显著反映当前的经济温度。 根据国家统计局数据&#xff0c;2023年1-12月&#xff0c;我国限额以上单位服装类商品零售额累计10352.9亿元&#xff0c;同比增长15.4%&#xff0c;增速比2022…

LLMs之DBRX:DBRX的简介、安装和使用方法、案例应用之详细攻略

LLMs之DBRX&#xff1a;DBRX的简介、安装和使用方法、案例应用之详细攻略 导读&#xff1a;2024年3月27日(美国时间)&#xff0c;DBRX是Databricks推出的一款新型开源大语言模型&#xff0c;主要特征和优势总结如下&#xff1a; >> 表现优异&#xff1a;DBRX在各类自然语…

Pixelmator Pro:专业级图像编辑,触手可及mac/win版

Pixelmator Pro是一款功能强大的图像编辑软件&#xff0c;专为Mac操作系统设计。它拥有直观的界面和丰富的工具&#xff0c;能够满足用户各种图像处理需求。 Pixelmator Pro软件获取 首先&#xff0c;Pixelmator Pro支持多种文件格式&#xff0c;包括JPEG、PNG、GIF、BMP、TIF…

投稿指南【NO.12_9】【极易投中】核心期刊投稿(现代电子技术)

近期有不少同学咨询投稿期刊的问题&#xff0c;大部分院校的研究生都有发学术论文的要求&#xff0c;少部分要求高的甚至需要SCI或者多篇核心期刊论文才可以毕业&#xff0c;但是核心期刊要求论文质量高且审稿周期长&#xff0c;所以本博客梳理一些计算机特别是人工智能相关的期…

算法第三十八天-故障键盘

故障键盘 题目要求 解题思路 提示&#xff1a;把反转看成是往字符串的头部添加字符。 具体来说&#xff1a; 如果当前处于「往字符串尾部添加字符」的状态&#xff0c;那么遇到 i 后&#xff0c;改成「往字符串头部添加字符」的状态。 如果当前处于「往字符串头部添加字符」…

基于8086贪吃蛇游戏系统方恨设计

**单片机设计介绍&#xff0c;基于8086贪吃蛇游戏系统方恨设计 文章目录 一 概要二、功能设计三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于8086的贪吃蛇游戏系统设计是一个结合了微处理器控制、游戏逻辑以及图形显示技术的综合性项目。该系统旨在通过8086微处理器…

n2.堆栈

1.堆栈的介绍 表达式求值 因为不同的符号优先级不同&#xff0c;所以计算起来相对困难一些 后缀表达式 这里后缀表达式就用到了堆栈。它先从左向右进行扫描&#xff0c;碰到运算数就记住&#xff0c;碰到运算符就将离着这个运算符最近的两个运算数进行运算… 堆栈是一种储存方…

六、从零实战企业级K8S本地部署ThingsBoard专业版集群

1、从 docker hub 拉取 ThingsBoard PE 映像&#xff08;所有节点&#xff09; 1.1、查看k8s信息&#xff08;主节点&#xff09; kubectl cluster-info #查看k8s集群信息 kubectl get node #查看节点信息 kubectl get pod -A #查看内部组件1.2、从 d…

Docker:探索容器化技术,重塑云计算时代应用交付与管理

一&#xff0c;引言 在云计算时代&#xff0c;随着开发者逐步将应用迁移至云端以减轻硬件管理负担&#xff0c;软件配置与环境一致性问题日益凸显。Docker的横空出世&#xff0c;恰好为软件开发者带来了全新的解决方案&#xff0c;它革新了软件的打包、分发和管理方式&#xff…

【C++第二阶段】继承多态电脑组装实例

你好你好&#xff01; 以下内容仅为当前认识&#xff0c;可能有不足之处&#xff0c;欢迎讨论&#xff01; 文章目录 继承继承语法继承方式继承中的对象模型继承中构造和析构顺序同名成员处理同名静态成员处理多继承语法菱形继承问题 多态多态基本概念重写&重载 多态原理多…

中仕公考:不同省事业编考试内容一样吗?

在各省份的事业单位公开招聘过程中&#xff0c;考试内容是不一样的。虽然每一年都有很多省份参加事业编联考&#xff0c;且这些联考的考试日期相同&#xff0c;但是考试内容并不一样。各省将依据当地的特定情况来设计考试题目&#xff0c;其中会涉及到与本省的地理、经济、文化…

文章分享:《呼吸道传染病标本采集及检测专家共识》

【摘要】呼吸道传染病临床特点多表现为发热和&#xff08;或&#xff09;呼吸道症状&#xff0c;病原学组成复杂&#xff0c;标本类型选择多样&#xff0c;如何从发热伴呼吸道症候群患者中早期正确识别出潜在呼吸道传染病患者是防控的关键环节。增强医务人员对呼吸道传染病临床…

【现代C++】Lambda表达式

在现代C中&#xff0c;Lambda表达式提供了定义匿名函数对象的能力&#xff0c;这在很多场合&#xff0c;如STL算法、线程构造函数、事件处理等&#xff0c;都非常有用。Lambda表达式使得函数定义更加灵活和简洁。 1. 基本语法 Lambda表达式的基本形式包括一个捕获列表、参数列…

【微信小程序】流量主-激励视频(激励广告)下发策略,每天三次免费体验,然后再次点击触发激励视频,当日不再触发。

如题&#xff1a; 允许用户有三次体验效果&#xff0c;然后弹出激励视频弹窗&#xff0c;之后当日不再弹出。 体验小程序&#xff1a; /*** 判断当前项目当天是否点击超过3次&#xff0c;触发广告效果。* 若&#xff0c;当天低于三次&#xff0c;则新增&#xff0c;若高于…

未来电商怎么走,是腾讯视频号,还是抖音小店?你更看好谁?

大家好&#xff0c;我是电商花花。 现在想做一些项目&#xff0c;做些生意基本上就离不开电商&#xff0c;网络这么发达&#xff0c;直播短视频这么火&#xff0c;未来的发展依然是直播电商。 现在线下很多实体店都被电商所冲击&#xff0c;而且不少实体店也都在网上开店卖货…

Spring 整合 Log4j2日志框架

1. Log4j2日志概述 在项目开发中&#xff0c;日志十分的重要&#xff0c;不管是记录运行情况还是定位线上问题&#xff0c;都离不开对日志的分析。日志记录了系统行为的时间、地点、状态等相关信息&#xff0c;能够帮助我们了解并监控系统状态&#xff0c;在发生错误或者接近某…

【面试HOT200】数组篇

系列综述&#xff1a; &#x1f49e;目的&#xff1a;本系列是个人整理为了秋招面试coding部分的&#xff0c;整理期间苛求每个算法题目&#xff0c;平衡可读性与代码性能&#xff08;leetcode运行复杂度均打败80%以上&#xff09;。 &#x1f970;来源&#xff1a;材料主要源于…