Spring框架初学习

Spring框架初学习

  摘要:今天我终于开始学习大名鼎鼎的Spring框架了,在上大学的时候,经常看见一些课设大佬Spring,Spring的,什么Spring boot,Spring MVC的,听的我发蒙,隐约了解到这是个写代码的技术,但它具体是什么东西,我是一点也不知道,如果如今事情都改变了,我也来学学Spring,以下笔记是我初学Spring时做的笔记整理

1.Spring概述

  Spring是什么东西呢?如摘要中所示,说它是一种技术也不为过,但这实在是太笼统了,Spring属于一种框架,那问题又来了,框架是啥?嗯...这个问题有点基础,如果你是个游戏爱好者,一定听说过游戏引擎这个名字,其实游戏引擎就是游戏的开发框架,而Spring也可以理解为我们在开发Java项目时用到的引擎,当然我不能指望所有人都了解游戏引擎,因此我们必须先详细的说说框架的本质,框架的本质实际上就是一套固定的开发代码的模式,框架本身也是用代码书写的,在框架中规定了一些特定功能的特定写法,这些写法往往是为我们的开发提供了方便,框架本身的代码会往往能够保证我们在书写尽量简洁的代码的同时,支持我们的代码能够正常运转,我们在使用框架之前可能会写上万行的代码,但使用框架后我们的代码量可能就会缩减到几千行,这当然不代表代码总量小了,我们要知道,框架本身也是使用代码书写的。于此同时框架还规定了一系列的设计模式,对于类的设计模式也好,对于类的实例化方式也好,框架的开发者都煞费苦心的为我们设计了一套非常好的方法,在开发时我们只要按照框架中规定好的模式书写,就能保证代码的高效以及低耦合,这可以有效地提升团队协作中的效率。如果我们再通俗易懂一些,我们可以把框架理解为房屋结构,房屋结构往往是由一些坐办公室的赚高工资的设计师设计的,而我们这些戴安全帽满身灰的工人们,只需要按照他给的图纸在相应的地方添砖加瓦即可,我们不需要考虑房屋框架是怎么实现的,只需按照这个房屋框架中指示的一切去加东西就好了,程序开发中的框架也是这个道理,当然这个比喻没有针对哪些群体的意思,咱们这些工人在经过努力奋斗之后,也是完全有可能成为设计师的。

  在介绍完框架之后,我们就可以来具体谈谈Spring了,Spring是一个开源代码的设计层面框架,它解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。下面是一些Spring的书面简介:Spring是于2003 年兴起的一个轻量级的Java开发框架,由Rod Johnson在其著作Expert One-On-One J2E Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。Spring的核心是控制反转(IOC)和面向切面(AOP)。简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式) 轻量级开源框架。

  IOC:控制反转,将创建对象的过程交给Spring进行管理。

  AOP:面向切面,在不修改源码的情况之下进行代码功能的增强。

  关于以上两个核心,如果你Java基础学得好就能跟迅速的意识到,IOC的原理是基于反射,而AOP的原理则基于代理,学好反射和代理,在各种各样的框架学习中我们将会占据优势。

