第一章 Spring初体验

target

了解什么是Spring
了解Spring产生的背景
了解Spring的生态体系
掌握如何编写一个Spring项目
掌握控制反转和依赖注入的思想

1. Spring概述

1.1 Spring简介

百度百科对于Spring的描述

Spring是Java EE编程领域的一个轻量级开源框架,该框架由一个叫Rod Johnson的程序员在 2002 年最早提出并随后创建,是为了解决企业级编程开发中的复杂性,实现敏捷开发的应用型框架 。 Spring是一个开源容器框架,它集成各类型的工具,通过核心的Bean factory实现了底层的类的实例化和生命周期的管理。在整个框架中,各类型的功能被抽象成一个个的 Bean,这样就可以实现各种功能的管理,包括动态加载和切面编程。 Spring是独特的,因为若干个原因:

  • 它定位的领域是许多其他流行的framework没有的。Spring致力于提供一种方法管理你的业务对象

  • Spring是全面的和模块化的。Spring有分层的体系结构,这意味着你能选择使用它孤立的任何部分,它的架构仍然是内在稳定的。例如,你可能选择仅仅使用Spring来简单化JDBC的使用,或用来管理所有的业务对象。

  • 它的设计从底部帮助你编写易于测试的代码。Spring是用于测试驱动工程的理想的framework。

  • Spring对你的工程来说,它不需要一个以上的framework。Spring是潜在地一站式解决方案,定位于与典型应用相关的大部分基础结构。它也涉及到其他framework没有考虑到的内容。

1.2 背景

Rod Johnson在2002年编著的《Expert one on one J2EE design and development》一书中,对Java EE 系统框架臃肿、低效、脱离现实的种种现状提出了质疑,并积极寻求探索革新之道。以此书为指导思想,他编写了interface21框架,这是一个力图冲破J2EE传统开发的困境,从实际需求出发,着眼于轻便、灵巧,易于开发、测试和部署的轻量级开发框架。Spring框架即以interface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日,发布了1.0正式版。同年他又推出了一部堪称经典的力作《Expert one-on-one J2EE Development without EJB》,该书在Java世界掀起了轩然大波,不断改变着Java开发者程序设计和开发的思考方式。在该书中,作者根据自己多年丰富的实践经验,对EJB的各种笨重臃肿的结构进行了逐一的分析和否定,并分别以简洁实用的方式替换之。至此一战功成,Rod Johnson成为一个改变Java世界的大师级人物。

传统J2EE应用的开发效率低,应用服务器厂商对各种技术的支持并没有真正统一,导致J2EE的应用没有真正实现Write Once及Run Anywhere的承诺。Spring作为开源的中间件,独立于各种应用服务器,甚至无须应用服务器的支持,也能提供应用服务器的功能,如声明式事务、事务处理等。

Spring致力于J2EE应用的各层的解决方案,而不是仅仅专注于某一层的方案。可以说Spring是企业应用开发的“一站式”选择,并贯穿表现层、业务层及持久层。然而,Spring并不想取代那些已有的框架,而是与它们无缝地整合。

EJB是重量级的,比如说你想做个事,一共有5步, 5步都必须去做,其中做完之后,有很多事没用的,但是你不写不行,会报错 ,所以开发成本比较大,维护成本大。

到底轻量级是哪些东西呢?首先是依赖资源少,我这个模块要启动了,和你一点关系都没有,不依赖别的模块。然后是消耗资源少,比如 window启动某个软件的时候,会告诉你,给我腾1个g的内存,否则我不启动。而Spring不是,他消耗的资源非常少。

Rod Johnson当初的描述如下(节选 Rod Johnson于2005年出版的 expertone- on-one 2EE Development without EJB,当时的 Java EE按Sun公司的标准命名称为2EE):

We believe that

 - J2EE should be easier to use.

 - It is best to program to interfaces, rather than classes. Spring reduces the complexity cost of using interfaces to zero

 - Javabean offers a great way of configuring applications

 - OO design is more important than any implemention technology, such as 2EE

 - Checked exceptions are overused in java. A platform should not force you to catch exceptions you are unlikely to recover from

 - Testability is essential and a platform such as spring should help make your code easie to test

 We aim that

 - Spring should be a pleasure to use.

 - Your application codes should not depend on spring apis

 - Spring should not compete with good exsiting solutions, but should foster Integration

