??xml version="1.0" encoding="utf-8" standalone="yes"?>ɱ̬:BlogJava - 4399ɱol|ɱ佫//www.lmlez.icu/mstar/黑灵的没啥技术含量的技术博? -> //zjumty.iteye.comzh-cnWed, 16 Oct 2019 02:31:50 GMTWed, 16 Oct 2019 02:31:50 GMT60在传输层上压~WebService的请求和响应 - 4399ɱol|ɱ佫//www.lmlez.icu/mstar/archive/2013/06/23/400884.html黑灵黑灵Sun, 23 Jun 2013 13:45:00 GMT//www.lmlez.icu/mstar/archive/2013/06/23/400884.html//www.lmlez.icu/mstar/comments/400884.html//www.lmlez.icu/mstar/archive/2013/06/23/400884.html#Feedback1//www.lmlez.icu/mstar/comments/commentRss/400884.html//www.lmlez.icu/mstar/services/trackbacks/400884.html阅读全文

黑灵 2013-06-23 21:45 发表评论
]]>
在MongoDB里实现@环序列功? - 4399ɱol|ɱ佫//www.lmlez.icu/mstar/archive/2013/04/26/398469.html黑灵黑灵Fri, 26 Apr 2013 14:57:00 GMT//www.lmlez.icu/mstar/archive/2013/04/26/398469.html//www.lmlez.icu/mstar/comments/398469.html//www.lmlez.icu/mstar/archive/2013/04/26/398469.html#Feedback1//www.lmlez.icu/mstar/comments/commentRss/398469.html//www.lmlez.icu/mstar/services/trackbacks/398469.html

环境是这LQ服务器是用Java做的Q?数据库是MongoDB

 

需求是q样的:我们的系l里要生成一个唯一IDQ前面的部分有一定的格式Qƈ和时间关联, _到微U,考虑到同一微秒内有可能存在q发情况Q? 所以后面在加两位序列号Q?pȝ需要定义ؓ1毫秒内的q发于100个,所以后面两位就够用了? Java服务器端有多台机器都可以用来生成q个唯一IDQ所以需要在不同的机器上不能生成相同的序列号Q所以需要在某一点上做全局的范围同步来保存q序? L唯一性?其实如果不考虑需求里的唯一ID是有一定意义的格式的, 用UUID或MongoDB的ObjectId都是更好的选择Q完全不需要在某一点上q行同步Q性能会更好?/p>

 

q个可以生成序列L点, 我们可以做一个序列号生成服务器来对应Q?也可以用数据库来对应? 单单个简单的功能准备一个服务器来做昄不合适?但是我们用的MongoDBq没有类gMySQL或Oracle中的SELECT FOR UPDATEq样的锁机制?所以没有办法简单的对这个序列号做原子操作? 但是MongoDB的对单个documentq行update操作中有很是h原子性的Q?例如

  • $set
  • $unset
  • $inc
  • $push
  • $pushAll
  • $pull
  • $pullAll

我们可以利用q些原子操作Q在数据库层以乐观锁的Ş式来实现循环序列字段。ؓ了方便调用我把这D逻辑做成数据库中的Javascript函数?cM与MySQL中的存储q程?/p>

 

首先我们需要一个collection来存攑ֺ列号Qƈ寚w要的需要的序列可行初始化。我们叫它counters?/p>

Js代码  收藏代码
  1. db.counters.save({_id:"SerialNo1", val:0, maxval:99})  

 

然后我们想system.js里添加一个Javascript函数

Js代码  收藏代码
  1. db.system.js.save({_id:"getNextUniqueSeq",  
  2. value:function (keyName) {  
  3.     var seqObj = db.counters.findOne({_id:keyName});  
  4.     if (seqObj == null) {  
  5.         print("can not find record with key: " + keyName);  
  6.         return -1;  
  7.     }  
  8.       
  9.     // the max value of sequence  
  10.     var maxVal = seqObj.maxval;  
  11.     // the current value of sequence  
  12.     var curVal = seqObj.val;  
  13.       
  14.     while(true){  
  15.         // if curVal reach max, reset it  
  16.         if(curVal >= maxVal){  
  17.             db.counters.update({_id : keyName, val : curVal}, { $set : { val : 0 }}, falsefalse);  
  18.             var err = db.getLastErrorObj();  
  19.             if( err && err.code ) {  
  20.                 print( "unexpected error reset data: " + tojson( err ) );  
  21.                 return -2;  
  22.             } else if (err.n == 0){  
  23.                 // fail to reset value, may be reseted by others  
  24.                 print("fail to reset value: ");  
  25.             }   
  26.   
  27.             // get current value again.  
  28.             seqObj = db.counters.findOne({_id:keyName});  
  29.             maxVal = seqObj.maxval;  
  30.             curVal = seqObj.val;  
  31.             continue;  
  32.         }   
  33.           
  34.         // if curVal not reach the max, inc it;  
  35.         // increase   
  36.         db.counters.update({_id : keyName, val : curVal}, { $inc : { val : 1 }}, falsefalse);  
  37.         var err = db.getLastErrorObj();  
  38.         if( err && err.code ) {  
  39.             print( "unexpected error inc val: " + tojson( err ) );  
  40.                return -3;  
  41.         } else if (err.n == 0){  
  42.             // fail to reset value, may be increased by others  
  43.             print("fail to inc value: ");  
  44.               
  45.             // get current value again.  
  46.             seqObj = db.counters.findOne({_id:keyName});  
  47.             maxVal = seqObj.maxval;  
  48.             curVal = seqObj.val;  
  49.             continue;  
  50.         } else {  
  51.             var retVal = curVal + 1;  
  52.             print("success to get seq : " + retVal);  
  53.             // increase successful  
  54.             return retVal;  
  55.         }  
  56.     }  
  57. }  
  58. });  

