posts - 16,comments - 17,trackbacks - 0
@ My Space
posted @ 2005-05-13 00:08 非飞 阅读(2453) | 评论 (2)编辑 收藏
@ My space
posted @ 2005-05-07 00:19 非飞 阅读(2219) | 评论 (0)编辑 收藏
在JDK1.4.2中加入了对NIO的支持,掌握其中的Selector个人认为是能实现好NIO的关键。

Selector是用来获取注册在其中的channel的相关事件的发生,也就是accept,read和write。selector中有3个key set。

key set:包含代表所有在其中注册的channel,可以通过selector.keys()得到。
selected-key set:包含所有被检测到有关注的操作已经就绪的key,通过selector.selectedKeys得到。
cancelled-key set:包含所有已经被cancel,但是还没有channel还没有deregister的key,这个集合是不能直接被访问的。

key通过调用channel的register方法被加入到key set中。被取消的key在select的时候会被从相应的key set中移除。

key set自身是不可以直接进行修改的。 无论是通过调用channel的close方法还是调用key的cancel方法,key都会被放置到canceled-key set中。取消的key会将其channel在下一次select时将注册撤销,同时将key从所有的key set中移除。

key在执行select操作时被加入到selected-key set中。在selected-key set中的key可以通过调用iterator的remove方法,将其从selected-key set中移除,不能通过其他的办法将其从selected-key set中移除。

通过selector的3个方法select(阻塞选择,直到有关心的事件发生时退出阻塞),selectNow(不阻塞选择),select(long)(指定超时选择,超时到达或者有关心事件发生时退出阻塞),来获取关心事件的发生。其执行步骤分为以下3步:

1、将存在于canceled-key set中的key从所有的key set中移除,撤销注册的channel,清空canceled-key set。
2、地层操作系统检查是否有关心的事件发生,当有关心的事件发生时,首先检查channel的key是否已经存在于selected-key set中,如果不存在,则将其加入到selected-key set中去,同时修改key的ready-operation set来表明当前ready的操作,而以前存在于ready-operation set中的信息会被删除。如果对应的key已经存在于selected-key set中,这直接修改其ready-operation set来表明当前ready的操作,删除原来ready-operation set中的信息。
3、如果在第二步中有加入到canceled-key set中的key,在这一步会执行第一步的操作。

selector自身是线程安全的,而他的key set却不是。在一次选择发生的过程中,对于key的关心事件的修改要等到下一次select的时候才会生效。 另外,key和其代表的channel有可能在任何时候被cancel和close。因此存在于key set中的key并不代表其key是有效的,也不代表其channel是open的。如果key有可能被其他的线程取消或关闭channel,程序必须小 心的同步检查这些条件。

阻塞了的select可以通过调用selector的wakeup方法来唤醒。
posted @ 2005-04-26 10:06 非飞 阅读(17354) | 评论 (3)编辑 收藏

在JavaScript中,可以通过window.location来获取url地址。但是window.location是一个对象,没有办法直接从里面获取出我们需要的参数。通常的做法就是使用一个隐藏的<input>,通过将window.location负值给input。其目的就是为了将location转换成String。写的过程中总是觉得太复杂了,后来发现使用document.URL就可以解决这个问题。
posted @ 2005-04-18 15:52 非飞 阅读(4088) | 评论 (3)编辑 收藏

今天在帮朋友写一个简单的产品发布网站,由于使用的空间是静态的,没有办法只能在javascript上下功夫了。首先想到的便是RIA,上网google了一下,发现这样的东西还真不少,可谓是十八般武艺各显灵通。看了看文明的bindows,感觉真的非常的好。可是选择它对于我要做的东西,可以说是过于复杂了。(http://www.bindows.net 有兴趣的朋友可以去看看)。
搜索了半天最后还是决定,采用javascript读取服务器端xml文件的办法来实现。尝试了一下感觉还不错,确定就是对使用的浏览器有依赖。
先写了一个商品的xml文件:

<?xml version="1.0"?>
<root>
 
<product id="0001" name="product1" price="10.00">
  
<description>
   Detail Description
  
</description>
 
</product>
 
<product id="0002" name="product2" price="20.00">
  
<description>
   Detail Description
  
</description>
 
</product>
</root>

 

使用javascript来读入xml实在是相当的简单,只需要两句话就可以搞定:

// 装载xml文件的函数
function loadXML(fileName) {
 
// 定义一个xml dom对象
 var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
 
 xmlDoc.load(fileName);
 xmlObj 
= xmlDoc.documentElement;
}

 

指定要载入的xml文件名就可以完成对xml的读入。

// 载入xml文件
loadXML("product.xml");

 

得到xml对象后就可以适用对象提供的相应方法和属性来获取xml中定义的数据信息。
xmlObj.hasChildNodes来判断是否含有子项;
xmlObj.childNodes.lenght 得到包含的子项的数量
子项可以用数字来作为索引,以product.xml为例。如果我们要获取第二条商品时,可以用xmlObj.childNodes(1)来获得,xmlObj.childNodes(1).childNodes(0)得到的是description
xmlObj.childNodes(1).childNodes(0).text 得到description的值
xmlObj.childNodes(1).getAttribute("name") 得到第二条商品的名字


posted @ 2005-04-09 12:23 非飞 阅读(4706) | 评论 (1)编辑 收藏

下载了一个Action Script Viewer 4.0对原来的swf文件进行反编译,虽然有的movie clip会出现一点问题,但是总的来说效果还是不错的,而且操作相当的简单。

1)使用ASV打开要进行反编译的SWF文件;
2)File-->export rebuild data。这时将swf文件分拆成单个的swf文件;
3)打开flash,创建一个空的fla文件;
4)File-->Import...-->Import to Library   将前面导出的swf文件导入,如果swf文件太多flash会报错,可以通过分批导入文件来绕过这个错误;
5)将新建的swf文件保存为rebuild.fla,并且3)导出的文件在同一目录;
6)运行3)产生的一个rebuild.jsfl文件,一切搞定。


