Spring工厂模式,模拟ApplicationContext实现

2023-09-15 01:43:42

一、什么是 Spring

        Spring 是一个轻量级的 Java 企业开发解决方案。它集合了众多优秀的设计模式如:单例、代理、工厂模式等。在这其中最基础的也就是工厂模式。

二、Spring 为什么是轻量级

        在 Spring 问世之前 JavaEE 开发主流使用 Enterprise JavaBean (EJB)来进行。但是这个框架是重量级的,扩展性以及移植性都是很大的问题并且运行环境苛刻。EJB 的运行依靠 EJB 容器并且 Tomcat 不支持。而在当时拥有这项服务的公司以及产品有 Oracle 公司的 Weblogic ApplicationService(运行环境) 以及 IBM 公司的 Websphere ApplicationServer。这两款产品 EJB 容器对 EJB代码的接口要求不同所以同样的代码不可以在两个平台运行,这就导致了它的扩展性差。并且因为是付费产品代码是闭源的,所以对于企业的不同个性化要求进行扩展是很难的。

       而 Spring 对于开发环境没有额外的要求,开源以及收费的容器都可以运行,并且移植性强。

三、 Spring 管理的层级

        我们熟知的 MyBatis 是作用在 Dao 数据库控制层的。而 Spring 是管理了从 Controller到Service以及Dao层。几乎所有的对象都可以交给 Spring 进行管理达到控制反转IoC的目的。

四、工厂模式是什么?

        工厂提起来就是批量工的一个“盒子”。只要我们需要的东西,都可以通过给工厂提出要求然后获得对象。工厂模式就是这样的思想。通过特定的如对象获取工厂,只需要传入参数或者不传入就可以得到对象达到解除耦合的效果。下面详细讲解为什么可以解耦。

4.1 耦合代码演示(无 Spring 思想)

UserService :

package com.day1springReflection;

public class UserServiceImpl implements UserService{
    // 通过 new 的方式来获取对象
    private UserDao userDao = new UserDaoImpl();

}

这种方式通过 new 的方式直接获得一个对象,这里的 UserDao 是一个接口,如果他的实现方法 UserDaoImpl 发生了变化的话就需要将所有的 UserDaoImpl 地方换成新的 UserDaoImplNew 方法,可能调用地方很多也可能不好定位,如果耦合高的地方可能不好修改甚至可能大幅度修改代码。

4.2 简易工厂类实现

这里我们需要配合配置文件。

思路: (主)通过反射的方式来获取到类对象。

先将类的名称以及类型以 key-value 形式存储在配置文件中,通过获取配置文件的信息来获取到类的类型,再通过反射的方式将对象创建出来。

application.properties :

# key - value 存储形式
userService = com.day1springReflection.UserServiceImpl

 BeanFactory :