上面q段会把指定的序列号的val?1Q如果val辑ֈ上限则从0开始。所以叫循环序列?/p>

 

其实上面的实现在原理上和Java里的AtomicIntegerpd的功能实现是cM的,利用循环重试和原子性的CAS来实现。这U实现方式在多线E的环境里由于锁QMonitorQ的范围很小Q所以ƈ发性上比排他锁要好一些?/p>

 

下面我们用Java来测试一下这个函数的正确性?卛_多线E的情况下会不会得到重复的序列号?/p>

 

W一个测试,val=0Q?maxval=2000Q?Java?0个线E每个线E@环调?00ơ??000ơ?所以正的情况下,??999应该每个数字只出Cơ?/p>

 

Java代码  收藏代码
  1. @Test  
  2. public void testGetNextUniqueSeq1() throws Exception {  
  3.   
  4.     final int THREAD_COUNT = 20;  
  5.     final int LOOP_COUNT = 100;  
  6.   
  7.     Mongo mongoClient = new Mongo("172.17.2.100"27017);  
  8.     DB db = mongoClient.getDB("im");  
  9.     db.authenticate("imadmin""imadmin".toCharArray());  
  10.     BasicDBObject q = new BasicDBObject();  
  11.     q.put("_id""UNIQUE_KEY");  
  12.   
  13.     BasicDBObject upd = new BasicDBObject();  
  14.     BasicDBObject set = new BasicDBObject();  
  15.     set.put("val"0);  
  16.     set.put("maxval", THREAD_COUNT * LOOP_COUNT);  
  17.     upd.put("$set", set);  
  18.   
  19.     db.getCollection("counters").update(q, upd);  
  20.   
  21.     Thread[] threads = new Thread[THREAD_COUNT];  
  22.     final int[][] results = new int[THREAD_COUNT][LOOP_COUNT];  
  23.     for (int i = 0; i < THREAD_COUNT; i++) {  
  24.         final int temp_i = i;  
  25.         threads[i] = new Thread("" + i) {  
  26.             @Override  
  27.             public void run() {  
  28.                 try {  
  29.                     Mongo mongoClient = new Mongo("172.17.2.100"27017);  
  30.                     DB db = mongoClient.getDB("im");  
  31.                     db.authenticate("imadmin""imadmin".toCharArray());  
  32.                     for (int j = 0; j < LOOP_COUNT; j++) {  
  33.                         Object result = db.eval("getNextUniqueSeq(\"UNIQUE_KEY\")");  
  34.                         System.out.printf("Thread %s, seq=%d\n", Thread.currentThread().getName(), ((Double) result).intValue());  
  35.                         results[temp_i][j] = ((Double) result).intValue();  
  36.                     }  
  37.                 } catch (UnknownHostException e) {  
  38.                     e.printStackTrace();  
  39.                 }  
  40.             }  
  41.         };  
  42.     }  
  43.   
  44.     for (Thread thread : threads) {  
  45.         thread.start();  
  46.     }  
  47.   
  48.     for (Thread thread : threads) {  
  49.         thread.join();  
  50.     }  
  51.   
  52.     for (int num = 1; num <= LOOP_COUNT * THREAD_COUNT; num++) {  
  53.         // every number appear 1 times only!  
  54.         int times = 0;  
  55.         for (int j = 0; j < THREAD_COUNT; j++) {  
  56.             for (int k = 0; k < LOOP_COUNT; k++) {  
  57.                 if (results[j][k] == num)  
  58.                     times++;  
  59.             }  
  60.         }  
  61.   
  62.         assertEquals(1, times);  
  63.     }  
  64. }  

 

然后我们再测试一下@环的情况?val=0, maxval=99?同样是Java?0个线E每个线E@环调?00ơ??000ơ。这ơ从0?9的数字每个应该取?0ơ?/p>

 

