【JavaWeb_Part07】功能堪比 502 的强大粘合剂?Spring(春天)框架表演秀

来源:互联网 发布:tf卡测速软件 编辑:程序博客网 时间:2024/04/28 22:32

前面我们已经讲完了 Dao 层(也就是持久层框架 mybatis )在开发中的大部分主要功能,秉承着中华上下五千年不太监的原则,本该这篇文章应该是写表现层框架的,经过我辗转反侧,夜不能寐的思考后,我决定还是排队来,先来写一下传说中后台开发的 502 神器-Spring,也就是春天这个框架。(PS:听说 Hibernate 是冬天,不信你去查 - -!)

老规矩,开篇还是说了一堆废话,讲框架,我们还是从入门开始讲起。Spring 的来源就不说了,不知道的出门左转百度百科。

为啥要学 Spring 框架呢?这里从百度爹爹那里抄来了一段话:你们将就着看。

1. 方便解耦,简化开发

Spring就是一个大工厂,可以将所有对象创建和依赖关系维护,交给Spring管理。

2. AOP编程的支持

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

3. 声明式事务的支持

只需要通过配置就可以完成对事务的管理,而无需手动编程。

4. 方便程序的测试

Spring对Junit4支持,可以通过注解方便的测试Spring程序。

5. 方便集成各种优秀框架

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

6. 降低JavaEE API的使用难度

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

看完上面的一段话不知道你们有什么感慨,反正劳资就是 45° 抬头,抽了一口烟,心里一万只草泥马呼啸而过,这他妈讲的些什么玩意。看不懂也没啥关系,反正劳资会用,是骡子是马拉出来遛遛就行了,懂那么多理论干嘛?又不能当饭吃。

好了,言归正传,直接开撸春天的入门程序。

Spring 入门

上次我们说 mybatis 的时候,第一步是干啥来着?搭环境?劳资一巴掌呼死你,还不赶紧去官网下 Spring ? Spring 都没有,搭尼玛的个锤子环境。
下载自己去百度搜索,本人比较懒,就不说 Spring 的下载了,不会的送你们一张图。
这里写图片描述

1. Spring 环境准备

下载下来 Spring 后,解压出来,你应该可以看到是这样的一个文件夹。
这里写图片描述

我这里的版本是 4.2 的,所以我就以 4.2 为基础开始记录了。里面有四个文件夹。

-schema  表示约束头(不懂没关系,去无脑百度就行了)-docs  这个就容易多了,文档呗。只不过和 mybatis 有点不同。什么?你不懂?那你滚吧。-dependencies 这个就是 spring 所需要的一些依赖。最后一个就是 spring 的文件夹咯。

点开 spring 文件夹,有如下的目录结构。
这里写图片描述

spring 核心的一些 jar 包全部在 spring 目录下,lib 下面包含了 spring 全部的 jar 包。
按规矩,我们还是由浅入深开始讲解。

2. 搭建简单 Spring 运行环境

新建 java 工程,拷贝最简单的 Spring jar 到 lib 目录下,所需要的 jar 包主要有如下 6 个。
这里写图片描述

beans 和 context 以及 core,expression 是 Spring 运行环境必须的 4 个jar 包,这个从文档中的图我们就可以看出来端倪。至于另外两个就是日志文件咯。依然还是 log4j。log4j 记得从 -dependencies 目录下去找。
这里写图片描述

看下面的 Core Container ,很明显就说了 4 个模块,每个模块对应的就是一个 jar 包。这个图示从文档上找来的,想看的话,自己去文档里面翻。(SpEL 就是 Spring Expression Spring 表达式)

jar 包现在已经有了,那么我们是不是就可以直接运行 Hello World 了呢?呸呸呸,明明是 Hello Spring。显然不能,我们还缺少一样致命的东西,记得我们讲 Mybatis 的时候,除了拷贝 jar 包,还做了一些什么了么?没错,核心配置文件,任何框架都有自己的核心配置文件,Spring 也同样有自己的配置文件-ApplicationContext.xml。(温馨提示:这个文件的名字不是固定的,但是还是不要改,因为开发中都是使用的这个名字。)

在 src 目录下新建文件,命名为 ApplicationContext.xml,有常识的人都知道,xml 前面应该有一个约束,Spring 也有,那么这个约束怎么写呢?别告诉我说你是记下来的,你疯了吧。命名空间你记下来?直接去文档中找不就得了。
这里写图片描述
动动你昂贵的脑子,直接搜索就可以了。拷贝这部分到 applicationContext.xml 就行了。

3. IOC 乱入

