(第二讲)Spring&Spring MVC&Spring Boot三者之间的区别与联系

Spring Framework的诞生让开发人员的工作从石器时代跨域到了工业时代,你是否还能记起手撸Servlet和JDBC的岁月?,你是否还对Struts1以及Struts2莫名其妙的404错误记忆犹新?从2004年3月Spring 1.0发布到至今,Spring的发展已经走过了15个年头,其创造的价值让人瞩目。今天,带着这样一个背景来梳理一下Spring Framework,Spring MVC和Spring Boot三者之间的区别。

我们使用Spring家族的系列产品这么长时间,不禁会问这样几个问题:Spring Framework是什么?Spring MVC是什么?Spring Boot又是什么?它们被设计出来的目的是什么?

你需要了解的知识

在接下来的内容中,将梳理这样几个知识点:

  • Spring Framework基本概述
  • Spring Framework主要解决的问题是什么?
  • Spring MVC基本概述
  • Spring MVC主要解决的问题是什么?
  • Spring Boot主要解决的问题是什么?
  • Spring,Spring MVC和Spring Boot三者之间的区别是什么?

Spring Framework 解决了哪些核心问题?

当你仔细思考这个问题的时候你会发现,很多地方它都有渗透到,貌似一个Spring就可以撑起开发的半边天,以至于很难一下子回答这个问题。那Spring Framework到底解决了哪些核心问题?

Spring Framework最重要也是最核心的特性是依赖注入。所有的Spring模块的核心就是DI(依赖注入)或者IoC(控制反转)。

依赖注入或控制反转是Spring Framework最大的特性,当我们正确使用DI(依赖注入)或IoC时,可以开发出一个高内聚低耦合的应用程序,而这一一个低耦合的应用程序可以轻松的对其实施单元测试。这就是Spring Framework解决的最核心的问题。

无依赖注入

请考虑这一一个案例:UserAction依赖于UserService来获取用户信息,在没有依赖注入的情况下,我们需要手动在UserAction中实例化一个UserService对象,这样的手工作业意味着UserAction和UserService必须精密的联系在一起,才能正常工作。如果一个Action需要多个Service提供服务,那实例化这些Service将是一个繁重的工作。下面我们给出一个不使用依赖注入的代码片段加以说明:

UserService.java

public interface UserService{
    User profile();
}

UserServiceImpl.java

public class UserServiceImpl implements UserService{
    @Override
    User profile(){
        // TODO
    }
}

UserAction.java

@RestController
public class UserAction{
    
    private UserService userService = new UserServiceImpl();
    // other services...
    
    @GetMapping("/profile")
    public User profile(){
        return userService.profile();
    }
}

引入依赖注入

引入依赖注入将会使整个代码看起来很清爽。为了能够开发出高内聚低耦合的应用程序,Spring Framework为我们做了大量的准备工作。下面我们使用两个简单的注解@Component@Autowired来实现依赖注入。

  • @Component : 该注解将会告诉Spring Framework,被此注解标注的类需要纳入到Bean管理器中。
  • @Autowired : 告诉Spring Framework需要找到一与其类型匹配的对象,并将其自动引入到所需要的类中。

在接下来的示例代码中,我们会看到Spring Framework将为UserService创建一个Bean对象,并将其自动引入到UserAction中。

UserService.java

public interface UserService{
    User profile();
}

UserServiceImpl.java

@Component
public class UserServiceImpl implements UserService{
    @Override
    User profile(){
        // TODO
    }
}

UserAction.java

@RestController
public class UserAction{
    @Autowired
    private UserService userService;
    // other services...
    
    @GetMapping("/profile")
    public User profile(){
        return userService.profile();
    }
}

对比上下两部分的代码,你是否发现了他们之间的区别?Action所依赖的Service的初始化工作全部交由Spring Framework来管理,我们只需要在适当的地方向Spring Framework索取想要服务即可。这就好比当我想要吃薯片的时候,我不需要自己亲自种土豆,施肥,收获...清洗,切片...一直到最后炸土豆片,想想都觉得累,而更简单的方法是直接去超市购买自己想要的薯片即可。

