Spring概述(含单例设计模式和工厂设计模式)

一、框架的初步了解

1.1 C/S架构和B/S架构

C/S架构和B/S架构是我们常见的软件系统架构。

C/S架构(Client/Server架构)是一种典型的分布式系统架构模式,它将应用程序分为客户端(Client)和服务器(Server)两个主要部分。其核心思想是将任务合理分配到客户端和服务器端,通过两者之间的协同工作来完成整个系统的功能。

B/S架构(Browser/Server,浏览器/服务器架构)是一种常见的软件系统架构模式,它将应用功能的主要部分集中在服务器端实现,简化了系统的开发维护和使用,而客户端仅需通过浏览器即可访问和使用系统功能。

1.2 框架概述

框架其实是软件开发的半成品,通过框架可以对一些开发中的通用问题进行解决,从而提高了开发效率。

在学习后端的过程中我们会接触到一些组件层级,下边我们介绍一下:

  • 持久层

Dao 操作数据库的层级,也Mapper,JDBC(java database connention) ,其内方法负责对数据库的操作。属于Mybatis框架。

  • 业务层

Servlet,其内的方法负责进行一些逻辑上的处理,同时要调用dao的方法,比如你要转账,就会涉及到一些sql语句,需要对数据库进行操纵,我们是将相应的功能封装起来,使用时进行调用。

  • 控制层

Controller,负责接受前端传输的数据,调用Servlet方法,来对业务进行处理,并将处理得到的结果响应到前端页面上。

1.3 常用的框架

SSH:Spring + Struts2 + Hibernate。(比较老的)

SSM:Spring + SpringMVC + MyBatis 。(配置文件很多,但是代码很简单)

SM:Spring Boot + MyBatis,相当于Spring Boot = Spring + SpringMVC。(配置文件和代码都简单)

二、Spring简介

2.1 Spring

Spring是一个轻量级的JavaEE的解决方案,是众多优秀设计模式的整合。

轻量级:针对于EJB而言的,spring代码可以运行在tomcat容器中。
JavaEE:java企业级开发 是一个整合框架,比如不同的框架是适用于对应的层,比如MyBatis是适用于持久层的。但是javaEE适用于软件开发的各层。

2.2 设计模式

前人总结的,用于特定问题的优秀的解决方案。如:单例设计模式、工厂设计模式、代理设计模式等等;没有特指,设计模式指的是GOF4人帮在20世纪80年代提出的23种设计模式。

单例设计模式:

单例模式是一种设计模式,它确保一个类只能创建一个实例。具体来说,无论调用多少次创建方法,返回的都是同一个对象实例,而不是多个独立的对象。

我在下边给大家总结几种单例模式的简单实现:

第一种:饿汉式

java 复制代码
public class Single {
    // 类加载时就创建实例
    private static final Single instance= new Single ();
    
    // 私有构造器,防止外部 new 实例
    private Single () {
    }
    
    // 提供全局访问点
    public static Single getInstance() {
        return instance;
    }
}

饿汉式就是直接在类中定义属性时就把对象定义出来,且对象时static的,是final的,也就是静态常量,属于这个类本身,这样再将构造器私有化,杜绝使用构造器创建对象,之后提供方法获取。同样,如果有其他属性可以在new时加上参数。

第二种:懒汉式

java 复制代码
public class Single {
    private static Single instance;
    
    private Single () {
    }
    
    // 需要时才创建实例(延迟加载)
    public static Single getInstance() {
        if (instance == null) {
            instance = new Single ();
        }
        return instance;
    }
}

懒汉式和饿汉式的区别在于,它并不是立马创建对象,而是提供一个公开的方法,当你需要的是时候调用它,才会把这个对象创建出来,但是上面这个示例线程不安全,在多线程的情况下可能会创建出多个实例。

工厂设计模式:

比如我们创建了一个对象Impl,如果我们之后想要将其改编为其他对象比如Impl2,那么我们就要将所有用到Impl都进行修改,会很麻烦,那怎么办呢。这时候我们就要提到工厂设计模式了。

工厂设计模式实际是用来帮助创建对象和为属性赋值的,也就是一个创建对象的工厂,目的是为了实现对象创建的解耦合,其本质上是将创建对象的权力转移给了工厂类,这样我们调用的是工厂类中的变量名,也就是存储对象的那个容器的名字,如果我们想要改变对象,就只需要改变容器里的值就行了,就只需要修改一次了。

有关具体的工厂设计模式的原理其实就是利用反射创建对象,

先将对象名和他对应的类的全限定名以键值格式存放在一个配置文件中,如下:

工厂中读取这个配置文件,并根据其中的全限定名,利用反射来创建实例的一个过程。

具体详细的原理在此就不总结了。

三、IOC和DI

首先我们了解一下正向控制的概念:

在程序需要什么对象就将其声明为成员变量,通过new的方式创建对象,创建对象的代码写死(硬编码)在程序中,不利于程序的维护。

3.1 IOC

IOC,又称控制反转:在程序需要什么对象就将其声明为成员变量,通过spring的工厂获取对象,所谓控制反转就是将对象创建的权力从代码中转移到配置文件中,好处:解耦合。

3.2 DI

DI,又叫依赖注入:程序运行过程需要什么,就代表依赖什么,就将其设置成成员变量,提供set方法/构造方法,之后将将成员变量赋值的权利交给spring,通过注入的方式完成赋值的方式,就叫依赖注入。

