Spring框架做什么?我应该使用它吗?为什么或者为什么不?


236

因此,我正在用Java启动一个全新的项目,并正在考虑使用Spring。我为什么要考虑春季?因为很多人告诉我我应该使用Spring!认真地说,每当我试图让人们解释Spring到底是什么或做什么时,他们永远无法给我一个直接的答案。我已经在SpringSource网站上查看了这些介绍,它们要么真的很复杂,要么真的是针对教程的,它们都没有给我一个很好的主意,为什么我应该使用它,或者它如何使我的生活更轻松。有时人们会抛出“依赖注入”这个术语,这使我更加困惑,因为我认为我对该术语的含义有不同的理解。

无论如何,这里有一些关于我的背景和我的应用程序的信息:

在Java中开发了一段时间,从事后端Web开发。是的,我进行了大量的单元测试。为了实现这一点,我通常制作(至少)一种方法的两个版本:一个使用实例变量,一个仅使用传递给该方法的变量。使用实例变量的一个调用另一个,提供实例变量。当进行单元测试时,我使用Mockito模拟对象,然后调用不使用实例变量的方法。这就是我一直以来所理解的“依赖注入”。

从CS的角度来看,我的应用程序非常简单。小型项目,需要1-2个开发人员。通常是CRUD类型的操作,并附带大量搜索。基本上是一堆RESTful Web服务,再加上Web前端,最后是一些移动客户端。我正在考虑使用直接的HTML / CSS / JS / JQuery进行前端,因此没有真正的计划使用JSP。使用Hibernate作为ORM,并使用Jersey来实现Web服务。

我已经开始编码,非常渴望在那里获得一个演示,我可以四处逛逛,看看是否有人想投资。因此,显然时间至关重要。我了解到Spring具有相当的学习曲线,而且看起来它需要一堆XML配置,而我通常会尽量避免这种麻烦。但是,如果这可以使我的生活更轻松,并且(尤其是)可以使我的生活和开发速度更快,那么我愿意痛不欲生,学习Spring。

所以,请。教我 我应该使用Spring吗?为什么或者为什么不?


10
我认为您确实需要一段时间尝试一下,以查看是否喜欢它以及它是否适合您的项目。我个人讨厌它。
理查德

1
虽然可以使用XML或注释;请记住,Spring在配置思路上采取了惯例。它不一定是您必须解决的项目的清单。
亚伦·麦克弗

14
虽然这个问题的确很广泛,但我认为应该保持开放。我将其读为“ Spring对中型项目有什么好处?”,这是一个很好的问题。
sleske 2012年

1
我强烈建议您阅读我最喜欢的技术书籍:Craig Walls撰写的Spring in Action,第三版。这是一本很好的读物,它将改变您的编程方式。
2014年

4
考虑到Enterprise Java,回答Spring不做的事情会更容易...
m3th0dman 2015年

Answers:


108

Spring框架做什么?我应该使用它吗?为什么或者为什么不?

Spring是一个框架,可以帮助您将不同的组件“连接”在一起。如果您有很多组件,并且您可能决定以不同的方式组合它们,或者希望根据不同的设置或环境轻松地将一个组件替换为另一个组件,则它非常有用。

这就是我一直以来所理解的“依赖注入”。

我会建议一个不同的定义:

“设计您的对象,以便它们依靠外部力量为它们提供所需的东西,并期望在任何人要求它们开始执行常规工作之前,总是注入这些依赖项。”

将其与以下内容进行比较:“每个对象都有责任出去,并在启动时查找所需的一切和​​每个人。”

看起来它需要一堆XML配置

好吧,大多数XML(或基于注释)的东西都在告诉Spring东西,例如:

  • 当有人要求“ HammerStore”时,我希望您创建一个实例example.HammerStore并返回它。下次缓存该实例,因为只需要一个存储即可。
  • 当有人要“ SomeHammer”时,我想让您问一个“ HammerStore”,并返回商店makeHammer()方法的结果。不要缓存此结果。
  • 当有人要求“ SomeWrench”时,我希望您创建的实例example.WrenchImpl,使用配置设置gaugeAmount并将其放入实例的setWrenchSize()属性中。不要缓存结果。
  • 当有人要求“ LocalPlumber”时,我要您创建一个实例example.PlumberImpl。将字符串“ Pedro”放入其setName()方法中,将“ SomeHammer”放入其setHammer()方法中,并将“ SomeWrench”放入其setWrench()方法中。返回结果,并缓存结果供以后使用,因为我们只需要一名水管工。

