首先,我要大字标语表达立场:

你所使用的framework & non-core features,就跟女人穿在身上的衣服一样,越少越好!

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZGVsdGF0YW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" height="289" width="349">

扯淡完成,说正经的。

让我们继续盯着花姐——啊,不——是 BeanFactory看。

	public static SearchService getSearchService() {
if(MOCK) {
return new SearchServiceMock();
} else {
LuceneDAO luceneDAO = getLuceneDAO();
MysqlDAO mysqlDAO = getMysqlDAO(); return new SearchServiceInRealBiz(luceneDAO, mysqlDAO);
}
}

有木有点儿标题所说的“春天在这里”的意思了?

纳尼?没看出来?

好吧,或许你习惯了spring的xml装配方式,所以认为把两者关联起来看实在须要超常的想象力,那么,

我把BeanFactory改头换面。简单的实现一个基于文本字符串的装配,咋们再来看看效果:

package cn.com.sitefromscrath;

import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.List;
import java.util.Map; public class BeanFactory { private static Map<String, String> appBean = new HashMap<String, String>();
private static Map<String, String[]> appRef = new HashMap<String, String[]>(); static {
appBean.put("luceneDAO", "cn.com.sitefromscrath.dao.LuceneDAOMock");
appBean.put("mysqlDAO", "cn.com.sitefromscrath.dao.MysqlDAOMock");
appBean.put("searchService", "cn.com.sitefromscrath.service.SearchServiceInRealBiz"); appRef.put("searchService", new String[]{"luceneDAO", "mysqlDAO"});
} public static Object getBean(String id) { try { String className = appBean.get(id);
Class clazz = Class.forName(className);
Constructor constructor; String[] ref = appRef.get(id); if(ref == null || ref.length == 0) {
constructor = clazz.getConstructor();
return (Object)constructor.newInstance();
} Class[] parameterTypes = new Class[ref.length];
Object[] initargs = new Object[ref.length]; for(int i = 0; i < ref.length; i++) {
String r = ref[i]; String rclassName = appBean.get(r);
parameterTypes[i] = Class.forName(rclassName).getInterfaces()[0]; //这里我偷懒了:)
initargs[i] = getBean(r);
} constructor = clazz.getConstructor(parameterTypes); return (Object)constructor.newInstance(initargs); } catch (Exception e) {
e.printStackTrace();
return null;
}
} public static void main(String ... arg) { LuceneDAO luceneDAO = (LuceneDAO) getBean("luceneDAO");
int[] vals = luceneDAO.findDocIDs("test");
for(int v : vals) {
System.out.println(v);
} String keywords = "test";
SearchService searchService = (SearchService)getBean("searchService");
List results = searchService.search(keywords);
for(int i = 0; i < results.size(); i++) {
Result result = (Result) results.get(i);
System.out.print("[" + result.title + "]");
System.out.println(result.content);
}
} }

执行结果输出:

1
2
3
4
[result 1]something..................
[result 2]something..................
[result 3]something..................
[result 4]something..................

结果正确!

再看看我们对类的装配:

	private static Map<String, String> appBean = new HashMap<String, String>();
private static Map<String, String[]> appRef = new HashMap<String, String[]>(); static {
appBean.put("luceneDAO", "cn.com.sitefromscrath.dao.LuceneDAOMock");
appBean.put("mysqlDAO", "cn.com.sitefromscrath.dao.MysqlDAOMock");
appBean.put("searchService", "cn.com.sitefromscrath.service.SearchServiceInRealBiz"); appRef.put("searchService", new String[]{"luceneDAO", "mysqlDAO"});
}

请比較和spring.xml的差别:

<?xml version="1.0" encoding="UTF-8"?>
<beans > <bean id="luceneDAO" class="cn.com.sitefromscrath.dao.LuceneDAOMock" /> <bean id="mysqlDAO" class="cn.com.sitefromscrath.dao.MysqlDAOMock" /> <bean id="searchService" class="cn.com.sitefromscrath.service.SearchServiceInRealBiz">
<constructor-arg index="1" ref="luceneDAO" />
<constructor-arg index="2" ref="mysqlDAO" />
</bean> </beans>

