@ My Space
posted @
2005-05-13 00:08 非飞 阅读(2450) |
评论 (2) |
编辑 收藏
@ My space
posted @
2005-05-07 00:19 非飞 阅读(2217) |
评论 (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 非飞 阅读(17351) |
评论 (3) |
编辑 收藏
在JavaScript中,可以通过window.location来获取url地址。但是window.location是一个对象,没有办法直接从里面获取出我们需要的参数。通常的做法就是使用一个隐藏的<input>,通过将window.location负值给input。其目的就是为了将location转换成String。写的过程中总是觉得太复杂了,后来发现使用document.URL就可以解决这个问题。
posted @
2005-04-18 15:52 非飞 阅读(4086) |
评论 (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 非飞 阅读(4703) |
评论 (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 非飞 阅读(2693) |
评论 (1) |
编辑 收藏
中午收到老姐来的电话,电话里她是一遍一遍又一遍的在我耳边唠叨,说,“不管你怎么忙,有多少东西要写,一定要按时睡觉”。还列出了一堆要按时睡觉的理由。其实谁不知道应该要按时睡觉,可是作为写程序的程序员来说,要真想做到这一点实在是难,难,难呀!
要按时睡觉的理由:
从人的排毒期入手:晚间11:00--1:00,肝的排毒期(必须在睡觉中进行)
从人的睡眠最佳时段入手:1:00--4:00,人的睡眠是质量最高的
不知道各位有谁是有正常的生活习惯的,能不能说一说你是怎么做到的。。。
posted @
2005-03-23 15:25 非飞 阅读(2106) |
评论 (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 非飞 阅读(3341) |
评论 (0) |
编辑 收藏
做了这么久的软件,从来就没有好好的学习过设计模式。写代码,做设计的时候都是稀里糊涂。做出来的设计,都会不同程度的让自己感觉到不安。这可能就是《设计模式精解》书中所说那种直觉吧。
引用:
留意你的知觉
出自本能的直觉能对设计质量做出令人惊讶的预测。所谓“出自本能的直觉”,是指当你看到某些不喜欢的东西时,你胃部的感觉。我知道这听起来并不科学(而且它的确不科学),但我的经验总是向我证明:当我从直觉上不喜欢一个设计时,一个更好的设计一定就躺在角落里。
Facade模式:关键特征
意图:希望简化现有系统的使用方法。你需要定义自己的接口。
问题:只需要使用一个复杂系统的一个子集。或者,需要用一种特殊的方式与系统交互。
解决方案:Facade向客户展现使用现有系统的一个新的接口。
参与者与协作者:向客户展现一个定制的接口,让客户更容易地使用现有系统。
效果:Facade模式简化了对所需子系统的使用。但是,由于Facade并不完整,因此某些功能对于客户可能是可用的。
现实:1)定义一个(或一组)新的类来提供所需要的接口。
2)让新的类使用现有的系统。
Facade模式使用于以下情况:
- 不需要使用一个复杂系统的所有功能,并且可以创建一个新的类来包容访问原有系统的接口的一个子集(通常它就是)比原始系统AP简单得多。
- 希望包装或隐藏原有系统。
- 希望使用原有系统的功能,并且希望增加一些新的功能。
- “编写一个新的类”的代价小于“让所有人学会使用原有系统”或“在未来维护整个系统”所需的代价
posted @
2005-03-13 23:41 非飞 阅读(2623) |
评论 (0) |
编辑 收藏
一个项目通常分为表示层、业务逻辑层和持久层,这是最为常见的三层结构。在组织团队进行项目开发的时候,选择如何分工对版本控制有很大的影响。团队在做开发的时候一般有两种模式:按层开发和按功能开发。
按层开发(本人赞同的模式)
在这种开发模式下,每个开发人员的目录结构相对固定和独立。对于CVS这类按文件夹来控制权限的版本控制服务器来说,比较容易实现对开发人员权限的划分,不易出现文件不同步而导致的版本混乱。
另外,这种开发模式下,更能集中开发人员的注意力,不需要了解太多与本层无关的其他技术。将精神全部集中在如何实现本层的功能上,更有利于写出功能强大,运行稳定的代码。例如:开发业务逻辑层的开发人员,他不可避免的会写很多逻辑上基本上一致的代码,在写代码的过程中,就能从中找出一些相对的共性,将公共的代码进行抽象,从而避免了出现大量的重复代码。由于工作范围相对较小,能有更多的时间去学习相关方面的最新技术和解决方案,并应用到程序中,能使程序在实现方式上较为先进、优越。
老天是公平的,万物有其好的一面也必然有其不好的一面,这种开发模式也不能例外。对于需求不明确,无法定义相对固定的对外接口时,这中按层开发的模式就有其无法避免的一个问题。各层开发人员需要在开发的过程中,反覆的修改接口,以便适应于变化了的需求。这必然就导致逻辑处理部分代码要做相应的修改。
按功能开发(本人持保留态度)
这种开发模式下,开发人员的目录结构基本是项目的完整目录接口,他们需要到各层去编写对应他们所开发的模块的所有代码。对于CVS这类版本控制服务器来说,基本上是无法做到对开发人员权限的界定。很容易造成版本控制混乱,导致文件版本不同步,是在开发过程中使用了公共文件的开发人员不能保证同步。例如:一个文件为多个开发人员所共同维护,开发人员各自都需要在其中添加自己功能所需要部分的代码。这样很容易出现多个人同时修改一个文件的情况,导致文件不同步而造成的版本混乱。
另外,这种开发模式对开发人员的技术要求相对较高,它要求开发人员掌握各层中所需要的技术。从界面显示到数据持久化,甚至到网络通信都需要一个开发人员去实现。在功能实现架构不是很确定的情况下,程序代码中将会出现大量的重复代码,因为每个人都有自己的实现机制,而逻辑处理相同或相近的情况在同一层中出现频率又比较高。导致程序的整体结构不统一,尽管层次结构相同。使得程序日后维护极度困难,大大的提高了维护成本。由于开发人员牵涉使用的技术过多,也很难保证程序实现方式的先进性和优越性。
posted @
2005-03-03 21:06 非飞 阅读(2295) |
评论 (0) |
编辑 收藏
Hibernate的继承映射包含了三种不同的策略:
- 每簇类使用一个表;
- 每个子类一个表;
- 每个具体内一个表(有限制)。
假设我们有四个类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 非飞 阅读(4586) |
评论 (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 非飞 阅读(2439) |
评论 (2) |
编辑 收藏
看了两天文档,总算对JMX有了一个整体的认识。发现使用mx4j实现JMX还是相当的轻松的。MBeans可以使用mx4j-tools中的 Xdoclet偷一下懒,让它自动的生成MBeans和Descriptions,ant有相应的支持,还是比较方便的,对于MBean接口的实现,自己写了。
对于如何产生和注册MBeans,mx4j提供了一个相当方便的工具,为什么说相当方便,是因为它真的实在是太方便了。通过写一个xml配置文件可以完成所有的工作。比起M-LET确实是强了不少。下面就是一个在MBean Server产生注册一个NamingService、JMXConnectorServer和一个自写的MBean的配置文件。
<?xml version="1.0" encoding="UTF-8"?>
<configuration port="9999">
<startup>
<create classname="mx4j.tools.naming.NamingService" objectname="naming:type=rmiregistry">
<arg type="int">1099</arg>
</create>
<call operation="start" objectname="naming:type=rmiregistry" />
<object objectid="rmi">
<call classname="javax.management.remote.JMXConnectorServerFactory" method="newJMXConnectorServer">
<arg type="javax.management.remote.JMXServiceURL">
<new classname="javax.management.remote.JMXServiceURL">
<arg type="string">service:jmx:rmi://localhost/jndi/rmi://localhost:1099/jmx</arg>
</new>
</arg>
<arg type="java.util.Map" />
<arg type="javax.management.MBeanServer" />
</call>
</object>
<register objectname="connectors:type=rmi,protocol=jrmp">
<arg type="object" refobjectid="rmi" />
</register>
<call method="start" refobjectid="rmi" />
<create classname="nsmp.examples.mbeans.rmi.MyRemoteServiceObject" objectname="services:type=my-remote" />
</startup>
<shutdown>
<call operation="stop" objectname="services:type=my-remote" />
<call method="stop" refobjectid="rmi" />
<call operation="stop" objectname="naming:type=rmiregistry" />
<unregister objectname="services:type=my-remote"/>
<unregister objectname="connectors:type=rmi,protocol=jrmp" />
<unregister objectname="naming:type=rmiregistry" />
</shutdown>
</configuration>
java代码:
package nsmp.agent;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.Reader;
import java.net.Socket;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;
import mx4j.tools.config.ConfigurationLoader;
import nsmp.util.NsmpGlobals;
/**//**
* @version 1.0
* @author tower
*
* TODO write the comment of this type
*/
public class NsmpServer {
public void startup() throws Exception {
MBeanServer server = MBeanServerFactory.newMBeanServer();
ConfigurationLoader loader = new ConfigurationLoader();
server.registerMBean(loader, ObjectName.getInstance("config:service=loader"));
Reader reader = new BufferedReader(new FileReader(NsmpGlobals.NSMP_HOME + "/conf/config.xml"));
loader.startup(reader);
reader.close();
System.out.println("Start the nsmp server successfully!");
}
public void shutdown() throws Exception {
String shutdownCommand = "shutdown";
Socket socket = new Socket("127.0.0.1", 9999);
socket.getOutputStream().write(shutdownCommand.getBytes());
socket.close();
}
}
startup方法调用配置文件的startup部分完成创建和注册,shutdown方法调用配置文件的shutdown部分释放相应的资源。通过调用 startup方法就可以起动MBeanServer提供服务了。对于shutdown开始搞了我半天startup后 ConfigurationLoader都没有创建一个侦听端口来接收shutdown命令,看了看mx4j的源码发现 ConfigurationLoader也没有发现什么特殊地方。捉摸半天终于发现了自己放了一个愚笨的错误,eclipse是用普通用户权限开的,没有办法创建侦听,改成root后一切ok。
接下就随便写了一个JMXConnector,代码:
/**//*
* Copyright (C) The MX4J Contributors.
* All rights reserved.
*
* This software is distributed under the terms of the MX4J License version 1.0.
* See the terms of the MX4J License in the documentation provided with this software.
*/
package nsmp.examples.mbeans.rmi;
import java.util.Map;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
/**//**
* @version $Revision: 1.3 $
*/
public class Client
{
public static void main(String[] args) throws Exception
{
JMXServiceURL address = new JMXServiceURL("service:jmx:rmi://localhost/jndi/rmi://localhost:1099/jmx");
Map creationEnv = null;
JMXConnector connector = JMXConnectorFactory.newJMXConnector(address, creationEnv);
Map connectionEnv = null;
connector.connect(connectionEnv);
MBeanServerConnection serverConnection = connector.getMBeanServerConnection();
ObjectName name = ObjectName.getInstance("services:type=my-remote");
MBeanInfo mbInfo = serverConnection.getMBeanInfo(name);
MBeanOperationInfo[] operationInfo = mbInfo.getOperations();
for (int i = 0; i < operationInfo.length; i++) {
System.out.println(operationInfo[i].getName());
}
serverConnection.invoke(name, "sayHello", new Object[] {"Tower He"}, new String[] {"java.lang.String"});
}
}
JMXConnector是通过获取一个MBeanServerConnection来实现远程调用的,运行了一下一切顺利通过。
下载:MX4JExample.rar
posted @
2005-02-05 19:07 非飞 阅读(5683) |
评论 (0) |
编辑 收藏