通过这种方式,Spring可以让您连接组件,为其添加标签,控制其生命周期/缓存以及根据配置更改行为。

为了方便[测试],我通常(至少)制作一个方法的两个版本:一个使用实例变量,一个仅使用传递给该方法的变量。

这听起来像是很多开销,但对我却没有太多好处。而是让您的实例变量具有protected或包可见性,然后在同一com.mycompany.whatever包中找到单元测试。这样,您可以在测试期间随时检查和更改实例变量。


65

首先,什么是依赖注入?

简单。您有一个类,它具有一个私有字段(设置为null),并声明一个公共设置方法,该方法提供该字段的值。换句话说,类(字段)的依赖项由外部类(通过设置器)注入。而已。没什么神奇的。

其次,可以在没有XML的情况下使用Spring(或很少使用)

如果您使用Spring 3.0.5.GA或更高版本,则可以使用JDK6 +的依赖注入支持。这意味着您可以使用@Component@Resource注释连接依赖项。

为什么要使用Spring?

显然,依赖注入促进了非常简单的单元测试,因为您的所有类都具有重要依赖项的设置器,并且可以使用您喜欢的模拟框架轻松地模拟这些设置器,以提供所需的行为。

除此之外,Spring还提供了许多模板,这些模板充当了基类,使使用JEE标准技术变得轻而易举。例如,JdbcTemplate与JDBC配合良好,JpaTemplate与JPA兼容,JmsTemplate使JMS非常简单。RestTemplate的简单性非常出色。例如:

RestTemplate restTemplate = new RestTemplate();
MyJaxbObject o = restTemplate.getForObject("https://secure.example.org/results/{param1}?param2={param2}",MyJaxbObject.class,"1","2");

到此为止。注入参数,您只需要为MyJaxbObject提供JAXB批注。如果您已经使用Maven JAXB插件从XSD自动生成了它们,那将完全没有时间。请注意,这里没有进行任何强制转换,也不需要声明编组器。一切都为您完成。

我可能永远都在谈论Spring的奇迹,但是也许最好的办法是尝试一个简单的代码尖峰,在这里您尝试连接RESTful Web服务以从支持事务的注入DAO中抽出数据。


4
是的RestTemplate非常棒。我有100行代码可以扔掉并替换为2-3行。
凯文

11
挑剔:依赖注入还包括基于构造函数的方法。您不一定需要有setter。
达连(Darien)

28

首先,您对依赖项注入的理解从根本上来说并不是错误的,但是与大多数人使用术语时的含义有很大不同。您所描述的是实现可测试性的一种非常奇怪且非常规的方法。我建议您不要使用它,因为其他开发人员会对这种代码感到困惑。

众所周知,依赖注入(由Spring实现)意味着,类本身(例如JDBC数据源)所具有的依赖关系不是由类本身获取的,而是由创建实例时的容器“注入的”。因此,每个使用数据源的方法都没有两个版本;取而代之的是,您有一个依赖项注入配置,其中注入了“真实”数据源,而有一个注入了模拟。或者,如果注入是通过构造函数或getter进行的,则测试代码可以显式进行注入。

其次,Spring不仅是依赖注入,尽管它是其核心功能。它还提供了声明式事务,作业计划,身份验证以及您可能需要的一系列其他功能(包括成熟的MVC Web框架)。还有其他框架提供相同的功能,但是除了Spring之外,只有Java EE才将它们全部集成在一起。


OP非常了解DI
Basilevs

19

关于为什么要使用Spring,可以在http://www.wrox.com/WileyCDA/Section/Why-Use-the-Spring-Framework-.id-130098.html上阅读