2.Spring与Servlet

  在很久以前,我们实际上早就接收过关于框架的知识,那就是Servlet,Servlet也是一种框架,只不过这种框架比较简单,比较基础。在Servlet中,它将所有的所谓操作层都放在自己一个人身上,如1.前端数据交互;2.业务处理;3.数据库交互,我们可见,Servlet一个人干成了这三件事,能干是一件好事,但是我们如果让一个人干所有的事,就相当于将所有鸡蛋放进了一个篮子里,如果哪天这个人没活了,拉胯了,也就意味着我们所有的事情都完蛋了,同理,我们将所有的操作层都使用Servlet框架来实现,这就意味着整个项目的耦合度非常高,如果我们的数据库内容改了,或者某个对象模式改了,就意味着我们需要修改整个项目,进行一次大改,这不是一件好事。因此如今的项目开发中,我们会使用分层的思路进行开发,并且需要注意的是,往往每个层都有自己的框架,在开发的时候这些层的开发是完全孤立的,我们只需调整接口,使用反射啊接口啊啥的就可以将每层联系起来,就像搭积木一样,每层之间关系不大,但是有一个大家都遵从的接口规则,接口的信息流入流出是一定类型的,不管其内部怎么变,只要这个接口规则不变,大家就能正常联系在一起,这就保证了如果哪天其中一层出现了变化,其他层的代码完全不用修改,在部署之后还能想发生变化前一样正常运行,这对于开发者而言实在是一件美事。在Servlet中尽管也存在分层的理念,但是由于Servlet本身原生且简单的限制,我们只能是在逻辑上分层,代码之间的联系程度还是非常紧密的,在Servlet中,开发者注入了自己的心血,切实的分出了不同的层,保证层与层之间的低耦合,需要注意的是:Spring致力于Java EE应用的各种解决方案,而不是仅仅专注于某一层的方案。可以说,Spring是企业的“一站式”选择,Spring贯穿表现层、业务层、持久层。可以理解为Spring中主要分为了三层:表现层、业务层、持久层,通常情况下,每层也都有自己的框架,其中表现层属于前端的层面,这层功能的实现往往交给了MVC框架,持久层的工作通常交给MyBatis,而业务层往往是使用Spring自身来进行开发。在使用Spring进行业务层开发的时候,我们就能够深刻的感受到IOC和AOP两个概念。

3.IOC 控制权反转

  IOC是Inversion of Control的缩写,直接翻译过来就是IOC,没什么高大上的就是缩写,这和我们管复方氨酚那敏颗粒叫感冒冲剂是一个道理的。那什么是控制权反转呢?如图,我们现在书写了三个类:A、B、C:

image-20220415105150270

  其中每个类中的代码都如图所示:

image-20220415105339874

  在A类中使用到了B类,在B类使用到了C类,C类中又使用到了A类,并且每个类中还有其他各自的一些方法,整个类的相互之间的依赖关系就是这样的:

image-20220415105536300

  三个类关系为三角形的循环依赖,这和妮妮扮家家酒中的三角恋爱关系不同,程序模块之间的依赖关系往往保证着一个模块能否正常的运行,也就是说在这个模型中,A模块依赖着B,意味着A模块的正常运行取决于B模块是否运行正常,同理,B模块的正常运行也取决于C模块是否运行正常,C模块的正常运行取决于A模块是否运行正常。而在这种依赖关系下,其中一个模块的运行异常就会导致所有的模块运行异常。如在B类中出现了一个严重的编译问题,就会导致整个项目的运行停止,为了解决这个问题,有些聪明的人制定了另外的思路,也就是说,一个类的对象能否生成,不由那个相应的类来决定,而是由另外的一个类来决定,如果A想要B的对象,那么他不能直接使用B的构造方法获得,而是要使用另外的一个类来进行获得,那个另外的类,我们便称之为Spring容器,它们的结构就变成了这样:

image-20220415155237973

  每个类不再依赖于其他的类,而是依赖Spring容器,A类中如果需要B类的对象,则需要向B类发出请求,Spring容器这时会尝试生成B类的对象,如果此时B类出现了严重的编译错误,那么Spring容器就会拦截住这个异常,并向A类中相应的方法中返回异常,而A类此时也不至于发生运行错误,此时A类中的其他方法仍然可用,不会造成上面提到的整个系统都不能用的情况,这样就降低了模块之间的耦合度,让整个系统的健壮性得到了增强。

4.AOP 面向切面编程

  这里不再详细说明这个知识点,面向切面编程的含义就是我们无须修改原方法中的代码,甚至不需要了解原来的代码是什么样子,我们只需直接书写自己的代码,就可与对原来的方法进行增强或者修改,遇到问题之后我们可以直接就地解决而不用追溯源头的错误,同时面向切面编程还可以让我们能够快速的根据实际情况对原方法进行特定类型的扩展。AOP的原理是基于代理的,关于这个知识点在之后会详细说明。

5.创建Spring项目并使用

  我们首先新建一个Maven工程,名字还有坐标可以自定义。

image-20220415161419250

  创建好之后我们首先导入Maven坐标依赖,我们导入下面的依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.12</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
</dependencies>

  如图所示:

image-20220415161615845

  我们首先现在main的java目录下创建一个包,包名和我们的坐标名同名,然后我们在这个包下创建一个测试类Demo

image-20220415161835913

package com.spruce;

public class Demo {
    public void hello() {
        System.out.println("hello world");
    }
}

  之后我们可以在test的目录下创建一个测试类,里边书写上main函数,测试一下我们写的Demo类:

image-20220415162032733

  但是这时我们使用的是最普通的方法在运行Demo对象,我们还没有使用Spring提供的各种方法,为了使用Spring,我们还需要在main目录下的resource目录下创建一个主配置文件,有了这个主配置文件我们才能使用Spring提供的各种接口,如图所示:

image-20220415162243074

  我们选择这个Spring Config并命名为applicationContext,我们最终会得到这样的一个配置文件:

image-20220415162405832

  需要注意的是这里的这些网址,都是我们引用的标签识别文件,有些标签我们不能直接使用,必须引用了相应的地址才行,这个问题在之后会进行详细的介绍。配置文件书写好之后,我们使用配置文件干些什么呢?我们在这个配置文件中,通常会配置扫描路径,那么扫描路径又是什么?这个问题我们就又需要好好讲讲了。

  在我们使用Servlet时,Servlet的启动实际上是基于Tomcat的,Tomcat中有一个反射机制,这个反射机制会扫描相应的目录,然后将这个目录下的相应Java项目进行反射,获取到这个项目中的一切信息,进而进行业务的运行。也就是说,如果我们想要运行一个别人书写的未知的Java程序,我们需要使用反射的方式进行相关运行,而我们如何找到那个类呢?我们使用的是扫描的方法,扫描的方法是java中提供的对目录的访问功能,在所有编程语言中都具备这个访问目录文件的功能,Java自然具备这个扫描功能,而Spring自然也可以使用这个功能,这样Spring就可以先扫描,然后反射,获取一切的类信息,之后Spring就可以使用反射的方式进行类的使用了,在这里我们先不研究为何使用反射,我们先书写一个例子。

  如下图所示,这个就是配置扫描路径的方式,下面的配置扫描路径的扫描对象是一个类:

image-20220415163400230

  我们使用这个语句进行配置:

<bean id="demo" class="com.spruce.Demo"></bean>

  在配置之后,在之后的操作中会先加载配置文件,然后生成一个对象,使用那个对象进行Demo对象的生成,这里内部实际上是一个反射机制,在这里我们先不深究这个机制。写好之后我们书写一个测试方法:

image-20220415171201493

package com.test;

import com.spruce.Demo;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DemoTest {
    @Test
    public void run(){
        //创建Spring工厂,加载配置文件
        ApplicationContext ac = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        //使用Spring工厂对象生成我们的目标对象
        Demo us = (Demo) ac.getBean("demo");
        //使用方法
        us.hello();

    }
}

  如图所示我们测试成功了,这个就是Spring的生成对象的方法。我们和之前使用的普通方式一对比,发现简直是脱了裤子放屁,我们首先是根据我们所书写的配置文件,生成了一个Spring工厂对象,或者说Spring容器,然后我们使用这个对象中的getBean方法来获取一个demo的对象,我们使用这个方法获取的对象不是相应的类型,而是一个Object类型,我们还要使用一个强转将其转化成Demo类型,之后我们才能使用Demo类中的hello方法。既然我们可以使用相应对象的构造器直接生成一个对象,我们为何还要使用这种复杂的方式生成一个对象呢?答案是:为了解耦,我们其实可以发现,这种Spring提供的生成对象的方式,实际上就是通过另外的一个对象来生成我们想要的对象,这里实际上就是上面提到的Spring中的IOC(控制权反转),我们使用这种方式进行解耦,这样可以降低模块之间的耦合度,提升系统整体的健壮性。

  以上就是针对Spring框架的初学习,我学习了Spring中的一些重要理念,以及创建了Spring项目,并且简单使用了Spring中的IOC方式创建了一个对象,在之后的学习中我会深入学习关于Spring中的IOC理念以及关于Spring IOC的知识。

posted @ 2022-04-15 17:55  云杉木屋  阅读(37)  评论(0编辑  收藏  举报