Spring Framework还有其他的核心特性吗?

#1:衍生的特性

Spring Framework的依赖注入是核心中的核心,在依赖注入核心特性的基础上,Spring Framework还衍生出了很多的高级模块:

  • Spring JDBC
  • Spring MVC
  • Spring AOP
  • Spring ORM
  • Spring JMS
  • Spring Test

对于这些新的高级模块,可能会产生这一一个问题:它们是否是一个全新的功能?答案是否定的,在不使用Spring Framework的情况下,我们依然能够使用JDBC连接数据库,依然能够对视图和数据模型进行控制,依然能够使用第三方的ORM框架。那Spring Framework干了什么?Spring Framework站在巨人的肩膀上,对这些原生的模块进行了抽象,而抽象可以带来这样一些好处:

  • 减少了应用中模板代码的数量
  • 降低了原生框架的技术门槛
  • 基于依赖注入特性,实现了代码的解耦,真正的高内聚、低耦合
  • 更细粒度的单元测试

这样的好处是显而易见的,比如与传统的JDBC相比,使用JDBCTemplate操作数据库,首先是代码量小了,其次是我们不需要再面对恐怖的try-catch。

#2:优秀的集成能力

Spring Framework还具备另外一个重要特性,那就是能够快速的与其他三方框架进行整合。与其自己造轮子,还不如想办法将好的轮子整合在一起,我想这句话应该可以用来概况Spring Framework这一特性。Spring Framework对于整合其他的框架,给出了不错的解决方案,下面将列举一些常见的方案:

  • 与Hibernate ORM框架整合
  • 与MyBatis 对象映射框架整合
  • 与Junit单元测试框架整合
  • 与Log4J日志记录框架整合

Spring MVC是什么?

Spring MVC提供了构建Web应用程序的全功能MVC模块,实现了Web MVC设计模式以及请求驱动类型的轻量级Web框架,即采用了MVC架构模式的思想,将Web层进行职责解耦。基于请求驱动指的是使用请求-响应模型,视图与数据模型分离,以简化Web应用的开发。

使用Spring MVC提供的Dispatcher Servlet,ModelAndView和ViewResolver等功能,可以轻松的开发出一个Web应用程序。

Spring Boot出现的原因是什么?

我们都知道,使用Spring Framework来开发应用程序,需要进行大量的配置工作以及依赖包的管理,工作繁重而且极易出现配置错误,尤为明显的是依赖包之间的版本冲突问题。

举一个简单的案例,当我们使用Spring MVC来开发Web应用程序时,我们大致需要经历这样几个步骤:

  • 1:配置组件扫描的包路径

  • 2:配置对应的Servlet程序

  • 3:配置视图解析器

  • 4:配置页面模板引擎(JSP、Freemarker等)

下面给出了一个小范围的举例:

...
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix">
        <value>/WEB-INF/pages</value>
    </property>
    <property name="suffix">
        <value>.jsp</value>
    </property>
</bean>
<mvc:resources mapping="/static/**" location="/static/"/>
...

此外,我们还需要配置先关的Servlet处理程序,它们大致是这样的:

<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>
        org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/todo-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

如果我们的应用程序还需要链接数据,则还需要配置数据源,实体对象管理器,事务管理器等众多配置:

<bean id="datasource" class="">
    ...
</bean>
<bean id="entityManagerFactory" class="">
    ...
</bean>
<bean id="transactionManager" class="">
    ...
</bean>
...

面对众多的配置文件,我们需要花费大量的时间去处理,这时你可能会问,我为什么要花费那么多的时间去管理Spring的配置工作?不是应该专注于应用本身的业务逻辑吗?现在,有了Spring Boot,这些烦心事就不需要你去操心了。

#1:Spring Boot的自动化配置能力

我为什么会把Spring Boot的自动化配置能力放在第一位,因为它极大的降低了我们使用Spring Framework所付出的成本。这是Spring Boot的自动化配置是一个最具价值的解决方案。

