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

你所使用的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. linux的shell函数参数

    在Shell中,调用函数时可以向其传递参数.在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数... 带参数的函数示例: #!/bin/bash funWit ...

  2. curl强制下载文件

    <?phpfunction download_remote_file_with_curl($file_url, $save_to) { $ch = curl_init(); curl_setop ...

  3. Java同步容器总结

    <0>StringBuffer适用于多线程场景,StringBuilder适用于字符串拼接[堆栈封闭] `Vector`实现`List`接口,底层和`ArrayList`类似,但是`Vec ...

  4. MAC软连接

    在mac上不设置环境变量有的时候也可以直接就访问到了某些文件.这个是为什么呢?答案是用了软连接. 1 查看加载文件 可以使用cat命令查看paths文件 cat etc/paths /usr/loca ...

  5. Spring Boot (22) Spring Security

    除了使用拦截器.过滤器实现对没有权限访问的页面跳转到登陆页外,还可以通过框架实现:Spring Security. 使用Spring Security 完成登陆验证: 1.pom.xml添加依赖 &l ...

  6. android黑科技系列——Apk混淆成中文语言代码

    一.前言 最近想爆破一个app,没有加壳,简单的使用Jadx打开查看源码,结果把我逗乐了,代码中既然都是中文,而且是一些比较奇葩的中文字句,如图所示: 瞬间感觉懵逼了,这app真会玩,我们知道因为Ja ...

  7. KVO的使用及底层实现

    1.概念 KVO(Key-Value-Observer)也就是观察者模式,是苹果提供的一套事件通知机制.允许对象监听另一个对象特定属性的改变,并在改变时接收到事件,一般继承自NSObject的对象都默 ...

  8. 【PostgreSQL-9.6.3】log参数的设置

    编辑数据目录中的postgresql.conf参数文件,我的数据目录是/usr/local/pgsql/data vi postgresql.conf 找到如下内容: ... #----------- ...

  9. MSCRM4 在过滤后的LOOKUP框中实现查找

    在MSCRM中让Lookup根据一定的条件实现过滤功能, 这个需求很常见, 在我接触的诸多项目中似乎都需要有这个功能. 但非常遗憾是, MSCRM 的SDK并没有提供实现这个功能的方法. 不过我们应该 ...

  10. HDU_5833_高斯消元

    参考自:http://www.cnblogs.com/flipped/p/5771492.html 自己做的时候不知道如何求种数.看了题解,感觉思路灰常巧妙.同时也感觉这是一道好题. 精髓在于转化为线 ...