【Spring从入门到实战教程】第一章 Spring概述

一、Spring 概述

1.1 什么是Spring

【Spring从入门到实战教程】第一章 Spring概述_第1张图片

    Spring 是一款目前主流的 Java EE 轻量级开源框架,是 Java 世界最为成功的框架之一。Spring 由“Spring 之父”Rod Johnson 提出并创立,其目的是用于简化 Java 企业级应用的开发难度和开发周期。
    
    自 2004 年 4 月,Spring 1.0 版本正式发布以来,Spring 已经步入到了第 5 个大版本,也就是我们常说的 Spring 5。
    
    Spring 自诞生以来备受青睐,一直被广大开发人员作为 Java 企业级应用程序开发的首选。时至今日,Spring 俨然成为了 Java EE 代名词,成为了构建 Java EE 应用的事实标准。
    
    Spring 框架不局限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何 Java 应用都可以从 Spring 中受益。Spring 框架还是一个超级粘合平台,除了自己提供功能外,还提供粘合其他技术和框架的能力。
    
    Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架。

具体描述 Spring:

    轻量:从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类。我们之前学习的Servlet就是侵入性的,因为一个Java类想要成为Servlet,必须实现或继承Servlet API,但是Spring基本上不会。
    
    核心思想:
        控制反转:IOC(inversion of control)。
        依赖注入:DI(dependency injection)。
        面向切面编程:AOP(aspect oriented programming)。
    
    容器:Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。
    
    框架:Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。
    
    一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(例如:Struts2和Hibernate框架之间的协同工作),Spring在程序中是一个桥梁或者管理者,整个应用程序的运行都依靠Spring。实际上Spring自身也提供了展现层的SpringMVC和持久层的SpringJDBC。

1.1.1 Spring 的诞生与发展

    早期的 J2EE(Java EE 平台)推崇以 EJB 为核心的开发方式,但这种开发方式在实际的开发过程中存在种种弊端,例如使用复杂、代码臃肿、代码侵入性强、开发周期长、移植难度大等。

    Rod Johnson 在其 2002 年编著的畅销书《Expert One-on-One J2EE Design and Development》中,针对 EJB 各种臃肿的结构进行了逐一的分析和否定,并分别以更加简洁的方式进行了替换。

    在这本书中,Rod Johnson 通过一个包含 3 万行代码的附件,展示了如何在不使用 EJB 的情况下构建一个高质量、可扩展的 Java 应用程序。在这个附件中,Rod Johnson 编写了上万行基础结构代码,其中包含了许多可重用的 Java 接口和类,例如 ApplicationContext、BeanFactory 等。这些类的根包被命名为 com.interface21,含义为:这是提供给 21 世纪的一个参考。

    这本书影响甚远,后来 Rod Johnson 将 com.interface21 的代码开源,并把这个新框架并命名为“Spring”,含义为:Spring 像一缕春风一样,扫平传统 J2EE 的寒冬。

    2003 年 2 月,Spring 0.9 版本发布,它采用了 Apache 2.0 开源协议;2004 年 4 月,Spring 1.0 版本正式发布。到目前为止,Spring 已经步入到了第 5 个大版本,也就是我们常说的 Spring 5。

1.1.2 Spring 的狭义和广义

    在不同的语境中,Spring 所代表的含义是不同的。下面我们就分别从“广义”和“狭义”两个角度,对 Spring 进行介绍。
    
    官网:https://spring.io/

广义的 Spring:Spring 技术栈

    广义上的 Spring 泛指以 Spring Framework 为核心的 Spring 技术栈。

    经过十多年的发展,Spring 已经不再是一个单纯的应用框架,而是逐渐发展成为一个由多个不同子项目(模块)组成的成熟技术,例如 Spring Framework、Spring MVC、SpringBoot、Spring Cloud、Spring Data、Spring Security 等,其中 Spring Framework 是其他子项目的基础。

    这些子项目涵盖了从企业级应用开发到云计算等各方面的内容,能够帮助开发人员解决软件发展过程中不断产生的各种实际问题,给开发人员带来了更好的开发体验。