Java代码  收藏代码
  1. @Test  
  2. public void testGetNextUniqueSeq2() throws Exception {  
  3.   
  4.     final int THREAD_COUNT = 20;  
  5.     final int LOOP_COUNT = 100;  
  6.   
  7.     Mongo mongoClient = new Mongo("172.17.2.100"27017);  
  8.     DB db = mongoClient.getDB("im");  
  9.     db.authenticate("imadmin""imadmin".toCharArray());  
  10.     BasicDBObject q = new BasicDBObject();  
  11.     q.put("_id""UNIQUE_KEY");  
  12.   
  13.     BasicDBObject upd = new BasicDBObject();  
  14.     BasicDBObject set = new BasicDBObject();  
  15.     set.put("val"0);  
  16.     set.put("maxval", LOOP_COUNT);  
  17.     upd.put("$set", set);  
  18.   
  19.     db.getCollection("counters").update(q, upd);  
  20.   
  21.     Thread[] threads = new Thread[THREAD_COUNT];  
  22.     final int[][] results = new int[THREAD_COUNT][LOOP_COUNT];  
  23.     for (int i = 0; i < THREAD_COUNT; i++) {  
  24.         final int temp_i = i;  
  25.         threads[i] = new Thread("" + i) {  
  26.             @Override  
  27.             public void run() {  
  28.                 try {  
  29.                     Mongo mongoClient = new Mongo("172.17.2.100"27017);  
  30.                     DB db = mongoClient.getDB("im");  
  31.                     db.authenticate("imadmin""imadmin".toCharArray());  
  32.                     for (int j = 0; j < LOOP_COUNT; j++) {  
  33.                         Object result = db.eval("getNextUniqueSeq(\"UNIQUE_KEY\")");  
  34.                         System.out.printf("Thread %s, seq=%d\n", Thread.currentThread().getName(), ((Double) result).intValue());  
  35.                         results[temp_i][j] = ((Double) result).intValue();  
  36.                     }  
  37.                 } catch (UnknownHostException e) {  
  38.                     e.printStackTrace();  
  39.                 }  
  40.             }  
  41.         };  
  42.     }  
  43.   
  44.     for (Thread thread : threads) {  
  45.         thread.start();  
  46.     }  
  47.   
  48.     for (Thread thread : threads) {  
  49.         thread.join();  
  50.     }  
  51.   
  52.     for (int num = 1; num <= LOOP_COUNT; num++) {  
  53.         // every number appear 20 times only!  
  54.         int times = 0;  
  55.         for (int j = 0; j < THREAD_COUNT; j++) {  
  56.             for (int k = 0; k < LOOP_COUNT; k++) {  
  57.                 if (results[j][k] == num)  
  58.                     times++;  
  59.             }  
  60.         }  
  61.   
  62.         assertEquals(20, times);  
  63.     }  
  64. }  

 

q个试跑了几次都是正确的?/p>

 

׃没有可以q行Ҏ其他的实现方式(例如排他锁)所以没有做性能试?/p>

 

写在最后?虽然MongoDB支持cM于存储过E的Stored JavascriptQ但是其实不使用q个来解军_杂问题。主要原因是没法调试Q维护v来太不方ѝ而且?.4之前MongoDBҎ务端 Javascript支持q不是很好, 一个mongodq程同时只能执行一DJavascript。如果能在应用层解决掉还是在应用层里实现逻辑比较好?/p>



黑灵 2013-04-26 22:57 发表评论
]]>
输出debug信息到postfix的log - 4399ɱol|ɱ佫//www.lmlez.icu/mstar/archive/2013/04/26/398459.html黑灵黑灵Fri, 26 Apr 2013 11:25:00 GMT//www.lmlez.icu/mstar/archive/2013/04/26/398459.html//www.lmlez.icu/mstar/comments/398459.html//www.lmlez.icu/mstar/archive/2013/04/26/398459.html#Feedback0//www.lmlez.icu/mstar/comments/commentRss/398459.html//www.lmlez.icu/mstar/services/trackbacks/398459.html
/etc/postfix/main.cf

debug_peer_list = example.com
debug_peer_level = 2

/etc/postfix/master.cf
smtp      inet  n       -       n       -       -       smtpd -v


黑灵 2013-04-26 19:25 发表评论
]]>
Java里的CompareAndSet(CAS) - 4399ɱol|ɱ佫//www.lmlez.icu/mstar/archive/2013/04/24/398351.html黑灵黑灵Wed, 24 Apr 2013 09:20:00 GMT//www.lmlez.icu/mstar/archive/2013/04/24/398351.html//www.lmlez.icu/mstar/comments/398351.html//www.lmlez.icu/mstar/archive/2013/04/24/398351.html#Feedback0//www.lmlez.icu/mstar/comments/commentRss/398351.html//www.lmlez.icu/mstar/services/trackbacks/398351.html Atomic 从JDK5开? java.util.concurrent包里提供了很多面向ƈ发编E的c? 使用q些cd多核CPU的机器上会有比较好的性能.
主要原因是这些类里面大多使用(p|-重试方式?乐观锁而不是synchronized方式的悲观锁.

今天有时间跟t了一下AtomicInteger的incrementAndGet的实?
本h对ƈ发编E也不是特别了解, 在这里就是做个笔? 方便以后再深入研I?

1. incrementAndGet的实?br />
    public final int incrementAndGet() {
        
for (;;) {
            
int current = get();
            
int next = current + 1;
            
if (compareAndSet(current, next))
                
return next;
        }
    }

首先可以看到他是通过一个无限@?spin)直到increment成功为止. 
循环的内Ҏ
1.取得当前?br />2.计算+1后的?br />3.如果当前D有效(没有?的话讄那个+1后的?br />4.如果讄没成?当前值已l无效了卌别的U程改过?, 再从1开?

2. compareAndSet的实?br />
    public final boolean compareAndSet(int expect, int update) {
        
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

直接调用的是UnSafeq个cȝ
compareAndSwapIntҎ
全称?/span>
sun.misc.Unsafe. q个cLOracle(Sun)提供的实? 可以在别的公司的JDK里就不是q个cM

3.
compareAndSwapInt的实?br />
    /**
     * Atomically update Java variable to <tt>x</tt> if it is currently
     * holding <tt>expected</tt>.
     * 
@return <tt>true</tt> if successful
     
*/
    
public final native boolean compareAndSwapInt(Object o, long offset,
                                                  
int expected,
                                                  
int x);

可以看到, 不是用Java实现? 而是通过JNI调用操作pȝ的原生程?

4.
compareAndSwapInt的native实现
如果你下载了OpenJDK的源代码的话在hotspot\src\share\vm\prims\目录下可以找到unsafe.cpp
UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))
  UnsafeWrapper(
"Unsafe_CompareAndSwapInt");
  oop p 
