Guice项目实战
引言
公元二零零七年,开源领域各IoC框架战火不断。Spring大红大紫,独领风骚;PicoContainer、Hivemind紧随其后,穷追不舍。正当各路豪杰稳步发展之时,一匹黑马悄悄杀进江湖,这就是号称比Spring快100倍的Guice,从此江湖又起风云!
Guice是由Bob lee设计的基于Java5 Annotation的轻量级IoC容器,它把组织对象依赖关系的逻辑从XML文件转移到对象内部,巧妙的实现了DI模式。本文并不打算详细讲解Guice的语法,如果你尚且不知道Guice是什么,可以先阅读附录中提供的文章了解Guice 相关信息。本文余下部分将用一个以Guice为基础的简单的MVC模式的参考实现(实在是不知道应该叫什么,暂且就称之为参考实现吧 )以及在该实现基础上开发的XXX示例来深入Guice应用开发实战。
声明:
本文所述之AromaRI,MVC Pattern Reference Implementation 完全出于演示目的,
请勿以名称及设计之好坏进行任何恶意评论,在此深表谢意!
本文组织结构
1、AromaRI实现原理
AromaRI是一个基于“请求-响应”方式的MVC参考实现(MVC
Pattern Reference Implementation),它非常的简单,只由为数不多的几个类构成。该部分简要介绍AromaRI的实现原理,并演示其使用方法。
2、XXX案例研究
案例是最能说明问题的表达方式,此处通过XXX案例详细讲解如何在AromaRI中使用Guice,在其他框架中也可以通过类似的方式集成Guice。你将发现,事情原来如此简单!
3、Guice源码分析
掌握一种开源框架并能够理解其设计思想,其终极之道莫过于阅读框架源码了。该部分将带领读者一起深入Guice框架内部,研究其实现原理,领会其设计思想。
4、EasyJWeb与Guice集成
EasyJWeb是一个国产的简易JA V A WEB开发框架,它简单、易用,可以很容易的和其他IoC框架进行集成。本部分详细讲解如何在EasyJWeb项目中使用Guice。
5、总结
说明
6、附录
附录中介绍了一些关于Guice框架的有用资源,读者可以通过阅读这些资源了解更多Guice相关知识。
接下来让我们一起开始愉快的Guice之旅!!
友情提醒:
编写本文之目的在于通过项目实战讲解Guice及其相关技术,让读者能够迅速获得
Guice开发经验,并能够应用于实际项目之中。所以,请明确你是在学习Guice而
非笔者设计的AromaRI!
AromaRI实现原理:
AromaRI,其名字本身并没有特殊内涵,笔者在设计时为取一个合适的名字而伤透脑筋。很多人喜欢把自己设计的东西称为“框架”、“Framework”,另一些人认为其原理或实现过于简单并不能称之为Framework,因而导致双方激烈的口舌之战。为避免不必要的争论,笔者没有采用XXX Framework的名字,而是起了一个简单的名字——AromaRI。尽管RI(Reference Implementation)也不恰当,但请读者勿以该名字为由进行任何评论!
或许此时此刻你会有这样的疑问:JA V A领域开源的MVC框架多如牛毛,你为什么还要自己写一个实现呢?就笔者的经验来看,任何一种MVC框架,无论是基于请求-响应模式还是基于事件驱动模式,或高或低都有一定的学习难度。编写本文之目的在于通过项目实战来讲解Guice及其相关技术,让读者能够迅速获得Guice开发经验并可以在自己的项目中应用Guice。因此,为了避免读者将时间花费在学习某种MVC框架上,笔者设计了现在的AromaRI。AromaRI是一个基于“请求-响应”方式的MVC参考实现(MVC Pattern Reference Implementation)。它非常简单,只由为数不多的几个类构成,实现了
MVC模式的基本功能,足够演示之用,而且读者掌握它几乎没有任何难度!
说了这么多废话,该是进入正题的时候了。AromaRI由一个Servlet、一个Container和若干Action构成。该Servlet应用了经典的J2EE前端控制器模式,实现了模型和视图相分离。下面让我们来看一下AromaRI的工作原理示例图:
AromaRI -MVC Pattern Reference Implementation
上图比较清晰地描述了AromaRI的工作原理,但略显复杂。因此,笔者特意将上图拆分成两部分进行讲解,如下:
AromaRI -Front Controller Architecture
如上图所示,AromaServlet作为应用唯一入口,统一接收用户请求并根据规则指派Action类处理用户请求。ActionContext用于在AromaServlet和Action之间传递数据,封装了HttpServletRequest参数。Container作为Action 容器,为当前请求提供Action实例。
注意:从Container中获取的Action实例已经按照Guice的规则自动进行依赖注入。
5
AromaRI -Container Architecture
该图演示了Container Architecture的工作方式:SingletonContainerLoader调用ConfigParser解析应用配置文件-aromari-components.xml,并根据解析结果(此处是Component数组)构造DefaultContainer实例,最后调用容器的init方法进行容器初始化。执行完毕,将该容器放入当前线程上下文中,以共其他地方引用。
注意:这里忽略了一个细节- 容器初始化过程中可以注册用户自定义的Module,后面会有详细讲解。
6
相信看到此处,稍有经验的读者都已经非常清楚AromaServlet和Action的原理和工作方式了。惟独这个Container会让大家心存疑惑: Container如何初始化?
Container和Guice之间是什么关系?
如何从Container获取Action对象?
Container中的Action如何实现自动注入依赖对象?
Container中的Action有没有作用域?
Container中的Action如何工作?
能否通过Container查找非Action对象?
或许思维敏捷的你还有更多的疑问,那么就请跟随笔者的思路一步步解开心中的疑惑。
在解答这些问题之前还是需要介绍一下AromaRI中Action的工作原理。Action接口参考了国产开源框架EasyJWeb中Action的设计原理,但做了大量的简化,因此功能上也削弱了大半。但作为演示之用,足以满足我们的需求。如果读者希望进行更加深入的研究,请到EasyJWeb官方网站了解更多信息。Action接口中只有一个方法:public void execute(ActionContext context);
ActionContext作为请求上下文封装了HttpServletRequest和HttpServletContext,实现与WEB层的分离。所有Http请求中的参数都会自动被填加到ActionContext中并传递给Action对象,在ActionContext中可以通过如下方法获取Http请求中的参数:
public Object getParameter(String name);
Action在处理完该请求之后可以调用
public void addResult(String name, Object value);
方法将结果设置到Http请求的属性当中,页面上可以直接引用这些结果对象。在ActionContext中还有一个方法用于设置响应页面public void setNextPage(String page);
仅此而已,剩下的工作就由AromaServlet自动完成。在WEB应用开发中经常会遇到这种情况:一个Action通常要处理多个操作,如对用户信息的增、删、改、查通常都会放到一个Action中以减少类的数量,降低维护成本。一个可选的办法就是在请求中设置一个参数代表当前的操作,然后在execute()方法中做N多的IF/ELSE判断来决定到底应该调用哪个操作,这也是很多人的正在采用的做法。AromaRI默认提供了一个Action支持类:ActionSupport,可以幽雅地解决这个问题。任何继承ActionSupport的类都可以定义若干个处理方法,然后在请求中增加一个参数“command=xxx”来决定具体调用哪个方法,没有任何IF/ELSE判断。但是这里有一个约定,所有方法都必须遵循如下的语法规则:
public void doXxxXxxx(ActionContext context) {}
相信这个约定不用我来解释,你一定已经非常熟悉它了!例如你的Action类中有这样一个修改用户信息的方法:
public void doEditUser(ActionContext context) {
String id = (String)context.getParameter("id");
String name = (String)context.getParameter("name");
userService.editUser(id,name);
}
那么如果你在request中增加一个参数“command=editUser”,该方法
就会被执行,注意参数的大小写!
友情提醒:
在AromaRI中并没有FormBean的概念,也就是说请求中的参数并不会被自动组装
成FormBean供你使用!ActionContext充当了参数传递的载体,但它并不是一个
FormBean,当你需要取得某个参数的值时可以调用ActionContext的getParameter
方法,AromaRI也不会对你的参数进行效验!
如果你也和我一样喜欢偷懒,那么你下面介绍的特性一定会让你很兴奋(如果你非常熟悉Webwork,那么也请看看如何通过注解来进行变量的自动注入)!在AromaRI中,你可以把要接收的参数定义成Action类的属性,然后为这些属性增加set和get方法,AromaRI会自动根据ActionContext中的值为这些属性设值。类似这样:
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
https://www.sodocs.net/doc/d714123560.html, = name;
}
public void doEditUser(ActionContext context) {
userService.editUser(id,name );
}
如果你连set和get方法都懒得写,那么你也可以使用AromaRI提供
的@Autowire注解来标记要进行自动设值的属性,无论是私有类型还是保护类型(不建议使用Public类型)!类似下面的用法:@Autowire private String id;
@Autowire private String name;
public void doEditUser(ActionContext context) {
userService.editUser(id,name );
}
AromaRI会根据自动为带有@Autowire注解的属性设值。所有这些是如何实现的呢?答案就在ActionEnhancer类。这是一个Action的增强类,可以在Action执行之前对Action做一些处理,例如属性的自动注入。ActionEnhancer类只有一个静态方法:
static Action enhance(Action action, ActionContext context) {
if (AromaUtil.isEmptyOrNull(action) ||
AromaUtil.isEmptyOrNull(context)) {
if (logger.isDebugEnabled()) {
logger.debug("Action or ActionContext may be null , so ignore it!");
}
return action;
}
autowireActionProperties(action, context);
return action;
}
该方法用于对Action类进行处理,其中下划线加粗的方法(限于篇幅,方法内容请查看源代码)用于进行属性的自动设值。显而易见,可以很容易的在该方法中对Action类进行方法拦截等其他操作。ActionEnhancer类并不用开发人员来手工调用,AromaServlet根据请求从Guice中取得Action实例后会自动调用ActionEnhancer对该
Action进行处理。尽管如此,充满好奇心和求知欲的你也一定迫不及待的想知道具体的调用方式,下面的代码片段或许会对你有所帮助,更加详细的信息请参看AromaServlet类的doGet方法。
beforeProcess(req, res, context);
Action action = ActionEnhancer.enhance((Action)
container.getBean(getActionName(req, res)), context);
if (AromaUtil.isEmptyOrNull(action)) {
handleError(req, res, "The action that you just request dose not exist!");
}
action.execute(context);
afterProcess(req, res, context);
写到这里,对Action的特性和用法似乎已经讲解的很清楚了,但是还有一个关键的特点有必要再提一下。在AromaRI中,动作处理类并不强制要求继承Action接口或继承ActionSupport!只要你的类中定义了符合如下声明格式的方法:
public Object doXxxXxxx(Map data) {}
那你就可以把它当成Action类来使用!AromaRI提供了一个ActionProxy类,它是一个代理类,负责调用你所指定的类来执行实际的业务逻辑。具体使用方法和上面对ActionSupport的介绍基本一致。唯一区别就是用户不用继承ActionProxy,也不用调用ActionProxy,这些事情都由容器替你做了。
对Action的讲解就到此为止,后面还会有一些简单的例子来演示具体用法。接下来该让我们揭开Container的神秘面纱了!
Container初始化流程及工作原理:
在AromaRI中,所有的Action和业务层组件,包括数据访问组件都是通过Guice进行管理,并实现依赖对象的自动注入。Container 是AromaRI和Guice的结合点,对Guice进行了适当的封装。开发人员只和Container交互,完全不用关心如何操作Guice的细节。在Guice 的用户指南上有这样一段描述:
自举(bootstrapping)对于依赖注入非常重要。总是显式地向Injector 索要依赖,这就将Guice 用作了服务定位器,而不是一个依赖注入框架。
你的代码应该尽量少地和Injector 直接打交道。相反,你应该通过注入一个根对象来自举你的应用。容器可以更进一步地将依赖注入根对象所依赖的对象,并如此迭代下去。最终,在理想情况下,你的应用中应该只有一个类知道Injector,每个其他类都应该使用注入的依赖关系。
在AromaRI中,这个Container就是唯一知道Injector的类。每个Action都可以看成是一个根对象,所有的Action都通过Container进行统一初始化和管理。
Container只有为数不多的几个方法,看一下它的定义:
public interface Container {
public Object getBean(String name);
public
public
public void init();
public void destroy();
}
前三个方法用于从容器中获取对象,后两个方法用于初始化和销毁容器。
待续
XXX案例研究:
待续
Guice源码分析:
待续
EasyJWeb与Guice集成:
待续
总结:
待续
附录:
相关资源:
?Guice中文指南
?Guice user guide
?解读超轻量级DI容器-Guice与Spring框架的区别相关项目:
Guice自身提供了对Struts和Spring的支持,可以非常容易的在Struts或Spring项目中集成Guice。另外著名的开源AJAX
开发框架DWR在最新的版本中也提供了Guice集成功能,通
过了解这些集成方式可以更好的理解Guice。
框架建筑的主要优点:空间分隔灵活,自重轻,节省材料;具有可以较灵活地配合建筑平面布置的优点,利于安排需要较大空间的建筑结构;框架结构的梁、柱构件易于标准化、定型化, 便于采用装配整体式结构,以缩短施工工期;采用现浇混凝土框架时,结构的整体性、刚度较好, 设计处理好也能达到较好的抗震效果,而且可以把梁或柱浇注成各种需要的截面形状。 框架结构体系的缺点为:框架节点应力集中显著;框架结构的侧向刚度小,属柔性结构框架, 在强烈地震作用下,结构所产生水平位移较大,易造成严重的非结构性破坏,适用于非抗震设计; 钢材和水泥用量较大,构件的总数量多,吊装次数多,接头工作量大,工序多,浪费人力,施工 受季节、环境影响较大;不适宜建造高层建筑,框架是由梁柱构成的杆系结构,其承载力和刚度 都较低,特别是水平方向的(即使可以考虑现浇楼面与梁共同工作以提高楼面水平刚度,但也是 有限的),它的受力特点类似于竖向悬臂剪切梁,其总体水平位移上大下小,但相对于各楼层而言,层间变形上小下大,设计时如何提高框架的抗侧刚度及控制好结构侧移为重要因素,对于钢 筋混凝土框架,当高度大、层数相当多时,结构底部各层不但柱的轴力很大,而且梁和柱由水平 荷载所产生的弯矩和整体的侧移亦显著增加,从而导致截面尺寸和配筋增大,对建筑平面布置和 空间处理,就可能带来困难,影响建筑空间的合理使用,在材料消耗和造价方面,也趋于不合理, 故一般适用于建造不超过15层的房屋。 滑模 滑模工程技术是我国现浇混凝土结构工程施工中机械化程度高、施工速度快、现场场地占用少、 结构整体性强、抗震性能好、安全作业有保障、环境与经济综合效益显著的一种施工技术,通常 简称为“滑模”。 建筑层高 建筑物上下两层间的高度差值(一般以楼面高度间的差值或上下横梁间的差值)称建筑层高。 结构层高 结构层高系指房屋上下两层结构层层面的垂直距离。 混凝土结构及砌体结构参考资料:框架变形缝 变形缝包括伸缩缝、沉降缝和防震缝三种。它们设置的原因、设置的方法各不相同,有区别也有联系。分 别介绍如下: ㈠伸缩缝 伸缩缝是为了避免温度应力和混凝土收缩应力使房屋产生裂缝而设置的。设置伸缩缝时只需断开上部 结构,基础可不断开。
企业的大框架 一、经营和管理 管理:使资源的运用规范(社会相关约束)、高效。或通过规范化高
经营就是确定一个方向,描绘一张蓝图,设定一个愿景,进行资源取舍,约定一个边界,就是画一个框。 管理就是按着既定的方向前进,按着蓝图进行建设,在约定的边界内,高效规范利用资源或取得资源,确定阶段性目标,达到目标,实现愿景。愿景开始发生变化,新一轮开始。 最典型的例子:毛泽东是经营者,周恩来是管理者。 在另一层面,周恩来是经营者,其他一些人是管理者。 企业经营管理活动层级 二、企业的愿景 一些企业觉得提出愿景很难,如果消除了顾虑,任何一个企业都可以很顺利地提出切合自身的愿景,即便不提也会实质性地存在着。如:企业长期生存下去。成为区域性口碑最好的企业。成为区域内这个行业规模最大的企业。成为某领域一家绿色企业等。 有些企业虽然没有提出来,但其行为和一些说法,其实已经把愿景表现出来了。 755曾一直将自己作为最好的军用电池企业来做,产品成本很高,
优先保证质量,采取质量一票否决等。 环宇电源,长时间将企业作为动力电池企业第一位,将电池的动力性能列为首位,集中发展动力电池,而不是发展所有的电池(动力电池的利润最高)。 天丰集团,长江以北最大的钢结构企业。 上述的例子,除了自身具备相应的优势,或发展出了相应的优势,同时也是资源相对有限,将资源集中,发展出差异化优势,形成自己的愿景,而且是可以达到的。 如果企业的愿景加上对社会某一方面的联系就,带有明显的使命感,愿景和使命就统一了。如微软提到:让每一张桌上和每一个家庭都有一台PC。 其内容应包括: 三、为了实现企业愿景而设定的目标 目标必须具备SMART(词的原义是聪明、敏捷等),代表了五个含义: S:目标必须是明确和具体的而不能是含糊的。 M:目标必须是可以量化的。
大部分框架网页出现在后台,管理系统的界面 制作步骤: 方法一:新建html ,插入--html-框架-选择其中一项 方法二:自定义框架 ①直接拖动边框可实现增加框架页面 ②反之也可以删除框架页面 ③按住ALT+SHIFT可实现选择其中的一个框架页面操作,可以拖拽其中的一个页 面 托错了,为什么撤销不了,是因为没有选中最外围的框架,即大框架 注意保存顺序: 保存的时候会保存四张页面,但是你要弄清楚保存的是哪个页面,为避免保存时不清楚那个是哪个的问题,保存的时候要能够给框架页面起名字不会无法在主框 架页嵌入不了页面,先保存三张内页,再保存框架页,以上两个保存顺序最好不要 颠倒 如何给框架命名:①在窗口---框架打开框架视图,这时的框架在程序的右下角; ②在框架视图上点击要命名的框架页,再在属性框架名称上输入框架名称,再在编 辑区域上相应的地方点击刚才命名的框架就好。 想要边框完全消失,就要设置边框为0,想要边框固定,那就框架四个页面都为否,想要页面不滚动,那就将框架的页面的滚动设置为否 框架页内部实现的超级链接,给要在显示的区域框架起名字,id =in和name=in