posted @ 2005-04-04 03:32 非飞 阅读(2695) | 评论 (1)编辑 收藏

中午收到老姐来的电话,电话里她是一遍一遍又一遍的在我耳边唠叨,说,“不管你怎么忙,有多少东西要写,一定要按时睡觉”。还列出了一堆要按时睡觉的理由。其实谁不知道应该要按时睡觉,可是作为写程序的程序员来说,要真想做到这一点实在是难,难,难呀!

要按时睡觉的理由


从人的排毒期入手:晚间11:00--1:00,肝的排毒期(必须在睡觉中进行)
从人的睡眠最佳时段入手:1:00--4:00,人的睡眠是质量最高的

不知道各位有谁是有正常的生活习惯的,能不能说一说你是怎么做到的。。。


posted @ 2005-03-23 15:25 非飞 阅读(2108) | 评论 (3)编辑 收藏

    做项目,无论是遗留产品的再生产,还是对遗留产品的再利用,都不可避免的会出现一大堆的异构现象。解决异构通信问题是这类项目的主要问题。以前看见这种情况第一个解决方案就是Socket通信。说实在的自己实现Socket通信,定制通信协议,或者是实现已有的通信协议都是很头痛的事情。本人有不堪回首的历史经历。

    最近同样在项目中需要去解决一个异构问题,由于时间的紧迫,以及先天的运行环境(两个部分是运行在同一台机器上的)。考虑到了使用JNI,结果表明JNI是完全可以胜任目前的角色的。以前没有了解过JNI,总是以为它这不好那不好,用了用,表现还不错,而且实现起来非常之简单。

    整个实现过程可以分为五步来完成:

1)写一个声明了native的Java文件:

package example;

public class TestJNI 
{
    
static 
{
        System.loadLibrary(
"test"
);
    }

    
    
public native String getNameCPP();
}


2) 使用javah产生对应的CPP头文件:
命令:javah -classpath <path> -jni example.TestJNI -d <out_dir>
生成的头文件example_TestJNI.h如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include 
<jni.h>
/* Header for class example_TestJNI */

#ifndef _Included_example_TestJNI
#define _Included_example_TestJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     example_TestJNI
 * Method:    getNameForCPP
 * Signature: ()Ljava/lang/String;
 
*/

JNIEXPORT jstring JNICALL Java_example_TestJNI_getNameForCPP
  (JNIEnv 
*, jobject);

#ifdef __cplusplus
}

#endif
#endif

3)实现对应的CPP代码:
#include "example_TestJNI.h"
#include 
<string>

JNIEXPORT jstring JNICALL Java_example_TestJNI_getNameForCPP
  (JNIEnv 
* env, jobject)
{
    
//TODO 可以在此调用其他的代码
    std::string strName = "Tower";
    
return env->NewStringUTF(strName.c_str());
}


4) 编译CPP代码
命令:g++ -o libtest.so -shared -I<include_path> -I<java_home>/include -I<java_home>/include/linux example_TestJNI.cpp

5)执行
package example;

public class Test {
    
public static void main(String[] args) {
        TestJNI test 
= new TestJNI();
        System.
out.println("Hello " + test.getNameForCPP());
    }

}


export LD_EXPORT_PATH=<so_path>
java -cp <path> -Djava.library.path=<so_path> example.Test
输出:Hello Tower
posted @ 2005-03-22 18:39 非飞 阅读(3343) | 评论 (0)编辑 收藏