= JNIHandles::resolve(obj);
  jint
* addr = (jint *) index_oop_from_field_offset_long(p, offset);
  
return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
UNSAFE_END

可以看到实际上调?/span>
AtomiccȝcmpxchgҎ.

5.
Atomic?/span>cmpxchg
q个cȝ实现是跟操作pȝ有关, 跟CPU架构也有? 如果是windows下x86的架?br />实现在hotspot\src\os_cpu\windows_x86\vm\目录的atomic_windows_x86.inline.hpp文g?br />
inline jint     Atomic::cmpxchg    (jint     exchange_value, volatile jint*     dest, jint     compare_value) {
  
// alternative for InterlockedCompareExchange
  int mp = os::is_MP();
  __asm {
    mov edx, dest
    mov ecx, exchange_value
    mov eax, compare_value
    LOCK_IF_MP(mp)
    cmpxchg dword ptr [edx], ecx
  }
}

在这里可以看到是用嵌入的汇编实现? 关键CPU指o?/span>
cmpxchg
到这里没法再往下找代码? 也就是说CAS的原子性实际上是CPU实现? 其实在这一点上q是有排他锁? 只是比v用synchronized, q里的排他时间要短的? 所以在多线E情况下性能会比较好.

代码里有?/span>
alternative for InterlockedCompareExchange
q个
InterlockedCompareExchange是WINAPI里的一个函? 做的事情和上面这D|~是一L
//msdn.microsoft.com/en-us/library/windows/desktop/ms683560%28v=vs.85%29.aspx

6. 最后再贴一下x86的cmpxchg指定

Opcode CMPXCHG


CPU: I486+
Type of Instruction: User

Instruction: CMPXCHG dest, src

Description: Compares the accumulator with dest. If equal the "dest"
is loaded with "src", otherwise the accumulator is loaded
with "dest".

Flags Affected: AF, CF, OF, PF, SF, ZF

CPU mode: RM,PM,VM,SMM
+++++++++++++++++++++++
Clocks:
CMPXCHG reg, reg 6
CMPXCHG mem, reg 7 (10 if compartion fails)


 


黑灵 2013-04-24 17:20 发表评论
]]>
Apache Mina 中文文译 - Ҏ?/title><link>//www.lmlez.icu/mstar/archive/2013/04/23/398309.html</link><dc:creator>黑灵</dc:creator><author>黑灵</author><pubDate>Tue, 23 Apr 2013 14:02:00 GMT</pubDate><guid>//www.lmlez.icu/mstar/archive/2013/04/23/398309.html</guid><wfw:comment>//www.lmlez.icu/mstar/comments/398309.html</wfw:comment><comments>//www.lmlez.icu/mstar/archive/2013/04/23/398309.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>//www.lmlez.icu/mstar/comments/commentRss/398309.html</wfw:commentRss><trackback:ping>//www.lmlez.icu/mstar/services/trackbacks/398309.html</trackback:ping><description><![CDATA[Ҏ?br />//mina.apache.org/mina-project/features.html<br /><br />MINA是一个简单的却有功能丰富的网l应用程序框Ӟ 它提供如下特性:<br /><ul class="znkp"><li class="znkp">为各U传输类型提供一套统一的API</li></ul><blockquote><ul class="znkp"><li class="znkp">通过Java NIO实现 TCP/IP & UPD/IP通信</li></ul></blockquote><blockquote><ul class="znkp"><li class="znkp">通过RXTX实现串口通信QRS232Q?/li></ul></blockquote><blockquote><ul class="znkp"><li class="znkp">VM内部道通信</li></ul></blockquote><blockquote><ul class="znkp"><li class="znkp">你可以实现自q通信方式</li></ul></blockquote><ul class="znkp"><li class="znkp">通过Filter接口实现扩展点;cM与Servlet的Filter</li></ul><ul class="znkp"><li class="znkp">低和高U的API</li></ul><blockquote><ul class="znkp"><li class="znkp">低Q用ByteBuffer</li></ul></blockquote><blockquote><ul class="znkp"><li class="znkp">高Q用戯定义的消息对象和~码</li></ul></blockquote><ul class="znkp"><li class="znkp">可以自由定制的线E模?/li></ul><blockquote><ul class="znkp"><li class="znkp">单线E?/li></ul></blockquote><blockquote><ul class="znkp"><li class="znkp">一个线E池</li></ul></blockquote><blockquote><ul class="znkp"><li class="znkp">多个U程池(例如 <a target="_blank" title="SEDA" >SEDA</a>Q?/li></ul></blockquote><ul class="znkp"><li class="znkp">利用Java5的SSLEngine实现的开即用的SSL,TLS, StartTLS功能</li></ul><ul class="znkp"><li class="znkp">q蝲保护 ?带宽限制</li></ul><ul class="znkp"><li class="znkp">通过Mock对象可以q行单体试</li></ul><ul class="znkp"><li class="znkp">通过JMX理服务?/li></ul><ul class="znkp"><li class="znkp">通过StreamIoHandler支持Z的I/O</li></ul><ul class="znkp"><li class="znkp">可以整合qPicoContainer和Spring{常用容?/li></ul><ul class="znkp"><li class="znkp">很容易从Nettyq移q来?/li></ul><br /><img src ="//www.lmlez.icu/mstar/aggbug/398309.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="//www.lmlez.icu/mstar/" target="_blank">黑灵</a> 2013-04-23 22:02 <a href="//www.lmlez.icu/mstar/archive/2013/04/23/398309.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Apache Mina 中文文译 - 概述 - 4399ɱol|ɱ佫//www.lmlez.icu/mstar/archive/2013/04/22/398241.html黑灵黑灵Mon, 22 Apr 2013 15:13:00 GMT//www.lmlez.icu/mstar/archive/2013/04/22/398241.html//www.lmlez.icu/mstar/comments/398241.html//www.lmlez.icu/mstar/archive/2013/04/22/398241.html#Feedback0//www.lmlez.icu/mstar/comments/commentRss/398241.html//www.lmlez.icu/mstar/services/trackbacks/398241.html原文链接Q//mina.apache.org/mina-project/index.html

