手记

如何搭建第一个 Spring 项目?

上文我们讲了 Spring IoC 的原理,这一篇我们动手实践一下,用两种方式搭建 Spring 项目,使用下 IoC 感受一下。

现在大都使用 maven 来构建项目,方便我们管理 jar 包;
但我这里先讲一下手动导入 jar 包的过程,中间会遇到很多问题,都是很好的学习机会。

在开始之前,我们先来看下图 - 大名鼎鼎的 Spring 模块图。

Spring Framework 八大模块

模块化的思想是 Spring 中非常重要的思想。

Spring 框架是一个分层架构,每个模块既可以单独使用,又可与其他模块联合使用。

每个「绿框」,对应一个模块,总共8个模块;
「黑色包」,表示要实现这个模块的 jar 包。

Core Container,我们刚才已经在文档里看到过了,就是 IoC 容器,是核心,可以看到它依赖于这4个 jar 包:

  • Beans
  • Core
  • Context
  • SpEL, spring express language

那这里我们就知道了,如果想要用 IoC 这个功能,需要把这 4个 jar 包导进去。
其中,Core 模块是 Spring 的核心,Spring 的所有功能都依赖于这个 jar 包,Core 主要是实现 IoC 功能,那么说白了 Spring 的所有功能都是借助于 IoC 实现的。

其他的模块和本文关系不大,不在这里展开了。

那当我们想搭建 Spring 项目时,当然可以把所有 jar 包都导进去,但是你的电脑能受得了吗。。 但是包越大,项目越大,问题就越多,所以尽量按需选择,不用囤货。。

Btw, 这张图在网上有很多,但是在我却没有在最新版的 reference doc 上找到。。
不过,既然那些老的教程里有,说明老版本的 doc 里有,那去老版本的介绍 里找找看😂

在本文第一张图 Spring Framework - Documentation 中我们选 4.3.26Reference Doc.,然后搜索“Framework Modules”,就有啦~
具体链接可以看文末参考资料。

还有一个方法,待会我们讲到 jar 包中的内容时再说。

知道要导入哪些 jar 包了,那就找吧😂。

一、手动加载 jar 包的方式

1. 下载

下载地址:

如果你要问我怎么找的,那就还是从刚才 4.3.26 版本的 Reference Doc 中进去,然后刚开头就有一个 Distribution Zip Files

好奇心带着我打开了它,发现…

发现了仓库地址!

打开后发现是各个版本的 jar 包啊~

我们搜 5.2.3 版的,它在最下面:

然后就可以愉快的使用了~

  • Dist.zip 是 jar 包
  • Docs.zip 是文档

其他的暂时先不用管~

下载好了之后,就好好看看 Spring 送我们的这份大礼包吧。

此处回答上文的遗留问题:哪里找 Spring Framework 框架图。

答案是:下载的 docs.zip → spring-framework-reference → images → spring-overview

我们需要导入 Intellij 的 jar 包在哪里呢?
Dist.zip → libs

这里可以看到,每个黑色框对应3个 jar 包,我们要导入 Intellij 的是 RELEASE.jar.

2. 不用 IoC 构建项目

我们 new project,不用 maven 构架,就新建一个普通的 Java 项目,比如我就叫它 Spring_HelloWorld,然后还是用我常用的 class Rectangle 的例子。

然后在 External Libraries 中导入我们刚才在模块图里看到的那4个模块所对应的 jar 包,结构如下:

这样你以为就大功告成了吗?Too young too simple 啊~

来运行一下:

出现了老盆友:no class def found error, 就是找不到这个类。

我们谷歌 Maven common logging 并下载它的 jar 包,再加到项目里就可以了。

我上图里是已经加过了的,所以你会看到一个 commons-logging-1.2.

再运行一下就可以了。这里的两个文件上文都有截图。

目前为止我们是手动用 set() 方法设置对象的,那怎么用 Spring IoC 呢?

3. Spring IoC 配置文件详解

还需要有一个配置文件,可是这个文件需要配置啥,该怎么配置呢?

官网里都给我们写好了:

第一段是一些命名空间及其规范的介绍,

第二段就是给 bean 的属性赋值了。

这里注意下 bean 里面的配置要改一下,改成我们这个项目对应的。
这里的 id, class 是什么意思呢?官网上也有解释,我这里简单概括下:

  • bean 标签:告诉 Spring 要创建的对象
  • id: 对象的唯一标识,就像每个人的身份证一样,不可重复
  • class: bean 的完全限定名,即从 package name 到 class name
  • property:给属性赋值,name 的名称取决于 set() 方法后面的参数;

其实也可以用 constructor 来赋值,name 的名称取决于参数列表;
更多给复杂数据类型赋值的使用可以在官网查到。

当然,在工作中更常用的是注解。但是往往也会有 xml 文件配合着一起使用的,所以还是要懂的。