项目名称 描述
Spring Data Spring 提供的数据访问模块,对 JDBC 和 ORM 提供了很好的支持。通过它,开发人员可以使用一种相对统一的方式,来访问位于不同类型数据库中的数据。
Spring Batch 一款专门针对企业级系统中的日常批处理任务的轻量级框架,能够帮助开发人员方便的开发出健壮、高效的批处理应用程序。
Spring Security 前身为 Acegi,是 Spring 中较成熟的子模块之一。它是一款可以定制化的身份验证和访问控制框架。
Spring Mobile 是对 Spring MVC 的扩展,用来简化移动端 Web 应用的开发。
Spring Boot 是 Spring 团队提供的全新框架,它为 Spring 以及第三方库一些开箱即用的配置,可以简化 Spring 应用的搭建及开发过程。
Spring Cloud 一款基于 Spring Boot 实现的微服务框架。它并不是某一门技术,而是一系列微服务解决方案或框架的有序集合。它将市面上成熟的、经过验证的微服务框架整合起来,并通过 Spring Boot 的思想进行再封装,屏蔽调其中复杂的配置和实现原理,最终为开发人员提供了一套简单易懂、易部署和易维护的分布式系统开发工具包。

狭义的 Spring:Spring Framework

    狭义的 Spring 特指 Spring Framework,通常我们将它称为 Spring 框架。

    Spring 框架是一个分层的、面向切面的 Java 应用程序的一站式轻量级解决方案,它是 Spring 技术栈的核心和基础,是为了解决企业级应用开发的复杂性而创建的。

    Spring 有两个核心部分: IoC 和 AOP。

核心 描述
IOC Inverse of Control 的简写,译为“控制反转”,指把创建对象过程交给 Spring 进行管理。
AOP Aspect Oriented Programming 的简写,译为“面向切面编程”。 AOP 用来封装多个类的公共行为,将那些与业务无关,却为业务模块所共同调用的逻辑封装起来,减少系统的重复代码,降低模块间的耦合度。另外,AOP 还解决一些系统层面上的问题,比如日志、事务、权限等。

    Spring 是一种基于 Bean 的编程技术,它深刻地改变着 Java 开发世界。Spring 使用简单、基本的 Java Bean 来完成以前只有 EJB 才能完成的工作,使得很多复杂的代码变得优雅和简洁,避免了 EJB 臃肿、低效的开发模式,极大的方便项目的后期维护、升级和扩展。

    在实际开发中,服务器端应用程序通常采用三层体系架构,分别为表现层(web)、业务逻辑层(service)、持久层(dao)。

    Spring 致力于 Java EE 应用各层的解决方案,对每一层都提供了技术支持。
    在表现层提供了对 Spring MVC、Struts2 等框架的整合;
    在业务逻辑层提供了管理事务和记录日志的功能;
    在持久层还可以整合 MyBatis、Hibernate 和 JdbcTemplate 等技术,对数据库进行访问。

    这充分地体现了 Spring 是一个全面的解决方案,对于那些已经有较好解决方案的领域,Spring 绝不做重复的事情。

    从设计上看,Spring 框架给予了 Java 程序员更高的自由度,对业界的常见问题也提供了良好的解决方案,因此在开源社区受到了广泛的欢迎,并且被大部分公司作为 Java 项目开发的首选框架。

1.1.3 Spring Framework 的特点

    Spring 框架具有以下几个特点。

    方便解耦,简化开发:Spring 就是一个大工厂,可以将所有对象的创建和依赖关系的维护交给 Spring 管理。

    方便集成各种优秀框架:Spring 不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如 Struts2、Hibernate、MyBatis 等)的直接支持。

    降低 Java EE API 的使用难度:Spring 对 Java EE 开发中非常难用的一些 API(JDBC、JavaMail、远程调用等)都提供了封装,使这些 API 应用的难度大大降低。

    方便程序的测试:Spring 支持 JUnit4,可以通过注解方便地测试 Spring 程序。

    AOP 编程的支持:Spring 提供面向切面编程,可以方便地实现对程序进行权限拦截和运行监控等功能。

    声明式事务的支持:只需要通过配置就可以完成对事务的管理,而无须手动编程。