Apache MINA 是一个网l应用框Ӟ 它可以帮助你单容易的开发高性能Q高可扩展性的|络应用E序。Apache MINA底层利用Java NIO实现Q在TCP/IP和UPD/IP{传输层上提供一个抽象的Z事g驱动的异步API?br />
Apache MINA一般被UCؓQ?br />
  • 一个NIO框架或库
  • 客户端,服务器框架或?/li>
  • 一个网lSocket?/li>
管如此QApache MINA要提供的比上面说的多得多?你可以看一下它的功能特性列表, 利用q些Ҏ你可以快速开发网l应用程序, 你还可以看一下h们是怎么说MINA的?请下载MINA的包Q尝试一下快速开始指南, 览一下FAQ或者加入我们的C֌?br />
Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at . //www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.



黑灵 2013-04-22 23:13 发表评论
]]>
Properties.storeToXMLҎ抛出I指针哦! - 4399ɱol|ɱ佫//www.lmlez.icu/mstar/archive/2013/04/19/398100.html黑灵黑灵Fri, 19 Apr 2013 08:42:00 GMT//www.lmlez.icu/mstar/archive/2013/04/19/398100.html//www.lmlez.icu/mstar/comments/398100.html//www.lmlez.icu/mstar/archive/2013/04/19/398100.html#Feedback0//www.lmlez.icu/mstar/comments/commentRss/398100.html//www.lmlez.icu/mstar/services/trackbacks/398100.html
cM下面q段代码:
    @Test(expected = IOException.class)
    
public void testPropertiesStoreToXml() throws IOException {
        Properties props 
= new Properties();
        props.put(
"key1"true);
        ByteArrayOutputStream baos 
= new ByteArrayOutputStream();
        props.storeToXML(baos,
null);
        String xml 
= new String(baos.toByteArray());
        Assert.fail(
"should not go to here");
    }

在生成XML的时候会抛出IOException. Dq个IOException的是做XMLTransform的时候出CNullPointerException