综上所述 :

  • J2EE应用程序倾向于包含过多的“管道”代码。许多代码检查反复显示出大部分不执行任何操作的代码:JNDI查找代码,传输对象,try / catch块以获取和释放JDBC资源。。。。编写和维护这样的管道代码证明大量消耗资源,这些资源应集中在应用程序的业务领域上。

  • 许多J2EE应用程序在不合适的地方使用分布式对象模型。这是代码过多和代码重复的主要原因之一。在很多情况下,这在概念上也是错误的。内部分布的应用程序比并置的应用程序更复杂,并且性能通常低得多。当然,如果您的业务需求决定了分布式体系结构,则您需要实现分布式体系结构并接受由此产生的折衷(Spring提供了在这种情况下可以提供帮助的功能)。但是,如果没有令人信服的理由,则不应这样做。

  • EJB组件模型过于复杂。EJB被认为是在J2EE应用程序中实现业务逻辑时降低复杂性的一种方法。在实践中,这一目标并未成功。

  • EJB被过度使用。EJB本质上是为内部分布的事务性应用程序设计的。尽管几乎所有非平凡的应用程序都是事务性的,但不应将分发构建到基本组件模型中。

  • 实际上,许多“ J2EE设计模式”不是设计模式,而是技术限制的解决方法。分发的过度使用以及诸如EJB之类的复杂API的使用已经产生了许多可疑的设计模式。重要的是要仔细检查这些内容,并寻找更简单,更有效的方法。

  • J2EE应用程序很难进行单元测试。在敏捷运动开始之前就定义了J2EE API,尤其是EJB组件模型。因此,他们的设计没有考虑单元测试的简便性。通过API和隐式合同,很难在应用程序服务器之外测试基于EJB和许多其他J2EE API的应用程序。但是,应用程序服务器外部的单元测试对于实现高测试覆盖率和重现许多失败情况(例如与数据库的连接丢失)至关重要。确保在开发或维护过程中可以快速运行测试,以最小化等待重新部署的非生产时间,这也是至关重要的。

  • 某些J2EE技术​​只是失败了。这里的主要罪魁祸首是实体bean,事实证明,它们对于生产力及其对面向对象的约束几乎没有造成灾难性的后果。


13

过去,我们仅使用核心Java,Servlet和JSP,html和xml,JDBC API编写了简单,高效,快速的应用程序和Web服务。足够好了;JUnit是一个很好的测试工具。我们很轻松地认为我们的代码可以正常工作。

Hibernate的出现是为了简化SQL并实现与Java对象的数据库表的真实映射,从而使层次关系可以反映在我们称之为“对象关系映射”或ORM中。我爱它。特别是我们不必将ResultSet映射回Java对象或数据类型。

Struts随之将Model View Controller模式添加到我们的Web应用程序,这很好。

EJB是一个巨大的开销,痛苦和注释使代码看起来像鸡的抓痒,现在Spring涌入了我们无辜的人们。这似乎对我来说太过分了。

例如,我们现在将简单的jdbc url(用户)打包,首先传递到jdbc.properties,然后传递到休眠属性,然后第三次传递到Spring bean!

相对于所有这些,考虑在真正需要的地方真正实现连接,就像在纯Java中所示的那样简单,这是我们在使用Spring完成所有热门工作之后真正要做的事情:

Connection connection = DriverManager.getConnection(url, user, pass);

这本身就是不言自明的,它绕着一个大回合,绕着一个回合就可以快速,轻松地完成一件简单的事情,而实际上并没有其他好处。这就像将大量礼品纸包裹在一个很小的精美礼物上一样,而这正是您真正要保留的。

另一个示例是批量更新。在使用Spring之前,它涉及很多类和接口,在使用JdbcTemplate进行批处理更新之前,它是令人费解的。使用普通的jdbc,其简单性是:

Statement statement = connection.createStatement();
statement.addBatch(sqlquery);
statement.executeBatch();

没有比这更简单或更快速的了。

我不支持该框架。抱歉。到底谁在每次需要注射时都想要注射?


6
该代码很简单,但是您的事务处理定义在哪里,以及如何对其进行测试?到春天,这两件事都变得更简单了。另外,您的Java代码直接绑定到db连接,除非您在外部存储连接URL和密码,否则在spring之前这也变得更加简单。
2012年

为此答案+1,请使用您自己的轻量级设计模式(GOF),单例进行连接池,为数据库对象提供sql(字符串)和值(数组)的代理类(此方法为上述方法) ,取决于http方法),则dbobject处理连接池,事务等,然后执行查询并释放。在所有模块中使用一个对象,没有人需要过多的模板代码。奖励积分,在代理类和dbobject上设置单元测试。
user2727195