好吧,没什么根本上的差别,我们相同可以解析xml,得到我们自己实现的BeanFactory所须要的一切要素。

好了。经过我们将代码从零開始,重复重构,到一个比較“经典”的模式。我们找到了“春天”。这也是spring的core features。

或许是对spring看待的角度不同,我发现我对spring的依赖注入和控制反转的用途和不少人并不一致。下一章。我打算结合一些开发和測试技巧,论述一下我的看法。

只是。如今,是吐槽spring的时间:

我在我的博文《thinking in asp》appendix A - 吐槽JAVA 中以前说到:

还有新版本号的spring,怎么说呢,它把java的annotation机制玩儿到了“奇技淫巧”的程度。

因为那个系列主要是讲视频编转码技术。因此。对spring仅仅是一带而过,如今总算找到机会了:)

Long long ago, in the old good times, spring还是依赖xml做装配的小姑娘,青春漂亮,带着点儿书卷学生气。

可是如今看,这丫头已经涂脂抹粉,跻身上流社会。出入商务场合。尽管不讨厌,可是不让人认为亲近了 -_-b

看传统的 spring.xml,就如同看电路板设计图,一个个元器件清清楚楚,什么型号,怎么走线。怎样装配。尽管没有图形化。可是一目了然,基本上能够做到不用查看源代码。就能把整个系统的逻辑关系梳理的八九不离十。

而自从有了annotation,比方autowire。xml不重要了,你无法再从一个基于spring的大型项目中迅速找到一份天然的“提纲”。

——spring開始不顾一切的媚俗。——或许俺是个受虐狂,只是“ruby way”和“傲娇”的python显然更对我的胃口——设计原则是不能够松口的:)

我以前问spring的一些使用者,怎样找到通过annotation装配尤其是自己主动装配的类,或者是某个隐藏在spring-mvc框架下annotation声明的URL,

给我的答案例如以下:

首先:

然后:

好吧。我得到的结论是:与其如此,不如不用:)

当然,假设你说。通过一些词法/语法解析器,也能够得到基于annotation的“提纲”。比方用 lex+yacc 亦或 antlr 打造一个工具。

本座的答复是:老子被编译原理搞的几宿没睡了,小心一指头把你戳出去三公里远去~~~!

接着。说说spring框架下怎样强測试的问题:

时刻记住。每个模块。甚至最“小”的方法,在实现它之前,都必需要先设计怎样測试它。

由于我们如今讨论的是一个web项目,我想说一个非常多开发人员会使用的方法:

ContextListener --> WebApplication --> BeanFactory

因为spring的“人性化”。这个步骤甚至不须要你写代码。

如今的问题是,假设我们的项目採取这种方式。你怎样做dao 或者 service层的单元測试?

比方前面提到的 SearchService,他须要通过spring装配LuceneDAO 和 MysqlDAO,可是问题出现了:

你假设想让SearchService的方法跑起来,你必须启动TOMCAT等web容器!

这样的紧耦合的程度简直是令人发指 :) 让一切单元測试成为不可能~~~~

而我,在前面的章节重复强调 “不须要启动tomcat。不须要查看网页的实际效果,也能保证系统模块的正确” 就是这个意思:)

当然。spring提供了ApplicationContext,在web容器中相同能用——这也是我使用的方式——可是,我想说的是。spring的WebApplication模式错误的诱导了开发人员。引发了大量的 bad smell。

在玩儿了一把怎样从最简单的需求出发。重复重构到模式/框架之后,下一章我会再次绕回去,spring已经说得够多的啦:)

to be continued.....