感觉很奇? 调试qProperties的代码看了一?

    public String getProperty(String key) {
    Object oval 
= super.get(key);
    String sval 
= (oval instanceof String) ? (String)oval : null;
    
return ((sval == null&& (defaults != null)) ? defaults.getProperty(key) : sval;
    }

原来Propertiesq货, 不是String的属性一码色的返回NULL?

l果在XMLTransform的时? 直接对这个NULLq行Ҏ调用.

后来看了一下Properties文, Propertiesl承至Hashtable, 所以有put和putAll之类的方? 但是不徏议?
因ؓq些Ҏ不限定Stringcd. 推荐使用setPropertyҎ, q个Ҏ的g定是String.

Because Properties inherits from Hashtable, the put and putAll methods can be applied to a Properties object. Their use is strongly discouraged as they allow the caller to insert entries whose keys or values are not Strings. The setProperty method should be used instead. If the store or save method is called on a "compromised" Properties object that contains a non-String key or value, the call will fail. Similarly, the call to the propertyNames or list method will fail if it is called on a "compromised" Properties object that contains a non-String key.

OK,我承认是我不好好看文?q? 但是我脚的如果你把非String的D用一下toString再用不是更好吗?



黑灵 2013-04-19 16:42 发表评论
]]>
关于spring-mvc的InitBinder注解的参?/title><link>//www.lmlez.icu/mstar/archive/2013/04/17/397945.html</link><dc:creator>黑灵</dc:creator><author>黑灵</author><pubDate>Tue, 16 Apr 2013 16:42:00 GMT</pubDate><guid>//www.lmlez.icu/mstar/archive/2013/04/17/397945.html</guid><wfw:comment>//www.lmlez.icu/mstar/comments/397945.html</wfw:comment><comments>//www.lmlez.icu/mstar/archive/2013/04/17/397945.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>//www.lmlez.icu/mstar/comments/commentRss/397945.html</wfw:commentRss><trackback:ping>//www.lmlez.icu/mstar/services/trackbacks/397945.html</trackback:ping><description><![CDATA[通过Spring-mvc的@InitBinder注释的方法可以对WebDataBinder做一些初始化操作?br />比如讄Validator?<br />我一直在惌不能为每个Request或者每个ActionҎ单独讄Validator?br />也就是说Controller里有多个被@InitBinder标注的方法?在不同的Action时被分别调用?br /><br />我注意到了@InitBinder的value参数Q?br /><br />api docs里是q样描述的:<br />The names of command/form attributes and/or request parameters that this init-binder method is supposed to apply to. <p>Default is to apply to all command/form attributes and all request parameters processed by the annotated handler class. Specifying model attribute names or request parameter names here restricts the init-binder method to those specific attributes/parameters, with different init-binder methods typically applying to different groups of attributes or parameters. <br /></p><p>是乎是可以针对不同的Form对象或命令调用不同的InitBinderҎ?/p><p>于是我写了下面的Controller试了一?/p><p></p><div style="background-color:#eeeeee;font-size:13px;BORDER:1px solid #CCCCCC;PADDING-RIGHT: 5px;PADDING-BOTTOM: 4px;PADDING-left: 4px;PADDING-TOP: 4px;WIDTH: 98%;word-break:break-all"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>//www.CodeHighlighter.com/<br><br>--><span style="color: #000000; ">@Controller<br /></span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">class</span><span style="color: #000000; "> HomeController {<br />    <br />    </span><span style="color: #0000FF; ">private</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">static</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">final</span><span style="color: #000000; "> Logger logger </span><span style="color: #000000; ">=</span><span style="color: #000000; "> LoggerFactory.getLogger(HomeController.</span><span style="color: #0000FF; ">class</span><span style="color: #000000; ">);<br />    <br />    @InitBinder(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">action1</span><span style="color: #000000; ">"</span><span style="color: #000000; ">)<br />    </span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">void</span><span style="color: #000000; "> initBinder1(WebDataBinder binder){<br />        logger.info(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">initBinder1</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />    }<br />    <br />    @InitBinder(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">action2</span><span style="color: #000000; ">"</span><span style="color: #000000; ">)<br />    </span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">void</span><span style="color: #000000; "> initBinder2(WebDataBinder binder){<br />        logger.info(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">initBinder2</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br />    }<br />    <br />    </span><span style="color: #008000; ">/**</span><span style="color: #008000; "><br />     * Simply selects the home view to render by returning its name.<br />     </span><span style="color: #008000; ">*/</span><span style="color: #000000; "><br />    @RequestMapping(value </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #000000; ">"</span><span style="color: #000000; ">/</span><span style="color: #000000; ">"</span><span style="color: #000000; ">, method </span><span style="color: #000000; ">=</span><span style="color: #000000; "> RequestMethod.GET)<br />    </span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> String home(Model model) {        <br />        <br />        Date date </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> Date();<br />        DateFormat dateFormat </span><span style="color: #000000; ">=</span><span style="color: #000000; "> DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);<br />        <br />        String formattedDate </span><span style="color: #000000; ">=</span><span style="color: #000000; "> dateFormat.format(date);<br />        <br />        model.addAttribute(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">serverTime</span><span style="color: #000000; ">"</span><span style="color: #000000; ">, formattedDate );<br />        <br />        </span><span style="color: #0000FF; ">return</span><span style="color: #000000; "> </span><span style="color: #000000; ">"</span><span style="color: #000000; ">home</span><span style="color: #000000; ">"</span><span style="color: #000000; ">;<br />    }<br />    <br />    </span><span style="color: #008000; ">/**</span><span style="color: #008000; "><br />     * Simply selects the home view to render by returning its name.<br />     </span><span style="color: #008000; ">*/</span><span style="color: #000000; "><br />    @RequestMapping(value </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #000000; ">"</span><span style="color: #000000; ">/doit</span><span style="color: #000000; ">"</span><span style="color: #000000; ">, method </span><span style="color: #000000; ">=</span><span style="color: #000000; "> RequestMethod.POST, params</span><span style="color: #000000; ">=</span><span style="color: #000000; ">"</span><span style="color: #000000; ">action1</span><span style="color: #000000; ">"</span><span style="color: #000000; ">)<br />    </span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> String doit1(@RequestParam(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">value1</span><span style="color: #000000; ">"</span><span style="color: #000000; ">) </span><span style="color: #0000FF; ">int</span><span style="color: #000000; "> value1,<br />            @RequestParam(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">action1</span><span style="color: #000000; ">"</span><span style="color: #000000; ">) String action, Model model) {        <br />        logger.info(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">value1={}</span><span style="color: #000000; ">"</span><span style="color: #000000; ">,value1);<br />        <br />        Date date </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> Date();<br />        DateFormat dateFormat </span><span style="color: #000000; ">=</span><span style="color: #000000; "> DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);<br />        <br />        String formattedDate </span><span style="color: #000000; ">=</span><span style="color: #000000; "> dateFormat.format(date);<br />        <br />        model.addAttribute(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">serverTime</span><span style="color: #000000; ">"</span><span style="color: #000000; ">, formattedDate );<br />        <br />        </span><span style="color: #0000FF; ">return</span><span style="color: #000000; "> </span><span style="color: #000000; ">"</span><span style="color: #000000; ">home</span><span style="color: #000000; ">"</span><span style="color: #000000; ">;<br />    }<br />    <br />    </span><span style="color: #008000; ">/**</span><span style="color: #008000; "><br />     * Simply selects the home view to render by returning its name.<br />     </span><span style="color: #008000; ">*/</span><span style="color: #000000; "><br />    @RequestMapping(value </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #000000; ">"</span><span style="color: #000000; ">/doit</span><span style="color: #000000; ">"</span><span style="color: #000000; ">, method </span><span style="color: #000000; ">=</span><span style="color: #000000; "> RequestMethod.POST, params</span><span style="color: #000000; ">=</span><span style="color: #000000; ">"</span><span style="color: #000000; ">action2</span><span style="color: #000000; ">"</span><span style="color: #000000; ">)<br />    </span><span style="color: #0000FF; ">public</span><span style="color: #000000; "> String doit2(@RequestParam(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">value1</span><span style="color: #000000; ">"</span><span style="color: #000000; ">) </span><span style="color: #0000FF; ">int</span><span style="color: #000000; "> value1,<br />            @RequestParam(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">action2</span><span style="color: #000000; ">"</span><span style="color: #000000; ">) String action, Model model) {        <br />        logger.info(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">value1={}</span><span style="color: #000000; ">"</span><span style="color: #000000; ">,value1);<br />        <br />        Date date </span><span style="color: #000000; ">=</span><span style="color: #000000; "> </span><span style="color: #0000FF; ">new</span><span style="color: #000000; "> Date();<br />        DateFormat dateFormat </span><span style="color: #000000; ">=</span><span style="color: #000000; "> DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);<br />        <br />        String formattedDate </span><span style="color: #000000; ">=</span><span style="color: #000000; "> dateFormat.format(date);<br />        <br />        model.addAttribute(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">serverTime</span><span style="color: #000000; ">"</span><span style="color: #000000; ">, formattedDate );<br />        <br />        </span><span style="color: #0000FF; ">return</span><span style="color: #000000; "> </span><span style="color: #000000; ">"</span><span style="color: #000000; ">home</span><span style="color: #000000; ">"</span><span style="color: #000000; ">;<br />    }<br />}<br /></span></div><p>画面上的Form是这L</p><p><br /></p><p></p><div style="background-color:#eeeeee;font-size:13px;BORDER:1px solid #CCCCCC;PADDING-RIGHT: 5px;PADDING-BOTTOM: 4px;PADDING-left: 4px;PADDING-TOP: 4px;WIDTH: 98%;word-break:break-all"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>//www.CodeHighlighter.com/<br><br>--><span style="color: #0000FF; "><</span><span style="color: #800000; ">form </span><span style="color: #FF0000; ">action</span><span style="color: #0000FF; ">="doit"</span><span style="color: #FF0000; "> method</span><span style="color: #0000FF; ">="post"</span><span style="color: #FF0000; "> enctype</span><span style="color: #0000FF; ">="application/x-www-form-urlencoded"</span><span style="color: #0000FF; ">></span><span style="color: #000000; "><br />    </span><span style="color: #0000FF; "><</span><span style="color: #800000; ">input </span><span style="color: #FF0000; ">type</span><span style="color: #0000FF; ">="text"</span><span style="color: #FF0000; "> name</span><span style="color: #0000FF; ">="value1"</span><span style="color: #FF0000; "> value</span><span style="color: #0000FF; ">="100"</span><span style="color: #0000FF; ">/></span><span style="color: #000000; "><br />    </span><span style="color: #0000FF; "><</span><span style="color: #800000; ">input </span><span style="color: #FF0000; ">type</span><span style="color: #0000FF; ">="submit"</span><span style="color: #FF0000; "> name</span><span style="color: #0000FF; ">="action1"</span><span style="color: #FF0000; "> value</span><span style="color: #0000FF; ">="Action1"</span><span style="color: #0000FF; ">/></span><span style="color: #000000; "><br />    </span><span style="color: #0000FF; "><</span><span style="color: #800000; ">input </span><span style="color: #FF0000; ">type</span><span style="color: #0000FF; ">="submit"</span><span style="color: #FF0000; "> name</span><span style="color: #0000FF; ">="action2"</span><span style="color: #FF0000; "> value</span><span style="color: #0000FF; ">="Action2"</span><span style="color: #0000FF; ">/></span><span style="color: #000000; "><br /></span><span style="color: #0000FF; "></</span><span style="color: #800000; ">form</span><span style="color: #0000FF; ">></span></div><br /><p>我的意愿是如果画面上Q点击action1按钮择调用initBinder1Ҏ?如果点击action2按钮则调用initBinder2Ҏ?/p><p>实际上也实是这L?<br /></p><p>当点击action1Ӟ<span style="color: #000000; ">logger.info(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">initBinder1</span><span style="color: #000000; ">"</span><span style="color: #000000; ">); 会执?/span></p><p>当点击action2是,<span style="color: #000000; ">logger.info(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">initBinder2</span><span style="color: #000000; ">"</span><span style="color: #000000; ">); 会执?/span></p><p>是乎是可以实现“每个ActionҎ单独讄Validator”这个目的?/p><p>但是其实q不是这L?/p><p>我调式进MInitBinder相关的源代码InitBinderDataBinderFactoryQ?l果发现它只是在对actionq个参数l定的时候调用了上面q个ҎQ?对value1l定的时候那个方法都没有调用。而我们常常要解决的是对同一个参数对于不同的action应用不同的Validator?<br /></p><p>所以目前还是没有好的方法能直接解决q个问题Q?/p><p>也许我们可以自己实现一个DataBinderFactory来解册个问题?/p><p><br /></p><img src ="//www.lmlez.icu/mstar/aggbug/397945.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="//www.lmlez.icu/mstar/" target="_blank">黑灵</a> 2013-04-17 00:42 <a href="//www.lmlez.icu/mstar/archive/2013/04/17/397945.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>KMP法里的next函数是怎么得到的? - 4399ɱol|ɱ佫//www.lmlez.icu/mstar/archive/2013/04/14/397824.html黑灵黑灵Sun, 14 Apr 2013 15:24:00 GMT//www.lmlez.icu/mstar/archive/2013/04/14/397824.html//www.lmlez.icu/mstar/comments/397824.html//www.lmlez.icu/mstar/archive/2013/04/14/397824.html#Feedback0//www.lmlez.icu/mstar/comments/commentRss/397824.html//www.lmlez.icu/mstar/services/trackbacks/397824.html也就是这?p?p?p⑶?.p(k-1Q?= ' p(j-k+1Qp(j-k+2Q……p(j-1Q’?Z么找到这个k以后用k的元素比较字W串中ip了?br />
现在扑ֈ一个最接近明白的就是百度百U上?br />
假设
MQs: ‘s?s?s?……s(nQ?;
模式?Qp: ‘p?p?p⑶?.p(mQ?br />把课本上的这一D늜完后Ql?br />现在我们假设 MWi个字W与模式串的Wj(j<=mQ个字符‘失配’后Q主串第i个字W与模式串的Wk(k<jQ个字符l箋比较
此时Qs(iQ≠p(jQ,?br />MQs⑴…?s(i-j+1Q…?s(i-1Q?s(i) ………?
|| Q相配) || ≠(失配Q?br />匚wԌp?...........p(j-1Q?p(j)
由此Q我们得到关pdQ?br />‘p?p?p⑶?.p(j-1Q?= ?s(i-j+1Q……s(i-1Q?br />׃s(iQ≠p(jQ,接下来s(iQ将与p(kQl比较,则模式串中的前(k-1Q个字符的子串必L下列关pdQƈ且不可能存在 k?gt;k 满下列关系式:Qk<j),
‘p?p?p⑶?.p(k-1Q?= ?s(i-k+1Qs(i-k+2Q……s(i-1Q?br />卻I
MQs⑴……s(i-k +1Q?s(i-k +2Q?……s(i-1Q?s(i) ………?
|| Q相配) || ||Q有待比较)
匚wԌp?p?…?.... p(k-1Q?p(k)
现在我们把前面ȝ的关pȝ合一?br />有:
s⑴…s(i-j +1Q?s(i-k +1Q?s(i-k +2Q?…?s(i-1Q?s(i) …?br />|| Q相配) || || || ≠(失配Q?br />p?……p(j-k+1Q?p(j-k+2Q??..... p(j-1Q?p(j)
|| Q相配) || ||Q有待比较)
p?p?…?..... p(k-1Q?p(k)
׃Q我们得到关p:
'p?p?p⑶?.p(k-1Q?= ' p(j-k+1Qp(j-k+2Q……p(j-1Q?br />
不知道是从哪个课本上抄来的?其实q是不太明白最后一步?br />

黑灵 2013-04-14 23:24 发表评论
]]>
单的监视某个端口的连接数的Linux命o - 4399ɱol|ɱ佫//www.lmlez.icu/mstar/archive/2012/10/30/linux_shell_watch_connection.html黑灵黑灵Tue, 30 Oct 2012 01:38:00 GMT//www.lmlez.icu/mstar/archive/2012/10/30/linux_shell_watch_connection.html//www.lmlez.icu/mstar/comments/390432.html//www.lmlez.icu/mstar/archive/2012/10/30/linux_shell_watch_connection.html#Feedback0//www.lmlez.icu/mstar/comments/commentRss/390432.html//www.lmlez.icu/mstar/services/trackbacks/390432.html
#!/bin/sh
netstat 
-anp | grep :$1 | awk '{print $5}' | awk -F: '{print $1}' | sort | uniq -c

然后执行命o:

watch -n 1 count_conn 8080

最后的参数是你要监视的端?



4399ɱol 2012-10-30 09:38 发表评论
]]>