ClassNotFoundException [sv]

Eclipse Debugging Error: ClassNotFoundException

I just hit a really annoying (sort of) bug in Eclipse. I could not debug any of my projects because they immediately stopped with a call stack like the following:
terrain.TerrainApp at localhost:49827
Thread [main] (Suspended (exception ClassNotFoundException))
ClassLoader.findBootstrapClass(String) line: not available [native method]
Launcher$ExtClassLoader(ClassLoader).findBootstrapClass0(String) line: not available
Launcher$ExtClassLoader(ClassLoader).loadClass(String, boolean) line: not available
Launcher$AppClassLoader(ClassLoader).loadClass(String, boolean) line: not available
Launcher$AppClassLoader.loadClass(String, boolean) line: not available
Launcher$AppClassLoader(ClassLoader).loadClass(String) line: not available
Launcher$AppClassLoader(ClassLoader).loadClassInternal(String) line: not available

I found people with similar issues on various message boards, but no solutions.

Then I figured out that if I kept hitting continue (to go past the breakpoint) it would eventually reach my actual application. Along the way though, java was triggering ClassNotFoundExceptions for every single class referenced in my code, which was causing Eclipse to break. It turns out that these ClassNotFoundExceptions are normal behavior – they are supposed to happen for every new class, but having eclipse set a breakpoint for each one is definitely not!

To solve the problem, I had to open up the breakpoint window and disable the breakpoint “ClassNotFoundException: caught and uncaught” — I have no idea how this breakpoint got set in the first place, I certainly didn’t do it!

So now I can finally debug my programs without relying on tons of print statements… that should help my progress.

103个Windows XP运行命令

用户必备资料 103个Windows XP运行命令

在Windows系统中,我们打开一些程序都是通过鼠标一步一步的点击来打开,但是以下列出的这些命令,可以让你在Windows XP的“运行”窗口中运行应用程序。

运行程序 运行命令
辅助功能选项 access.cpl

添加硬件向导 hdwwiz.cpl

添加或删除程序 appwiz.cpl

管理工具 control admintools

自动更新 wuaucpl.cpl

Bluetooth文件传送向导 fsquirt

计算器 calc

证书管理控制台 certmgr.msc

字符映射表 charmap

磁盘检查工具 chkdsk

剪贴簿查看器 clipbrd

命令行提示符 cmd

组件服务 dcomcnfg

计算机管理 compmgmt.msc

日期和时间属性 timedate.cpl

DDE共享 ddeshare

设备管理器 devmgmt.msc

Direct X控制面板(如果已经安装)* directx.cpl

Direct X诊断工具 dxdiag

磁盘清理工具 cleanmgr

磁盘碎片整理程序 dfrg.msc

磁盘管理 diskmgmt.msc

磁盘分区管理器 diskpart

显示属性 control desktop

显示属性 desk.cpl

显示属性的外观选项卡 control color

Dr. Watson系统诊断工具 drwtsn32

Driver Verifier Manager verifier

事件查看器 eventvwr.msc

文件签名验证 sigverif

快速查找 findfast.cpl

文件夹选项 control folders

字体文件夹 control fonts

字体文件夹 fonts

空档接龙游戏 freecell

游戏控制 joy.cpl

组策略编辑器(XP专业版) gpedit.msc

红心大战游戏 mshearts

Iexpress向导 iexpress

索引服务 ciadv.msc

Internet属性 inetcpl.cpl

IP配置实用程序(显示连接配置) ipconfig /all

IP配置实用程序(显示DNS缓存内容) ipconfig /displaydns

IP配置实用程序(删除DNS缓存内容) ipconfig /flushdns
IP配置实用程序(释放全部(或指定)适配器的由DHCP分配的动态IP地址) ipconfig /release

IP配置实用程序(为全部适配器重新分配IP地址) ipconfig /renew

IP配置实用程序(刷新DHCP并重新注册DNS) ipconfig /registerdns

IP配置实用程序(显示DHCP Class ID) ipconfig /showclassid

IP配置实用程序(修改DHCP Class ID) ipconfig /setclassid

Java控制面板(如果已经安装) jpicpl32.cpl

Java控制面板(如果已经安装) javaws

键盘属性 control keyboard

本地安全设置 secpol.msc

本地用户和组 lusrmgr.msc

从Windows注销 logoff

微软聊天程序 winchat

扫雷游戏 winmine

鼠标属性 control mouse

鼠标属性 main.cpl

网络连接 control netconnections

网络连接 ncpa.cpl

网络安装向导 netsetup.cpl

记事本 notepad

Nview桌面管理器(如果已经安装) nvtuicpl.cpl

对象包装程序 packager

ODBC数据源管理器 odbccp32.cpl

屏幕键盘 osk

