2006年8月30日星期三

appfuse(1.9.3)中的几个小问题

1.如果创建了一个新的应用,ApplicationResources_zh_CN.properties在创建过程中被转换为乱码。简单的做法就是用appfuse原来的文件直接覆盖。
2.displaytag_zh_CN.properties没被转换。修改build.xml的copy-resources task:
<!-- Copy any resource or configuration files -->
<target name="copy-resources" depends="prepare"
description="Copy .properties and .xml files from source directory">
<copy todir="${build.dir}/web/classes" includeEmptyDirs="no">
<fileset dir="web/WEB-INF/classes">
<exclude name="ApplicationResources_zh*.properties"/>
<exclude name="displaytag_zh_CN.properties"/>
<include name="*.properties"/>
<include name="*.xml"/>
<include name="*.vm"/>
</fileset>
<filterset refid="variables.to.replace"/>
</copy>
<native2ascii src="web/WEB-INF/classes" dest="${build.dir}/web/classes"
includes="*_zh*.properties" encoding="UTF-8"/>
<generate-database-properties/>
<copy todir="${build.dir}/web/classes" file="database.properties"/>
</target>
3.appgen的ant install的做法
ant install的所做的工作包括了ant[default]的工作,好像文档写的不是很准确。而且这个appgen一股脑的将ibtias and hibernate的dao都产生出来,没有一个设置目标DAO的地方。
忘了在哪里看到的说法:j2ee开发中deploy是一个非常关键的过程,确实真知灼见。
发布过程要有几个特征:
1.方便(自动化的发布);
2.灵活(定制);
3.有升级的功能(持续的升级);
4.速度要快。这样才能减少测试-开发-测试需要的round时间。

4.中文编码的问题
刚开始遇到中文问题的时候,觉得小case:统一将编码改为gb2312,原来就是经常这么干的。后来网上查了会儿,原来大家现在都用UTF-8了,就像google一样,cool!
appfuse本身就是utf-8的配置,问题在于数据库的编码,需要在my.ini中加入:
[mysqld]
default-character-set=utf8
或者mysqld命令行带上参数。
但是ant setup-db后,依然乱码。后来发现新建表的character set为latin1,column也为latin1,god! 都改为utf8后问题解决。而如何让ant setup-db自动创建utf-8的table呢?
所以appfuse的中文问题就是所有地方都要用utf-8编码!

2006年8月16日星期三

continuation in Spring Web Flow

   平心而论,SWF是现在java中对continuation支持最好的和最现实的,虽然这种支持是模拟的。其他的一些框架都有点技术上的理想而造成的不成熟。
    SWF默认使用的控制是SimpleFlowExecutionRepository,这是不支持continuation的,比如浏览器回退、新开浏览器等。如果要支持,要使用ContinuationFlowExecutionRepository。SWF这样的设置是很灵活的,因为一般的应用可以使用SimpleFlowExecutionRepository来避免continuation引起的不必要的开销。
    以swf-sample中的guessnumber为例(guess number是一个经典的例子),修改/web-inf/dispatcher-servlet.xml相关内容如下:
     <bean name="/play.htm" class="org.springframework.webflow.executor.mvc.FlowController">
            <property name="flowExecutor" ref="flowExecutor"/>
     </bean>
    <bean id="flowExecutor" class="org.springframework.webflow.executor.FlowExecutorImpl">
        <constructor-arg ref="repositoryFactory"/>
    </bean>
    <bean id="repositoryFactory" class="org.springframework.webflow.execution.repository.continuation.ContinuationFlowExecutionRepositoryFactory">
        <constructor-arg ref="flowRegistry"/>
    </bean>   
   
如此后,应用就支持浏览器后退键了。这里的后退键是跟后台逻辑关联在一起的:按下后退键,相当于刚才的猜测不算,再猜一次,而计数也“后退”(或者说“恢复”)到前面到状态。如果是购物篮应用,后退就表示“退回”刚才购买的商品。(这种方式也可能造成用户感觉上的混乱)
    这种功能用一般的会话变量(比如将计数存在session中、将购物篮存在session中)是很难处理的。这里的会话变量比如计数、购物篮是一个会话活动中多个步骤的结果的记录,用一个变量是无法记录这些步骤的先后顺序的。而一般的会话变量只是一个步骤中标志或者状态的记录,一个变量就足够使用。
    SWF的解决方法就是在每个步骤中添加一个标志,当这个步骤提交时,后台根据提交上来的标志恢复(在回退的情况下)当时这个步骤的上下文,这样就可以在work flow中继续运行下去。
    例如当步骤1->2->3->4,当浏览器在步骤4时回退时,浏览器会把步骤2提交的数据再次提交。
    用户每次提交,后台都要形成一个上下文的continuation(每次提交的数据都可能不一样),这可能会占用大量的资源。

Spring中Singletons的线程安全

Thread-safe在Java Concurrency in Practice这本书里面的定义是:

A class is thread-safe if it behaves correctly when accessed from multiple threads, regardless of the scheduling or interleaving of the execution of those threads by the runtime environment, and with no additional synchronization or other coordination on the part of the calling code.

Spring本人不是很熟悉,网上Google了下相关方面的话题,得到的有用的结果很少。可以参考的是:Thread safety, singletons and Spring。还有一篇是:Thread-safe webapps using Spring
基本上,Spring的thread-safe是其API自身的thread-safe。比如一个常见的场景(from appfuse):
public class UserManagerImpl extends BaseManager implements UserManager {
private UserDao dao;
......
public class UserDaoHibernate extends BaseDaoHibernate implements UserDao, UserDetailsService {
......
public class BaseDaoHibernate extends HibernateDaoSupport implements Dao {
这些bean都是Singletons的。
一个类如果没有成员变量,那这个类肯定是thread-safe的,所以UserDaoHibernate的thread-safe取决于其父类。而 UserManagerImpl 的安全性又取决于UserDaoHibernate,最后是HibernateTemplate。可以看出,这里的bean都小心翼翼的维护其成员变量,或者基本没有成员变量,而将thread-safe转嫁给Spring的API。如果开发者按照约定的或者用自动产生的工具(appgen不错)来编写数据访问层,是没有线程安全性的问题的。Spring本身不提供这方面的保证。
或者bean的定义为Singletons="false",也可以参考前面的一篇文章Thread safety, singletons and Spring,用lookup-method。<pro spring> charpter 5介绍的更详细:
Lookup Method Injection was added to Spring to overcome the problems encountered when a bean depends on another bean with a different lifecycle—specifically, when a singleton depends on a non-singleton. In this situation, both setter and constructor injection result in the singleton maintaining a single instance of what should be a non-singleton bean. In some cases, you will want to have the singleton bean obtain a new instance of the non-singleton every time it requires the bean in question.
显然,如果A(Singletons) depends B(Propotype),使用这种方式可以避免A对B的访问并发和争用的问题。
<pro spring>这本书(强于spring in action,后者感觉是本reference book)也对Singletons=“true/false"的选择做了个小结:
使用Singletons的情况有:
1.Shared objects with no state;
2.Shared object with read-only state;
3.Shared object with shared state;
4.High throughput objects with writable state. (synchronizing is need)
使用propotype的情况有:
1.Objects with writable stat;
2.Objects with private state.
与Spring的高度灵活不同,EJB的规范将同步作为一个服务(one of primary services),开发者开编写bean时不必考虑(也不能)线程相关的问题。session bean其分为两类,也有同步上的考虑。
虽然thread-safe的问题总是存在,EJB也没有从本质上解决这个问题,但是其提出了这个问题,并给出了规范。