package com.day1springReflection;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class BeanFactory {
    private static Properties env = new Properties();

    static {
        try {
            // 获取IO输入流   BeanFactory.class 通过反射来获取 BeanFactory对象
            InputStream inputStream = BeanFactory.class.getResourceAsStream("/application.properties");
            // 文件内容封装到 properties 中,保存为 key = userService,value = com.day1_Spring反射工厂
            env.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    // 获取方式变为
    public static UserService getUserService() {
        UserService userService = null;

        try {
            Class clazz = Class.forName(env.getProperty("userService"));
            userService = (UserService) clazz.newInstance();
        } catch (ClassNotFoundException e) {
            System.out.println("问题1");
            System.out.println(userService);
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return userService;
    }

}

userService获取方式变为:

    // 获取方式变为
    public static UserService getUserService() {
        UserService userService = null;

        try {
            Class clazz = Class.forName(env.getProperty("userService"));
            userService = (UserService) clazz.newInstance();
        } catch (ClassNotFoundException e) {
            System.out.println("问题1");
            System.out.println(userService);
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return userService;
    }

4.3 通用工厂的设计

        这时候我们发现每次获取对象都有代码的重复,如Class.forName.....  所以我们考虑写一个   getBean 方法来将冗余的重复代码写在这个方法里,并且 key 通过参数的方式来传入。所以有了下面的代码

package com.day1springReflection;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class BeanFactory {
    private static Properties env = new Properties();

    static {
        try {
            // 获取IO输入流   BeanFactory.class 通过反射来获取 BeanFactory对象
            InputStream inputStream = BeanFactory.class.getResourceAsStream("/application.properties");
            // 文件内容封装到 properties 中,保存为 key = userService,value = com.day1_Spring反射工厂
            env.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static Object getBean(String key) {
        Object ret = null;
        try {
            Class clazz = Class.forName(env.getProperty(key));
            ret = clazz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ret;
    }


}

此时 userService 的获取变成了:

package com.day1springReflection;

public class UserServiceImpl implements UserService{
   private UserDao userDao = (UserDao) BeanFactory.getBean("userDao");

}

这样实现就解除了代码的耦合,如果有新的方法替代只需要在配置文件中写入方法名以及类型就好。这样就只需要最外层的代码中修改就好了。

这个工厂的本质就是 ApplicationContext 。配置文件就是 applicationContext.xml

更多推荐

【C# 基础精讲】抽象类与接口

抽象类(AbstractClass)和接口(Interface)是面向对象编程中两种重要的概念,它们用于定义类的结构、行为和关系,是实现多态性、代码复用和系统设计的关键手段。在C#及其他面向对象编程语言中,抽象类和接口都发挥着重要作用。本文将详细解释抽象类和接口的概念、特点、用法以及在C#中的应用。1.抽象类的概念与特

同城信息服务源码 本地生活服务小程序源码

同城信息服务源码本地生活服务小程序源码功能介绍:基本设置:网站参数、安全设置、分站管理、支付设置、操作日志、地区设置、公交地铁、国际区号、清理缓存、模板风格、模块管理、域名管理、底部菜单、消息通知、登录设置其他设置:关键词管理、单页文档、网站公告、帮助信息、网站协议、广告设置、友情链接、举报管理、意见反馈、投诉列表短信

CH573-09-BLE蓝牙安卓应用二次开发——RISC-V内核BLE MCU快速开发教程

一、基础工程搭建在上一章最后一讲的BLE蓝牙例程中,我们使用了沁恒官方的BLE调试助手完成数据发送,接下来我们使用AndroidStudio完成一款简易的BLE调试助手。1、参考文章我这里参考了CSDN中的一位博主“摸爬滚打的程序媛”的文章以及对应文章中的AndroidStudioBLE应用工程的Demo。版权声明:链

MP3算法及代码例程

MP3(MPEG-1AudioLayerIII)是一种数字音频压缩算法,用于对音频进行高效的压缩。MP3算法能够显著减小音频文件的大小,同时保持较高的音质。以下是MP3算法的主要步骤:采样率转换:将输入音频信号的采样率转换为固定的值,通常为44.1kHz。这是因为人耳对于音频的感知范围大约在20Hz到20kHz之间,因

9.3.5网络原理(应用层HTTP/HTTPS)

一.HTTP:1.HTTP是超文本传输协议,除了传输字符串,还可以传输图片,字体,视频,音频.2.3.HTTP协议报文格式:a.首行,b.请求头(header),c.空行(相当于一个分隔符,分隔了header和body),d.正文(body).4.5.URL:唯一资源描述符(长度不限制).a.b.注意:查询字符串(qu

第29章_瑞萨MCU零基础入门系列教程之改进型环形缓冲区

本教程基于韦东山百问网出的DShanMCU-RA6M5开发板进行编写,需要的同学可以在这里获取:https://item.taobao.com/item.htm?id=728461040949配套资料获取:https://renesas-docs.100ask.net瑞萨MCU零基础入门系列教程汇总:https://b

【初阶数据结构】树(tree)的基本概念——C语言

目录一、树(tree)1.1树的概念及结构1.2树的相关概念1.3树的表示1.4树在实际中的运用(表示文件系统的目录树结构)二、二叉树的概念及结构2.1二叉树的概念2.2现实中真正的二叉树2.3特殊的二叉树2.4二叉树的性质2.5二叉树的存储结构一、树(tree)1.1树的概念及结构树是一种非线性的数据结构,它是由n(

Softing物联网(IoT)方案之OT/IT数据集成

一利用数据提高效率和绩效多年以来数据集成和工业物联网一直在推动着市场的发展,目前我们已经能够集成并成功使用先进的技术、大量的传感器和复杂的数据格式等。而在工业物联网或工业4.0中,还有运营技术(OT)和信息技术(IT)它们之间的无缝数据交换对于企业提升竞争力而言同样非常重要。将生产和业务数据深度集成到IT层中可为新的利

【Oracle】Oracle系列--Oracle数据类型

文章目录前言1.字符类型2.数字类型3.大对象类型4.时间及时间间隔类型5.其他类型前言ORACLE基本数据类型,又叫内置数据类型(built-indatatypes)可以按类型分为:字符串类型、数字类型、大对象类型(LOB类型)、日期类型、LONGRAW&RAW类型、ROWID&UROWID类型。1.字符类型数据类型

浅说 MySQL 数据库日志有哪些?作用是什么?

目录1.MySQL日志有哪些?2.各种日志分析2.1错误日志2.2二进制日志2.3通用查询日志2.4慢查询日志2.5中继日志2.6数据定义语句日志2.7补充点3.日志有什么用(优点)4.日志的弊端1.MySQL日志有哪些?MySQL数据库为我们提供了很多种不同类型的日志文件,用来存储不同类型的日志。主要有错误日志,二进

Redis+SpringBoot企业版集群实战------【华为云版】

目录安装复制及集群bgsaverdbaofSpringBoot+Redis操作操作string操作hash操作set操作sortedset获取所有key&删除设置key的失效时间SpringDataRedis整合使用哨兵机制安装下载地址Redis上传至服务器解压tarzxvfredis-5.0.3.tar.gz安装依赖

热文推荐