AC3解码器(如果已经安装 ac3filter.cpl

密码属性 password.cpl

性能 perfmon.msc

性能 perfmon

电话与调制解调器选项 telephon.cpl

电源选项属性 powercfg.cpl

打印机和传真 control printers

打印机文件夹 printers

TrueType造字程序 eudcedit

Quicktime(如果已经安装 QuickTime.cpl

区域和语言选项 intl.cpl

注册表编辑器 regedit

注册表编辑器 regedit32

远程桌面 mstsc

可移动存储 ntmsmgr.msc

可移动存储操作请求 ntmsoprq.msc

策略的结果集 (XP专业版) rsop.msc

扫描仪与相机 sticpl.cpl

任务计划 control schedtasks

Windows安全中心 wscui.cpl

服务 services.msc

共享文件夹 fsmgmt.msc

关闭Windows shutdown

声音和音频设备属性 mmsys.cpl

蜘蛛牌游戏 spider

SQL Client客户端网络实用工具 cliconfg

系统配置编辑器 sysedit

系统配置实用程序 msconfig

系统文件检查工具(立即扫描) sfc /scannow

系统文件检查工具(下次启动时扫描) sfc /scanonce

系统文件检查工具(每次启动时扫描) sfc /scanboot

系统文件检查工具(返回默认设置) sfc /revert

系统文件检查工具(清除文件缓存) sfc /purgecache

系统文件检查工具(设置缓存大小=x) sfc /cachesize=x

系统属性 sysdm.cpl

任务管理器 taskmgr

Telnet客户端 telnet

用户帐户管理 nusrmgr.cpl

辅助工具管理器 utilman

Windows防火墙 firewall.cpl

Windows放大镜 magnify

Windows管理体系结构 wmimgmt.msc

Windows系统安全工具 syskey

运行Windows更新 wupdmgr

漫游Windows XP tourstart

写字板 write

台湾清华彭明辉教授的研究生指导手册

2006-3-22

——————————————————————————–

台湾清华彭明辉教授的研究生指导手册 编者注:彭明辉教授的文章系统地介绍了自己培养研究生的一些经验,很值得一读。文章开头说的好:“在论文中,你必须要有能力提出足够的证据来让读者信服说:针对这个应用场合,你所提出来的方法确实有比文献中一切既有方法更优越之处。此外,你必须要能清楚指出这个方法在应用上的限制,并且提出充分证据来说服读者:任何应用场合,只要能够满足你所提出来的假设(前提)条件,你的方法就一定适用,而且你所描述的优点就一定会存在。你还必须要在论文中清楚指出这个方法的限制和可能的缺点(相对于其它文献上的既有方法,或者在其它应用场合里)。”这种一丝不苟探求学问的精神尤其值得倡导和发扬。 一、论文的要求 我对硕士论文的基本要求是: (1)论文的主要内容,是叙述一套方法在一个特定场合中的应用。 (2)这套方法必须要有所创新或突破,并因而对学术界有所贡献。因此,它或者是解决既有问题的新方法,或者是既有方法的新应用,或者是以一个新的方法开启一整片新的应用领域。 (3)在论文中,你必须要有能力提出足够的证据来让读者信服:针对这个应用场合,你所提出来的方法确实有比文献中一切既有方法更优越之处。 (4)此外,你必须要能清楚指出这个方法在应用上的限制,并且提出充分证据来说服读者:任何应用场合,只要能够满足你所提出来的假设(前提)条件,你的方法就一定适用,而且你所描述的优点就一定会存在。 (5)你还必须要在论文中清楚指出这个方法的限制和可能的缺点(相对于其它文献上的既有方法,或者在其它应用场合里)。假如这个方法有任何重大缺点,在口试时才被口试委员指出来,其后果有可能是论文无法通过。 (6)行文风格上,它是一篇论证严谨,逻辑关系清晰,而且结构有条理的专业论述。也就是说,在叙述你的方法的过程,你必须要清清楚楚地交代这个方法的应用程序以及所有仿真或实验结果的过程,使得这个专业领域内的任何读者,都有办法根据你的描述,在他的实验室下复制出你的研究成果,以便确定你的结论确实是可以“在任何时间、任何地点、任何人”都具有可重复性(可重复性是「科学」的根本要求)。 (7)而且,你对这个方法的每一个步骤都必须要提供充分的理由说明“为什么非如此不可”。 (8)最后,你的论文必须要在适当位置清楚注明所有和你所研究之题目相关的文献。而且,你必须要记得:只要是和你所研究的问题相关的学术文献(尤其是学术期刊论文),你都有必要全部找出来(如果漏掉就是你的过失),仔细读过。假如你在学位论文口试时,有口试委员指出有一篇既有文献,在你所讨论的问题中处理得比你的方法还好,这就构成你论文无法及格的充分理由。 (9)第(2)款所谓“对学术界的贡献”,指的是:把你的所有研究成果扣除掉学术界已经发表过的所有成果(不管你实际上有没有参考过,没有参考过也算是你的重大过失),剩下的就是你的贡献。假如这个贡献太少,也构成你论文无法及格的充分理由。 上面所叙述的九款要件中,除第(2)款之外,通通都是必须要做到的,因此没有好坏之分。一篇硕士论文的好坏(以及成绩的评定标准),主要是看第(2)款所谓「对学术界的贡献」的多寡与重要性而定。假如你要申请国外的博士班,最重要的也是看你的硕士论文有什么“贡献”而定(这往往比TOFEL、GRE、GPA还重要)。 一个判断硕士论文的好坏有一个粗浅办法:假如你的研究成果可以在国外著名学术期刊(journals,而非 magazines)上发表,通常就比一篇只能在国外学术会议(conferences)上发表的硕士论文贡献多;一篇国外学术会议的论文又通常比无法发表的论文贡献多;在国际顶尖学术期刊上发表的论文通常比一篇二流的学术期刊论文贡献多。SCI有一种叫做 Impact Factor 的指数,统计一个期刊每篇论文被引述的次数。通常这个次数(或指数)愈高,对学术界的影响力就愈大。以机械视觉相关领域的期刊而言,Impact Factor 在 1.0 以上的期刊,都算是顶尖的期刊。这些期刊论文的作者,通常是国外顶尖学府的著名教授指导全球一流的博士生做出来的研究成果。 二、完成硕士论文所需要的能力 从前面的叙述可以归纳出来,完成硕士论文所需要的能力包括以下数项,依它们的培养先后次序逐项讨论。 (1)资料检索的能力:在给定(或自己拟定)的题目范围内,你必须有能力利用文资料索引系统,查出所有相关的论文,而无任何遗漏(否则你可能在论文口试时才发现同一个题目已经有人发表过了)。 你到底要用什么样的关键词和查所程序去保证你已经找出所有相关的文献?这是第一个大的挑战。每一组关键词(包含联集与交集)代表一个论文所构成的集合,假如你用的关键词不恰当,你可能找到的集合太小,没有涵盖所有的相关文献;假如你用的关键词太一般化(譬如image),通常你找到的集合会太大,除了所有相关文献之外还加上好几十倍的毫不相关的文献。 (2)资料筛选的能力:即使你使用了恰当的搜寻策略,通常找到的文献集合都还是明显地比你所需要的集合大,而且通常文献比数大概在一两百篇或数百篇之间,而其中会和你的研究子题直接且密切相关的论文,通常只有廿、卅篇左右。你如何可以只读论文的题目、摘要、简介和结论,而还没有完全看懂内文,就准确地判断出这篇论文中是否有值得你进一步参考的内容,以便快速地把需要仔细读完的论文从数百篇降低到廿、卅篇?这考验着你从事资料筛选的能力。 (3)期刊论文的阅读能力:期刊论文和大学部的课本截然不同。大学部的课本是寻次渐进地从最基本的知识背景逐步交代出整套有系统的知识,中间没有任何的跳跃,只要你逐页读下去,就可以整本都读懂,不需要在去别的地方找参考资料。但是期刊论文是没头没尾的十几页文献,只交代最核心的创意,并援引许多其它论文的研究成果(但只注明文献出处,而完全没有交代其内容)。因此,要读懂一篇论文,一定要同时读懂数篇或十数篇被援引的其它论文。偏偏,这十几篇被援引的论文又各自援引十数篇其它论文。因此,相对于大学部的教科书而言,期刊论文是一个极端没有系统的知识,必须要靠读者自己从几十篇论文中撷取出相关的片段,自己组织成一个有系统的知识,然后才有办法开始阅读与吸收。要培养出这种自己组织知识的能力,需要在学校靠着大量而持续的时间去摸索、体会,而不可能只利用业余的零星时间去培养。因此,一个大学毕业后就不再念研究所的学生,不管他在大学部有多优秀,都很难在工业界利用业余的时间去培养出这种能力。所以,硕士毕业生和大学毕业生最大的差别,就是:学士只学习过吸收系统知识的能力(也就是读别人整理、组织好的知识,典型的就是课本);但硕士则学习过自己从无组织的知识中检索、筛选、组织知识的能力。 (4)期刊论文的分析能力:为了确定你的学位论文研究成果确实比所有相关的学术期刊论文都更适合处理你所拟定的应用场域,首先你必须要有能力逐篇分析出所有相关期刊论文的优点与缺点,以及自己的研究成果的优点与缺点,然后再拿他们来做比较,总结出你的论文的优点和缺点(限制)。但是,好的期刊论文往往是国外著名学府的名师和一流的博士生共同的研究成果,假如你要在锁定的应用场域上「打败」他们,突出自己的优点,这基本上是一个极端困难的挑战。即使只是要找出他们的缺点,都已经是一个相当困难的工作了。一个大学毕业生,四年下来都是假定“课本是对的”这样地学下来的,从来没有学习如何分析课本知识的优缺点,也就是“只有理解的能力,而没有批判的能力”。硕士生则必须要有“对一切既有进行精确批判”的能力。但是,这个批判并非个人好恶或情绪化的批判,而是真的找得到充分理由去支持的批判。这个批判的能力,让你有能力自己找到自己的优、缺点,因此也有机会自己精益求精。所以,一个大学毕业生在业界做事的时候,需要有人指导他(从事批判性检验),帮他找出缺点和建议改进的可能性。但是,一个严格训练过的合格硕士,他做事的时候应该是不需要有人在背后替他做检证,他自己就应该要有能力分析自己的优、缺点,主动向上级或平行单位要求支持。其实,至少要能够完成这个能力,才勉强可以说你是有“独立自主的判断能力”。 (5)创新的能力:许多大学毕业的工程师也能创新,但是硕士的创新是和全世界同一个学术团体内所有的名师和博士生挑战。因此,两者是站在不同的比较基础上在进行的:前者往往是一个企业内部的“闭门造车”,后者是一个全球的开放性竞争。其次,工程师的创新往往是无法加以明确证明其适用条件,但是学术的创新却必须要能够在创新的同时厘清这个创新的有效条件。因此,大学毕业生的主要能力是吸收既有知识,但硕士毕业生却应该要有能力创造知识。此外,台湾历年来工业产品的价位偏低,这一部分是因为国际大厂的打压以及国际消费者的信任不易建立。但是,另一方面,这是因为台湾的产品在品质上无法控制,因此只好被当作最粗 糙的商品来贩卖。台湾的产品之所以无法有稳定的品质,背后的技术原因就是:各种创新都是只凭一时偶然的巧思,却没有办法进一步有系统地厘清这些巧思背后可以成立的条件。但是,创新其实是可以有一套“有迹可寻”的程序的,这是我最得意的心得,也是我最想教的。 三、为什么要坚持培养阅读与分析期刊论文的能力 我所以一直坚持要训练研究生阅读与分析期刊论文的能力,主要是为了学生毕业后中长期的竞争力着想。 台湾从来都只生产国外已经有的产品,而不事创新。假如国外企业界比国外学术的技术落后三年,而台湾的技术比国外技术落后五年,则台湾业界所需要的所有技术都可以在国外学术期刊上找到主要的理论依据和技术核心构想(除了一些技术的细节和 know how 之外)。因此,阅读期刊的能力是台湾想要保持领先大陆技术的必备条件。 此外,只要能够充分掌握阅读与分析期刊论文的技巧,就可以水到渠成地轻松进行“创新”的工作。所以,只要深入掌握到阅读与分析期刊论文的技巧,就可以掌握到大学生不曾研习过的三种能力:(1)自己从无组织的知识中检索、筛选、组织知识的能力、(2)对一切既有进行精确批判的独立自主判断能力、(3)创造新知识的能力。 创新的能力在台湾一直很少被需要(因为台湾只会从国外买整套设备、制程和设计与制造的技术)。但是,大陆已经成为全球廉价品制造中心,而台商为了降低成本也主动带技术到大陆设厂(包括现在的晶元代工),因此整个不具关键性技术的制造业都会持续往大陆移动;甚至 IC 的设计(尤其数字的部分)也无可避免地会迅速朝向“台湾开系统规格,进行系统整合,大陆在前述架构下开发特定数位模块”的设计代工发展。因此,未来台湾将必然会被逼着朝愈来愈创意密集的创意中心走(包括商务创意、经营创意、产品创意、与技术创新)。因此,不能因为今天台湾的业界不需要创新的能力,就误以为自己一辈子都不需要拥有创新的能力。 我在协助民间企业发展技术研发的过程中,碰到过一位三十多岁的厂长。他很聪明,但从小家穷,被环境逼着去念高工,然后上夜校读完工专。和动态性能(bandwidth、response speed等)无关的技术他都很深入,也因为产品升级的需要而认真向我求教有关动态性能的基本观念。但是,怎么教他都不懂,就只因为他不懂工程数学。偏偏,工程数学不是可以在工厂里靠自修读会的。一个那么聪明的人,只因为不懂工数,就注定从三十岁以后一辈子无法在专业上继续成长!他高工毕业后没几年,廿多岁就当课长,家人与师长都以他为荣;卅岁当厂长,公司还给他技术股,前途无量;谁想得到他会在卅岁以后被逼着「或者升级,或者去大陆,或者失业」? 每次想起这位厂长,看着迫不急待地要到台积电去「七年赚两千万退休金」的学生,或者只想学现成可用的技术而不想学研究方法的学生,我总忍禁不住地要想:十年后,我教过的学生里,会不会有一堆人就只因为不会读期刊论文而被逼提前退休? 再者,技术的创新并不是全靠聪明。我熟谙一套技术创新的方法,只要学会分析期刊论文的优缺点,就可拿这套方法分析竞争对手产品的优缺点;而且,只要再稍微加工,就可以从这套优缺点的清单里找到突破瓶颈所需的关键性创意。这套创新程序,可以把“创新”变成不需要太多天分便可以完成的事,从而减轻创意的不定性与风险性。因此,只要会分析论文,几乎就可以轻易地组合出你所需要的绝大部分创意。聪明是不可能教的,但这套技巧却是可以教的;而且只要用心,绝大部分硕士生都可以学会。 就是因为这个原因,我的实验室整个训练的重心只有一个:通过每周一次的 groupmeeting,培养学生深入掌握阅读与分析期刊论文的技巧,进而培养他们在关键问题上突破与创新的能力。 四、期刊论文的分析技巧与程序 一般来讲,好的期刊论文有较多的创意。虽然读起来较累,但收获较多而深入,因此比较值得花心思去分析。读论文之前,参考SCI Impact Factor 及学长的意见是必要的。 一篇期刊论文,主要分成四个部分。 (1)Abstract: 说明这篇论文的主要贡献、方法特色与主要内容。最慢硕二上学期必须要学会只看Abstract 和Introduction便可以判断出这篇论文的重点和你的研究有没有直接关连,从而决定要不要把它给读完。假如你有能力每三十篇论文只根据摘要和简介便能筛选出其中最密切相关的五篇论文,你就比别人的效率高五倍以上。以后不管是做事或做学术研究,都比别人有能力从更广泛的文献中挑出最值得参考的资料。 (2)Introduction: Introduction 的功能是介绍问题的背景和起源,交代前人在这个题目上已经有过的主要贡献,说清楚前人留下来的未解问题,以及在这个背景下这篇论文的想解决的问题和它的重要性。对初学的学生而言,从这里可以了解以前研究的概况。通常我会建议初学的学生,对你的题目不熟时,先把跟你题目可能相关的论文收集个30~40篇,每篇都只读Abstract 和 Introduction,而不要读 Main Body(本文),只在必要时稍微参考一下后面的 Illustrative examples和 Conclusions,直到你能回答下面这三个问题: (2A)在这领域内最常被引述的方法有哪些? (2B)这些方法可以分成哪些主要派别? (2C)每个派别的主要特色(含优点和缺点)是什么? 问题是,你怎么去找到这最初的30~40篇论文?有一种期刊论文叫做“review paper”,专门在一个题目下面整理出所有相关的论文,并且做简单的回顾。你可以在搜寻 Compendex 时在 keywords 中加一个“review”而筛选出这类论文。然后从相关的数篇review paper 开始,从中根据 title 与 Abstract 找出你认为跟你研究题目较相关的30~40篇论文。 通常只要你反复读过该领域内30~40篇论文的Abstract 和 Introduction,你就应该可以从Introduction的评论中回答(2A)和(2B)这两个问题。尤其要记得,当你阅读的目的是要回答(2A)和(2B)这两个问题时,你一定要先挑那些Introduction写得比较有观念的论文念(很多论文的Introduction 写得像流水帐,没有观念,这种论文刚开始时不要去读它)。假如你读过假如30~40篇论文的Abstract 和 Introduction之后,还是回答不了(2C),先做下述的工作。 你先根据(2A)的答案,把这领域内最常被引述的论文找齐,再把他们根据(2B)的答案分成派别,每个派别按日期先后次序排好。然后,你每次只重新读一派的Abstract 和 Introduction(必要时简略参考内文,但目的只是读懂Introduction内与这派有关的陈述,而不需要真的看懂所有内文),照日期先后读,读的时候只企图回答一个问题:这一派的创意与主要诉求是什么?这样,你逐派逐派地把每一派的Abstract 和 Introduction 给读完,总结出这一派主要的诉求、方法特色和优点(每一篇论文都会说出自己的优点,仔细读就不会漏掉)。 其次,你再把这些论文拿出来,但是只读Introduction,认真回答下述问题:“每篇论文对其它派别有什么批评?”然后你把读到的重点逐一记录到各派别的“缺点”栏内。 通过以上程序,你就应该可以掌握到(2A)、(2B)、和(2C)三个问题的答案。 这时你对该领域内主要方法、文献之间的关系算是相当熟捻了,但是你还是只仔细读完Abstract 和 Introduction而已,内文则只是笼统读过。 这时候,你已经掌握到这领域主要的论文,你可以用这些论文测试看看你用来搜寻这领域论文的 keywords 到底恰不恰当,并且用修正过的 keywords 再搜寻一次论文,把这领域的主要文献补齐,也把原来30~40篇论文中后来发现关系较远的论文给筛选掉,只保留大概20篇左右确定跟你关系较近的文献。如果有把握,可以甚至删除一两个你不想用的派别(要有充分的理由),只保留两、三个派别(也要有充分的理由)继续做完以下工作。 然后你应该利用(2C)的答案,再进一步回答一个问题(2D):“这个领域内大家认为重要的关键问题有哪些?有哪些特性是大家重视的优点?有哪些特性是大家在意的缺点?这些优点与缺点通常在哪些应用场合时会比较被重视?在哪些应用场合时比较不会被重视?”然后,你就可以整理出这个领域(研究题目)主要的应用场合,以及这些应用场合上该注意的事项。 最后,在你真正开始念论文的 main body 之前,你应该要先根据(2A)和(2C)的答案,把各派别内的论文整理在同一个档案夹里,并照时间先后次序排好。然后依照这些派别与你的研究方向的关系远近,一个派别一个派别地逐一把各派一次念完一派的 main bodies。 (3)Main body(含simulation and/or experimental examples): 在你第一次有系统地念某派别的论文 main bodies 时,你只需要念懂:(3A)这篇论文的主要假设是什么(在什么条件下它是有效的),并且评估一下这些假设在现实条件下有多容易(或多难)成立。愈难成立的假设,愈不好用,参考价值也愈低。(3B)在这些假设下,这篇论文主要有什么好处。(3C)这些好处主要表现在哪些公式的哪些项目的简化上。至于整篇论文详细的推导过程,你不需要懂。除了三、五个关键的公式(最后在应用上要使用的公式,你可以从这里评估出这个方法使用上的方便程度或计算效率,以及在非理想情境下这些公式使用起来的可靠度或稳定性)之外,其它公式都不懂也没关系,公式之间的恒等式推导过程可以完全略 过去。假如你要看公式,重点是看公式推导过程中引入的假设条件,而不是恒等式的转换。 但是,在你开始根据前述问题念论文之前,你应该先把这派别所有的论文都拿出来,逐篇粗略地浏览过去(不要勉强自己每篇或每行都弄到懂,而是轻松地读,能懂就懂,不懂就不懂),从中挑出容易念懂的 papers,以及经常被引述的论文。然后把这些论文照时间先后次序依序念下去。记得:你念的时候只要回答(3A)、(3B)、(3C)三个问题就好,不要念太细。 这样念完以后,你应该把这一派的主要发展过程,主要假设、主要理论依据、以及主要的成果做一个完整的整理。其次,你还要在根据(2D)的答案以及这一派的主要假设,进一步回答下一个问题:(3D)这一派主要的缺点有哪些。最后,根据(3A)、(3B)、(3C)、(3D)的答案综合整理出:这一派最适合什么时候使用,最不适合什么场合使用。 记住:回答完这些问题时,你还是不应该知道恒等式是怎么导出来的! 当你是生手的时候,你要评估一个方法的优缺点时,往往必须要参考它的Examples。但是,要记得:老练的论文写作高手会故意只 present 成功的案例而遮掩失败的案例。所以,simulation examples and/or experiments 很棒不一定表示这方法真的很好。你必须要回到这个方法的基本假设上去,以及他在应用时所使用的主要公式(resultant equations)去,凭自己的思考能力, 并且参考(2C)和(2D)的答案,自己问问看:当某某假设在某些实用场合上无法成立时,这个方法会不会出什么状况?猜一猜,预测一下这个方法应该会在哪些条件下(应用场合)表现优异,又会在哪些条件下(应用场合)出状况?根据这个猜测再检验一次simulation examples and/or experiments,看它的长处与短处是不是确实在这些examples 中充分被检验,且充分表现出来。 那么,你什么时候才需要弄懂一篇论文所有的恒等式推导过程,或者把整篇论文细细读完?NEVER!你只需要把确定会用到的部分给完全搞懂就好,不确定会不会用到的部分,只需要了解它主要的点子就够了。 硕士生和大学生最主要的差别:大学生读什么都必须要从头到尾都懂,硕士生只需要懂他用得着的部分就好了!大学生因为面对的知识是有固定的范围,所以他那样念。硕士生面对的知识是没有范围的,因此他只需要懂他所需要的细腻度就够了。 硕士生必须学会选择性的阅读,而且必须锻炼出他选择时的准确度以及选择的速度,不要浪费时间在学用不着的细节知识!多吸收「点子」比较重要,而不是细部的知识。 五、方法与应用场合特性表(有迹可寻的创意程序) 试着想象从论文阅读步骤的第(4)与(5)步骤分别获得以下两张表: 譬如,当你的题目是“如何标定fiducial mark 之中心位置”,你就必须要仔细搜寻出文献上所有可能可以用来做这一个工作的方法。或许你找到的方法一共有四种,依序如下。 譬如(随便乱举例),「方法一」可能表示:「以面积形心标定fiducial mark 之中心位置」,「方法二」可能表示「以 Hugh transform标定fiducial mark 之中心位置」,「方法三」可能表示:「以局部弧形 matching 的方法标定fiducial mark 之中心位置」,「方法四」可能表示:「以 ring code 标定fiducial mark 之中心位置」。 这些方法各有它的特色(优缺点),譬如(随便乱举例),特性1可能表示“计算速度”(因此,根据上表左边第一个 row,可以发现:方法一的计算速度很快,方法二与方法三的计算速度很慢,而方法四的计算速度普通。其次,特性2可能代表“光源亮度不稳定时计算位置的误差大小”,特性3可能代表“噪声对计算出的位置干扰多大”,特性4可能代表“图形边缘有破损时计算的可靠度”,特性5可能代表“对象有彼此的遮蔽时方法的适用性”等等。所以,以上左图中第五个row为例,可以发现:当对象有彼此的遮蔽时,除方法二之外其它三个方法的适用性都很好。 但是,同样一个方法可能有许多不同的应用场合,而不同应用场合可能会对适用(或最佳)的方法有不同要求。所以,让我们来看右边的“问题特性分析表”。譬如(随便乱举例),应用甲可能是“标定fiducial mark 之中心位置”的方法在“电路插件组装(SMT)”里的应用,应用乙可能是“标定fiducial mark 之中心位置”的方法在“生物检验自动化影像处理”里的应用,而应用丙则可能是“标定fiducial mark 之中心位置”的方法在“巡乂飞弹目标搜寻”里的应用。这三种应用场合更有其关注的特性。譬如,根据上面右表第二个 row 的资料,三种应用场合对特性2(光源亮度不稳定时计算位置的误差大小)都很在意。再譬如,根据上面右表第四个 row 的资料,三种应用场合中除了应用甲(电路插件组装(SMT))之外,其它两种应用场合对特性4(图形边缘有破损时计算的可靠度)都很在意。 那么,四个方法中哪个方法最好?你可能会回答说:方法二:因为它的优点最多,缺点最少。但是,这样的回答是错的!一个方法只有优缺点,而没有好坏。当它被用在一个适合表现其优点而不在乎其缺点的场合里,它就显得很好;但是,当它被用在一个不适合表现其优点而很在乎其缺点的场合里,它就显得很糟。譬如,方法二在应用场合乙,它的表现会非常出色(因为所有的优点刚好那个应用场合都在意,而所有的缺点刚好那个应用场合都不在意);但是,方法二在应用场合甲里它的表现却会非常糟糕(它所有的缺点刚好那个应用场合都很在意,而它大部分的优点刚好那个应用场合却都不在意)。所以,必须要学会的第一件是就是:方法没有好坏,只有相对优缺点点;只有当方法的特性与应用场合的特性不合时,才能下结论说这方法“不适用”;而当方法的特性与应用场合的特性吻合时,则下结论说这方法“很适用”。因此,一定要同时有方法特性表与应用场合特性分析表放在一起后,才能判断一个方法的适用性。 更重要的是:上面的方法与问题分析对照表还可以用来把“突破瓶颈所需的创意”简化成一种有迹可寻的工作。譬如,假定我们要针对应用甲发展一套适用的方法,首先我们要先从上右表中标定这个应用场合关心哪些问题特性。根据上右表第一个 column,甲应用场合只关心四个特性:特性1、2、3、5(即“计算速度”、光源亮度不稳定时计算位置的误差大小、噪声对计算出的位置的干扰、对象有彼此的遮蔽时方法的适用性)。那么,哪个方法最适用呢?看起来是方法一,它除了特性2表现普通之外,其它三个特性的表现都很出色。但是,假如我们对方法一的表现仍不够满意,怎么去改善它?最简单的办法就是从上左表找现成的方法和方法一结合,产生出一个更适用的方法。因为方法一只有在特性2上面表现不够令人满意,所以我们就优先针对在特性2上面表现出色的其它方法加以研究。 根据上表,在特性2上面表现出色的方法有方法二和方法四,所以我们就去研究这两个方法和方法一结合的可能性。或许(随便举例)方法四的创意刚好可以被结合进方法一而改善方法一在特性2上面的表现,那么,我们就可以因此轻易地获得一个方法一的改良,从而突破甲应用场合没有适用方法的瓶颈。 有没有可能说单纯常识结合既有方法优点仍无法突破技术瓶颈的状况?可能有。这时候真的需要完全新颖的创意了。但是,这种时候很罕见。多半时候只要应用上一段的分析技巧就可以产生足以解决实用问题的创意了。至少,要产生出一篇学术期刊论文并非那么困难。 六、论文阅读的补充说明 硕士生开始学读期刊论文时,就容易犯的毛病就是戒除不掉大学部的习惯:(1)老是想逐行读懂,有一行读不懂就受不了。(2)不敢发挥自己的想象,读论文像在读教科书,论文没写的就不会,瘫痪在那里;被我逼着去自己猜测或想象时,老怕弄错作者的意思,神经绷紧,脑筋根本动不了。 大学毕业后(不管是念硕、博士或工作),可以参考的资料都没有秩序地交错成一团,而且永远都读不完。用大学生的心态读书,结果一定时间永远不够用。因此,每次读论文都一定要带着问题去读,每次读的时候都只是图回答你要回答的问题。 因此,一定是选择性地阅读,一定要逐渐由粗而细地一层一层去了解。上面所规划的读论文的次序,就是由粗而细,每读完一轮,你对这问题的知识就增加一层。根据这一层知识就可以问出下一层更细致的问题,再根据这些更细致的问题去重读,就可以理解到更多的内容。因此,一定是一整批一起读懂到某个层次,而不是逐篇逐篇地整篇一次读懂。 这样读还有一个好处:第一轮读完后,可以根据第一轮所获得的知识判断出哪些论文与你的议题不相关,不相关的就不需要再读下去了。这样才可以从广泛的论文里逐层准确地筛选出你真正非懂不可的部分。不要读不会用到的东西,白费的力气必须被极小化!其实,绝大部分论文都只需要了解它的主要观念(这往往比较容易),而不需要了解它的详细推导过程(这反而比较费时)。 其次,一整批一起读还有一个好处:同一派的观念,有的作者说得较易懂,有的说得不清楚。整批读略过一次之后,就可以规划出一个你以为比较容易懂的阅读次序,而不要硬碰硬地在那里撞墙壁。你可以从甲论文帮你弄懂以论文的一个段落,没人说读懂甲论文只能靠甲论文的信息。所以,整批阅读很像在玩跳棋,你要去规划出你自己阅读时的「最省力路径」。 大学部学生读东西一定要循规蹈矩,你还没修过机械视觉相关课程之前可能也只好循规蹈矩地逐行去念。但是一旦修过机械视觉相关课程,许多论文中没被交代的段落你也已经可以有一些属于你的想象(虽然有可能猜错,尤其刚开始时经常猜错,但没关系,下面详述)。这些想象往往补足论文跳跃处最快速的解决方案。其实,一个大学毕业生所学已经很多了,对许多是都可以有一个不太离谱的想象能力。但是大部分学生却根本不敢去想象。我读论文远比学生快,分析远比学生深入,主要的是我敢想象与猜测,而且多年训练下来想象与猜测的准确度很高。所以,许多论文我根本不是读懂的,而是猜对了! 假如猜错了怎么办?不用怕!猜完以后要根据你的猜测在论文里找证据,用以判断你的猜测对不对。猜对了,就用你的猜测(其实是你的推理架构)去吸收作者的资讯与创意(这会比从头硬生生地去迁就作者的思路轻松而容易);猜错了,论文理会有一些信息告诉你说你错了,而且因为猜错所以你读到对的答案时反而印象更深刻。 七、论文报告的要求与技巧 报告一篇论文,我要求做到以下部分(依报告次序排列): (1)投影片第一页必须列出论文的题目、作者、论文出处与年份。 (2) 以下每一页投影片只能讲一个观念,不可以在一张投影片里讲两个观念。 (3)说明这篇论文所研究的问题的重点,以及这个问题可能和工业界哪些应用相关。 (4)清楚交代这篇论文的主要假设,主要公式,与主要应用方式(以及应用上可能的解题流程)。 (5)说明这篇论文的范例(simulation examples and/or experiments),预测这个方法在不同场合时可能会有的准确度或好用的程度 (6)你个人的分析、评价与批评,包括:(6A)这篇论文最主要的创意是什么?(6B)这些创意在应用上有什么好处?(6C)这些创意和应用上的好处是在哪些条件下才能成立?(6D)这篇论文最主要的缺点或局限是什么?(6E)这些缺点或局限在应用上有什么坏处?(6F)这些缺点和应用上的坏处是因为哪些因素而引入的?(6G)你建议学长学弟什么时候参考这篇论文的哪些部分(点子)? 一般来讲,刚开始报告论文(硕一上学期)时只要做到能把前四项要素说清楚就好了,但是硕一结束后(暑假开始)必须要设法做到六项要素都能触及。硕二下学期开始的时候,必须要做到六项都能说清楚。 注意:读论文和报告论文时,最重要的是它的创意和观念架构,而不是数学上恒等式推导过程的细节(顶多只要抓出关键的 equation 去弩懂以及说明清楚即可)。 你报告观念与分析创意,别人容易听懂又觉得有趣;你讲恒等式,大家不耐烦又浪费时间。

关闭本窗口

IoC 容器和Dependency Injection 模式

撰文/Martin Fowler 编译/透明
Java 社群近来掀起了一阵轻量级容器的热潮,这些容器能够帮助开发者将来自不同项目的组件
组装成为一个内聚的应用程序。在它们的背后有着同一个模式,这个模式决定了这些容器进行组
件装配的方式。人们用一个大而化之的名字来称呼这个模式:“控制反转”( Inversion of
Control,IoC)。在本文中,我将深入探索这个模式的工作原理,给它一个更能描述其特点的名
字——“依赖注入”(Dependency Injection),并将其与“服务定位器”(Service Locator)
模式作一个比较。不过,这两者之间的差异并不太重要,更重要的是:应该将组件的配置与使用
分离开——两个模式的目标都是这个。
在企业级Java 的世界里存在一个有趣的现象:有很多人投入很多精力来研究主流J2EE 技术的
替代品——自然,这大多发生在open source 社群。在很大程度上,这可以看作是开发者对主
流J2EE 技术的笨重和复杂作出的回应,但其中的确有很多极富创意的想法,的确提供了一些可
供选择的方案。J2EE 开发者常遇到的一个问题就是如何组装不同的程序元素:如果web 控制
器体系结构和数据库接口是由不同的团队所开发的,彼此几乎一无所知,你应该如何让它们配合
工作?很多框架尝试过解决这个问题,有几个框架索性朝这个方向发展,提供了更通用的“组装
各层组件”的方案。这样的框架通常被称为“轻量级容器”,PicoContainer 和Spring 都在此
列中。
在这些容器背后,一些有趣的设计原则发挥着作用。这些原则已经超越了特定容器的范畴,甚至
已经超越了Java 平台的范畴。在本文中,我就要初步揭示这些原则。我使用的范例是Java 代
码,但正如我的大多数文章一样,这些原则也同样适用于别的OO 环境,特别是.NET。
组件和服务
“装配程序元素”,这样的话题立即将我拖进了一个棘手的术语问题:如何区分“服务”(service)
和“组件”(component)?你可以毫不费力地找出关于这两个词定义的长篇大论,各种彼此
矛盾的定义会让你感受到我所处的窘境。有鉴于此,对于这两个遭到了严重滥用的词汇,我将首
先说明它们在本文中的用法。
所谓“组件”是指这样一个软件单元:它将被作者无法控制的其他应用程序使用,但后者不能对
组件进行修改。也就是说,使用一个组件的应用程序不能修改组件的源代码,但可以通过作者预
留的某种途径对其进行扩展,以改变组件的行为。
服务和组件有某种相似之处:它们都将被外部的应用程序使用。在我看来,两者之间最大的差异
在于:组件是在本地使用的(例如JAR 文件、程序集、DLL、或者源码导入);而服务是要通过
——同步或异步的——远程接口来远程使用的(例如web service、消息系统、RPC,或者
socket)。
在本文中,我将主要使用“服务”这个词,但文中的大多数逻辑也同样适用于本地组件。实际上,
为了方便地访问远程服务,你往往需要某种本地组件框架。不过,“组件或者服务”这样一个词
组实在太麻烦了,而且“服务”这个词当下也很流行,所以本文将用“服务”指代这两者。
一个简单的例子
为了更好地说明问题,我要引入一个例子。和我以前用的所有例子一样,这是一个超级简单的例
子:它非常小,小得有点不够真实,但足以帮助你看清其中的道理,而不至于陷入真实例子的泥
潭中无法自拔。
在这个例子中,我编写了一个组件,用于提供一份电影清单,清单上列出的影片都是由一位特定
的导演执导的。实现这个伟大的功能只需要一个方法:
class MovieLister…
public Movie[] moviesDirectedBy(String arg) {
List allMovies = finder.findAll();
for (Iterator it = allMovies.iterator(); it.hasNext();) {
Movie movie = (Movie) it.next();
if (!movie.getDirector().equals(arg)) it.remove();
}
return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]);
}
你可以看到,这个功能的实现极其简单:moviesDirectedBy 方法首先请求finder(影片搜寻
者)对象(我们稍后会谈到这个对象)返回后者所知道的所有影片,然后遍历finder 对象返回
的清单,并返回其中由特定的某个导演执导的影片。非常简单,不过不必担心,这只是整个例子
的脚手架罢了。
我们真正想要考察的是finder对象,或者说,如何将MovieLister对象与特定的finder对象连
接起来。为什么我们对这个问题特别感兴趣?因为我希望上面这个漂亮的moviesDirectedBy
方法完全不依赖于影片的实际存储方式。所以,这个方法只能引用一个finder对象,而finder
对象则必须知道如何对findAll 方法作出回应。为了帮助读者更清楚地理解,我给finder定义了
一个接口:
public interface MovieFinder {
List findAll();
}
现在,两个对象之间没有什么耦合关系。但是,当我要实际寻找影片时,就必须涉及到
MovieFinder 的某个具体子类。在这里,我把“涉及具体子类”的代码放在MovieLister 类的
构造子中。
class MovieLister…
private MovieFinder finder;
public MovieLister() {
finder = new ColonDelimitedMovieFinder(“movies1.txt”);
}
这个实现类的名字就说明:我将要从一个逗号分隔的文本文件中获得影片列表。你不必操心具体
的实现细节,只要设想这样一个实现类就可以了。
如果这个类只由我自己使用,一切都没问题。但是,如果我的朋友叹服于这个精彩的功能,也想
使用我的程序,那又会怎么样呢?如果他们也把影片清单保存在一个逗号分隔的文本文件中,并
且也把这个文件命名为“ movie1.txt ”,那么一切还是没问题。如果他们只是给这个文件改改名,
我也可以从一个配置文件获得文件名,这也很容易。但是,如果他们用完全不同的方式——例如
SQL 数据库、XML 文件、web service,或者另一种格式的文本文件——来存储影片清单呢?
在这种情况下,我们需要用另一个类来获取数据。由于已经定义了MovieFinder接口,我可以
不用修改moviesDirectedBy 方法。但是,我仍然需要通过某种途径获得合适的MovieFinder
实现类的实例。
图1:“在MovieLister 类中直接创建MovieFinder 实例”时的依赖关系
图1 展现了这种情况下的依赖关系:MovieLister 类既依赖于MovieFinder接口,也依赖于具
体的实现类。我们当然希望MovieLister 类只依赖于接口,但我们要如何获得一个MovieFinder
子类的实例呢?
在Patterns of Enterprise Application Architecture 一书中,我们把这种情况称为“插件”
(plugin):MovieFinder的实现类不是在编译期连入程序之中的,因为我并不知道我的朋友会
使用哪个实现类。我们希望MovieLister 类能够与MovieFinder的任何实现类配合工作,并且
允许在运行期插入具体的实现类,插入动作完全脱离我(原作者)的控制。这里的问题就是:如
何设计这个连接过程,使MovieLister 类在不知道实现类细节的前提下与其实例协同工作。
将这个例子推而广之,在一个真实的系统中,我们可能有数十个服务和组件。在任何时候,我们
总可以对使用组件的情形加以抽象,通过接口与具体的组件交流(如果组件并没有设计一个接口,
也可以通过适配器与之交流)。但是,如果我们希望以不同的方式部署这个系统,就需要用插件
机制来处理服务之间的交互过程,这样我们才可能在不同的部署方案中使用不同的实现。
所以,现在的核心问题就是:如何将这些插件组合成一个应用程序?这正是新生的轻量级容器所
面临的主要问题,而它们解决这个问题的手段无一例外地是控制反转(Inversion of Control)
模式。
控制反转
几位轻量级容器的作者曾骄傲地对我说:这些容器非常有用,因为它们实现了“控制反转”。这
样的说辞让我深感迷惑:控制反转是框架所共有的特征,如果仅仅因为使用了控制反转就认为这
些轻量级容器与众不同,就好象在说“我的轿车是与众不同的,因为它有四个轮子”。
问题的关键在于:它们反转了哪方面的控制?我第一次接触到的控制反转针对的是用户界面的主
控权。早期的用户界面是完全由应用程序来控制的,你预先设计一系列命令,例如“输入姓名”、
“输入地址”等,应用程序逐条输出提示信息,并取回用户的响应。而在图形用户界面环境下,
UI 框架将负责执行一个主循环,你的应用程序只需为屏幕的各个区域提供事件处理函数即可。
在这里,程序的主控权发生了反转:从应用程序移到了框架。
对于这些新生的容器,它们反转的是“如何定位插件的具体实现”。在前面那个简单的例子中,
MovieLister 类负责定位MovieFinder 的具体实现——它直接实例化后者的一个子类。这样一
来,MovieFinder 也就不成其为一个插件了,因为它并不是在运行期插入应用程序中的。而这
些轻量级容器则使用了更为灵活的办法,只要插件遵循一定的规则,一个独立的组装模块就能够
将插件的具体实现“注射”到应用程序中。
因此,我想我们需要给这个模式起一个更能说明其特点的名字——“控制反转”这个名字太泛了,
常常让人有些迷惑。与多位IoC 爱好者讨论之后,我们决定将这个模式叫做“依赖注入”
(Dependency Injection)。
下面,我将开始介绍Dependency Injection 模式的几种不同形式。不过,在此之前,我要首
先指出:要消除应用程序对插件实现的依赖,依赖注入并不是唯一的选择,你也可以用Service
Locator 模式获得同样的效果。介绍完Dependency Injection 模式之后,我也会谈到Service
Locator 模式。
依赖注入的几种形式
Dependency Injection 模式的基本思想是:用一个单独的对象(装配器)来获得MovieFinder
的一个合适的实现,并将其实例赋给MovieLister 类的一个字段。这样一来,我们就得到了图2
所示的依赖图:
图2:引入依赖注入器之后的依赖关系
依赖注入的形式主要有三种,我分别将它们叫做构造子注入(Constructor Injection)、设值
方法注入(Setter Injection)和接口注入(Interface Injection)。如果读过最近关于IoC 的
一些讨论材料,你不难看出:这三种注入形式分别就是type 1 IoC(接口注入)、type 2 IoC
(设值方法注入)和type 3 IoC(构造子注入)。我发现数字编号往往比较难记,所以我使用了
这里的命名方式。
使用PicoContainer 进行构造子注入
首先,我要向读者展示如何用一个名为PicoContainer 的轻量级容器完成依赖注入。之所以从
这里开始,主要是因为我在ThoughtWorks 公司的几个同事在PicoContainer 的开发社群中
非常活跃——没错,也可以说是某种偏袒吧。
PicoContainer 通过构造子来判断“如何将MovieFinder 实例注入MovieLister 类”。因此,
MovieLister 类必须声明一个构造子,并在其中包含所有需要注入的元素:
class MovieLister…
public MovieLister(MovieFinder finder) {
this.finder = finder;
}
MovieFinder 实例本身也将由PicoContainer来管理,因此文本文件的名字也可以由容器注入:
class ColonMovieFinder…
public ColonMovieFinder(String filename) {
this.filename = filename;
}
随后,需要告诉PicoContainer:各个接口分别与哪个实现类关联、将哪个字符串注入
MovieFinder组件。
private MutablePicoContainer configureContainer() {
MutablePicoContainer pico = new DefaultPicoContainer();
Parameter[] finderParams = {new
ConstantParameter(“movies1.txt”)};
pico.registerComponentImplementation(MovieFinder.class,
ColonMovieFinder.class, finderParams);
pico.registerComponentImplementation(MovieLister.class);
return pico;
}
这段配置代码通常位于另一个类。对于我们这个例子,使用我的MovieLister 类的朋友需要在
自己的设置类中编写合适的配置代码。当然,还可以将这些配置信息放在一个单独的配置文件中,
这也是一种常见的做法。你可以编写一个类来读取配置文件,然后对容器进行合适的设置。尽管
PicoContainer 本身并不包含这项功能,但另一个与它关系紧密的项目NanoContainer 提供
了一些包装,允许开发者使用XML 配置文件保存配置信息。NanoContainer能够解析XML 文
件,并对底下的PicoContainer 进行配置。这个项目的哲学观念就是:将配置文件的格式与底
下的配置机制分离开。
使用这个容器,你写出的代码大概会是这样:
public void testWithPico() {
MutablePicoContainer pico = configureContainer();
MovieLister lister = (MovieLister)
pico.getComponentInstance(MovieLister.class);
Movie[] movies = lister.moviesDirectedBy(“Sergio Leone”);
assertEquals(“Once Upon a Time in the West”,
movies[0].getTitle());
}
尽管在这里我使用了构造子注入,实际上PicoContainer 也支持设值方法注入,不过该项目的
开发者更推荐使用构造子注入。
使用Spring 进行设值方法注入
Spring 框架是一个用途广泛的企业级Java 开发框架,其中包括了针对事务、持久化框架、web
应用开发和JDBC 等常用功能的抽象。和PicoContainer 一样,它也同时支持构造子注入和设
值方法注入,但该项目的开发者更推荐使用设值方法注入——恰好适合这个例子。
为了让MovieLister 类接受注入, 我需要为它定义一个设值方法,该方法接受类型为
MovieFinder的参数:
class MovieLister…
private MovieFinder finder;
public void setFinder(MovieFinder finder) {
this.finder = finder;
}
类似地,在MovieFinder的实现类中,我也定义了一个设值方法,接受类型为String 的参数:
class ColonMovieFinder…
public void setFilename(String filename) {
this.filename = filename;
}
第三步是设定配置文件。Spring 支持多种配置方式,你可以通过XML 文件进行配置,也可以
直接在代码中配置。不过,XML 文件是比较理想的配置方式。
<beans>
<bean id=”MovieLister” class=”spring.MovieLister”>
<property name=”finder”>
<ref local=”MovieFinder”/>
</property>
</bean>
<bean id=”MovieFinder” class=”spring.ColonMovieFinder”>
<property name=”filename”>
<value>movies1.txt</value>
</property>
</bean>
</beans>
于是,测试代码大概就像下面这样:
public void testWithSpring() throws Exception {
ApplicationContext ctx = new
FileSystemXmlApplicationContext(“spring.xml”);
MovieLister lister = (MovieLister) ctx.getBean(“MovieLister”);
Movie[] movies = lister.moviesDirectedBy(“Sergio Leone”);
assertEquals(“Once Upon a Time in the West”,
movies[0].getTitle());
}
接口注入
除了前面两种注入技术,还可以在接口中定义需要注入的信息,并通过接口完成注入。Avalon
框架就使用了类似的技术。在这里,我首先用简单的范例代码说明它的用法,后面还会有更深入
的讨论。
首先,我需要定义一个接口,组件的注入将通过这个接口进行。在本例中,这个接口的用途是将
一个MovieFinder实例注入继承了该接口的对象。
public interface InjectFinder {
void injectFinder(MovieFinder finder);
}
这个接口应该由提供MovieFinder 接口的人一并提供。任何想要使用MovieFinder 实例的类
(例如MovieLister 类)都必须实现这个接口。
class MovieLister implements InjectFinder…
public void injectFinder(MovieFinder finder) {
this.finder = finder;
}
然后,我使用类似的方法将文件名注入MovieFinder的实现类:
public interface InjectFilename {
void injectFilename (String filename);
}
class ColonMovieFinder implements MovieFinder, InjectFilename……
public void injectFilename(String filename) {
this.filename = filename;
}
现在,还需要用一些配置代码将所有的组件实现装配起来。简单起见,我直接在代码中完成配置,
并将配置好的MovieLister 对象保存在名为lister的字段中:
class IfaceTester…
private MovieLister lister;
private void configureLister() {
ColonMovieFinder finder = new ColonMovieFinder();
finder.injectFilename(“movies1.txt”);
lister = new MovieLister();
lister.injectFinder(finder);
}
测试代码则可以直接使用这个字段:
class IfaceTester…
public void testIface() {
configureLister();
Movie[] movies = lister.moviesDirectedBy(“Sergio Leone”);
assertEquals(“Once Upon a Time in the West”,
movies[0].getTitle());
}
使用Service Locator
依赖注入的最大好处在于:它消除了MovieLister类对具体MovieFinder实现类的依赖。这样
一来, 我就可以把MovieLister 类交给朋友, 让他们根据自己的环境插入一个合适的
MovieFinder实现即可。不过,Dependency Injection 模式并不是打破这层依赖关系的唯一
手段,另一种方法是使用Service Locator 模式。
Service Locator 模式背后的基本思想是:有一个对象(即服务定位器)知道如何获得一个应用
程序所需的所有服务。也就是说,在我们的例子中,服务定位器应该有一个方法,用于获得一个
MovieFinder 实例。当然,这不过是把麻烦换了一个样子,我们仍然必须在MovieLister 中获
得服务定位器,最终得到的依赖关系如图3 所示:
图3:使用Service Locator 模式之后的依赖关系
在这里,我把ServiceLocator 类实现为一个Singleton 的注册表,于是MovieLister 就可以
在实例化时通过ServiceLocator 获得一个MovieFinder 实例。
class MovieLister…
MovieFinder finder = ServiceLocator.movieFinder();
class ServiceLocator…
public static MovieFinder movieFinder() {
return soleInstance.movieFinder;
}
private static ServiceLocator soleInstance;
private MovieFinder movieFinder;
和注入的方式一样,我们也必须对服务定位器加以配置。在这里,我直接在代码中进行配置,但
设计一种通过配置文件获得数据的机制也并非难事。
class Tester…
private void configure() {
ServiceLocator.load(new ServiceLocator(new
ColonMovieFinder(“movies1.txt”)));
}
class ServiceLocator…
public static void load(ServiceLocator arg) {
soleInstance = arg;
}
public ServiceLocator(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
下面是测试代码:
class Tester…
public void testSimple() {
configure();
MovieLister lister = new MovieLister();
Movie[] movies = lister.moviesDirectedBy(“Sergio Leone”);
assertEquals(“Once Upon a Time in the West”,
movies[0].getTitle());
}
我时常听到这样的论调:这样的服务定位器不是什么好东西,因为你无法替换它返回的服务实现,
从而导致无法对它们进行测试。当然,如果你的设计很糟糕,你的确会遇到这样的麻烦;但你也
可以选择良好的设计。在这个例子中,ServiceLocator 实例仅仅是一个简单的数据容器,只需
要对它做一些简单的修改,就可以让它返回用于测试的服务实现。
对于更复杂的情况,我可以从ServiceLocator 派生出多个子类,并将子类型的实例传递给注册
表的类变量。另外,我可以修改ServiceLocator 的静态方法,使其调用ServiceLocator 实例
的方法,而不是直接访问实例变量。我还可以使用特定于线程的存储机制,从而提供特定于线程
的服务定位器。所有这一切改进都无须修改ServiceLocator 的使用者。
一种改进的思路是:服务定位器仍然是一个注册表,但不是Singleton。Singleton 的确是实现
注册表的一种简单途径,但这只是一个实现时的决定,可以很轻松地改变它。
为定位器提供分离的接口
上面这种简单的实现方式有一个问题:MovieLister 类将依赖于整个ServiceLocator 类,但它
需要使用的却只是后者所提供的一项服务。我们可以针对这项服务提供一个单独的接口,减少
MovieLister 对ServiceLocator 的依赖程度。这样一来,MovieLister 就不必使用整个的
ServiceLocator 接口,只需声明它想要使用的那部分接口。
此时,MovieLister 类的提供者也应该一并提供一个定位器接口,使用者可以通过这个接口获得
MovieFinder实例。
public interface MovieFinderLocator {
public MovieFinder movieFinder();
真实的服务定位器需要实现上述接口,提供访问MovieFinder 实例的能力:
MovieFinderLocator locator = ServiceLocator.locator();
MovieFinder finder = locator.movieFinder();
public static ServiceLocator locator() {
return soleInstance;
}
public MovieFinder movieFinder() {
return movieFinder;
}
private static ServiceLocator soleInstance;
private MovieFinder movieFinder;
你应该已经注意到了:由于想要使用接口,我们不能再通过静态方法直接访问服务——我们必须
首先通过ServiceLocator 类获得定位器实例,然后使用定位器实例得到我们想要的服务。
动态服务定位器
上面是一个静态定位器的例子——对于你所需要的每项服务,ServiceLocator 类都有对应的方
法。这并不是实现服务定位器的唯一方式,你也可以创建一个动态服务定位器,你可以在其中注
册需要的任何服务,并在运行期决定获得哪一项服务。
在本例中,ServiceLocator 使用一个map 来保存服务信息,而不再是将这些信息保存在字段
中。此外,ServiceLocator 还提供了一个通用的方法,用于获取和加载服务对象。
class ServiceLocator…
private static ServiceLocator soleInstance;
public static void load(ServiceLocator arg) {
soleInstance = arg;
}
private Map services = new HashMap();
public static Object getService(String key){
return soleInstance.services.get(key);
}
public void loadService (String key, Object service) {
services.put(key, service);
}
同样需要对服务定位器进行配置,将服务对象与适当的关键字加载到定位器中:
class Tester…
private void configure() {
ServiceLocator locator = new ServiceLocator();
locator.loadService(“MovieFinder”, new
ColonMovieFinder(“movies1.txt”));
ServiceLocator.load(locator);
}
我使用与服务对象类名称相同的字符串作为服务对象的关键字:
class MovieLister…
MovieFinder finder = (MovieFinder)
ServiceLocator.getService(“MovieFinder”);
总体而言,我不喜欢这种方式。无疑,这样实现的服务定位器具有更强的灵活性,但它的使用方
式不够直观明朗。我只有通过文本形式的关键字才能找到一个服务对象。相比之下,我更欣赏“通
过一个方法明确获得服务对象”的方式,因为这让使用者能够从接口定义中清楚地知道如何获得
某项服务。
用Avalon 兼顾服务定位器和依赖注入
Dependency Injection 和Service Locator 两个模式并不是互斥的,你可以同时使用它们,
Avalon 框架就是这样的一个例子。Avalon 使用了服务定位器,但“如何获得定位器”的信息
则是通过注入的方式告知组件的。
对于前面一直使用的例子,Berin Loritsch 发送给了我一个简单的Avalon 实现版本:
public class MyMovieLister implements MovieLister, Serviceable {
private MovieFinder finder;
public void service( ServiceManager manager )
throws ServiceException
{
finder = (MovieFinder)manager.lookup(“finder”);
}
service 方法就是接口注入的例子, 它使容器可以将一个ServiceManager 对象注入
MyMovieLister 对象。ServiceManager则是一个服务定位器。在这个例子中,MyMovieLister
并不把ServiceManager 对象保存在字段中,而是马上借助它找到MovieFinder 实例,并将
后者保存起来。
作出一个选择
到现在为止,我一直在阐述自己对这两个模式( Dependency Injection 模式和Service
Locator 模式)以及它们的变化形式的看法。现在,我要开始讨论他们的优点和缺点,以便指出
它们各自适用的场景。
Service Locator vs. Dependency Injection
首先,我们面临Service Locator 和Dependency Injection 之间的选择。应该注意,尽管我
们前面那个简单的例子不足以表现出来,实际上这两个模式都提供了基本的解耦合能力——无论
使用哪个模式,应用程序代码都不依赖于服务接口的具体实现。两者之间最重要的区别在于:这
个“具体实现”以什么方式提供给应用程序代码。使用Service Locator 模式时,应用程序代
码直接向服务定位器发送一个消息,明确要求服务的实现;使用Dependency Injection 模式
时,应用程序代码不发出显式的请求,服务的实现自然会出现在应用程序代码中,这也就是所谓
“控制反转”
控制反转是框架的共同特征,但它也要求你付出一定的代价:它会增加理解的难度,并且给调试
带来一定的困难。所以,整体来说,除非必要,否则我会尽量避免使用它。这并不意味着控制反
转不好,只是我认为在很多时候使用一个更为直观的方案(例如Service Locator 模式)会比
较合适。
一个关键的区别在于:使用Service Locator 模式时,服务的使用者必须依赖于服务定位器。
定位器可以隐藏使用者对服务具体实现的依赖,但你必须首先看到定位器本身。所以,问题的答
案就很明朗了:选择Service Locator 还是Dependency Injection,取决于“对定位器的依
赖”是否会给你带来麻烦。
Dependency Injection 模式可以帮助你看清组件之间的依赖关系:你只需观察依赖注入的机
制(例如构造子),就可以掌握整个依赖关系。而使用Service Locator 模式时,你就必须在源
代码中到处搜索对服务定位器的调用。具备全文检索能力的IDE 可以略微简化这一工作,但还
是不如直接观察构造子或者设值方法来得轻松。
这个选择主要取决于服务使用者的性质。如果你的应用程序中有很多不同的类要使用一个服务,
那么应用程序代码对服务定位器的依赖就不是什么大问题。在前面的例子中,我要把
MovieLister 类交给朋友去用,这种情况下使用服务定位器就很好:我的朋友们只需要对定位器
做一点配置(通过配置文件或者某些配置性的代码),使其提供合适的服务实现就可以了。在这
种情况下,我看不出Dependency Injection 模式提供的控制反转有什么吸引人的地方。
但是,如果把MovieLister 看作一个组件,要将它提供给别人写的应用程序去使用,情况就不
同了。在这种时候,我无法预测使用者会使用什么样的服务定位器API,每个使用者都可能有自
己的服务定位器,而且彼此之间无法兼容。一种解决办法是为每项服务提供单独的接口,使用者
可以编写一个适配器,让我的接口与他们的服务定位器相配合。但即便如此,我仍然需要到第一
个服务定位器中寻找我规定的接口。而且一旦用上了适配器,服务定位器所提供的简单性就被大
大削弱了。
另一方面,如果使用Dependency Injection 模式,组件与注入器之间不会有依赖关系,因此
组件无法从注入器那里获得更多的服务,只能获得配置信息中所提供的那些。这也是
Dependency Injection 模式的局限性之一。
人们倾向于使用Dependency Injection 模式的一个常见理由是:它简化了测试工作。这里的
关键是:出于测试的需要,你必须能够轻松地在“真实的服务实现”与“供测试用的‘伪’组件”
之间切换。但是,如果单从这个角度来考虑,Dependency Injection 模式和Service Locator
模式其实并没有太大区别:两者都能够很好地支持“伪”组件的插入。之所以很多人有
“Dependency Injection 模式更利于测试”的印象,我猜是因为他们并没有努力保证服务定
位器的可替换性。这正是持续测试起作用的地方:如果你不能轻松地用一些“伪”组件将一个服
务架起来以便测试,这就意味着你的设计出现了严重的问题。
当然,如果组件环境具有非常强的侵略性(就像EJB 框架那样),测试的问题会更加严重。我的
观点是:应该尽量减少这类框架对应用程序代码的影响,特别是不要做任何可能使“编辑-执行”
的循环变慢的事情。用插件(plugin)机制取代重量级组件会对测试过程有很大帮助,这正是
测试驱动开发(Test Driven Development,TDD)之类实践的关键所在。
所以,主要的问题在于:代码的作者是否希望自己编写的组件能够脱离自己的控制、被使用在另
一个应用程序中。如果答案是肯定的,那么他就不能对服务定位器做任何假设——哪怕最小的假
设也会给使用者带来麻烦。
构造子注入 vs. 设值方法注入
在组合服务时,你总得遵循一定的约定,才可能将所有东西拼装起来。依赖注入的优点主要在于:
它只需要非常简单的约定——至少对于构造子注入和设值方法注入来说是这样。相比于这两者,
接口注入的侵略性要强得多,比起Service Locator 模式的优势也不那么明显。
所以,如果你想要提供一个组件给多个使用者,构造子注入和设值方法注入看起来很有吸引力:
你不必在组件中加入什么希奇古怪的东西,注入器可以相当轻松地把所有东西配置起来。
设值函数注入和构造子注入之间的选择相当有趣,因为它折射出面向对象编程的一些更普遍的问
题:应该在哪里填充对象的字段,构造子还是设值方法?
一直以来,我首选的做法是尽量在构造阶段就创建完整、合法的对象——也就是说,在构造子中
填充对象字段。这样做的好处可以追溯到Kent Beck 在Smalltalk Best Practice Patterns
一书中介绍的两个模式:Constructor Method 和Constructor Parameter Method。带有参
数的构造子可以明确地告诉你如何创建一个合法的对象。如果创建合法对象的方式不止一种,你
还可以提供多个构造子,以说明不同的组合方式。
构造子初始化的另一个好处是:你可以隐藏任何不可变的字段——只要不为它提供设值方法就行
了。我认为这很重要:如果某个字段是不应该被改变的,“没有针对该字段的设值方法”就很清
楚地说明了这一点。如果你通过设值方法完成初始化,暴露出来的设值方法很可能成为你心头永
远的痛。(实际上,在这种时候我更愿意回避通常的设值方法约定,而是使用诸如initFoo 之类
的方法名,以表明该方法只应该在对象创建之初调用。)
不过,世事总有例外。如果参数太多,构造子会显得凌乱不堪,特别是对于不支持关键字参数的
语言更是如此。的确,如果构造子参数列表太长,通常标志着对象太过繁忙,理应将其拆分成几
个对象,但有些时候也确实需要那么多的参数。
如果有不止一种的方式可以构造一个合法的对象,也很难通过构造子描述这一信息,因为构造子
之间只能通过参数的个数和类型加以区分。这就是Factory Method 模式适用的场合了,工厂
方法可以借助多个私有构造子和设值方法的组合来完成自己的任务。经典Factory Method 模
式的问题在于:它们往往以静态方法的形式出现,你无法在接口中声明它们。你可以创建一个工
厂类,但那又变成另一个服务实体了。“工厂服务”是一种不错的技巧,但你仍然需要以某种方
式实例化这个工厂对象,问题仍然没有解决。
如果要传入的参数是像字符串这样的简单类型,构造子注入也会带来一些麻烦。使用设值方法注
入时,你可以在每个设值方法的名字中说明参数的用途;而使用构造子注入时,你只能靠参数的
位置来决定每个参数的作用,而记住参数的正确位置显然要困难得多。
如果对象有多个构造子,对象之间又存在继承关系,事情就会变得特别讨厌。为了让所有东西都
正确地初始化,你必须将对子类构造子的调用转发给超类的构造子,然后处理自己的参数。这可
能造成构造子规模的进一步膨胀。
尽管有这些缺陷,但我仍然建议你首先考虑构造子注入。不过,一旦前面提到的问题真的成了问
题,你就应该准备转为使用设值方法注入。
在将Dependecy Injection 模式作为框架的核心部分的几支团队之间,“构造子注入还是设值
方法注入”引发了很多的争论。不过,现在看来,开发这些框架的大多数人都已经意识到:不管
更喜欢哪种注入机制,同时为两者提供支持都是有必要的。
代码配置 vs. 配置文件
另一个问题相对独立,但也经常与其他问题牵涉在一起:如何配置服务的组装,通过配置文件还
是直接编码组装?对于大多数需要在多处部署的应用程序来说,一个单独的配置文件会更合适。
配置文件几乎都是XML 文件,XML 也的确很适合这一用途。不过,有些时候直接在程序代码中
实现装配会更简单。譬如一个简单的应用程序,也没有很多部署上的变化,这时用几句代码来配
置就比XML 文件要清晰得多。
与之相对的,有时应用程序的组装非常复杂,涉及大量的条件步骤。一旦编程语言中的配置逻辑
开始变得复杂,你就应该用一种合适的语言来描述配置信息,使程序逻辑变得更清晰。然后,你
可以编写一个构造器(builder)类来完成装配工作。如果使用构造器的情景不止一种,你可以
提供多个构造器类,然后通过一个简单的配置文件在它们之间选择。
我常常发现,人们太急于定义配置文件。编程语言通常会提供简捷而强大的配置管理机制,现代
编程语言也可以将程序编译成小的模块,并将其插入大型系统中。如果编译过程会很费力,脚本
语言也可以在这方面提供帮助。
通常认为,配置文件不应该用编程语言来编写,因为它们需要能够被不懂编程的系统管理人员编
辑。但是,这种情况出现的几率有多大呢?我们真的希望不懂编程的系统管理人员来改变一个复
杂的服务器端应用程序的事务隔离等级吗?只有在非常简单的时候,非编程语言的配置文件才有
最好的效果。如果配置信息开始变得复杂,就应该考虑选择一种合适的编程语言来编写配置文件。
在Java 世界里,我们听到了来自配置文件的不和谐音——每个组件都有它自己的配置文件,而
且格式还各各不同。如果你要使用一打这样的组件,你就得维护一打的配置文件,那会很快让你
烦死。
在这里,我的建议是:始终提供一种标准的配置方式,使程序员能够通过同一个编程接口轻松地
完成配置工作。至于其他的配置文件,仅仅把它们当作一种可选的功能。借助这个编程接口,开
发者可以轻松地管理配置文件。如果你编写了一个组件,则可以由组件的使用者来选择如何管理
配置信息:使用你的编程接口、直接操作配置文件格式,或者定义他们自己的配置文件格式,并
将其与你的编程接口相结合。
分离配置与使用
所有这一切的关键在于:服务的配置应该与使用分开。实际上,这是一个基本的设计原则——分
离接口与实现。在面向对象程序里,我们在一个地方用条件逻辑来决定具体实例化哪一个类,以
后的条件分支都由多态来实现,而不是继续重复前面的条件逻辑,这就是“分离接口与实现”的
原则。
如果对于一段代码而言,接口与实现的分离还只是“有用”的话,那么当你需要使用外部元素(例
如组件和服务)时,它就是生死攸关的大事。这里的第一个问题是:你是否希望将“选择具体实
现类”的决策推迟到部署阶段。如果是,那么你需要使用插入技术。使用了插入技术之后,插件
的装配原则上是与应用程序的其余部分分开的,这样你就可以轻松地针对不同的部署替换不同的
配置。这种配置机制可以通过服务定位器来实现(Service Locator 模式),也可以借助依赖注
入直接完成(Dependency Injection 模式)。
更多的问题
在本文中,我关注的焦点是使用Dependency Injection 模式和Service Locator 模式进行服
务配置的基本问题。还有一些与之相关的话题值得关注,但我已经没有时间继续申发下去了。特
别值得注意的是生命周期行为的问题:某些组件具有特定的生命周期事件,例如“停止”、“开始”
等等。另一个值得注意的问题是:越来越多的人对“如何在这些容器中运用面向方面(aspect
oriented)的思想”产生了兴趣。尽管目前还没有认真准备过这方面的材料,但我也很希望以
后能在这个话题上写一些东西。
关于这些问题,你在专注于轻量级容器的网站上可以找到很多资料。浏览PicoContainer
(http://www.picocontainer.org)或者Spring(http://www.springframework.org)的
网站,你可以找到大量相关的讨论,并由此引申出更多的话题。
结论和思考
在时下流行的轻量级容器都使用了一个共同的模式来组装应用程序所需的服务,我把这个模式称
为Dependency Injection,它可以有效地替代Service Locator 模式。在开发应用程序时,
两者不相上下,但我认为Service Locator 模式略有优势,因为它的行为方式更为直观。但是,
如果你开发的组件要交给多个应用程序去使用,那么Dependency Injection 模式会是更好的
选择。
如果你决定使用Dependency Injection 模式,这里还有几种不同的风格可供选择。我建议你
首先考虑构造子注入;如果遇到了某些特定的问题,再改用设值方法注入。如果你要选择一个容
器,在其之上进行开发,我建议你选择同时支持这两种注入方式的容器。
Service Locator 模式和Dependency Injection 模式之间的选择并是最重要的,更重要的是:
应该将服务的配置和应用程序内部对服务的使用分离开。
致谢
在此,我要向帮助我理解本文中所提到的问题、并对本文提出宝贵意见的几个人表示感谢,他们
是Rod Johnson、Paul Hammant、Joe Walnes、Aslak Hellesoy、Jon Tirsen 和Bill Caputo。
另外,Berin Loritsch 和Hamilton Verissimo de Oliveira 在Avalon 方面给了我非常有用的
建议,一并向他们表示感谢。

Trackback: http://tb.donews.net/TrackBack.aspx?PostId=461311

Install Spring plug-in

Spring IDE is a set of Eclipse plugins packaged as a feature. This feature is hosted on a website (aka updatesite) which is accessed by Eclipse’s update manager. To use Spring IDE’s BeansXmlEditor the Web Standard Tools (WST) project (see below) is required.

The following instructions describe how to install Spring IDE together with GEF via Eclipse’s update manager:
Open Eclipse. Go to Help -> Software Updates -> Find and Install.
Select “Search for new features to install”. Click “Next”.
Click “New Remote Site”. Enter “Spring IDE updatesite” for the Name and “http://springide.org/updatesite/” for the URL (Screenshot). Click “OK”.
You should now see a a new entry name “Spring IDE updatesite” with a mark next to it (Screenshot). Click on that and check “Spring IDE”.
Click on the mark next to “Eclipse.org updatesite” and check the version of GEF which is sufficient for your version of Eclipse. Click “Next”.
Select the features “Graphical Editing Framework” and the latest version of “Spring IDE” from the list. Click “Next”.
Check “I accept…” and click “Next”. Select or add the appropriate site to install the features. Click “Finish”.
Click Install on the warning dialogs during feature verification (both features are not digitally signed).
After successfully downloading and installing the features click “Yes” on the “Would you like to restart now?” dialog.

Congratulations. You have made it!

After restarting Eclipse you can check if Spring IDE is available by opening Eclipse’s about dialog (Screenshot) and clicking on the Spring logo.
Required Software

Eclipse 3.1 (or newer) is required to run Spring IDE with it’s basic features (BeansView, BeansConfigValidator, BeansSearch). For Spring IDE’s BeansGraph you have to install the corresponding version of Eclipse’s Graphical Editing Framework (GEF).

To use the more advanced features of Spring IDE (BeansXmlEditor, WebFlowEditor) the Web Standard Tools (WST) project is required. WST itself has strict requirements, e.g. for version 1.0.x these are as follows:
Eclipse 3.1.x
GEF 3.1.x
EMF/SDO/XSD 2.1.x
JEM 1.1.0.x

You can download WST and all required packages manually from here or use Eclipse’s update manager as described here.
Alternate Types of Installation
Installation of Spring IDE with required dependecies from the Callisto Discovery Site

If you already have Eclipse 3.2 installed then you can also use Eclipse’s update manager to install Spring IDE with all required features from the Callisto Discovery Site. A detailed description is available in the wiki page SpringideCallistoInstall.
Installation of archived version of Spring IDE’s update site

An archived version of the update site (springide_updatesite_x.x.x.zip) can also be downloaded from http://springide.org/updatesite/ and used locally with Eclipse’s update manager. Do not unzip these archives into your Eclipse installation directory. This will destroy your Eclipse installation!

There is also a developer updatesite available where you can install development versions of Spring IDE from. The procedure to install from the dev updatesite is the same as described above; expect that you have to use http://springide.org/updatesite_dev/ as URL.

Previous releases of Spring IDE (starting with v1.1) can be installed from the updatesite http://springide.org/updatesite_old/.

Subversion / TortoiseSVN SSH HowTo

Because many new subversion users run into problems when attempting to use subversion with SSH, i compiled a HowTo for that issue. Perhaps i will expand this HowTo later on and submit it to the subversion or torteoiseSVN docs.

————————-
Our Scenario:
————————-
Server: Linux or unix like system
Client: Windows 2000/XP (or variant)

—————————————–
Installing subversion (server)
—————————————–
I won’t go into details here, because this topic is covered in great length in the oficial subversion documentation. But one thing i want to point out nevertheless. If you compile subversion from source and dont provide any argument to ./configure, Subversion creates a “bin” directory under /usr/local and places its binaries there. This is no problem as long as you run subversion as daemon, but if you want to use tunneling mode with SSH, you have to be aware that the user logging into via SSH can execute the svnserve program and some other binaries. For this reason, either place /usr/local/bin into the PATH variable or create symlinks of your binaries to the /usr/sbin directory or any other directory which is commonly in the PATH.

To make sure that everything is ok. Login in with SSH and the target user to the system later on and type: “which svnserve”. This command should tell you if svnserve is reachable.

Furthermore this document assumes that you allready have a subversion repository created with “svnadmin create”. Please pay attention to the ACL of the repository in order to reduce possible problems. Check that each user coming in via SSH has apropriate rights to work with the repository.

Sometimes your system has ‘mesg y’ put into the global bashrc file. This will make connections with TortoisePlink fail, since that line will make SSH throw out an error “stdin: is not a tty”. You must remove that line from your bashrc file.
————————————————
OpenSSH and certificates (server)
————————————————
Again i wont go into details about OpenSSH installation, this is covered elsewhere better. But on most systems, enabling SSH is just a matter of installing a RPM. If you rent a pre-installed linux server from a hosting company, SSH is most likely allready installed. To be sure everything is in place, type: “ps xa | grep sshd” and watch out for SSH jobs.

Assuming OpenSSH is installed, one of the most important steps is to create a keypair for authentication. There are two possible ways of creating the keys. The first way is to create the keys with puttygen (a program of the putty family), upload the public key to your server and use the private key with putty. Because of some problems with this approach, i prefer the other way. This way creates the keypair with the OpenSSH tool ssh-keygen and download the private key to your client and convert the private key to a putty-style private key.

Lets do this step by step:

- login to your server
- type: ssh-keygen -b 1024 -t dsa -N passphrase -f mykey
- change “passphrase” to a secret keyword only you know
- type: ls -l mykey*

We just created a SSH2 DSA key with 1024 bit keyphrase. You will see two files. One named “mykey” and one named “mykey.pub”. As you might guess, the .pub file is the public key file, the other is the private one. Next create a user on the server with a home directory:

- type: useradd -m myuser

You will have a directory under /home with the name “myuser”, create a new directory in “myuser” called “.ssh”:

- type: cd /home/myuser
- type: mkdir .ssh

Then go to the directory where you created your keys and copy the public key to the .ssh userfolder with the following command:

- type: cp mykey.pub /home/myuser/.ssh/authorized_keys

Please pay attention to the filename, it really must be “authorized_keys”. In some old OpenSSH implementations, it was “authorized_keys2″. Now download the private key file to your client computer. Remeber, the file was “mykey”

————————————————————
SSH key generation and connection check (client)
————————————————————
Grab the tools we need for doing SSH on windows on this site:
http://www.chiark.greenend.org.uk/~sgtatham/putty/

Just go to the download section and get “Putty”, “Plink”, “Pageant” and “Puttygen”

In order to use the private key we get from the server, we have to convert it to a putty format. This is because the private key file format is not specified by some standard body. To do this we simple open “puttygen” and open the “conversions” menu and chose “Import Key”. Then browse to your file “mykey” which you got from the server enter your provided passphrase upon creation of the key. Finally click “Save private key” and save the file as “mykey.PPK” somewhere on disk.

Now we are ready to use this key for the first time to test the connection. In order to do this, we open the program “putty” and create a new session like this:

Session->HostName: Hostname or IP Adress of your server
Session->Protocol: SSH
Session->Saved Sessions: MyConnection
SSH->Prefered SSH Protocol version: 2
SSH->Auth->Private Key file for auth: $PATH$\mykey.PKK (replace $PATH$ with real path to the mykey.PKK file)

Then go back to Session tab and hit “save” button. You will see “MyConnection” in the list of available connections.

Next click “open” and you should see a telnet login prompt. Use “myuser” as username (without double quotes of course) and if everything is ok, you dont have to provide a password to your system. If the system still requires a password, something went wrong. See Debugging Section of this HowTo.

———————————————–
Testing SSH with TortoiseSVN (client)
———————————————–
After installing TortoiseSVN (http://tortoisesvn.tigris.org/download.html) right click on some folder inside your Windows Explorer. You will see a menu item called TortoiseSVN->RepoBrowser. After opening the browser you have to enter a URL like this:

svn+ssh://myuser@MyConnection/usr/local/repos

Lets talk briefly about the URL (if you need more infos, check the subversion docs). The Schema name is “svn+ssh”, this tells Tortoise how to handle the requests to the server. After the double slashed, you can provide the user which is trying to connect to the server, in our case this is “myuser”. After the “@”, we supply our putty session name. This session name contains all details like where to find the private key and the servers IP or DNS. Last we have to provide the full path to the repository. Its assumed that a subversion repository resides at /usr/local/repos

If you submit the URL, you will see a opened tree on the next screen until the node “repos”. Yet, there has not been made any connection, because the tree representation comes from the supplied URL. When you hit the “+” button in front of “repos”, the connection will be established and you will see the “+” sign dissapearing if you dont have anything in the repository or you will see your allready imported projects and files.

Right now, you should have a running SSH Tunnel in conjunction with TortoiseSVN.

———————————————–
Configuration Variants (pagent)
———————————————–
Now i will continue to show some configuration variants, that can be helpful during everyday work.

One way to simplify the URL in TortoiseSVN is to set the user inside the putty session. For this you have to load your allready defined session “MyConnection” in putty make the following entry:

connection->Auto Login username: myuser

Then save your putty session as before and try the following URL inside Tortoise:
svn+ssh://MyConnection/usr/local/repos

This time we only provide the putty session “MyConnection” to the SSH client TortoiseSVN uses (TortoisePlink.exe). This client is capable of checking the session for all necessary details like loginuser oder server ip.

Some people like using pageant for storing all their keys and in fact each howto explains that its important to place your keys there. In fact, because a putty session is capable of storing a key, you dont need pageant for normal business. But imagine you want to store keys for several users, in that case, you would have to edit the putty session over and over again, depending on the user you are trying to connect with. For this situation pagent makes perfectly sense, because when putty, plink, tortoisePlink or any other putty-based tool is trying to connect to a SSH server, it checks all private keys that pageant carries to initiate the connection.

For this task, simply start pageant and add a key. It should be the same private key you defined in the putty session above. If you use pageant for private keys storage, you can delete the “SSH->Auth->Private Key file for auth” section inside your putty session. You can add more keys for other systems or other users of course. If you dont want to repeat this procedure after every reboot of your client, you should place the pageant in autostart group of your windows installation. You can append the keys with complete paths as command line arguments to pageant.exe

The last way to connect to a SSH server is by just using this URL inside TortoiseSVN:

svn+ssh://myuser@100.101.102.103/usr/local/repos

As you can see, we dont use a saved putty session but an IP address as connection target. We also supply the user, but you might ask how the private key file will be found. Because TortoisePlink.exe (the standard SSH client for TortoiseSVN) is a modified version of the plink tool from the putty suite, also TortoiseSVN looks for a running pageant and will try all the keys stored in pageant.

—————————————-
Debugging / Troubleshooting
—————————————-

See the other articles in the SSH section of our FAQ

——————-
Feedback
——————-
For comments or corrections on this howto, please use the TortoiseSVN mailinglist on http://tortoisesvn.tigris.org/

This is a copy of the original at: http://www.logemann.org/day/archives/000099.html

dependency injection

Dependency injection (DI) is a programming design pattern and architectural model, sometimes also referred to as Inversion of Control or IoC, although technically speaking, dependency injection specifically refers to an implementation of a particular form of IoC. The pattern seeks to establish a level of abstraction via a public interface, and to remove dependency on components by (for example) supplying a plug-in architecture. The architecture unites the components rather than the components linking themselves or being linked together. Dependency injection is a pattern in which responsibility for object creation and object linking is removed from the objects themselves and transferred to a factory. Dependency injection therefore is obviously inverting the control for object creation and linking, and can be seen to be a form of IoC.

There are three common forms of dependency injection: setter, constructor and interface based injection.

Dependency injection is a way to achieve loose coupling. The technique results in highly testable objects, particularly when applying test-driven development using mock objects: Avoiding dependencies on the implementations of collaborating classes (by depending only on interfaces that those classes adhere to) makes it possible to produce controlled unit tests that focus on exercising the behavior of, and only of, the class under test. To achieve this, dependency injection is used to cause instances of the class under test to interact with mock collaborating objects, whereas, in production, dependency injection is used to set up associations with bona fide collaborating objects.
[edit]

Existing Frameworks

Dependency of Injection frameworks exist for a number of platforms and languages including:

Java
Spring Framework
PicoContainer
HiveMind
JBoss Microcontainer
Seasar

Ruby
Copland
Needle

Perl
The IOC Module

Python
PyContainer

.NET
Puzzle.NFactory
Castle DynamicProxy/Windsor
Spring.NET
ObjectBuilder
PicoContainer.NET

C++
QtIocContainer

Courses 2006H

你不能没有的心机(刘庸)

一、说话有分寸,祸多从口出

俗话说:“病从口入,祸从口出”,也许一句本不该说的话说出去以后就可能毁灭一个女人的幸福。所以,女人在这方面就要多用“心计”,掌握说话的各种技巧,把握说话分寸,避免惹祸上身,葬送自己的幸福。

二、说话不能太绝,嘴不遮掩难成大事

做人要有“心机”,很多时候体现在语言上,有些人话说得绝对,信誓旦旦,又嘴不遮掩,处处许诺,结果能做到的很少,泡汤的很多,最终累得自己半死,还遭人讨厌,真是得力不讨好,费心还伤神。

三、给自己施恩,懂得选择放弃
生命就是一个不断选择和放弃的过程,人生要背负的东西很多,久而久之就会成为负担。只有懂得适时选择和放弃的人才有资格赢得幸福的青睐。

四、舍卒保车,懂得选择放弃
舍卒保车是一种“心计”、一种眼光、一种谋略。纵观天下,凡成就大事的男人   无不懂得选择和放弃。只有放弃某些利益,有时放弃是为了更好的拥有!

五、做人拥有好心态——想得开活得不累

宠辱不惊,看庭前花开花落;去留无意,望天上云春云舒。

心态决定一切,有好的心态就活得潇洒不累。

做人若能做到“宠辱不惊”的境界,人生不管遇上什么大事难题也无所畏惧,哪怕天塌下来,也一样能应付自如。

六、懂方圆之道:没事不惹事,来事不怕事

做人要有“心机”,就要懂得方圆之道。能够“亦方亦圆”,那么何为“方”何为“圆”?

一般来说,自然形成的都是圆的,人为修饰的都是方的,因此,方为动,圆为静,方是原则,圆是机变,方是以不变应万变,圆是一万变应不变。外表要圆(大智若愚),内心要方(清静明志);对己要方(严于律己),对人要圆(宽以待人)有圆无方则不立,有方无圆则滞泥。所以,做人时能以方亦圆,方中有圆,圆内容方,才能够在交际中应付自如。没事不惹事,来事不怕事。

七、打破常规,尊重权威但不被权威所左右

大多时候,人们已经习惯了权威的存在,在权威的指导下做事。但有主见的男人会发现如此的随波逐流注定将一事无成。我们面对权威要尊重,但决不能被权威所左右。只有敢于打破权威的主人才能打到成大事的入口。

八、心态决定一切:好“心计”是好心态的前提

良好的心态是做大事绝对不能少的条件,而好“心计”是好心态的前提。

每个人在做事过程中,总是有许多挫折相伴,无论怎样坚强的人都难免产生各种各样的不良情绪,自卑、沮丧。甚至一蹶不振,许多本可成就大事的人,由于不好的心态,事业就此夭折,生命就此黯淡。面对此种情况,必须明白,胜败乃兵家常事,要想做事成功,首先磨练自己的心态,好好利用自己的“心计”,让它足以应对一切。

九、感情投资、冷庙香热身香都要烧

有古语说:商不厌诈,所以生意场上的风云变幻莫测便可想而知了。而人情是生意场上一本难念又不能不念的“经”。

十、重在思考:不浮不躁想清楚了再做

三思而后行,想好了再做,事情就能做得圆满。

做事不要犹豫是要你思考得清楚再做,而不是思考鲁莽去做。思考是做事的前提,果断是做事的方法。

做事要有“心计”,就是重在思考,不浮不躁想清楚了再做。

十一、打破常规:不被规则束缚手脚

保守的人做事往往会被规则束缚住手脚,没有创新,不能够打破常规,事情办得再好,也是费功夫不讨好的事情。

做事有“心计”的人,往往能够打破常规,用最简单的方法做最快的事,而且能够做得圆满。

关闭 Windows 没用的服务,让你的电脑提速百倍

在控制面板→管理工具→服务或在运行里直接输入“services.msc”也可。
Alerter
微软: 通知选取的使用者及计算机系统管理警示。如果停止这个服务,使用系统管理警示的程序将不会收到通知。如果停用这个服务,所有依存于它的服务将无法启动。
补充: 一般家用计算机根本不需要传送或接收计算机系统管理来的警示(Administrative Alerts),除非你的计算机用在局域网络上
依存: Workstation
建议: 已停用

Application Layer Gateway Service
微软: 提供因特网联机共享和因特网联机防火墙的第三方通讯协议插件的支持
补充: 如果你不使用因特网联机共享 (ICS) 提供多台计算机的因特网存取和因特网联机防火墙 (ICF) 软件你可以关掉
依存: Internt Connection Firewall (ICF) / Internet Connection Sharing (ICS)
建议: 已停用
Application Management (应用程序管理)
微软: 提供指派、发行、以及移除的软件安装服务。
补充: 如上说的软件安装变更的服务
建议: 手动

Automatic Updates
微软: 启用重要 Windows 更新的下载及安装。如果停用此服务,可以手动的从 Windows Update 网站上更新*作系统。
补充: 允许 Windows 于背景自动联机之下,到 Microsoft Servers 自动检查和下载更新修补程序
建议: 已停用

Background Intelligent Transfer Service
微软: 使用闲置的网络频宽来传输数据。
补充: 经由 Via HTTP1.1 在背景传输资料的?#124;西,例如 Windows Update 就是以此为工作之一
依存: Remote Procedure Call (RPC) 和 Workstation
建议: 已停用

ClipBook (剪贴簿)
微软: 启用剪贴簿检视器以储存信息并与远程计算机共享。如果这个服务被停止,剪贴簿检视器将无法与远程计算机共享信息。如果这个服务被停用,任何明确依存于它的服务将无法启动。
补充: 把剪贴簿内的信息和其它台计算机分享,一般家用计算机根本用不到
依存: Network DDE
建议: 已停用

COM+ Event System (COM+ 事件系统)
微软: 支持「系统事件通知服务 (SENS)」,它可让事件自动分散到订阅的 COM 组件。如果服务被停止,SENS 会关闭,并无法提供登入及注销通知。如果此服务被停用,任何明显依存它的服务都无法启动。
补充: 有些程序可能用到 COM+ 组件,像 BootVis 的 optimize system 应用,如事件检视器内显示的 DCOM 没有启用
依存: Remote Procedure Call (RPC) 和 System Event Notification
建议: 手动

COM+ System Application
微软: 管理 COM+ 组件的设定及追踪。如果停止此服务,大部分的 COM+ 组件将无法适当?#092;作。如果此服务被停用,任何明确依存它的服务将无法启动。
补充: 如果 COM+ Event System 是一台车,那么 COM+ System Application 就是司机,如事件检视器内显示的 DCOM 没有启用
依存: Remote Procedure Call (RPC)
建议: 手动

Computer Browser (计算机浏览器)
微软: 维护网络上更新的计算机清单,并将这个清单提供给做为浏览器的计算机。如果停止这个服务,这个清单将不会被更新或维护。如果停用这个服务,所有依存于它的服务将无法启动。
补充: 一般家庭用计算机不需要,除非你的计算机应用在区网之上,不过在大型的区网上有必要开这个拖慢速度吗?
依存: Server 和 Workstation
建议: 已停用

Cryptographic Services
微软: 提供三个管理服务: 确认 Windows 档案签章的 [类别目录数据库服务]; 从这个计算机新增及移除受信任根凭证授权凭证的 [受保护的根目录服务]; 以及协助注册这个计算机以取得凭证的 [金钥服务]。如果这个服务被停止,这些管理服务将无法正确工作。如果这个服务被停用,任何明确依存于它的服务将无法启动。
补充: 简单的说就是 Windows Hardware Quality Lab (WHQL)微软的一种认证,如果你有使用 Automatic Updates ,那你可能需要这个
依存: Remote Procedure Call (RPC)
建议: 手动

DHCP Client (DHCP 客户端)
微软: 透过登录及更新 IP 地址和 DNS 名称来管理网络设定。
补充: 使用 DSL/Cable 、ICS 和 IPSEC 的人都需要这个来指定动态 IP
依存: AFD 网络支持环境、NetBT、SYMTDI、TCP/IP Protocol Driver 和 NetBios over TCP/IP
建议: 手动

Distributed Link Tracking Client (分布式连结追踪客户端)
微软: 维护计算机中或网络网域不同计算机中 NTFS 档案间的连结。
补充: 维护区网内不同计算机之间的档案连结
依存: Remote Procedure Call (RPC)
建议: 已停用

Distributed Transaction Coordinator (分布式交易协调器)
微软: 协调跨越多个资源管理员的交易,比如数据库、讯息队列及档案系统。如果此服务被停止,这些交易将不会发生。如果服务被停用,任何明显依存它的服务将无法启动。
补充: 如上所说的,一般家庭用计算机用不太到,除非你启用的 Message Queuing
依存: Remote Procedure Call (RPC) 和 Security Accounts Manager
建议: 已停用

DNS Client (DNS 客户端)
微软: 解析并快取这台计算机的网域名称系统 (DNS) 名称。如果停止这个服务,这台计算机将无法解析 DNS 名称并寻找 Active Directory 网域控制站的位置。如果停用这个服务,所有依存于它的服务将无法启动。
补充: 如上所说的,另外 IPSEC 需要用到
依存: TCP/IP Protocol Driver
建议: 手动

Error Reporting Service
微软: 允许对执行于非标准环境中的服务和应用程序的错误报告。
补充: 微软的应用程序错误报告
依存: Remote Procedure Call (RPC)
建议: 已停用

Event Log (事件记录文件)
微软: 启用 Windows 为主的程序和组件所发出的事件讯息可以在事件检视器中检视。这个服务不能被停止。
补充: 允许事件讯息显示在事件检视器之上
依存: Windows Management Instrumentation
建议: 自动

Fast User Switching Compatibility
微软: 在多使用者环境下提供应用程序管理。
补充: 另外像是注销画面中的切换使用者功能
依存: Terminal Services
建议: 手动

Help and Support
微软: 让说明及支持中心能够在这台计算机上执行。如果这个服务停止,将无法使用说明及支持中心。如果这个服务被停用,它的所有依存服务将无法启动。
补充: 如果不使用就关了吧
依存: Remote Procedure Call (RPC)
建议: 已停用

Human Interface Device Access
微软: 启用对人性化接口装置 (HID) 的通用输入存取,HID 装置启动并维护对这个键盘、远程控制、以及其它多媒体装置上事先定义的快捷纽的使用。如果这个服务被停止,这个服务控制的快捷纽将不再起作用。如果这个服务被停用,任何明确依存于它的服务将无法启动。
补充: 如上所提到的
依存: Remote Procedure Call (RPC)
建议: 已停用

IMAPI CD-Burning COM Service
微软: 使用 Image Mastering Applications Programming Interface (IMAPI) 来管理光盘录制。如果这个服务被停止,这个计算机将无法录制光盘。如果这个服务被停用,任何明确地依赖它的服务将无法启动。
补充: XP 整合的 CD-R 和 CD-RW 光驱上拖放的烧录功能,可惜比不上烧录软件,关掉还可以加快 Nero 的开启速度
建议: 已停用

Indexing Service (索引服务)
微软: 本机和远程计算机的索引内容和档案属性; 透过弹性的查询语言提供快速档案存取。
补充: 简单的说可以让你加快搜查速度,不过我想应该很少人和远程计算机作搜寻吧
依存: Remote Procedure Call (RPC)
建议: 已停用

Internet Connection Firewall (ICF) / Internet Connection Sharing (ICS)
微软: 为您的家用网络或小型办公室网络提供网络地址转译、寻址及名称解析服务和/或防止干扰的服务。
补充: 如果你不使用因特网联机共享(ICS)或是 XP 内含的因特网联机防火墙(ICF)你可以关掉
依存: Application Layer Gateway Service、Network Connections、Network Location Awareness(NLA)、Remote Access Connection Manager
建议: 已停用

IPSEC Services (IP 安全性服务)
微软: 管理 IP 安全性原则并启动 ISAKMP/Oakley (IKE) 及 IP 安全性驱动程序。
补充: 协助保护经由网络传送的数据。IPSec 为一重要环节,为虚拟私人网络 (VPN) 中提供安全性,而 VPN 允许组织经由因特网安全地传输数据。在某些网域上也许需要,但是一般使用者大部分是不太需要的
依存: IPSEC driver、Remote Procedure Call (RPC)、TCP/IP Protocol Driver
建议: 手动

Logical Disk Manager (逻辑磁盘管理员)
微软: 侦测及监视新硬盘磁盘,以及传送磁盘区信息到逻辑磁盘管理系统管理服务以供设定。如果这个服务被停止,动态磁盘状态和设定信息可能会过时。如果这个服务被停用,任何明确依存于它的服务将无法启动。
补充: 磁盘管理员用来动态管理磁盘,如显示磁盘可用空间等和使用 Microsoft Management Console(MMC)主控台的功能
依存: Plug and Play、Remote Procedure Call (RPC)、Logical Disk Manager Administrative Service
建议: 自动

Logical Disk Manager Administrative Service (逻辑磁盘管理员系统管理服务)
微软: 设定硬盘磁盘及磁盘区,服务只执行设定程序然后就停止。
补充: 使用 Microsoft Management Console(MMC)主控台的功能时才用到
依存: Plug and Play、Remote Procedure Call (RPC)、Logical Disk Manager
建议: 手动

Messenger (信差)
微软: 在客户端及服务器之间传输网络传送及 [Alerter] 服务讯息。这个服务与 Windows Messenger 无关。如果停止这个服务,Alerter 讯息将不会被传输。如果停用这个服务,所有依存于它的服务将无法启动。
补充: 允许网络之间互相传送提示讯息的功能,如 net send 功能,如不想被骚扰话可关了
依存: NetBIOS Interface、Plug and Play、Remote Procedure Call (RPC)、Workstation
建议: 已停用

MS Software Shadow Copy Provider
微软: 管理磁盘区阴影复制服务所取得的以软件为主的磁盘区阴影复制。如果停止这个服务,就无法管理以软件为主的磁盘区阴影复制。如果停用这个服务,任何明确依存于它的服务将无法启动。
补充: 如上所说的,用来备份的?#124;西,如 MS Backup 程序就需要这个服务
依存: Remote Procedure Call (RPC)
建议: 已停用

Net Logon
微软: 支持网域上计算机的账户登入事件的 pass-through 验证。
补充: 一般家用计算机不太可能去用到登入网域审查这个服务
依存: Workstation
建议: 已停用

NetMeeting Remote Desktop Sharing (NetMeeting 远程桌面共享)
微软: 让经过授权的使用者可以使用 NetMeeting 透过公司近端内部网络,由远程访问这部计算机。如果这项服务停止的话,远程桌面共享功能将无法使用。如果服务停用的话,任何依赖它的服务将无法启动。
补充: 如上说的,让使用者可以将计算机的控制权分享予网络上或因特网上的其它使用者,如果你重视安全性不想多开后门,就关了吧
建议: 已停用

Network Connections (网络联机)
微软: 管理在网络和拨号联机数据夹中的对象,您可以在此数据夹中检视局域网络和远程联机。
补充: 控制你的网络联机
依存: Remote Procedure Call (RPC)、Internet Connection Firewall (ICF) / Internet Connection Sharing (ICS)
建议: 手动

Network DDE (网络 DDE)
微软: 为动态数据交换 (DDE) 对在相同或不同计算机上执行的程序提供网络传输和安全性。如果这个服务被停止,DDE 传输和安全性将无法使用。如果这个服务被停用,任何明确依存于它的服务将无法启动。
补充: 一般人好像用不到
依存: Network DDE DSDM、ClipBook
建议: 已停用

Network DDE DSDM (网络 DDE DSDM)
微软: 讯息动态数据交换 (DDE) 网络共享。如果这个服务被停止,DDE 网络共享将无法使用。如果这个服务被停用,任何明确依存于它的服务将无法启动。
补充: 一般人好像用不到
依存: Network DDE
建议: 已停用

Network Location Awareness (NLA)
微软: 收集并存放网络设定和位置信息,并且在这个信息变更时通知应用程序。
补充: 如果不使用 ICF 和 ICS 可以关了它
依存: AFD网络支持环境、TCP/IP Procotol Driver、Internet Connection Firewall (ICF) / Internet Connection Sharing (ICS)
建议: 已停用

NT LM Security Support Provider (NTLM 安全性支持提供者)
微软: 为没有使用命名管道传输的远程过程调用 (RPC) 程序提供安全性。
补充: 如果不使用 Message Queuing 或是 Telnet Server 那就关了它
依存: Telnet
建议: 已停用

Performance Logs and Alerts (效能记录文件及警示)
微软: 基于事先设定的排程参数,从本机或远程计算机收集效能数据,然后将数据写入记录或?#124;发警讯。如果这个服务被停止,将不会收集效能信息。如果这个服务被停用,任何明确依存于它的服务将无法启动。
补充: 没什么价值的服务
建议: 已停用

Plug and Play (随插随用)
微软: 启用计算机以使用者没有或很少的输入来识别及适应硬件变更,停止或停用这个服务将导致系统不稳定。
补充: 顾名思义就是 PNP 环境
依存: Logical Disk Manager、Logical Disk Manager Administrative Service、Messenger、Smart Card、Telephony、Windows Audio
建议: 自动

Portable Media Serial Number
微软: Retrieves the serial number of any portable music player connected to your computer
补充: 透过联机计算机重新取得任何音乐拨放序号?没什么价值的服务
建议: 已停用

Print Spooler (打印多任务缓冲处理器)
微软: 将档案加载内存中以待稍后打印。
补充: 如果没有打印机,可以关了
依存: Remote Procedure Call (RPC)
建议: 已停用

Protected Storage (受保护的存放装置)
微软: 提供受保护的存放区,来储存私密金钥这类敏感数据,防止未授权的服务、处理、或使用者进行存取。
补充: 用来储存你计算机上密码的服务,像 Outlook、拨号程序、其它应用程序、主从架构等等
依存: Remote Procedure Call (RPC)
建议: 自动

QoS RSVP (QoS 许可控制,RSVP)
微软: 提供网络讯号及区域流量控制安装功能给可识别 QoS 的程序和控制小程序项。
补充: 用来保留 20% 频宽的服务,如果你的网络卡不支持 802.1p 或在你计算机的网域上没有 ACS server ,那么不用多说,关了它
依存: AFD网络支持环境、TCP/IP Procotol Driver、Remote Procedure Call (RPC)
建议: 已停用

Remote Access Auto Connection Manager (远程访问自动联机管理员)
微软: 当程序参照到远程 DNS 或 NetBIOS 名称或地址时,建立远程网络的联机。
补充: 有些 DSL/Cable 提供者,可能需要用此来处理登入程序
依存: Remote Access Connection Manager、Telephony
建议: 手动

Remote Access Connection Manager (远程访问联机管理员)
微软: 建立网络联机。
补充: 网络联机用
依存: Telephony、Internet Connection Firewall (ICF) / Internet Connection Sharing (ICS)、Remote Access Auto Connection Manager
建议: 手动

Remote Desktop Help Session Manager
微软: 管理并控制远程协助。如果此服务停止的话,远程协助将无法使用。停止此服务之前,请先参阅内容对话框中的 [依存性]标签。
补充: 如上说的管理和控制远程协助,如果不使用可以关了
依存: Remote Procedure Call (RPC)
建议: Disable

Remote Procedure Call (RPC) (远程过程调用,RPC)
微软: 提供结束点对应程序以及其它 RPC 服务。
补充: 一些装置都依存它,别去动它
依存: 太多了,自己去看看
建议: 自动

Remote Procedure Call (RPC) Locator (远程过程调用定位程序)
微软: 管理 RPC 名称服务数据库。
补充: 如上说的,一般计算机上很少用到,可以尝试关了
依存: Workstation
建议: Disable

Remote Registry (远程登录服务)
微软: 启用远程使用者修改这个计算机上的登录设定。如果这个服务被停止,登录只能由这个计算机上的使用者修改。如果这个服务被停用,任何明确依存于它的服务将无法启动。
补充: 基于安全性的理由,如果没有特别的需求,建议最好关了它,除非你需要远程协助修改你的登录设定
依存: Remote Procedure Call (RPC)
建议: 已停用

Removable Storage (卸除式存放装置)
微软: None
补充: 除非你有 Zip 磁盘驱动器或是 USB 之类可携式的硬件或是 Tape 备份装置,不然可以尝试关了
依存: Remote Procedure Call (RPC)
建议: Disable

Routing and Remote Access (路由和远程访问)
微软: 提供连到局域网络及广域网络的公司的路由服务。
补充: 如上说的,提供拨号联机到区网或是 VPN 服务,一般用户用不到
依存: Remote Procedure Call (RPC)、NetBIOSGroup
建议: 已停用

Secondary Logon
微软: 启用在其它认证下的起始程序。如果这个服务被停止,这类的登入存取将无法使用。如果这个服务被停用,任何明确依存于它的服务将无法启动。
补充: 允许多个使用者处理程序,执行分身等
建议: 自动

Security Accounts Manager (安全性账户管理员)
微软: 储存本机账户的安全性信息。
补充: 管理账号和群组原则(gpedit.msc)应用
依存: Remote Procedure Call (RPC)、Distributed Transaction Coordinator
建议: 自动

Server (服务器)
微软: 透过网络为这台计算机提供档案、打印、及命名管道的共享。如果停止这个服务,将无法使用这些功能。如果停用这个服务,所有依存于它的服务将无法启动。
补充: 简单的说就是档案和打印的分享,除非你有和其它计算机分享,不然就关了
依存: Computer Browser
建议: 已停用

Shell Hardware Detection
微软: 为自动播放硬件事件提供通知。
补充: 一般使用在记忆卡或是CD装置、DVD装置上
依存: Remote Procedure Call (RPC)
建议: 自动

Smart Card (智慧卡)
微软: 管理这个计算机所读取智能卡的存取。如果这个服务被停止,这个计算机将无法读取智能卡。如果这个服务被停用,任何明确依存于它的服务将无法启动。
补充: 如果你不使用 Smart Card ,那就可以关了
依存: Plug and Play
建议: 已停用

Smart Card Helper (智能卡协助程序)
微软: 启用对这个计算机使用的旧版非随插即用智能卡读取头的支持。如果这个服务被停止,这个计算机将不支持旧版读取头。如果这个服务被停用,任何明确依存于它的服务将无法启动。
补充: 如果你不使用 Smart Card ,那就可以关了
建议: 已停用

SSDP Discovery Service
微软: 在您的家用网络上启用通用随插即用装置的搜索。
补充: 如上说的,通用随插即用服务 (Universal Plug and Play, UPnP) 让计算机可以找到并使用网络上的装置,经由网络联机透过 TCP/IP 来搜索装置,像网络上的扫瞄器、数字相机或是打印机,亦即使用 UPnP 的功能,基于安全性没用到的大可关了
依存: Universal Plug and Play Device Host
建议: 已停用

System Event Notification (系统事件通知)
微软: 追踪诸如 Windows 登入、网络、和电源事件的系统事件。通知这些事件的 COM+ 事件系统订阅者。
补充: 如上所说的
依存: COM+ Event System
建议: 自动

System Restore Service
微软: 执行系统还原功能。若要停止服务,从我的计算机->内容,[系统还原] 中关闭系统还原
补充: 将计算机回复至先前的状态,不使用就关了
依存: Remote Procedure Call (RPC)
建议: 已停用

Task Scheduler (工作排程器)
微软: 让使用者能够在这个计算机上设定和排定自动的工作。如果停止这个服务,这些工作在它们排定的时间时将不会执行。如果停用这个服务,任何明确依存于它的服务将无法启动。
补充: 设定排定自动的工作,像一些定时磁盘扫瞄、病毒定时扫瞄、更新等等
依存: Remote Procedure Call (RPC)
建议: 自动

TCP/IP NetBIOS Helper (TCP/IP NetBIOS 协助程序)
微软: 启用 [NetBIOS over TCP/IP (NetBT)] 服务及 NetBIOS 名称解析的支持。
补充: 如果你的网络不使用 NetBios 或是 WINS ,你大可关闭
依存: AFD 网络支持环境、NetBt
建议: 已停用

Telephony (电话语音)
微软: 为本机计算机上及经由局域网络连接到正在执行此服务的服务器上,控制电话语音装置和 IP 为主语音联机的程序,提供电话语音 API (TAPI) 支持。
补充: 一般的拨号调制解调器或是一些 DSL/Cable 可能用到
依存: Plug and Play、Remote Procedure Call (RPC)、Remote Access Connection Manager、Remote Access Auto Connection Manager
建议: 手动

Telnet
微软: 启用一个远程使用者来登入到这台计算机和执行应用程序,以及支持各种 TCP/IP Telnet 客户端,包含以 UNIX 为基本和以 Windows 为基本的计算机。如果服务停止了,远程使用者可能无法存取应用程序。如果服务停用了,任何明确地依存于这项服务的其它服务将会启动失败。
补充: 允许远程使用者用 Telnet 登入本计算机,一般人会误解关了就无法使用BBS,这其实和BBS无关,基于安全性的理由,如果没有特别的需求,建议最好关了
依存: NT LM Security Support Provider、Remote Procedure Call (RPC)、TCP/IP Protocol Driver
建议: 已停用

Terminal Services (终端机服务)
微软: 允许多位使用者互动连接到同一部计算机、桌面的显示器及到远程计算机的应用程序。远程桌面的加强 (包含系统管理员的 RD)、快速切换使用者、远程协助和终端机服务器。
补充: 远程桌面或是远程协助的功能,不需要就关了
依存: Remote Procedure Call (RPC)、Fast User Switching Compatibility、InteractiveLogon
建议: 已停用

Themes
微软: 提供使用者经验主题管理。
补充: 很多人使用布景主题,不过如果没有使用的人,那就可以关闭
建议: 自动

Uninterruptible Power Supply (不断电供电系统)
微软: 管理连接到这台计算机的不断电电源供应 (UPS)。
补充: 不断电电源供应 (UPS)一般人有用到吗?除非你的电源供应器有具备此功能,不然就关了
建议: 已停用

Universal Plug and Play Device Host
微软: 提供主机通用随插即用装置的支持。
补充: 用来侦测安装通用随插即用服务 (Universal Plug and Play, UPnP)装置,像是数字相机或打印机
依存: SSDP Discovery Service
建议: 已停用

Volume Shadow Copy
微软: 管理及执行用于备份和其它目的的磁盘区卷影复制。如果这个服务被停止,卷影复制将无法用于备份,备份可能会失败。如果这个服务被停用,任何明确依存于它的服务将无法启动。
补充: 如上所说的,用来备份的?#124;西,如 MS Backup 程序就需要这个服务
依存: Remote Procedure Call (RPC)
建议: 已停用

WebClient
微软: 启用 Windows 为主的程序来建立、存取,以及修改因特网为主的档案。如果停止这个服务,这些功能将无法使用。如果停用这个服务,任何明确依存于它的服务将无法启动。
补充: 使用 WebDAV 将档案或数据夹上载到所有的 Web 服务,基于安全性的理由,你可以尝试关闭
依存: WebDav Client Redirector
建议: 已停用

Windows Audio
微软: 管理用于 Windows 为主程序的音讯装置。如果这个服务被停止,音讯装置和效果将无法正常?#092;作。如果这个服务被停用,任何明确依存于它的服务将无法启动。
补充: 如果你没有声卡可以关了他
依存: Plug and Play、Remote Procedure Call (RPC)
建议: 自动

Windows Image Acquisition (WIA) (Windows影像取得程序)
微软: 为扫描仪和数字相机提供影像撷取服务。
补充: 如果扫描仪和数字相机内部具有支持WIA功能的话,那就可以直接看到图档,不需要其它的驱动程序,所以没有扫描仪和数字相机的使用者大可关了
依存: Remote Procedure Call (RPC)
建议: 已停用

Windows Installer (Windows 安装程序)
微软: 根据包含在 .MSI 档案内的指示来安装,修复以及移除软件。
补充: 是一个系统服务,协助使用者正确地安装、设定、追踪、升级和移除软件程序,可管理应用程序建立和安装的标准格式,并且追踪例如档案群组、登录项目及快捷方式等组件
依存: Remote Procedure Call (RPC)
建议: 手动

Windows Management Instrumentation (WMI)
微软: 提供公用接口及对象模型,以存取有关*作系统、装置、应用程序及服务的管理信息。如果这个服务已停止,大多数的 Windows 软件将无法正常?#092;作。如果这个服务已停用,所有依存于它的服务都将无法启动。
补充: 如上说的,是一种提供一个标准的基础结构来监视和管理系统资源的服务,由不得你动他
依存: Event Log、Remote Procedure Call (RPC)
建议: 自动

Windows Management Instrumentation Driver Extensions (Windows Management Instrumentation 驱动程序延伸)
微软: 提供系统管理信息给予/取自驱动程序。
补充: Windows Management Instrumentation 的延伸,提供信息用的
建议: 手动

Windows Time (Windows 时间设定)
微软: 维护在网络上所有客户端及服务器的数据及时间同步处理。如果这个服务停止,将无法进行日期及时间同步处理。如果这个服务被停用,所有依存的服务都会停止。
补充: 网络对时校准用的,没必要就关了
建议: 已停用

Wireless Zero Configuration
微软: 为 802.11 适配卡提供自动设定
补充: 自动配置无线网络装置,言下之意就是说,除非你有在使用无线网络适配卡装置,那么你才有必要使用这个网络零管理服务
依存: NDIS Usermode I/O Protocol、Remote Procedure Call (RPC)
建议: 已停用

WMI Performance Adapter
微软: 提供来自 WMIHiPerf 提供者的效能链接库信息。
补充: 如上所提
依存: Remote Procedure Call (RPC)
建议: 已停用l

Workstation (工作站)
微软: 建立并维护到远程服务器的客户端网络联机。如果停止这个服务,这些联机将无法使用。如果停用这个服务,所有依存于它的服务将无法启动。
补充: 因特网联机中所必要的一些功能
依存: Alerter、Background Intelligent Transfer Service、Computer Browser、Messenger、Net Logon、Remote Procedure Call (RPC) Locator
建议: 自动

« Older entries