不过请查看Spring-Data-JPA!将pojo注释为实体,使用合理的名称(例如findHammerByWeight())实现接口并定义方法签名,并且spring为您实现方法,从而为您提供可注入的存储库,您可以在所有其他业务服务或控制器类中使用该存储库。
mancini0

13

Spring框架做什么?

春天不仅是今天,它被称为一个简单的框架,它是一个完整的生态系统。

春季生态系统涵盖的主题:

  • Spring框架(例如,依赖注入,AOP ...)

  • 春云

  • 春季数据

  • 春季安全

  • 春季批

  • 春季社交

有关生态系统的完整信息,请参见此处。可以挑选项目,以便您可以使用Google Guice for DI和例如Spring Security来处理与安全相关的事情。您不必购买整个生态系统。

春季框架本身主要涵盖了今天

  • 依赖注入

  • 面向方面的编程,包括Spring的声明式事务管理

  • Spring MVC Web应用程序和RESTful Web服务框架

  • 对JDBC,JPA,JMS的基础支持

来源spring.io

通常,您可以说Spring是代码中已实施的模式和实践的集合,可以帮助改善或加快您的应用程序开发周期。

它(核心框架)最著名的是它在依赖注入领域的功能。Spring本身具有所谓的“控制容器反转”或“较短的IoC容器”甚至更短的容器(有时将“ spring”用作同义词)。

什么是依赖注入?

依赖注入意味着,您的对象通过外部机制接收对其他对象的每个依赖。

假设您有一辆汽车,通常的实现方式是:

public class Car {

    Engine e;

    public Car() { 
        e = new Engine(); 
    }

}

汽车对象取决于引擎。由于发动机是汽车的一部分,因此不能将其换成测试发动机。

现在依赖注入开始起作用:

public class Car {

    Engine e;

    public Car(Engine e) { 
        this.e = e; 
    }

}

之后,您就可以切换引擎了。上面看到的称为构造函数注入。还有其他类型,例如setter -injection或method- injection。Spring如何帮助您?Spring允许它用注解标记要注入的组件@Autowired,并自动完成被注入对象的接线-可能是,您要注入的组件本身具有依赖性。注射剂-可以说-通过以下方式标记@Component

public class Car {

    Engine e;

    @Autowired
    public Car(Engine e) { 
        this.e = e; 
    }

}

但这只是Spring提供的众多功能之一。

我应该使用Spring吗?为什么或者为什么不?

由于Spring的侵入性不是很高,因此可以提供很多帮助,因此您应该考虑使用spring。尤其对于新项目,Spring Boot非常有吸引力。start.spring.io提供了易于使用的point'n'click -interface生成项目模板以进行入门。甚至可以curl用来检索模板:

curl start.spring.io

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

:: Spring Initializr ::  https://start.spring.io

This service generates quickstart projects that can be easily customized.
Possible customizations include a project's dependencies, Java version, and
build system or build structure. See below for further details.

The services uses a HAL based hypermedia format to expose a set of resources
to interact with. If you access this root resource requesting application/json
as media type the response will contain the following links:
+-----------------+-----------------------------------------+
| Rel             | Description                             |
+-----------------+-----------------------------------------+
| gradle-build    | Generate a Gradle build file            |
| gradle-project  | Generate a Gradle based project archive |
| maven-build     | Generate a Maven pom.xml                |
| maven-project * | Generate a Maven based project archive  |
+-----------------+-----------------------------------------+

...

另一方面,诸如sparkdropwizard之类的框架也为快速创建Web应用程序提供了良好的起点。


1
很有信息的答案!
GOXR3PLUS

同意,很好的答案。OP,我同情您。我也有几个人向我展示Spring演示,他们在其中通过添加XML文件和2层间接寻址来“简化”代码,以便他们可以在类上调用构造函数:)您确实只需要深入研究或进入真正好的演示文稿,最终将弄清楚优点和缺点在哪里
Adam Hughes

4

这是一个用Java编写的框架,其中包含许多使Web应用程序正常运行的功能(例如,对国际化的支持)。它还提供了一种将应用程序分层组织的好方法。使用它,从长远来看,它将节省大量时间。

关于Spring的一本好书是:Spring MVC和Web Flow专家

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.