四、Spring的注解式开发

IOC和DI都需要使用到spring工厂模式,我们总不能每次都自己写一个工厂吧,那也太麻烦了。欸!spring里已经为我们封装好了对应的工厂代码,我们只需要按照要求去使用就可以了。

同样的,其实在使用过程中,初学者对于工厂是如何实现的并不太需要深入了解,我们可以先搞明白如何使用工厂创建对象,如何使用工厂进行注入,会使用,就可以了。

4.1 利用注解创建对象

创建对象相关的注解:

1)@Component 都可以使用,但一般使用对应的注解

2)@Repository 一般用于Dao对象的创建 在MyBatis的环境上用不上

3)@Service 一般用于Service对象的创建

4)@Controller 一般用于Controller对象的创建

具体的使用,下面以@Component为例:

  • 首先,扫描注解所在的包,这个需要在applicationContext.xml中配置
XML 复制代码
<!-- 扫描指定包以及子包所有使用了注解的类,扫描到了会自动的配置bean -->
<context:component-scan base-package="配置需要创建对象所在的包"/>
  • 第二步,在类的上方添加 @Component注解,这里注解()里面的值,可以选择不填,默认是类名首字母小写,是用来下一步调用的。
java 复制代码
@Component("u")
public class User {
    private Integer id;
    private String username;
    private String password;
}
  • 第三步,使用该类创建对象。
java 复制代码
public class TestComponent {
@Test
public void testUser(){
    //获取工厂
    ApplicationContext ctx = new
        ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    User user = (User) ctx.getBean("u");
    System.out.println(user);
}
}

上述代码是在测试类中,我首先创建一个工厂对象,也就是使用 ApplicationContext接收,需要注意的是,利用工厂创建对象默认是单例的,所以其实工厂建立时已经扫描过对应的类了,对象其实已经被创建了,下面我们调用的getBean方法其实是获取了已经创建好的对象。

如果想要让工厂创建的对象不是单例的,可以在类上加上@Scope注解,该注解决定了对象创建的次数。@Scope的属性值默认为singleton,也就是单例,可以通过将属性值设置为prototype设置为非单例,一般情况下不会设置为非单例。

4.2 利用注解为属性注入值

我们可以在对应的属性上添加上一些注解,来完成属性的注入。

  • @Autowired
  1. @Autowired注解根据属性的类型,从spring的容器中获取对象,完成属性的赋值。

  2. @Autowired注解可以使用在属性上,通过反射直接操作属性为属性赋值,不会使用set方法。

  3. @Autowired注解可以使用在set方法上,通过反射直接操作set方法完成赋值。

  4. @Autowired注解修饰的属性是必须的,如果注入失败会抛出异常,可以设置required=false允许注入失败。

  5. @Autowired注解默认按照类型寻找需要的属性,可以通过@Resource注解按照名字寻找需要的属性

  • @Qualifier("bean的id值")

该注解需要与@Autowired配合使用,当有多个满足属性要求的bean对象时,可以用Qualifier指定要注入的对象。

当按照@Autowired注解默认按照类型进行注入匹配时,要求此类型的对象只能存在一个。否则会报错。

解决方案:使用@Qualifier("bean的id值")指定要注入的依赖。

  • @Value注解

用于为简单属性赋值,还可以读取properties配置文件中的参数

例如,配置文件jdbc.properties如下:

XML 复制代码
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/baizhi
name=root
password=root

value注解使用:

java 复制代码
@Component("w")
public class Worker {
    @Value("1")
    private Integer id;

    @Value("cpx")
    private String name;

    @Value("3000.0")
    private Double salary;

    //读取配置文件
    @Value("${name}")
    private String username;

    @Value("${password}")
    private String password
}

五、结语

依赖注入其实主要还分为set注入,和构造器注入,顾名思义,一个是利用set方法为属性赋值,另一个是利用构造器为属性赋值,二者都需要将赋值的权利转移到配置文件中,从而实现弱耦合,具体原理在此就不做总结了。

真正当我们使用spring Boot时,其实我们不需要像这样那么复杂,又要在配置文件中配置扫描包什么的,那我每一次加注解都要配置一变也比较麻烦。所以我们可以在启动类里统一配置,也不需要在测试类里调用工厂类去获取对象了,可以直接使用注解为属性注入值啊,所以这些都是帮助理解原理是什么,具体使用起来倒是要方便很多。

相关推荐
好好研究2 小时前
SpringBoot扩展SpringMVC
java·spring boot·spring·servlet·filter·listener
毕设源码-郭学长2 小时前
【开题答辩全过程】以 高校项目团队管理网站为例,包含答辩的问题和答案
java
NE_STOP3 小时前
spring6-工厂设计模式与bean的实例化方式
spring
玄〤3 小时前
Java 大数据量输入输出优化方案详解:从 Scanner 到手写快读(含漫画解析)
java·开发语言·笔记·算法
tb_first3 小时前
SSM速通3
java·jvm·spring boot·mybatis
独自破碎E3 小时前
总持续时间可被 60 整除的歌曲
java·开发语言
Python+JAVA+大数据3 小时前
TCP_IP协议栈深度解析
java·网络·python·网络协议·tcp/ip·计算机网络·三次握手
丶小鱼丶3 小时前
Java基础之【多线程】
java