1.2 Spring体系结构

    Spring 框架是一个分层架构,每个模块既可单独存在,又可与其他模块联合实现,其架构如下图所示:

【Spring从入门到实战教程】第一章 Spring概述_第2张图片

     Spring Core:Core模块是Spring的核心类库,Spring的所有功能都依赖于该类库,Core主要实现IOC功能,Sprign的所有功能都是借助IOC实现的。
    
    Spring AOP:AOP模块是Spring的AOP库,为Spring容器管理的对象提供了对面向切面编程的支持。
    
    Spring DAO:Spring 提供对JDBC的支持,对JDBC进行封装,允许JDBC使用Spring资源,同时还基于AOP模块提供了事务管理。
    
    Spring ORM:Spring 的ORM模块提供对常用的ORM框架的管理和辅助支持,Spring支持常用的Hibernate,ibtas,jdo等框架的支持,Spring本身并不对ORM进行实现,仅对常见的ORM框架进行封装,并对其进行管理。
    
    Spring Context:Context模块提供框架式的Bean访问方式,其他程序可以通过Context访问Spring的Bean资源。增加了对国际化、事件传播,以及验证等的支持,此外还提供了许多企业服务及对模版框架集成的支持。
    
    Spring Web:WEB模块是建立于Context模块之上,提供了一个适合于Web应用的上下文。另外,也提供了Spring和其它Web框架(如Struts1、Struts2、JSF)的集成。
    
    Spring Web MVC:WEB MVC模块为Spring提供了一套轻量级的MVC实现,是一个全功能的 Web 应用程序,容纳了大量视图技术,如 JSP、Velocity、POI等。

1.3 理解控制反转与依赖注入

    IoC 是 Inversion of Control 的简写,译为“控制反转”,它不是一门技术,而是一种设计思想,是一个重要的面向对象编程法则,能够指导我们如何设计出松耦合、更优良的程序。

    Spring 通过 IoC 容器来管理所有 Java 对象的实例化和初始化,控制对象与对象之间的依赖关系。我们将由 IoC 容器管理的 Java 对象称为 Spring Bean,它与使用关键字 new 创建的 Java 对象没有任何区别。

    IoC 容器是 Spring 框架中最重要的核心组件之一,它贯穿了 Spring 从诞生到成长的整个过程。

1.3.1 通俗理解

Address类:

public class Address {
    
    /**
     * 在Address类中使用到了String类与Integer类
     * 可以理解为,Address类依赖了String,Integer
     */
    private String city; //城市
    private String street; //街道
    private Integer no; //门牌号

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public Integer getNo() {
        return no;
    }

    public void setNo(Integer no) {
        this.no = no;
    }
}

Person类:

public class Person {
    /**
     * Person类依赖了String, Integer, Address类
     */
    private String name;
    private Integer age;
    private Address address;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public void show(){
        System.out.println("hello");
    }
}

测试:

public class SpringTest {
    @Test
    public void testNewObject() {
        //传统创建对象的方式:由代码编写者创建对象,对象的生命周期由程序员决定
        //根据对象定义位置的不同,对象的生命周期也不相同
        System.out.println("address对象的生命周期开始");
        if (true) {
            Address address = new Address();

            //使用对象
            address.setCity("郑州市");
            address.setStreet("迎春路");
            System.out.println(address.getCity());

            //如果把创建Address对象的代码放在if语句块中,那么if执行结束,我们可以认为对象生命周期就结束了
        }

        //System.out.println(address); //定义在if中,在if外无法使用address

        //如果Address对象放在test1()中,那么方法执行结束,我们可以认为对象生命周期就结束了
        System.out.println("address对象的生命周期结束");
    }

