`
chenge
  • 浏览: 44863 次
  • 性别: Icon_minigender_1
  • 来自: 上海
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

spring的价值的质疑

阅读更多

我一直对spring的做法不十分理解,最近这个讨论证实了我的疑问《依赖注入是否值得?》。

 

spring的主要价值似乎是支持单元测试,而这个工作可以由mock框架完成。

 

我现在做的项目是asp.net, 主要用到NHibernate, 确实没感觉到用spring的必要。

 

我学习过spring当然了解有限,不过感觉中小型项目都不必要采用,徒然增加复杂性和开发人员的学习负担,没有必要别扭地采用IOC。

 

评论
23 楼 fch0402 2008-01-16  
这个还用讨论,楼主觉得怎么用方便就怎么用啊,大家用得着如此苦心婆口吗。又:楼主实际用过SPRING没有?
22 楼 chenge 2008-01-16  
如果没有更清楚的例子说明的话,那只能说明依赖注入是不必要的。

spring的价值应该是体现在事务处理和AOP。
解决测试问题应该用mock,而不是spring.(without ejb书中似乎也是在说DI支持测试)

开发人员需要优先学习struts/jsf,hibernate,mock. 我买的spring书的钱和时间可能白花了。

21 楼 dwangel 2008-01-15  
spring 是粘合剂,strategy模式也可以被粘进去。
20 楼 chenge 2008-01-12  
skydream:

我看了你的例子,我明白你的意思了。你的例子我觉得可以用Strategy策略模式解决,实际上有个说法就是spring就是策略模式。

19 楼 daquan198163 2008-01-11  
<div class='quote_title'>chenge 写道</div><div class='quote_div'><pre name='code' class='java'>        Publisher publisher = new Publisher();
        publisher.add(subscriber);
</pre> Publisher, Subscriber不就是相当于您说的A,B吗?</div><p>你这不就是自己手动实现的依赖注入吗,跟我例子里的A,B怎么会是一回事呢?</p><p>并不是所有场景都适合用“观察者”模式的。</p><p> </p><p>如果出现了这样的代码:InterfaceB b=new B();你还怎么替换b?<img title='confused' src='../../../../../../images/smiles/icon_confused.gif' border='0' alt='confused'/> </p><p> </p>
18 楼 skydream 2008-01-11  
去看了一下“依赖注入是否值得?”的那个帖子,发现有些道理和我上面举的列子是相通的:

1. "虽然能够方便地编写Mock代码是很棒的特性,但这只是主要利益之外的附带好处,主要的利益是降低了对象间的耦合。我可以修改数据访问部分的代码,而不需要触及负责工资计算的引擎,这是我得到的主要益处。"

我的例子中如何注册和如何获取“用户名的最大长度”,成功解耦。任意修改一个都不对对方造成任何影响。

2."简单来说,依赖注入让你的代码更容易改变。这就是它在敏捷社群中流行的原因,他们的整个软件开发实践都围绕着快速变化。"

我的例子中完成ldap取配制的需求时,明显体现了快速变化的优势。
17 楼 skydream 2008-01-11  
花了一个小时回贴,自己都觉得辛苦,呵呵

希望能对楼主有所帮助。
16 楼 skydream 2008-01-11  
chenge 写道

楼上朋友能给出一个无法mock的例子吗?


这儿应该不是能与不能的问题,不是那么绝对,如果一定要用能与不能来做判断,那么java都不必出现了,理论上没有c+=甚至c,汇编搞不定的问题。

而是说,依赖注入对设计有利,而spring则促进了依赖注入的使用。

如果业务处理类,它所使用的倚赖,都是依靠在这个类内部实现或者查找,那么必然使得正常的业务逻辑和获取依赖的方法混在一起。

我取个最简单的场景,某个注册的工作类,它需要获取当前"容许的用户名的最大长度",这个依赖非常简单吧?基本每个注册类都有这个限制,我们现在把场景考虑的全面一点,对于复杂一点的系统,这个最大长度的限制可能来源很多,比如配制文件,数据库,可能类工作在前台比如web而配制在后台,可能需要和第三放系统一起工作而需要到第三方系统中获取而对方只提供web service...

这么一个简单的依赖,“用户名的最大长度”,如果用依赖注入,只要一个简单的setUsernameMaxLength()方法就可以搞定。考虑上面那么多种可能都出现,最恶劣的情况是要求一个系统可以同时支持然后通过配制方式进行,这对于将一个产品卖给n家客户的公司来说是最正常不过的要求。

那么我们来看一个很有"spring"风格的采用依赖注入的设计,通常都将会是这样:

注册工作类:
public void RegisterWork {
    public void setUsernameMaxLengthProvider(UsernameMaxLengthProvider provider) {
        int maxLength = provider.getUsernameMaxLength(); //简单获取结果,不管provider细节
    }
    ....
}
“用户名的最大长度”的提供者接口
public interfacd UsernameMaxLengthProvider {
    public int getUsernameMaxLength();
}
“用户名的最大长度”的提供者则可以有以下实现,都只负责读取数据,不关心数据被谁使用,怎么使用:
1.直接提供,可以用spring 构造函数方式注入usernameMaxLength值,也可以junit测试时直接new DirectdProvide对象
public class DirectdProvider implements UsernameMaxLengthProvider  {
    private int usernameMaxLength = 10;
    public int getUsernameMaxLength() {
        return UsernameMaxLength;
    }
    public DirectdProvider (int usernameMaxLength) {
        this.usernameMaxLength = usernameMaxLength;
    }
}
2.读本地配制文件
public class LocalConfigFileProvider implements UsernameMaxLengthProvider  {   
    public void read(File configFile) {
        usernameMaxLength = ....
    }
}
3.类似的从数据库读取 DatabaseProvide
4.类似的web service从第三方读取 WebServiceProvider
5.其他的可能扩展的方式

开发时逻辑清晰,代码可读性超强,基本看类名和函数名搞定。测试时,轻松测试RegisterWork,testcase中只要worker.setUsernameMaxLengthProvider(new DirectdProvider(20))就搞定。而针对UsernameMaxLengthProvider的几个实现类,更是轻松使用junit,每个都覆盖一遍。

呵呵,现在我们可以砍刀,最简单的一个int型的“用户名的最大长度”,都可能遭遇如此复杂的场景。如果不用倚赖注入,而是选择在RegisterWork中自己搞定“用户名的最大长度”的获取,那么可能要遇到以下问题:
1. RegisterWork极其复杂,可以想像类似的依赖肯定还有其他
2. 获取“用户名的最大长度”的方式和注册的业务处理逻辑完全没有直接联系,对注册过程来说它只关注结果,“用户名的最大长度”是10还是20,而不是到底读本地文件还是读数据库。喧宾夺主了,次要逻辑干扰了主要逻辑
3. 难于测试。获取“用户名的最大长度”的方式的这些代码,被藏在RegisterWork类中,而且很有可能是private方法不对外暴露(如果不依赖注入还需要暴露吗?暴露给谁呢),怎么用mock测试?怎么能保证以上几种的实现都覆盖到?
4. 难于扩展。就算上面都搞定了,某一天突然来了一个变态需求,要求用ldap从另一个地方取配置呢?难道再把ldap请求的那一大片代码也写到RegisterWork里面?
5. 更难于被第三方扩展。运气好,上面这个ldap取配制的变态需求客户开始没有要求。顺利开发完成测试通过然后准备上线,最后一晚了客户才发现,"哦,给忘了,你们想办法给加上,快,快,明天一早就要上线运行了...你们写死在代码里面了?那只能你们修改了原代码了"。吐血了吧,先骂一顿,可是活还的干啊,咬牙切齿的把新的实现代码加上了,还得编译打包更新重启...如果是spring多好,单独写一个LdapProvider类,测试(这个测试比杂在RegisterWork里面测试简单的多)通过后单独提供这个class仍classpath下,修改spring的配制将原来的***Provider替换掉,轻松搞定,甚至可以把这活仍给客户的开发人员,告诉他们怎么替换就可以了,管你ladp还是其他,谁让你们需求不明确,自己扩展去。
6. 容易出错。刚吐血完成上面的变态需求,更新完毕,一会客户电话来了,“...怎么...不正常了?”。又吐血几升地检查,终于找出来了,原来是刚才写ladp访问的代码时不小心改错了RegisterWork的一个地方,谁让RegisterWork类有几十上百个方法好几千行呢,一时急,又没有测试到......可是客户不会理解的。

上述的场景,spring + 依赖注入的设计方式,优点很明显吧。

再考虑一下维护和二次开发的问题,上面的spring + 依赖注入的代码,好看易懂,方便扩展,维护起来轻松。如果是那么堆在RegisterWork里面,在那个大堆中代码要找出这些代码并读懂,估计不是件轻松的事情。

代码维护是需要成本的,写出易于维护的代码,是一个优秀程序员的基本素养,至少,不能让下一个接手的人骂娘吧?
15 楼 dwangel 2008-01-11  
DI不是只是用来作单元测试的。
14 楼 fuliang 2008-01-11  
<div class='quote_title'>chenge 写道</div><div class='quote_div'><p>我一直对spring的做法不十分理解,最近这个讨论证实了我的疑问<a href='http://www.infoq.com/cn/news/2007/12/does-di-pay-off'>《依赖注入是否值得?》。</a></p><p> </p><p>spring的主要价值似乎是支持单元测试,而这个工作可以由mock框架完成。</p><p> </p><p>我现在做的项目是asp.net, 主要用到NHibernate, 确实没感觉到用spring的必要。</p><p> </p><p>我学习过spring当然了解有限,不过感觉中小型项目都不必要采用,徒然增加复杂性和开发人员的学习负担,没有必要别扭地采用IOC。</p><a href='http://www.infoq.com/cn/news/2007/12/does-di-pay-off'/><p> </p></div><p><br/>Spring IOC使用起来相当自然,何谈扭曲的使用...,即使你只使用Spring的基本ioc容器,你也会获益良多...</p><p>"spring的主要价值似乎是支持单元测试",容易进行单元测试只是spring带来的一点附加值而已... </p><p>依赖注入那么好的编程模型如果都不值得的话,真不知道还有什么值得的了...</p>
13 楼 chenge 2008-01-11  
<pre name='code' class='java'>import org.jmock.Mockery;
import org.jmock.Expectations;

class PublisherTest extends TestCase {
    Mockery context = new Mockery();

    public void testOneSubscriberReceivesAMessage() {
        // set up
        final Subscriber subscriber = context.mock(Subscriber.class);

        Publisher publisher = new Publisher();
        publisher.add(subscriber);
       
        final String message = "message";
       
        // expectations
        context.checking(new Expectations() {{
            one (subscriber).receive(message);
        }});

        // execute
        publisher.publish(message);
       
        // verify
        context.assertIsSatisfied();
    }
}</pre> Publisher, Subscriber不就是相当于您说的A,B吗?<br/>
12 楼 daquan198163 2008-01-11  
您仔细看看我的代码,A里面写死了InterfaceB b=new B();
这种情况下,怎么把b替换成mock来测?
11 楼 chenge 2008-01-11  
那个JMock的例子似乎回答了您的问题。
10 楼 daquan198163 2008-01-11  
chenge 写道
用接口也就是更灵活的插件式结构,但是这个是有代价的。应该是只在需要的地方用。

楼上朋友能给出一个无法mock的例子吗?

感觉这个问题的讨论还是有价值的,hibernate的价值是明显的,界面层是必需的,而spring觉得不是必需的,至少是中小型项目不需要。


Class A{
public void doSth(){
 InterfaceB b=new B();
 b.do();
 .....
 .....
}
}

这种情况,怎么mock B来隔离测试A呢?

9 楼 chenge 2008-01-11  
<p>我看了Guice的说明。<br/><br/>我感觉当时的背景是j2ee难以测试,而mock也是新出来的技术。spring出来后能解决这个测试难的问题(有比较大的代价),于是受到欢迎,似乎遮蔽了mock框架。<br/><br/>我接触过NMock, TypeMock. java有JMock.这些都是动态mock框架,根本不需要写如下的mock class:                 public class MockService implements Service <br/><br/>所以只是因为测试问题是应该采用mock框架。</p><p> </p><p>这里是<a href='http://www.jmock.org/getting-started.html'>Jmock的例子</a></p><p> </p>
8 楼 eddie404956 2008-01-11  
你用了SPRING,维护的人会感谢你的
7 楼 robert 2008-01-11  
lz 不知道用的什么 mock 方法?可否贴一个上来?
Spring 就是一个 ioc 容器,所以你的问题实际上是 ioc 模式的作用,简而言之,就是真正地分割各对象,将对象的实例化放到对象外面去。
Google guice 的网站上的使用说明上给了很强很和谐的例子,去看看好了。
6 楼 chenge 2008-01-11  
用接口也就是更灵活的插件式结构,但是这个是有代价的。应该是只在需要的地方用。

楼上朋友能给出一个无法mock的例子吗?

感觉这个问题的讨论还是有价值的,hibernate的价值是明显的,界面层是必需的,而spring觉得不是必需的,至少是中小型项目不需要。
5 楼 skydream 2008-01-11  
依赖注入啊,一定要尽量坚持这个原则,否则junit测试简直无法进行。

即使不用spring,也要尽量使用依赖注入,这样写出来的代码才是测试友好的。

mock再方便,也不如一个setter方法调用简单。
4 楼 daquan198163 2008-01-11  
<div class='quote_title'>chenge 写道</div><div class='quote_div'><p>我一直对spring的做法不十分理解,最近这个讨论证实了我的疑问<a href='http://www.infoq.com/cn/news/2007/12/does-di-pay-off'>《依赖注入是否值得?》。</a></p><p> </p><p>spring的主要价值似乎是支持单元测试,<span style='color: #ff0000;'>而这个工作可以由mock框架完成</span>。</p><p> </p><p>我现在做的项目是asp.net, 主要用到NHibernate, 确实没感觉到用spring的必要。</p><p> </p><p>我学习过spring当然了解有限,不过感觉中小型项目都不必要采用,徒然增加复杂性和开发人员的学习负担,没有必要别扭地采用IOC。</p><a href='http://www.infoq.com/cn/news/2007/12/does-di-pay-off'/><p> </p></div><p>spring的主要价值之一是让单元测试更容易,否则组件之间都硬链接,你会发现无从mock</p>

相关推荐

    Spring Boot整合Spring Batch,实现批处理

    在Java开发领域,Spring Boot和Spring Batch的整合是构建高效...通过学习和实践这个示例,你不仅可以掌握如何在Spring Boot中使用Spring Batch,还能了解批处理的最佳实践,这对于处理大数据量的应用场景非常有价值。

    Spring Integration + Spring WS 整合

    Spring Integration + Spring WS 整合 在 Java 领域中,Spring Integration 和 Spring WS 是两个常用的框架,它们分别负责集成系统和 Web 服务。今天,我们将探讨如何将这两个框架整合在一起,实现一个完整的 Web ...

    spring2.0升级到spring3.0.5的开发包

    Spring框架是Java应用程序开发中的一个核心组件,它提供了一个丰富的IOC(Inversion of Control,控制反转)和AOP(Aspect-Oriented Programming,面向切面编程)功能,使得开发者能够更方便地管理对象和实现模块化...

    SpringCloud中文文档

    它提供了多种具体方式来促进云原生应用程序的开发风格,鼓励在持续交付和价值驱动开发领域轻松采用最佳实践。 Spring Cloud 的核心组件包括 Spring Cloud Context 和 Spring Cloud Commons。Spring Cloud Context ...

    spring配置 spring配置 spring配置 spring配置 spring配置

    spring配置 spring配置 spring配置 spring配置 spring配置

    SpringBatch+Spring+Mybatis+MySql (spring batch 使用jar)

    Spring Batch是一个轻量级的,完全面向Spring的批处理框架,可以应用于企业级大量的数据处理系统。Spring Batch以POJO和大家熟知的Spring框架为基础,使开发者更容易的访问和利用企业级服务。Spring Batch可以提供...

    Spring技术内幕:深入解析Spring架构与设计原理[汇编].pdf

    Spring技术内幕:深入解析Spring架构与设计原理 Spring是Java企业应用开发的主要框架之一...Spring架构和设计原理对Java开发者具有重要影响,Spring的核心概念、架构设计和关键技术点对Java开发者具有重要参考价值。

    Spring Cloud Gateway 整合 Spring Security 统一登录认证鉴权

    在构建分布式系统时,Spring Cloud Gateway 作为微服务架构中的边缘服务或 API 网关,扮演着至关重要的角色。它负责路由请求到相应的微服务,并可以提供过滤器功能,如限流、熔断等。而Spring Security 则是 Java ...

    spring3.0.5 所有jar文件

    包含spring 3.0.5的所有jar文件: org.springframework.aop-3.0.5.RELEASE.jar org.springframework.asm-3.0.5.RELEASE.jar org.springframework.aspects-3.0.5.RELEASE.jar org.springframework.beans-3.0.5.RELEASE...

    spring类库 spring类库

    Spring框架是Java开发中不可或缺的一部分,它以其模块化、松耦合和强大的功能特性而闻名。这个"spring类库"包含的资源可以帮助开发者快速搭建基于Spring的项目环境。以下是对Spring框架及其核心组件的详细解释。 ...

    learning spring boot 2.0

    书中除了可能包含基础入门知识外,也很可能涵盖了对于Spring Boot高级特性的讨论,比如微服务架构和响应式编程的实践,这些内容在当下Java开发领域中非常流行且具有实际应用价值。 标签“spring boot”、“java”、...

    SpringCloud.pdf

    云原生应用程序是Spring Cloud 支持的一种开发范式,鼓励采用持续交付和以价值为导向的开发实践。Spring Cloud 通过与12要素应用原则保持一致,利用声明式编程和监控来推动这些实践。它在 Spring Boot 的基础上增加...

    spring3.1 官方全部jar包

    spring3.1官方所有的jar包 org.springframework.aop-3.1.RELEASE.jar org.springframework.asm-3.1.RELEASE.jar org.springframework.aspects-3.1.RELEASE.jar org.springframework.beans-3.1.RELEASE.jar org....

    spring-framework-5.3.20

    本次我们将深入探讨Spring Framework的最新版本5.3.20,揭示其在企业级开发中的核心价值与重要特性。 一、Spring Framework概述 Spring Framework是Spring生态系统的基石,它提供了一个全面的编程和配置模型,旨在...

    spring3框架 spring3框架

    Spring 框架是Java开发中的一个核心框架,尤其在企业级应用开发中广泛使用。Spring3作为其较早的一个版本,尽管已经被后续的...虽然Spring3已经比较老旧,但其基本思想和设计模式在现代Java开发中仍然具有很高的价值。

    spring-petsore spring官方最新demo

    这个项目对于学习Spring MVC、Spring Data、Spring Boot等技术具有极大的参考价值。 一、Spring MVC Spring MVC是Spring框架的一部分,负责处理Web应用程序的请求和响应。在PetClinic中,Spring MVC扮演着控制器的...

    Spring学习笔记(精华全记录)

    尽管有人质疑Spring是否完全遵循Java标准,但其广泛应用和良好口碑证明了它的价值。 #### Spring的核心特点 1. **轻量级**:Spring框架非常小巧,与重量级的企业Java Beans (EJB) 相比,它更适用于小型项目或模块...

    spring4.3.1官方全套jar包下载

    spring4.3.1全套jar下载。 4.3.1/spring-aop-4.3.1.RELEASE.jar 4.3.1/spring-aspects-4.3.1.RELEASE.jar 4.3.1/spring-beans-4.3.1.RELEASE.jar 4.3.1/spring-context-4.3.1.RELEASE.jar 4.3.1/spring-core-4.3.1....

    spring-boot中文教程

    名称:Spring Boot中文文档 类型:文档 描述:Spring Boot中文文档是Spring Boot官方文档的中文翻译版,它包含了Spring Boot的基本介绍、快速入门、核心...其他说明:Spring Boot中文文档是一份非常有价值的参考资料

Global site tag (gtag.js) - Google Analytics