做了这么久的软件,从来就没有好好的学习过设计模式。写代码,做设计的时候都是稀里糊涂。做出来的设计,都会不同程度的让自己感觉到不安。这可能就是《设计模式精解》书中所说那种直觉吧。

引用:

留意你的知觉

出自本能的直觉能对设计质量做出令人惊讶的预测。所谓“出自本能的直觉”,是指当你看到某些不喜欢的东西时,你胃部的感觉。我知道这听起来并不科学(而且它的确不科学),但我的经验总是向我证明:当我从直觉上不喜欢一个设计时,一个更好的设计一定就躺在角落里。

Facade模式:关键特征

意图:希望简化现有系统的使用方法。你需要定义自己的接口。
问题:只需要使用一个复杂系统的一个子集。或者,需要用一种特殊的方式与系统交互。
解决方案:Facade向客户展现使用现有系统的一个新的接口。
参与者与协作者:向客户展现一个定制的接口,让客户更容易地使用现有系统。
效果:Facade模式简化了对所需子系统的使用。但是,由于Facade并不完整,因此某些功能对于客户可能是可用的。
现实:1)定义一个(或一组)新的类来提供所需要的接口。
             2)让新的类使用现有的系统。

Facade模式使用于以下情况:

  • 不需要使用一个复杂系统的所有功能,并且可以创建一个新的类来包容访问原有系统的接口的一个子集(通常它就是)比原始系统AP简单得多。
  • 希望包装或隐藏原有系统。
  • 希望使用原有系统的功能,并且希望增加一些新的功能。
  • “编写一个新的类”的代价小于“让所有人学会使用原有系统”或“在未来维护整个系统”所需的代价

 

posted @ 2005-03-13 23:41 非飞 阅读(2626) | 评论 (0)编辑 收藏


    一个项目通常分为表示层、业务逻辑层和持久层,这是最为常见的三层结构。在组织团队进行项目开发的时候,选择如何分工对版本控制有很大的影响。团队在做开发的时候一般有两种模式:按层开发和按功能开发。

按层开发(本人赞同的模式)

    在这种开发模式下,每个开发人员的目录结构相对固定和独立。对于CVS这类按文件夹来控制权限的版本控制服务器来说,比较容易实现对开发人员权限的划分,不易出现文件不同步而导致的版本混乱。

    另外,这种开发模式下,更能集中开发人员的注意力,不需要了解太多与本层无关的其他技术。将精神全部集中在如何实现本层的功能上,更有利于写出功能强大,运行稳定的代码。例如:开发业务逻辑层的开发人员,他不可避免的会写很多逻辑上基本上一致的代码,在写代码的过程中,就能从中找出一些相对的共性,将公共的代码进行抽象,从而避免了出现大量的重复代码。由于工作范围相对较小,能有更多的时间去学习相关方面的最新技术和解决方案,并应用到程序中,能使程序在实现方式上较为先进、优越。

    老天是公平的,万物有其好的一面也必然有其不好的一面,这种开发模式也不能例外。对于需求不明确,无法定义相对固定的对外接口时,这中按层开发的模式就有其无法避免的一个问题。各层开发人员需要在开发的过程中,反覆的修改接口,以便适应于变化了的需求。这必然就导致逻辑处理部分代码要做相应的修改。

按功能开发(本人持保留态度)

    这种开发模式下,开发人员的目录结构基本是项目的完整目录接口,他们需要到各层去编写对应他们所开发的模块的所有代码。对于CVS这类版本控制服务器来说,基本上是无法做到对开发人员权限的界定。很容易造成版本控制混乱,导致文件版本不同步,是在开发过程中使用了公共文件的开发人员不能保证同步。例如:一个文件为多个开发人员所共同维护,开发人员各自都需要在其中添加自己功能所需要部分的代码。这样很容易出现多个人同时修改一个文件的情况,导致文件不同步而造成的版本混乱。

    另外,这种开发模式对开发人员的技术要求相对较高,它要求开发人员掌握各层中所需要的技术。从界面显示到数据持久化,甚至到网络通信都需要一个开发人员去实现。在功能实现架构不是很确定的情况下,程序代码中将会出现大量的重复代码,因为每个人都有自己的实现机制,而逻辑处理相同或相近的情况在同一层中出现频率又比较高。导致程序的整体结构不统一,尽管层次结构相同。使得程序日后维护极度困难,大大的提高了维护成本。由于开发人员牵涉使用的技术过多,也很难保证程序实现方式的先进性和优越性。



posted @ 2005-03-03 21:06 非飞 阅读(2296) | 评论 (0)编辑 收藏



Hibernate的继承映射包含了三种不同的策略:

  1. 每簇类使用一个表;
  2. 每个子类一个表;
  3. 每个具体内一个表(有限制)。