    @Test
    public void testIOC() {
        /*
         * 控制反转:IOC
         * 将创建对象的权力转交给Spring,由Spring来负责对象的创建、销毁和管理
         * 程序员无需创建对象,只需要从Spring容器中获取对象和使用对象即可
         */
    }

    @Test
    public void testDI() {
        Address address = new Address();

        /*
         * 首先我们理解什么是依赖:
         *  在Address类中使用到了String类与Integer类
         *  可以理解为,Address类依赖了String,Integer
         */
        //那么为依赖类型的属性赋值,就叫做依赖注入
        address.setCity("郑州市");
        address.setStreet("迎春路");
        address.setNo(18);

        Person p = new Person();
        //注入字面值
        p.setName(new String("张三"));
        p.setAge(new Integer(20));
        //注入其他的对象
        p.setAddress(address);
    }
}

1.3.2 控制反转

    在传统的 Java 应用中,一个类想要调用另一个类中的属性或方法,通常会先在其代码中通过 new Object() 的方式将后者的对象创建出来,然后才能实现属性或方法的调用。为了方便理解和描述,我们可以将前者称为“调用者”,将后者称为“被调用者”。也就是说,调用者掌握着被调用者对象创建的控制权。

    但在 Spring 应用中,Java 对象创建的控制权是掌握在 IOC 容器手里的,其大致步骤如下。
        1、开发人员通过 XML 配置文件、注解、Java 配置类等方式,对 Java 对象进行定义,例如在 XML 配置文件中使用 标签、在 Java 类上使用 @Component 注解等。
        
        2、Spring 启动时,IoC 容器会自动根据对象定义,将这些对象创建并管理起来。这些被 IOC 容器创建并管理的对象被称为 Spring Bean。
        
        3、当我们想要使用某个 Bean 时,可以直接从 IOC 容器中获取(例如通过 ApplicationContext 的 getBean() 方法),而不需要手动通过代码(例如 new Obejct() 的方式)创建。

    IoC 带来的最大改变不是代码层面的,而是从思想层面上发生了“主从换位”的改变。原本调用者是主动的一方,它想要使用什么资源就会主动出击,自己创建;但在 Spring 应用中,IOC 容器掌握着主动权,调用者则变成了被动的一方,被动的等待 IOC 容器创建它所需要的对象(Bean)。

    这个过程在职责层面发生了控制权的反转,把原本调用者通过代码实现的对象的创建,反转给 IOC 容器来帮忙实现,因此我们将这个过程称为 Spring 的“控制反转”。

1.3.3 依赖注入

    在了解了 IoC 之后,我们还需要了解另外一个非常重要的概念:依赖注入。

    依赖注入(Denpendency Injection,简写为 DI)是 Martin Fowler 在 2004 年在对“控制反转”进行解释时提出的。Martin Fowler 认为“控制反转”一词很晦涩,无法让人很直接的理解“到底是哪里反转了”,因此他建议使用“依赖注入”来代替“控制反转”。

    在面向对象中,对象和对象之间是存在一种叫做“依赖”的关系。简单来说,依赖关系就是在一个对象中需要用到另外一个对象,即对象中存在一个属性,该属性是另外一个类的对象。

例如,有一个名为 B 的 Java 类,它的代码如下:

public class B {
    String bid;
    A a;
}

    从代码可以看出,B 中存在一个 A 类型的对象属性 a,此时我们就可以说 B 的对象依赖于对象 a。而依赖注入就是就是基于这种“依赖关系”而产生的。

    我们知道,控制反转核心思想就是由 Spring 负责对象的创建。在对象创建过程中,Spring 会自动根据依赖关系,将它依赖的对象注入到当前对象中,这就是所谓的“依赖注入”。