开发,从需求出发 &#183; 之四 春天在这里的更多相关文章

  1. 开发,从需求出发 &#183; 之三 春天在哪里

    <西游降魔>里面的<儿歌三百首>里面有首儿歌叫做<春天在哪里> 歌词是这种: 春天在哪里 春天在哪里 春天就在小朋友的眼睛里 通过俺的渣英语翻译之后是这种: whe ...

  2. 开发,从需求出发 &#183; 之二 造飞机的工厂

    CD镇楼~~! 如今.让我们切换到后端开发者的角度看问题.我们须要做的是实现一下这个类,让它返回真实的业务数据. package cn.com.sitefromscrath.service; impo ...

  3. 吴裕雄--天生自然PythonDjangoWeb企业开发:需求

    开发或者做一个项目,是要有一个需求过来的,而不是无缘无故的,启动一个项目,或者推动整个项目进行下一步迭代.这个需求可能是根据用户反馈增加的,可能是老板提出来的,也有可能是产品经理提出来的,但是无论是什 ...

  4. [eShopOnContainers 学习系列] - 00 - 开发环境需求

    开发环境需求 https://github.com/dotnet-architecture/eShopOnContainers/wiki/00.-Dev-machine-requirements 我的 ...

  5. 开发人员需求能kill杀死其它阻塞自己的会话,测试发现需要alter system权限有风险

    模拟开发人员需求,可以杀死其它阻塞自己的会话1.能有查询阻塞会话确认的权限SQL> grant select on v_$session to testa;SQL> grant selec ...

  6. DNF邀请码开发再开发方案需求

    一.原因分析:   1.现实原因:主播粉丝量级有限,一定规模粉丝注册消耗完后无法进 行之后合作 2.主播资源有限,能合作主播数量少   3.直播粉丝真实接近核心用户,但是不能将其有效转化为平台流水   ...

  7. 测试开发【提测平台】分享3-正式开发产品需求&项目初始化

    上两个分享主要是介绍和演示基本前后端所要使用的框架,接下来我们将正式进入到[提测平台的开发] 提要先给出依赖和内容点: 提测平台定义和产品原型需求说明 使用github创建代码仓库进行项目管理 Fla ...

  8. HBase应用开发回顾与总结系列之四:HBase配置管理类接口设计

      利用Eclipse进行HBase应用开发时,至少需要确定三个配置信息,如下表所示: #hbase config #HMaster服务部署主机及端口号 hbase.master=hdp-wuyong ...

  9. iOS开发——项目需求-快速回到当前界面的顶部

    利用UIWindow实现快速到达顶部 如下图,在状态栏添加一个没有颜色的UIWindow(里面添加一个按钮),实现点击这个按钮时能快速的回到当前界面的顶部 核心代码 一.利用UIWindow实现到达顶 ...

随机推荐

  1. Java压缩技术(三) ZIP解压缩——Java原生实现

    原文:http://snowolf.iteye.com/blog/642492 JavaEye的朋友跟我说:“你一口气把ZIP压缩和解压缩都写到一个帖子里,我看起来很累,不如分开好阅读”.ok,面向读 ...

  2. hdu4405Aeroplane chess(概率与期望dp)

    Aeroplane chess Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...

  3. VScode常用插件(持续更新)

  4. 使用javac编译java文件

    过程中遇到的几个问题记录如下: 1.java -version正常显示java版本,但是javac却显示[不是内部外部命令] 原因:JAVA_HOME设置成了用户环境变量,Path里用%JAVA_HO ...

  5. Windows phone开发之文件夹与文件操作系列(一)文件夹与文件操作

    Windows phone7中文件的存储模式是独立的,即独立存储空间(IsolatedStorage).对文件夹与文件操作,需要借助IsolatedStorageFile类. IsolatedStor ...

  6. 【VB】api实现窗口最小化

    Const WM_SYSCOMMAND = &H112 Const SC_MINIMIZE = &HF020& SendMessage hWnd, WM_SYSCOMMAND, ...

  7. 使用DOM解析XML文档

    简单介绍一下使用DOM解析XML文档,解析XML文件案例: <?xml version="1.0" encoding="UTF-8"?> -< ...

  8. C# 写入二进制文件

    写入整型25 文件在MiniHex中显示 写入字符串I am happy 0A 6D - 6D - 这一行数据是C#把字符串转换为16进制形式 不知道为啥用MiniHex打开多了个0A 写入空&quo ...

  9. vue货币格式化组件、局部过滤功能以及全局过滤功能

    一.在这里介绍一个vue的时间格式化插件: moment 使用方法: .npm install moment --save. 2 定义时间格式化全局过滤器 在main.js中 导入组件 import ...

  10. webpack学习(三)

    前篇:webpack学习(二) jquery不需要在项目中自己下载,而是作为一个模块引入.jquery的存放路径是在 node_modules目录下.1.首先给项目安装jquery,npm insta ...