这难道不值得我们拍案叫好吗?如果你想要开发一个Web应用程序,你需要做的事情就是将Spring Boot Web包引入到项目的类路径下,Spring Boot就可以帮你解决后续的大多数配置工作。

  • 如果Hibernate的依赖被放到了类路径上,Spring Boot会自动配置数据源
  • 如果Spring MVC的依赖被放到了类路径上,Spring Boot又会自动配置Dispatcher Servlet

当Spring Boot检测到有新的依赖包添加到类路径上,Spring Boot会采用默认的配置对新的依赖包进行设置,如果我们想自己配置依赖包时,只需要手动覆盖默认的配置项即可。

  1. Spring Boot扫描类路径上可用的框架信息
  2. 获取应用程序现有的配置信息
  3. 如果应用程序没有提供框架的配置信息,Spring Boot将采用默认的配置来配置框架,这就是Spring Boot的自动配置特性(Auto Configuration)

#2:Spring Boot Starter项目

在传统模式的开发过程中,我们需要反复的确认应用程序所需要的第三方JAR包,以及这些JAR的版本和依赖关系。例如,现在我们打算开发一款Web应用程序,应用程序大概需要如下的一些依赖包:Spring MVC,Jackson Databind(用于数据绑定),Hibernate-Validator(用于服务端的数据校验)和Log4j(用于日志记录)。现在,我们需要去下载对应的jar包到应用程序中,并且还需要处理依赖包之间版本冲突的问题。

<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>4.2.2.RELEASE</version>
</dependency>

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.5.3</version>
</dependency>

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.0.2.Final</version>
</dependency>

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

这不是一件简单的事情,特别是发生版本冲突的时候,让应用程序能够正常运行起来就需要花费一定的时间。

Spring Boot Starter是一组用于管理依赖关系的描述符,通过这些描述符,我们可以在应用程序中轻松的管理依赖包,你可以以开箱即用的方式获取想要的依赖包,而无需去Maven仓库总检索对应的依赖,并将依赖配置复制粘贴到应用程序的pom文件中。例如,如果你想要使用Spring和JPA进行数据库访问,只需要在pom中添加spring-boot-starter-data-jpa依赖项就可以。

现在,如果我们想要开发一个Web应用程序,使用Spring Boot Starter Web依赖会是一个不错的选择。我们可以通过使用Spring INitializr快速构建一个Web应用程序,并将Spring Boot Starter Web添加到项目中。此时我们的pom文件只需要很少的配置:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Spring Boot Starter Web会为我们预装如下的一些依赖:

  • Spring : core,beans,context,aop
  • Web MVC : Spring MVC
  • Jackson : JSON Binding
  • Validation : Hibernate Validator,Validation API
  • Embedded Servlet Container: Tomcat
  • Logging : logback,slf4j

对于开发人员而言,我们不需要去担心这些依赖项的管理工作以及解决他们之间的兼容性问题,Spring Boot已经帮我们解决了。

Spring Boot的核心目标

Spring Boot的核心目标在于快速实现生产就绪的应用程序,这将包含这样几个部分:

  • 执行器 : 启用高级监控和跟踪应用程序功能
  • 嵌入式服务器:Spring Boot已经内置了多个Web服务器,如Undertow,jetty,tomcat,因此我们不需要再额外的配置服务器,就可以完成应用程序的调试工作。
  • 默认的异常处理机制
  • 开箱即用的依赖项管理机制
  • 自动化配置

总结

通过上述的梳理,我们可以看到,Spring Framework是一个提供了DI(依赖注入)和IoC(控制反转)的开发框架,使用Spring Framework可以帮助我们开发出高内聚,低耦合的应用程序,Spring MVC是在Spring Framework基础上发展出来的基于MVC模式的全功能Web开发框架,实现了Model,View和Controller之间的职责解耦;Spring Boot为我们提供了一个能够快速使用Spring Framework的优秀解决方案,通过最小化的配置,我们就可以使用Spring Framework,严格意义上讲,Spring Boot并不是某种框架,它只是为开发人员提供了一个更好的更方便的使用Spring Framework的解决方案。

作者:谭朝红
链接:(第二讲)Spring&Spring MVC&Spring Boot三者之间的区别与联系
来源:谭朝红的技术分享博客

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

推荐阅读更多精彩内容