2018-03-27 Spring之旅
Posted 大梦几千秋
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2018-03-27 Spring之旅相关的知识,希望对你有一定的参考价值。
最近一直陷入一个误区,老是找一些网上关于SSM速成等视频学习,然后盲目的跟着\'复制\'代码,当时跟着视频敲完代码,实现了某些功能后,感觉自己对Spring等一些框架已经有了足够的了解(其实只是知其然,不知其所以然。) 过了一段时间,工作中用不到Spring,等到某天需要使用的时候,突然发现连手动搭建一个基本的Spring项目环境都不会。。。幡然领悟~~跟着视频敲的代码果然都是别人的@_@。故此,买了<Spring Action>这本书,开始系统性的了解Spring(@_@)。读完第一章,总结了其中几个知识点:
Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。其中一站式是指使用Spring框架就可以构建一个WEB应用,DAO层Spring JDBC Template,WEB层SpringMVC,SERVICE层Spring的IoC。Spring最根本的使命:简化Java开发。那么Spring是怎么做到简化Java开发的?
围绕这个使命,Spring采取以下4中关键策略来减低Java开发的复杂性:
1.基于POJO的轻量级和最小侵入性编程
POJO(Plain Ordinary Java Object):简单的Java对象,实际就是普通JavaBeans。
侵入式编程方式:框架通过强迫应用继承它们的类或实现它们的接口,将应用与框架绑死,紧耦合。
而Spring不会强迫你实现Spring规范的接口或继承Spring规范的类,在基于Spring构建的应用中,它的类没有任何痕迹表明你使用了Spring,就算你在类中使用Spring注解,但它仍然是POJO,这样应用对象彼此之间保持松散耦合。那么Spring是怎么做到这一点的呢? 方式之一就是通过DI(依赖注入)来装配它们。
2.通过依赖注入和面向接口实现松耦合
依赖注入(DI):对象的依赖关系将由系统中负责协调个对象的第三方组件在创建对象的时候进行设定,对象无需自行创建或管理他们的依赖关系。
任何一个有实际意义的应用都会有两个或更多的类组成,这些类之间进行协作来完成特定的业务逻辑。在传统的做法中,每个对象负责管理与自己相互协作的对象(即它所依赖的对象)的引用,这将会导致高度耦合和难以测试的代码。如下:
package chapter1; import infs.Knight; public class DamselRescuingKnight implements Knight { //DamselRescuingKnight类所依赖对象的引用 private RescueDamselQuest quest; /** * 在构造函数中创建所依赖对象 */ public DamselRescuingKnight() { this.quest = new RescueDamselQuest(); //与RescueDamselQuest紧耦合 } public void embarkOnQuest() { //该骑士只能执行RescueDamselQuest探险任务 quest.embark(); } }
在该代码中,DamselRescuingKnight与RescueDamselQuest紧密地耦合到一起,极大地限制了这个骑士执行探险的能力(即无法扩展该骑士的能力,若需要骑士去救援,则必须另外在写一个类),更糟糕的是无法进行单元测试。
耦合具有两面性,一方面,紧密耦合的代码难以测试、难以复用、难以理解;另一方面,一定的耦合是必须的,不同的类必须以适当的方式进行交互。
如下,Spring通过DI,达到了松耦合的目的。
图1.1 依赖注入会将所依赖的关系自动交给目标对象,而不是让对象自己去获取依赖
package chapter1; import infs.Knight; import infs.Quest; public class BraveKnight implements Knight { //使用Quest接口 private Quest quest; /** * 通过构造函数的方式注入Quest * 只要是实现了Quest接口的类对象都可以注入 * @param quest */ public BraveKnight(Quest quest) { this.quest = quest; } public void embarkOnQuest() { //完全不知道是哪种类型的Quest quest.embark(); } }
以上代码最重要的点是BraveKnight没有与特定的Quest实现发生耦合,对于它来说,只要求探险任务实现了Quest接口,具体是哪种类型的探险无关紧要。这就是DI所带来的最大收益--松耦合。
对依赖进行替换的一个最常用的方法就是在测试的时候使用mock实现。
package chapter1; import static org.mockito.Mockito.*; import org.junit.Test; import infs.Quest; public class BraveKnightTest { @Test public void knightShouldEmbarkOnQuest() { //使用mock(class)创建Quest对象 Quest mockQuest = mock(Quest.class); //注入Quest BraveKnight knight = new BraveKnight(mockQuest); knight.embarkOnQuest(); //当调用embarkOnQuest()方法时,使用verify要求Mockito框架验证Quest的mock实现的embark()方法仅调用了一次 verify(mockQuest, times(1)).embark(); } }
现在BraveKnight类可以接受任意一种Quest探险任务,如果我现在需要这位勇敢的骑士去消灭一条恶龙,那么怎么将消灭恶龙这个特定的Quest任务传给它?
package chapter1; import java.io.PrintStream; import infs.Quest; public class DestoryDragonQuest implements Quest { private PrintStream stream; public DestoryDragonQuest(PrintStream stream) { this.stream = stream; } public void embark() { stream.println("去消灭恶龙吧!"); } }
以上是关于2018-03-27 Spring之旅的主要内容,如果未能解决你的问题,请参考以下文章
Kotlin学习之旅解决错误:kotlin.NotImplementedError: An operation is not implemented: Not yet implemented(代码片段
我的C语言学习进阶之旅解决 Visual Studio 2019 报错:错误 C4996 ‘fscanf‘: This function or variable may be unsafe.(代码片段
我的C语言学习进阶之旅解决 Visual Studio 2019 报错:错误 C4996 ‘fscanf‘: This function or variable may be unsafe.(代码片段
我的Android进阶之旅关于Android平台获取文件的mime类型:为啥不传小写后缀名就获取不到mimeType?为啥android 4.4系统获取不到webp格式的mimeType呢?(代码片段
我的Android进阶之旅关于Android平台获取文件的mime类型:为啥不传小写后缀名就获取不到mimeType?为啥android 4.4系统获取不到webp格式的mimeType呢?(代码片段