我的 service 文件配置如下:

4. 最后一步,我们再来看它是怎么用的:

这里面并没有直接的 new 这个 service,但是 Spring 容器帮我们创建了这个对象。

那么 Spring 是如何帮我们创建对象的呢?

ApplicationContextIoC 容器的入口,其实也就是 Spring 程序的入口,
刚才已经说过了它的两个具体的实现子类,在这里用了从 class path 中读取数据的方式;

然后第二行,就是获取具体的 bean 了。这个其实有很多方式,在使用的时候就能看到:

点进去发现,是在 BeanFactory.class 里定义的:

这其中比较常用的是通过

  • Id → 需要 cast
  • Bean 的类型 → 只能在 Singleton 的时候使用,否则不知道用哪个呀
  • Id + 类型 → 下图代码示例

来获取对象,最后两种 String, Class objects 这种可变参数的方式用的很少。

照猫画虎,我的 test 文件改动如下:

成功运行~~🎉🎉

Follow up 1. 对象在容器中默认是单例的

实践是检验的唯一标准:

再用 getBean() 得到一个对象,测试是否还是同一个。

即:

public class MyTest {
  public void test myTest() {
    ApplicationContext context = new ClassPathXmlApplicationContext("service.xml");
        Rectangle rect = context.getBean("rectangle", Rectangle.class);
        Rectangle rect2 = context.getBean("rectangle", Rectangle.class);
        System.out.println(rect == rect2);
    }
  }
}

返回 True or False?

答:True

因为默认是单例的,如果要改,需要在配置文件里改<bean … scope = “prototype”>.

至于这些标签的用法,这里不再延伸了~

Follow up 2. 容器中的对象是什么时候创建的?

实践是检验的唯一标准:

定义一个无参的 constructor,里面打印一句话,然后只 new ClassPathXmlApplicationContext,如下图:

发现也是可以打印的,所以其实是每次启动容器的时候,就已经创建好容器中的所有对象了。(当然,这在 scope = "prototype" 的时候不适用,只是 singleton 的时候。)

多说一句,其实最好应该一直保留一个无参的 constructor,因为这里 bean 对象的创建是通过反射,

  • clazz.newInstance() 默认是调用无参的 constructor

不过,现在已经被弃用掉了,换用了这个:

  • clazz.getDeclaredConstructor().newInstance()

二、使用 Maven 构建项目

我们再回到最开始的构建项目,相信大家都体会到了手动导入 jar 包的繁琐之处,其实我们还可以用 Maven 来管理项目中的 jar 包,在公司中也是比较常用的一种方式,免除了手动下载 jar 包的过程。

1. 新建项目

使用 Maven 的话就简化很多了,首先我们创建一个 Maven 项目,不同于刚才的过程在于:

New Project 的时候要选择从 Maven 构建,而不是一个简单的 Java 项目。

建好之后,我们会发现比起刚才的 Java 项目,多了很多东西:

和之前的空项目不太一样,这里有 main, test,其中 resources 是放配置文件的地方,也就是我们刚才的 service.xml 应该放在这里,如果没有放对位置是代码找不到哦~

2. 添加对应的 pom 依赖,就不用手动导 jar 包了

  1. 仓库地址 https://mvnrepository.com/

  2. spring

  3. 选择 Spring context5.2.3 release,把里面的配置 copy 到 pom.xml

最终在左边 external libraries 会自动出现所需的包,一键导入,不要太方便~

3. 写代码~~🎉🎉

小结

我们最后再来体会一下用 Spring 创建对象的过程:

通过 ApplicationContext 这个 IoC 容器的入口,用它的两个具体的实现子类,从 class path 或者 file path 中读取数据,用 getBean() 获取具体的 bean instance。

那使用 Spring 到底省略了我们什么工作?

答:new 的过程。把 new 的过程交给第三方来创建、管理,这就是「解藕」。

Spring 也是用的 set() 方法,它只不过提供了一套更加完善的实现机制而已。

而说到底,底层的原理并没有很复杂,只是为了提高扩展性、兼容性,Spring 提供了丰富的支持,所以才觉得源码比较难。

因为框架是要给各种各样的用户来使用的,它们考虑的更多的是扩展性。如果让我们来实现,或许三五行就能搞定,但是我们实现的不完善、不完整、不严谨,总之不高大上,所以它写三五十行,把框架设计的尽可能的完善,提供了丰富的支持,满足不同用户的需求,才能占领更大的市场啊。

以上就是本文的全部内容了,如果你喜欢这篇文章,记得给我点赞留言哦~你们的支持和认可,就是我创作的最大动力,我们下篇文章见!

我是小齐,纽约程序媛,终生学习者,每天晚上 9 点,云自习室里不见不散!

更多干货文章见我的 Github: https://github.com/xiaoqi6666/NYCSDE

0人推荐
随时随地看视频
慕课网APP