

Life for Idea – forever young
发现用spring有一个问题,如果某个人忘记加入一个类文件,而这个依赖是在spring中体现的,那么在编译时不会报错, 而显然是不好的.这种错误应该在编译的时候就应该报出来. 考虑在编译时检查一次bean依赖, 最简单就是初始化一次application-context.
用springide验证了一下xml文件,得到这个错误
Destroy-method 'shutdown' not found in bean class 'org.enhydra.jdbc.pool.StandardXAPoolDataSource'
bean的配置如下:
也就是说springide认为这个bean没有shutdown的方法.查了一下xapool的source,发现是有的,但是是shutdown(boolean).destroy-method属性的定义:
Attribute : destroy-method
The name of the custom destroy method to invoke on bean factory shutdown. The method must
have no arguments, but may throw any exception. Note: Only invoked on beans whose lifecycle is
under the full control of the factory - which is always the case for singletons, but not guaranteed
for any other scope.
在来看spring的source终于发现玄机所在:
DisposableBeanAdapter的invokeCustomDestroyMethod 方法:
Class[] paramTypes = destroyMethod.getParameterTypes();
if (paramTypes.length > 1) {
logger.error("Method '" + destroyMethodName + "' of bean '" + this.beanName +
"' has more than one parameter - not supported as destroy method");
}
else if (paramTypes.length == 1 && !paramTypes[0].equals(boolean.class)) {
logger.error("Method '" + destroyMethodName + "' of bean '" + this.beanName +
"' has a non-boolean parameter - not supported as destroy method");
}
else {
Object[] args = new Object[paramTypes.length];
if (paramTypes.length == 1) {
args[0] = Boolean.TRUE;
}
if (!Modifier.isPublic(destroyMethod.getModifiers()) ||
!Modifier.isPublic(destroyMethod.getDeclaringClass().getModifiers())) {
destroyMethod.setAccessible(true);
}
红色标记的地方就看到了,这个方法只会接受一个无参数方法或者参数唯一并且是boolean的方法.boolean值得意义就是force
附方法的注释:
This implementation invokes a no-arg method if found, else checking
for a method with a single boolean argument (passing in "true",
assuming a "force" parameter), else logging an error.
显然SpringIDE没有考虑到这点.
刚刚“领略”了一些spring-modules的源代码看到了FactoryBean和InitiliazingBean的用处。记在这里
这个方法比较容易理解,是在spring根据配置文件设置了bean的属性后调用的,一般这里会做一些初始化的工作。比如,xml配置中只是提供了resource的路径,在这个方法里 就要根据resource的路径初始化一些成员变量(那些不能被注入或者没有被注入的成员变量)。
public void afterPropertiesSet() throws Exception {
if (this.definitionLocation == null) {
throw new FatalBeanException("Property [definitionLocation] of class ["
+ ProcessDefinitionFactoryBean.class.getName()
+ "] is required.");
}
InputStream inputStream = null;
try {
inputStream = this.definitionLocation.getInputStream();
this.processDefinition = ProcessDefinition.parseXmlInputStream(inputStream);
// 这里就是初始化的地方,spring的配置文件中只配置了definitionLocation的信息,其他的事就在这里做
}
finally {
if (inputStream != null) {
inputStream.close();
}
}
}
在比较配置文件和源代码的时候我很疑惑,为什么类型都不对头,怎么可以注入的?答案就在FactoryBean的这两个方法里
public Object getObject() throws Exception {
return this.processDefinition;
}
public Class getObjectType() {
return (processDefinition == null) ? ProcessDefinition.class : processDefinition.getClass();
}
getObject返回的是成员变量processDefinition,getObjectType返回的也不是this.class,而是processDefinition.getClass();spring在加载这样的factorybean的时候就会根据这两个方法来决定类型和实例。比如在xml中配置了ref="someFactoryBean"的 时候,实际的引用可以是任意的,只要你提供了这两个方法。-好像有点表达不清楚。
如果IOC是运行时对象依赖关系的注入的话,那么AOP是不是就是运行期执行流的注入呢?
每个注入点(point cut)就对应IOC中的sette或构造函数参数.每个处理方法(advice)就对应IOC中的一个对象
(最初发布在JavaResearch.org,现在整理好放到自己的地方.)
有人说spring aop+ spring ioc, 才~~~是spring
简单一点,是一个容器. 什么容器,容纳什么?是对象,或者说bean的容器.
那为什么叫轻量级容器呢?相对于EJB container,使用spring不需要写符合容器规范的代码,即容器不会"侵入"了你的代码.
这 个容器会提供你的应用(程序)中用到的所有对象,并对这些对象进行统一的生命周期管理和组装.在通常的开发中,我们在需要某个对象的时候只是 new MyObject(). 在Java中,这样没有什么不好,因为gc会打理好"善后"工作,是系统级的. 而用spring,在需要某个对象 时,只要向容器请求相应的对象,spring会找到并准备好这些对象并提供给你.她也会打理好"善后"工作,但是是在应用级的.
另一方面,spring还会帮助你打理对象之间的依赖关系.
比如原来的做法:
class A{
}
class B{
A a ;
public B(){ a = new A();}
}
而使用spring的做法
class A{
}
class B{
A a;
public B(){}
void setA(A a){this.a=a}
A getA(){return this.a}
}
(希望你不要单纯地认为spring会写很多代码)
但 从前一个方面,你可能觉得spring只是一个对象容器.从这里你就应该看出,spring是bean容器,因为spring需要你的类符合bean规 范:相应于每一个成员域,都需要提供setter和getter方法.spring要使用这些方法来注入依赖关系,也就是 dependence injection, 或者inversion of control. 我个人觉得还是di更容易理解,直到现在我还是要考虑 怎么去向别人很好的解释ioc.控制反转(倒转),我的理解是就如同上面的两个例子里看到的,依赖(控制)不在体现在代码逻辑里(如第一个例子),而是在 配置文件里,而在代码中我们只提供注入点(也就是setter和getter).
希望我对IoC的概念的讲解能够给你一些启发.
你 可能要问了,为什么我要这样做呢?原来的做法有什么不妥的地方么?没有什么不妥,只是两种理念而已,没有绝对的好还是不好,但我还是给你我的解释--我理 解的IoC的好处,希望有所帮助.通常在程序设计的时候,我们在需要某些功能时,会相应的去设计一些方法,然后根据OO去将方法和一成员变量组成一个类. 实际上,我们最终设计出的程序是:一组类的实例互相交互完成某个特定的任务.
除了一些核心的业务方法,以外我们还要做组装对象的工作.比如我有了 一个工厂,里面有很多机器,机器在开动时要装配相应的模具.那么在工厂的生产过程中, 首先我要有工厂,机器,模具这样三个类.然后我的"动作"有:装 配,开机.通常的做法我们要做装配,然后再去开机.而用spring,我们只是专注于开机.这样我们就把装配这个动作抽离出了核心的"生产过程".当某些 机器改变了装配模具时,不在需要修改核心业务代码.这就是解耦.如:
public class Production{
public static void main(String[] args){
Factory factory = (Factory)BeanFactory.getBean("factory");
factory.launchProduction();
}
}
class Factory{
Machine machine1,machine2;
void launchProduction(){
machine1.start(); machine2.start();
}
// setters and getters
}
class Machine{
Tool tool;
void start(){
}
// setters and getters
}
在launchProduction()方法中只需要开动每台机器即可.而不需要每次都装配机器.装配的工作交给了别人.现在只要按下start按钮.生产就开始了!要是原来:
void launchProduction(){
machine1 = new MachineA();
machine1.setTool(new ToolA());
machine2 = new MachineB();
machine2.setTool(new ToolB());
machine1.start();
machine2.start();
}
这就是工作分工,是不是感觉轻松了许多?从此以后,我们都是面向构件去开发,而不需要过多地在代码中体现构件之间的依赖关系.
AOP
推荐你看一下<<effective enterprise java>>的第一章,对AOP有很清晰,易懂的解释.其实AOP并非很艰深晦涩的概念,但是从架构角度去理解她的重要性可能不是我这样的new fish一时半会儿可以领悟到的.
我这里只是想说,有些概念你要知道是怎么回事,但理解到多深,除了天赋以外更多的是经验和悟.所以不要心急.--像是在自我解嘲.
也许在不知不觉中你就使用了很多AOP的概念,比如servlet里的filter,比如在写一个command类时,给她的调用类在每次调用command时前后加上:preProcess和postProcess...
我不想解释太多,<<eej>>的解释已经足够.
Hope helps.
作者:Edmon Begoli May 5, 2005
翻译:ZhangV 2005-07-22
原文出自:DevX.com
原文链接:http://www.devx.com/webdev/Article/28041/0/page/1
Spring WebFlow是一个全新的Web框架,她带给我们一种全新且高度结构化的Web应用构建方法.让我们来看看她的一些特性.
Spring框架正准备推出一种新的技术.在下一个版本中(1.3,预计在2005年夏天发布)Spring将正式将Spring WebFlow整合进来.Spring WebFlow是一个及其优秀的Web开发框架,用于在Web应用内部创建和配置可重用的Web流程.
熟悉Spring的人可能先入为主地以为Spring WeFlow和SpringMVC没有什么区别.那就错了.Spring MVC是一个轻量级的Web开发框架,而Spring WebFlow 则提出一种全新的视角.她使得Web架构师们可以将精力集中在Web应用开发的抽象层次上:Web流程的逻辑结构和Web事件条件的定义.此外,她还提出许多新的概念.(稍后会介绍到)
本文将回顾这一个新框架前的一些关键概念,用一个经典的用户登录例子来分析流程标记语言的主要组成元素并向您解释为什么WebFlow如此诱人.(读者必需要有Spring 1.2基础).
Spring WebFlow 概念和组件
作为一个Web框架,WebFlow无论在理论上还是在实际开发上都有诸多优点.深厚的软件工程学架构保证了他的稳定性,同时,其组件合理,易于理解,易于使用.
事实上,它更适合中大型应用的开发,因为它的组件模型专门针对架构重用,高效管理性和可配置性进行了优化.
用例研究
本文以一个常见的web应用流程作为示例, 一个身份认证流程,讲解它的一些代码片断.一个Web认证的全过程包括:登录表单,注册表单,认证action,注册action,以及对这些action的结构修饰.这个例子用来展示那些修饰登录表单的组件的配置.
自动操作架构
Spring WebFlow以有限状态机(Finite State machine)的概念为基础.Web应用内部的用户交互行为和事务被建模为一般的状态机,这是一种非常流行的软件工程建模方法.(见图1).自动机为基础的设计是一种很好的设计方法,同时正在越来越收到应用架构的青睐 -- 因为它在对Web交互行为建模时显得相对清晰且严谨.

WebFlow的核心组件
一个Spring WebFlow应用中包含一个或多个流程,通常每个流程包括执行Action的动作状态(ActionStates),显示状态(ViewStates),跳转动作(Transitions).
流程
一个流程是一个预先定义好的用户交互行为的集合,表示为一个由动作状态和显示状态构成的树,状态之间通过跳转联系.
下面的登录注册是一个webflow的例子,包含了一些典型的构件,例如loginForm,ActionState,transition.这些构件通过一个XML文件描述:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE webflow PUBLIC "-//SPRING//DTD WEBFLOW//EN"
"http://www.springframework.org/dtd/spring-webflow.dtd">
<webflow id="LoginSequence" start-state="loginForm">
<action-state id="loginForm">
<action bean="loginFormAction"/>
<transition on="success" to="formView"/>
</action-state>
...
<view-state id="formView" view="enterCredentials">
<transition on="submit" to="bindAndValidateForm"/>
</view-state>
...
<end-state id="successView" view="displayMain"/>
这个流程以loginForm开始,以"successView"结束(修饰主页面"displayMain" 的组件.流程可以通过XML文档配置,或者AbstractFlowBuilder的子类.
动作状态(ActionStates)
ActionStates对用户事件或其他事件进行响应.ActionStates自身又可以包含其他可执行的Action和transition.下面的代码配置了"loginForm"这个ActionState.
<action-state id="loginForm">
<action bean="loginFormAction"/>
<transition on="success" to="formView"/>
</action-state>
动作(Actions)
Action是ActionState可以连接,重用,声明调用的最小单位.Action继承自AbstractAction类,该类实现了doExecuteAction方法.这个方法的参数:RequestContext,WebFlow(其中封装了所有流程相关的数据).loginForm动作状态通过Spring的自动装配特性调用LoginFormAction动作.doExecute
Action方法被自动调用,同时可以处理一些登录准备,预先装入等操作.
public LoginFormAction extends AbstractAction{
protected Event doExecuteAction(RequestContext context)
throws Exception{
//perform some login specific setup operations
...
}//end method
}//end class
显示状态(ViewState)
ViewState初始化对显示组件(jsp,tile等)的修饰操作.下面是一个ViewState的配置代码
<view-state id="formView" view="enterCredentials">
<transition on="submit" to="bindAndValidateForm"/>
</view-state>
当来自loginForm的ActionState返回一个"success"时,这个ViewState将会被调用.它将修饰"enterCredentials"显示组件(可以是一个常见的struts forward).
跳转(Transition)
和通常的状态机一样,WebFlow定义了状态以及状态之间跳转动作.这些跳转动作很类似struts中的ActionForward.同样是负责连接两个状态.
后继动作(Continuation)
后继动作(Continuation)允许你回退并重新开始程序执行流程 -- 从程序执行的角度来看是一个适时的逆流程.Continuation的概念最早来自编程语言,但是却从来没有被用于像Java,VB,C++这样主流的编程语言中.WebFlow创造性地实现了continuation.由于continuation可以用来持久和重造任何一个流程状态,从而提供给你极大的自由.
重用
WebFlow中的流程定义,如登录流程,有针对性地被结构化以便重用.他们定义封装了自己的生命周期.这些定义可以很容易的用支持Spring的其他Web组件配置重用.架构师应该识别出并定义通用的流程,如登录,搜索等以便今后的重用.
此外,Action如果正确的设计与Spring的结合,也可以被重用.他们可以同时被不同流程的action state使用.这些重用,既有应用级的又有流程级的,增强了维护性和代码可读性.
与struts结合
WebFlow与struts的结合部分地通过标准的Spring类和org.springframework.web.struts包中的一些配置.要与WebFlow相关概念(Action,ActionFlow)结合只需要注册WebFlow规格的struts action,并像普通的WebFlow action一样使用.
下面的配置代码来自struts-config.xml,描述了Struts的Action如何配置成流程的入口.注意WebFlow规格的Action类(org.springframework.web.flow.struts.FlowAction)和属性"flowId",它们将Action与登陆流程连接起来.例子中的登录流程在Spring的应用上下文(ApplicationContext)中作为一个loginFlow的bean管理.你还需要将这个流程注册为一个由Spring管理的bean.
<!- flow actions ->
<action path="/loginFlow"
type="org.springframework.web.flow.struts.FlowAction"
name="actionForm" scope="request"
className="org.springframework.web.flow.struts.FlowActionMapping">
<set-property property="flowId" value="loginAction" />
</action>
在这个例子中还用到了Spring中的RequestProcessor(org.springframework.web.struts.BindingRequestProcessor),是Spring的自动绑定form和bean.这一特性避免再去写单独的ActionForm对象.
<controller processorClass="org.springframework.web.struts.BindingRequestProcessor"/>
同时,它还要求一个使用工具类来自动绑定Web表单中的值到一个对象.
<plug-in className="org.springframework.web.struts.BindingPlugin"/>
WebFlow的预发布现在可以下载,其中包含一个样例应用("birthdate"),详细描述了这个整合过程.
如果你正在着手建立一个Web应用,Spring是一个非常不错的选择.Spring MVC非常容易上手并且可以很方便的同其他组件整合.另一方面,即将出现的Spring WebFlow将提供给你各种复杂的新特性.使你能够开发出高度重用和结构化的Web应用.如果你在开发的是一个大规模的企业应用,这一点是很重要的.这也是为什么struts如此流行.
总的来说,J2EE Web框架目前处在一种群雄逐鹿的状态,没有一个领导者.Struts是最流行的,但是它的主架构师也是主要的开发者已经抛弃了它.被称为Struts取代者的JSF目前还没有获得足够的影响力.而同时,其他的框架正在慢慢开始流行.
你也许会问,"我应该选择哪个?"Spring WebFlow出现可以让你以后再去考虑这个问题.WebFlow允许你在不需要较大改动的情况下方便的切换框架.像前面说过的,Spring WebFlow是一个抽象的框架,可以让你只专注于业务流程和重用.无论是Struts,JSF还是Spring MVC都可以作为它的业务流程实现.因此,你也就不需要马上作出上面说的那个选择了.