假设我们有四个类Animal,Dog,Cat,其代码如下:
文件名:Animal.java
class Animal {
    
private String identifier;
    
private String name;
    
private String category;
    
// setter and getter
}

文件名:Dog.java
class Dog extends Animal {
    
private String 
    
// setter and getter
}

文件名:Cat.java
class Cat extends Animal {
    
private String 
    
// setter and getter
}

  • 每簇类使用一个表
       使用每簇类使用一个表的策略时,有一个限制就时子类不能有NOT NULL,映射文件为:
       文件名:Animal.hbm.xml
       <class name="Animal" table="TB_ANIMAL">
          
<id name="identifier" type="string" column="IDENTIFIER">
             
<generator class="uuid.hex"/>
          
</id>
          
<discriminator column="ANIMAL_TYPE" type="string"/>
          
<property name="name" column="NAME" type="string"/>
          
          
<subclass name="Dog" discriminator-value="DOG">
             
          
</subclass>
          
<subclass name="Cat" discriminator-value="CAT">
             
          
</subclass>
       
</class>

  • 每个子类一个表
       使用每个子类一个表的策略时,可以使用一个映射文件实现,也可以分成多个映射文件来实现。每个子类一个映射文件的情况:
       文件名:Animal.hbm.xml
       <class name="Animal" table="ANIMAL">
          
<id name="identifier" column="IDENTIFIER" type="string">
             
<generator class="uuid.hex"/>
          
</id>
          
<property >
       
</class>
       文件名:Dog.hbm.xml
       
<joined-subclass name="Dog" table="DOG" extends="Animal">
          
<key column="DOG_ID"/>
          
       
</joined-subclass>
       文件名:Cat.hbm.xml
       
<joined-subclass name="Cat" table="CAT" extends="Cat">
          
<key column="CAT_ID"/>
          
       
</joined-subclass>

       每个子类一个表的策略实际上一种one-to-one的映射。
  • 每个具体内一个表(有限制)
       使用每个具体内一个表(有限制)策略时,每一个子类的映射文件将要包含所有父类中的属性,映射文件:
       文件名:Dog.hbm.xml
       <class name="Dog" table="DOG">
          
<id name="identifier" column="IDENTIFIER" type="string">
             
<generator class="uuid.hex"/>
          
</id>
          
<property name="name" column="NAME" type="string"/>
          
       
</class>
       文件名:Cat.hbm.xml
       
<class name="Cat" table="CAT">
          
<id name="identifier" column="IDENTIFIER" type="string">
             
<generator class="uuid.hex"/>
          
</id>
          
<property name="name" column="NAME" type="string"/>
          
       
</class>




posted @ 2005-03-02 22:31 非飞 阅读(4588) | 评论 (1)编辑 收藏
    网上一大堆关于PO,POJO,DTO,VO等等对象的讨论,通常都是各持己见,公说公有理,婆说婆有理,讨论到最后也没有什么定论。今天看到一个应用的代码,发现其讲PO直接做为VO(view object)在表示层使用。只从代码上讲,这样做确实省去了跟多操作。不用重复的做对象的赋值、构造。但是会过头来看,这样无疑增加了代码的耦合性。做一个简单的假设,如果对持久层的PO进行了修改,相应的使用PO做为对应的VO(value object)业务逻辑层和使用PO最为VO(view object)的表示层都必须做相应的修改,如此的应用给代码的维护带来了很大的负担,可谓是一动则百动。
    在J2EE应用开发中,是不应该出现这中PO共享使用的方式的。实体对象不应该被跨层使用,各层维护自己的实体对象。这点看书我想大家都知道,而在实际应用中很多人都选择不遵循这一规则。(在使用hibernate时有所不同,引用:“不过由于Hibernate的强大功能,例如动态生成PO,PO的状态管理可以脱离Session,使得在应用了Hibernate的J2EE框架中,PO完全可以充当VO,因此我们下面把PO和VO合并,统称为PO。”引文:结合struts和hibernate谈J2EE架构的数据表示。)出现这总现象,我想原因只有一个就是贪图了一时的省事,在一次性应用开发中,相对的业务对象改动可能性相当的少,很多时候在做项目的时候并不会出现预料不到的改变,没有必要去管理一大堆各式各样的实体对象,这样就自然的导致了PO在各层中共享使用。可是就我目前接触到的项目基本上没有需求是如此明确的,通常需求都是在不断的改变,甚至有时到了最后发版的时候,一些客户都会提出修改需求的要求。另外就是自做需求的情况就更是如此了,这种项目的需求是不断的在变化的。为了保证项目的适应性和可扩展性,就必须保证各层之间的相对独立,尽可能降低耦合度。



posted @ 2005-03-01 12:40 非飞 阅读(2442) | 评论 (2)编辑 收藏