针对 Rod Johnson的观点,简要分析:

  • 这段话中谈及的 J2EE 更容易使用是针对EB而言的,因为EJB容器十分复杂,难以使用,当时使用EJB2的时候需要很多配置文件。

  • 基于接口的编程是一种理念,强调OOD的设计理念,比技术实现更为重要,因为实现可以多样化,但是如果没有一个好的设计理念,那么代码可读性就会变差,从而导致后期难以开发、维护和扩展。

  • 与此同时,他也指出了当时Java开发的通病一一大量使用 try.. catch. finally,因为大量的数据库操作都需要用try. catch. finally.去控制业务逻辑,这往往被大部分程序员滥用,导致代码非常复杂,而 Spring改造了它们。

  • 由于使用EJB需要从EB容器中获得服务,所以测试人员只能不断地部署和配置。对于测试而言,有时候一个对象比较复杂,它往往需要由其他对象作为属性组成。比如一套餐具,由碟子、碗、筷子、勺子和杯子组成,测试人员就想测试一下勺子好不好用,但是不得不需要自己构建碟子、筷子、勺子和杯子这套餐具,然后才能测试勺子。这显然存在很大的弊病,

  • 在当时的Java技术中,很多框架都是侵入性的,也就是必须使用当前框架所提供的类库,才能实现功能,这样会造成应用对框架的依赖。

  • Spring技术不是为了取代现有技术(当时的 Struts、 Hibernate、EJB、JDO等),而是提供更好的整合模板使它们能够整合到 Spring技术上来

同时 Rod Johnson也指出了 Spring的一些优势。

1.3 框架特征

轻量——从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类。

控制反转——Spring通过一种称作控制反转(IoC)的技术促进了低耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。它的底层设计模式采用了工厂模式,所有的 Bean 都需要注册到Bean工厂中,将其初始化和生命周期的监控交由工厂实现管理。程序员只需要按照规定的格式进行Bean开发,然后利用XML文件进行bean 的定义和参数配置,其他的动态生成和监控就不需要调用者完成,而是统一交给了平台进行管理。 [4] 控制反转是软件设计大师 Martin Fowler在 2004 年发表的”Inversion of Control Containers and the Dependency Injection pattern”提出的。这篇文章系统阐述了控制反转的思想,提出了控制反转有依赖查找和依赖注入实现方式。控制反转意味着在系统开发过程中,设计的类将交由容器去控制,而不是在类的内部去控制,类与类之间的关系将交由容器处理,一个类在需要调用另一个类时,只要调用另一个类在容器中注册的名字就可以得到这个类的实例,与传统的编程方式有了很大的不同,“不用你找,我来提供给你”,这就是控制反转的含义 [5] 。

面向切面——Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。

容器——Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。

框架——Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。

MVC——Spring的作用是整合,但不仅仅限于整合,Spring 框架可以被看做是一个企业解决方案级别的框架。客户端发送请求,服务器控制器(由DispatcherServlet实现的)完成请求的转发,控制器调用一个用于映射的类HandlerMapping,该类用于将请求映射到对应的处理器来处理请求。HandlerMapping 将请求映射到对应的处理器Controller(相当于Action)在Spring 当中如果写一些处理器组件,一般实现Controller 接口,在Controller 中就可以调用一些Service 或DAO 来进行数据操作 ModelAndView 用于存放从DAO 中取出的数据,还可以存放响应视图的一些数据。 如果想将处理结果返回给用户,那么在Spring 框架中还提供一个视图组件ViewResolver,该组件根据Controller 返回的标示,找到对应的视图,将响应response 返回给用户。

所有Spring的这些特征使你能够编写更干净、更可管理、并且更易于测试的代码。它们也为Spring中的各种模块提供了基础支持。

1.4 Spring体系结构

Spring框架是一个分层结构,它包含一系列的功能要素并被分为大约20个模块。

spring体系结构.jpg

其中:

  • Core Container:核心容器

    • Beans:管理bean

    • Core:核心

    • Context:上下文(配置文件)

    • Expression Language:SpEl表达式

  • AOP:切面编程

  • Aspects:Aop框架

  • Data Access/integration:数据访问/整合

    • JDBC:jdbcTemplate数据库开发

    • ORM:整合hibernate、mybatis

    • Transactions:事务管理(tx)

  • Web

    • Web:web开发

    • Struts:整合Struts框架

    • Servlet:服务连接器

2. 第一个Spring项目

2.1 下载 Jar

下载地址

Spring的jar下载目录

解压缩后,在lib文件夹下有好多jar包。

2.2 增加插件

为了编写时有一些提示、自动生成一些配置信息,可以给eclipse增加支持spring的插件:spring tool suite ,注意要下载和eclipse对应的版本。

在eclipse中,Help--> Eclipse Marketplace ,会弹出一个install的对话框:

增加spring插件

然后一直下一步,接受,按照步骤装就行。最后记得重启eclipse。

注意:需要选择sts3的相关版本,sts4无法生成spring配置文件。