满心期待跑起来 Hello Spring,却发现来了一个 IOC,这又是个什么鬼?嗯。不讲 IOC 的话,显然我们下面无法进行下去。那就先说说 IOC 吧。究竟 IOC 是什么?IOC 全程为 Invocation of Control, 翻译过来就是“控制反转”。那什么又是控制反转呢? 我们来举一个例子。
1. 新建一个接口 UserService 和一个实现类 UserServiceImpl
2. 在 UserService 中定义一个 sayHello() 方法,在 UserServiceImpl 中实现该方法。

//接口中定义的方式public interface UserService {    void sayHello();}//实现类中实现的方法public class UserServiceImpl implements UserService {    @Override    public void sayHello() {        System.out.println("hello spring");    }}

新建测试类 TestSpring.java
我们要想调用 sayHello 方法,是不是需要用 new 关键字创建一个 UserServiceImpl 的实例出来?用实例.方法名的方式调用方法?嗯,没错。

@Testpublic void testOld(){    UserService userService = new UserServiceImpl();    userService.sayHello();}

运行的结果我就不贴出来了,太简单。

上面的方式就是传统的方式,嗯,这很优雅。但是你们想一下,这算不算使我们主动创建对象的实例?也就是说创建对象的主动权现在在我们手上。也就是控制正转(PS:不知道有没有这个说法,没有的话就当他是虚构的吧。don’t mind!),既然 Spring 容器提倡控制反转(IOC),那就是就是说我们不应该去占有对象的创建权利,而把创建对象的权利交给 Spring 去帮我们创建。我们只负责调用方法即可。

既然 Spring 去帮我们创建对象,那么我们应该怎么去做呢?首先在 Spring 的配置文件中配置我们需要创建对象的那个类。具体配置如下:

<bean id ="userService" class="com.student.spring.service.UserServiceImpl"/>

class 是我们创建对象的全路径名称, id 是给这个实例取一个名字。切记 class 这里需要填写实现类的全路径。

最后在测试类中写上我们的新的测试方法:

@Testpublic void TestNew(){   //创建工厂   ApplicationContext applicationContext           = new ClassPathXmlApplicationContext("applicationContext.xml");   //获取对象   UserService userService = (UserService) applicationContext.getBean("userService");   //调用方法   userService.sayHello();}

运行截图如下
这里写图片描述

到这里,我们的 Hello Spring 就已经完成了,我们没有通过 new 关键字来生成过 UserServiceImpl 对象的实例,但是 sayHello 中的打印信息确实是打印出来了。这说明 Spring 帮我们做了创建对象这一个过程。

ApplicationContext.xml 配置文件详解

目前我们的配置文件中只有

<bean id="userService" class="com.student.spring.service.UserServiceImpl"/>

这样一行代码,实际上 bean 的标签中还有一些其他的标签属性,例如

Scope
init-method
destroy-method

其中 scope 是代表范围的意思,我们都知道单例模式,如果我想让 Spring 帮我们生成的 UserServiceImpl 实例是单例或者多例的,便可以配置

//在 Spring 框架整合 Struts2 框架的时候,Action 类也需要交给 Spring 做管理,配置把 Action 类配置成多例!!scope="singleton" //单例scope="prototype" //多例

后面的 init-method 和 detroy-method 实际上就是初始化方法和销毁方法
比如我们可以在 UserServiceImpl 中添如下两个方法:

public class UserServiceImpl implements UserService {    @Override    public void sayHello() {        System.out.println("hello spring");    }    public void initMethod(){        System.out.println("执行初始化");    }    public void destroyMethod(){        System.out.println("销毁");    }}

在配置文件中加上

<bean id="userService" class="com.student.spring.service.UserServiceImpl" init-method="initMethod" destroy-method="destroyMethod"/>

执行结果
这里写图片描述

见图知意,我就不过多解释了。

对了,如果你要看到上图的效果,必须手动调用 Spring 工厂的 close() ,方法,不然 Spring 工厂是不会自动关闭的。同时还必须使用 ApplicationContext 的实现类 ClassPathXmlApplicationContext 去创建工厂。因为 ApplicationContext 这个接口中是没有 close 方法的。

Spring 依赖注入(Injection Dependencies)

依赖注入(DI) 也是 Spring 框架的核心之一,可能你不太理解依赖注入,没关系,我们先来看一个例子。很多时候,我们开发项目都是使用 MVC 的开发模式,MVC 开发模式分为三层:表现层调用业务层,业务层调用 dao 层。那么我们很容易写出如下代码:(几个接口就不写出来了,就是方法声明)
UserDaoImpl.java

public class UserDaoImpl implements UserDao {    @Override    public void save() {        System.out.println("dao 层操作数据库去保存用户数据");    }}

UserServiceImpl.java

public class UserServiceImpl implements UserService {    @Override    public void save() {        System.out.println("业务层操作 Dao 去保存用户");        new UserDaoImpl().save();    }}

测试方法和结果就直接看图吧。
这里写图片描述

传统的方式都是依靠 new 关键字来创建对象的。比如测试方法和 UserServiceImpl 类中。

UserService userService = new UserServiceImpl();new UserDaoImpl().save();

但是现在我们学了 Spring 的 IOC 功能,我们就可以把创建对象的功能交给 Spring 容器。UserServiceImpl 和 UserDaoImpl 的创建对象任务都交给 Spring 去管理。那么我们需要在配置文件中配置如下两个 bean 对象。

 <bean id="userService" class="com.student.spring.service.UserServiceImpl"/> <bean id="userDao" class="com.student.spring.dao.UserDaoImpl"/>

既然这样,那么问题来了,UserServiceImpl 中需要依赖 UserDaoImpl 的实例去调用 save 方法,那么我们就需要在 UserServiceImpl 中生成一个 UserDaoImpl 的实例,那么怎么生成呢?Spring 作为一个功能强大的框架,自然能够帮我们做到这点。

我们更改 UserServiceImpl 中的代码

public class UserServiceImpl implements UserService {    private UserDao userDao;    public void setUserDao(UserDao userDao) {        this.userDao = userDao;    }    @Override    public void save() {        System.out.println("业务层操作 Dao 去保存用户");        userDao.save();    }}

UserServiceImpl 需要一个 UserDaoImpl 的实例,我们就通过配置文件给它注入一个就好。继续更改我们的配置文件:

<bean id="userService" class="com.student.spring.service.UserServiceImpl">    <property name="userDao" ref="userDao1"/></bean><bean id="userDao1" class="com.student.spring.dao.UserDaoImpl"/>

property 中的 name 就是我们定义的成员变量的名称
property 中的 ref 就是我们下面定义的 bean 中的 id
property 中除了 ref 之外,还有一种选值 value。value 是给基本数据类型赋值所用的。

上面的配置就体现了 Spring 框架的依赖注入功能。运行结果:
这里写图片描述

UserServiceImpl 中需要一个 UserDaoImpl,我们利用配置文件给它注入了一个 UserDaoImpl 实例。那为什么要生成 set 方法呢?在配置文件中配置的默认注入方式就是 set 方法,如果你没有 set 方法,那么注入一定会失败。有兴趣的可以自己去试试。注入有很多种方式,我们后面来讲解。

还记得上面说了一个 ref 和 value 么?现在我们来试一试 value。

在 UserServiceImpl 中添加成员变量 name,提供 set 方法。

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

配置文件中做如下更改:

<bean id="userService" class="com.student.spring.service.UserServiceImpl">    <property name="userDao" ref="userDao"/>    <property name="name" value="楚乔"/></bean><bean id="userDao" class="com.student.spring.dao.UserDaoImpl"/>

输出结果:
这里写图片描述

这样是不是就一目了然了?

value 是给属性注入值(一般应用于基本数据类型)
ref 是给属性注入引用(一般应用于引用类型)

4. 总结

IOC 和 DI 的概念

IOC: Inverse of Control,控制反转,将对象的创建权反转给 Spring !
DI:Dependency Injection,依赖注入,在 Spring 框架负责创建 Bean 对象时,动态的将依赖对象注入到 Bean 组件中!

DI(依赖注入)

例如:如果 UserServiceImpl 的实现类中有一个属性,那么使用 Spring 框架的 IOC 功能时,可以通过依赖注入把该属性的值传入进来!
具体的配置如下


结语

依赖注入的方式有很多,但是主流的注入方式始终只有一两种,我们也只打算讲一两种,其他的如果你们有兴趣,可是去试试。
1. Set 方法注入(☆☆☆☆)
2. 构造函数注入(☆☆)
3. 注解注入(☆☆☆☆☆)
4. p 名称空间注入(☆)
5. SpEL 注入方式注入(☆)

后面的星星代表优先级,我们今天讲的注入方式就是通过 set 方式注入,本来想讲一下这几种注入方式的,但是看了一下篇幅,好像废话有点多,导致篇幅过长,那今天就先暂时到这里吧。依赖注入的几种方式我们留到下一节再去讲解。主要讲前三种注入方式,从星星的数量上来说,你们应该也知道哪些注入方式比较重要。今天就到这里吧,能力有限,写出来的东西难免有错误,如果有错误,还希望各位不吝指正。同时也欢迎小伙伴们留言交流。

阅读全文
0 0