1.3.4 IOC 的工作原理

    在 Java 软件开发过程中,系统中的各个对象之间、各个模块之间、软件系统和硬件系统之间,或多或少都存在一定的耦合关系。

    若一个系统的耦合度过高,那么就会造成难以维护的问题,但完全没有耦合的代码几乎无法完成任何工作,这是由于几乎所有的功能都需要代码之间相互协作、相互依赖才能完成。因此我们在程序设计时,所秉承的思想一般都是在不影响系统功能的前提下,最大限度的降低耦合度。

    IoC 底层通过工厂模式、Java 的反射机制、XML 解析等技术,将代码的耦合度降低到最低限度,其主要步骤如下。
        1、在配置文件(例如 Bean.xml)中,对各个对象以及它们之间的依赖关系进行配置;
        
        2、我们可以把 IoC 容器当做一个工厂,这个工厂的产品就是 Spring Bean;
        
        3、容器启动时会加载并解析这些配置文件,得到对象的基本信息以及它们之间的依赖关系;
        
        4、IoC 利用 Java 的反射机制,根据类名生成相应的对象(即 Spring Bean),并根据依赖关系将这个对象注入到依赖它的对象中。

    由于对象的基本信息、对象之间的依赖关系都是在配置文件中定义的,并没有在代码中紧密耦合,因此即使对象发生改变,我们也只需要在配置文件中进行修改即可,而无须对 Java 代码进行修改,这就是 Spring IoC 实现解耦的原理。

1.4 搭建Spring开发环境

1.4.1 创建一个Java项目

    在Spring的基础模块中,没有和Web相关内容,无需创建JavaWEB项目,建立Java项目即可。

1.4.2 导入核心的jar包

Spring 框架的核心包:

名称 作用
spring-core-x.x.xx.jar 包含 Spring 框架基本的核心工具类,Spring 其他组件都要用到这个包中的类,是其他组件的基本核心。
spring-beans-x.x.xx.jar 所有应用都要用到的,它包含访问配置文件、创建和管理 Bean 以及进行 Inversion of Control(IoC)或者 Dependency Injection(DI)操作相关的所有类。
spring-context-x.x.xx.jar Spring 提供在基础 IoC 功能上的扩展服务,此外还提供许多企业级服务的支持,如邮件服务、任务调度、JNDI 定位、EJB 集成、远程访问、缓存以及各种视图层框架的封装等。
spring-expression-x.x.xx.jar 定义了 Spring 的表达式语言。 需要注意的是,在使用 Spring 开发时,除了 Spring 自带的 JAR 包以外,还需要一个第三方 JAR 包 commons.logging 处理日志信息。

方式一:引入jar包

【Spring从入门到实战教程】第一章 Spring概述_第3张图片

 方式二:maven依赖配置


    
    
        org.springframework
        spring-core
        4.3.18.RELEASE
    
    
    
        org.springframework
        spring-beans
        4.3.18.RELEASE
    
    
    
        org.springframework
        spring-context
        4.3.18.RELEASE
    
    
    
        org.springframework
        spring-expression
        4.3.18.RELEASE
    
    
        junit
        junit
        4.12
        test
    

1.4.3 编写Bean

HelloWorld.java

public class HelloWorld {
    
    public String show() {
        return "Hello Spring";
    }
}

1.4.4 编写Spring配置文件

    applicationContext.xml为默认名称,作用是在SpringIOC容器中配置需要让Spring来管理的Bean对象。
    
    Spring的配置管理可以利用XML方式进行配置,而XML里面就有命名空间这个概念。实际上就和标签的意思有点像,你给一个命名空间以后,这个XML文件里面就可以用那个命名空间上下文里面的标签了。
    
    1、beans:xml文件的根节点。
    
    2、xmlns:是XML NameSpace的缩写,因为XML文件的标签名称都是自定义的,自己写的和其他人定义的标签很有可能会重复命名,而功能却不一样,所以需要加上一个namespace来区分这个xml文件和其他的xml文件,类似于java中的package。
    
    3、xmlns:xsi:是指xml文件遵守xml规范,xsi全名:xml schema instance,是指具体用到的schema资源文件里定义的元素所准守的规范。即http://www.w3.org/2001/XMLSchema-instance这个文件里定义的元素遵守什么标准。
    
    4、xsi:schemaLocation:是指本文档里的xml元素所遵守的规范,这些规范都是由官方制定的,可以进你写的网址里面看版本的变动。xsd的网址还可以帮助你判断使用的代码是否合法。





    
    
    