还有一个更好的方法,直接下载一个软件"STS",会集成所有spring所有功能。
STS = Spring所有插件 + eclipse

2.3 开发spring程序

新建一个Java项目:Spring-01

① 导入jar

我们基础开发需要4+1个jar:

spring-beans-4.3.9.RELEASE.jar

spring-context-4.3.9.RELEASE.jar

spring-core-4.3.9.RELEASE.jar

spring-expression-4.3.9.RELEASE.jar

commons-logging-1.2.jar:第三方提供日志jar包

将上面5个jar复制,粘贴到src目录下,然后全部选中,右键Build Path-->add to build path

② 创建实体类

首先新建一个Student类:

package com.lee.spring.bean;

public class Student {
    private int no;
    private String name;
    private int age;
    
    // getter、setter、构造、toString省略
    
}

在写一个测试方法:

package com.lee.spring.test;

public class TestDemo {
    public static void main(String[] args) {
        Student student = new Student(1001, "张三", 23);
        System.out.println(student);    
    }
}

以前我们创建对象是这样去做的。

现在用ioc来创建一个对象:

③ 编写配置文件

在src下右键 --> 新建 --> Other,


新建spring配置文件

在弹出的对话框中起一个名字,一般叫:applicationContext .xml,单击finish。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="stu" class="com.lee.spring.bean.Student">
        <property name="no" value="2002"></property>
        <property name="name" value="李四"></property>
        <property name="age" value="24"></property>
    </bean>
</beans>

④ 测试

TestDemo.java:

package com.lee.spring.test;

public class TestDemo {
    
    @Test
    public void test01() {
      // 1. 获取上下文对象:Context
      ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
      // 2. 获取bean对象
      Student student = (Student)context.getBean("stu");
      System.out.println(student);
    }
}

输出:Student [no=2002, name=李四, age=24]

到此为止,我们就已经实现了第一个spring程序。来看一下和传统方式有什么不一样的地方:

  • 不需要new对象

  • 省略了对象属性的赋值

对象创建不是new的,而是用配置文件创建的,配置文件其实就是spring的IOC容器。

创建好对象后,赋值操作也是在配置文件中操作的。既然IOC容器已经为我们把这一切都做好了,所以直接从容器里面拿对象就可以了。

2.4 解释配置文件

bean标签:表示创建一个对象。

id:表示创建对象的名字。

class:表示实体类的全类名。

property:用来给对象赋值。

其中:

<bean id="stu" class="com.lee.entity.Student"> 
就相当于 
Student stu = new Student();

需要注意:
<bean id="stu" class="com.lee.entity.Student">调用了Student的无参构造,当我们把无参构造删除时,bean标签就会报错。bean的id就是对象名

3. 控制反转和依赖注入

3.1 IoC(控制反转)

首先想说说IoC(Inversion of Control,控制反转)。这是spring的核心,贯穿始终。所谓IoC,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系。

这是什么意思呢,举个简单的例子,我们是如何找女朋友的?常见的情况是,我们到处去看哪里有长得漂亮身材又好的mm,然后打听她们的兴趣爱好、qq号、电话号………,想办法认识她们,投其所好送其所要,然后……这个过程是复杂深奥的,我们必须自己设计和面对每个环节。传统的程序开发也是如此,在一个对象中,如果要使用另外的对象,就必须得到它(自己new一个,或者从JNDI中查询一个),使用完之后还要将对象销毁(比如Connection等),对象始终会和其他的接口或类藕合起来。

那么IoC是如何做的呢?有点像通过婚介找女朋友,在你和女朋友之间引入了一个第三方机构:婚姻介绍所。婚介管理了很多男男女女的资料,我可以向婚介提出一个列表,告诉它我想找个什么样的女朋友,比如长得像贾玲,身材像贾玲,唱歌像岳云鹏,幽默程度像贾玲之类的,然后婚介就会按照我们的要求,提供一个mm,我们只需要去和她谈恋爱、结婚就行了。简单明了,如果婚介给我们的人选不符合要求,我们就会抛出异常。整个过程不再由我自己控制,而是有婚介这样一个类似容器的机构来控制。Spring所倡导的开发方式就是如此,所有的类都会在spring容器中登记,告诉spring你是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。

3.2 DI(依赖注入)

IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的

比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了 spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。在系统运行时,spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系的控制。A需要依赖 Connection才能正常运行,而这个Connection是由spring注入到A中的,依赖注入的名字就这么来的。

那么DI是如何实现的呢? Java 1.3之后一个重要特征是反射(reflection),它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring就是通过反射来实现注入的。

理解了IoC和DI的概念后,一切都将变得简单明了,剩下的工作只是在spring的框架中堆积木而已。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容