Schema和DTD的区别:

    Schema是对XML文档结构的定义和描述,其主要的作用是用来约束XML文件,并验证XML文件有效性。DTD的作用是定义XML的合法构建模块,它使用一系列的合法元素来定义文档结构。它们之间的区别有下面几点:

    1、Schema本身也是XML文档,DTD定义跟XML没有什么关系,Schema在理解和实际应用有很多的好处。

    2、DTD文档的结构是“平铺型”的,如果定义复杂的XML文档,很难把握各元素之间的嵌套关系;Schema文档结构性强,各元素之间的嵌套关系非常直观。

    3、DTD只能指定元素含有文本,不能定义元素文本的具体类型,如字符型、整型、日期型、自定义类型等。Schema在这方面比DTD强大。

    4、Schema支持元素节点顺序的描述,DTD没有提供无序情况的描述,要定义无序必需穷举排列的所有情况。Schema可以利用xs:all来表示无序的情况。

    5、对命名空间的支持。DTD无法利用XML的命名空间,Schema很好满足命名空间。并且,Schema还提供了include和import两种引用命名空间的方法。

    6、XML Schema不能像DTD一样定义实体,比DTD更复杂,但Xml Schema现在已是w3c组织的标准,它正逐步取代DTD。

Schema好处:

    1、XML用户在使用XML Schema的时候,不需要为了理解XML Schema而重新学习,节省了时间;
    
    2、由于XML Schema本身也是一种XML,所以许多的XML编辑工具、API 开发包、XML语法分析器可以直接的应用到XML Schema,而不需要修改。
    
    3、作为XML的一个应用,XML Schema理所当然的继承了XML的自描述性和可扩展性,这使得XML Schema 更具有可读性和灵活性。
    
    4、由于格式完全与XML一样,XML Schema除了可以像XML一样处理外,也可以同它所描述的XML文档以同样的方式存储在一起,方便管理。
    
    5、XML Schema与XML格式的一致性,使得以XML为数据交换的应用系统之间,也可以方便的进行模式交换。
    
    6、XML有非常高的合法性要求,XML DTD对XML的描述,往往也被用作验证XML合法性的一个基础,但是XML DTD本身的合法性却缺少较好的验证机制,必需独立处理。XML Schema则不同,它与XML有着同样的合法性验证机制。

1.4.5 测试

@Test
public void testSpringIOC() {
    //1、创建IOC容器ApplicationContext
    //ClassPathXmlApplicationContext是ApplicationContext接口的实现类,该对象通过加载类路径下面的spring配置文件
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

    //2、从容器中获取bean对象
    /**
         * Object getBean(String name)
         * 参数name: 获取对象的名称,对象的唯一标识符,bean标签的id属性值
         * 返回值Object: 对象
         */
    Object obj = ac.getBean("helloworld");
    System.out.println(obj instanceof HelloWorld);
    HelloWorld helloWorld = (HelloWorld) obj;
    String str = helloWorld.show();
    System.out.println("方法的返回值为:" + str);

    Object obj1 = ac.getBean("helloworld");

    System.out.println(obj == obj1);
}

关于以上代码,需要注意以下两点:

  • 创建 ApplicationContext 对象时使用了 ClassPathXmlApplicationContext 类,这个类用于加载 Spring 配置文件、创建和初始化所有对象(Bean)。

  • ApplicationContext.getBean() 方法用来获取 Bean,该方法返回值类型为 Object,通过强制类型转换为 HelloWorld 的实例对象,调用其中的 show() 方法。

你可能感兴趣的:(#,Spring,spring,java,后端,SSM,javaee)