blogjava-凯发k8网页登录http://www.blogjava.net/xylz/关注后端架构、中间件、分布式和并发编程zh-cnsat, 08 apr 2023 20:35:01 gmtsat, 08 apr 2023 20:35:01 gmt60世界邦旅行网(北京)招聘java高级/资深工程师前端工程师/移动开发工程师等_20150616更新http://www.blogjava.net/xylz/archive/2013/11/05/406019.htmlimxylzimxylztue, 05 nov 2013 09:01:00 gmthttp://www.blogjava.net/xylz/archive/2013/11/05/406019.htmlhttp://www.blogjava.net/xylz/comments/406019.htmlhttp://www.blogjava.net/xylz/archive/2013/11/05/406019.html#feedback15http://www.blogjava.net/xylz/comments/commentrss/406019.htmlhttp://www.blogjava.net/xylz/services/trackbacks/406019.html
  • 工作地点:北京
  • 世界邦旅行网是一个新型出境自助旅行社区和电子商务开放平台,以提供“个性化行程定制服务,高性价比、高质量境外自助游”为目标。
  • 我们的网站:
  • 关于凯发k8网页登录:
  • b轮数亿
  • 招聘职位
    • java 高级/资深工程师
    • php 工程师
    • 测试工程师
    • 前端工程师
    • 移动开发工程师(android/ios)
    • 其它市场、推广、运营、产品、设计等人才
  • 待遇
    • 与互联网公司看齐 期权 (价值几何问自己)
  • 特别说明

    • 有github帐号, stackoverflow 有贡献分为佳
    • 不会翻qiang的不建议投递简历
    • 尽管融资有点钱,但依然条件艰苦(创业何其艰)
    • 必须自认为聪明(即使别人认为自己不聪明,要有这份霸气)
    • 对旅游或者旅行有兴趣
    • 一个能够快速自我成长的环境,如果不能建议立即去寻找他处
    • 无意义的技术、工具要求没有
  • 最后的最后

    • 简历写各种精通的,建议不用考虑
  • 凯发天生赢家一触即发官网的联系方式
    • imxylz##gmail.com
  • 更新时间: 2015/06/16



    imxylz 2013-11-05 17:01 发表评论
    ]]>
    java 8 入门/新特性http://www.blogjava.net/xylz/archive/2013/10/16/405031.htmlimxylzimxylztue, 15 oct 2013 16:33:00 gmthttp://www.blogjava.net/xylz/archive/2013/10/16/405031.htmlhttp://www.blogjava.net/xylz/comments/405031.htmlhttp://www.blogjava.net/xylz/archive/2013/10/16/405031.html#feedback8http://www.blogjava.net/xylz/comments/commentrss/405031.htmlhttp://www.blogjava.net/xylz/services/trackbacks/405031.html2013/09/05 已经发布了的版本。 在 所有新特性已经封版, m8 作为开发者预览版,基本上可用,可用。 按照版本 应该在2014年3月份发布,如果顺利正式版估计和ga版本相同,也就是说在明年3月份就正式使用jdk 8了。

    这次jdk 8 一共带来了,目前所有api应该都已经冻结, 正在进行零bug测试。这次更新的力度比jdk 6/jdk 7都要大,延期了几次,也非常令人期待。 我个人准备花费几个月的学习时间,努力跟上java 8的发布节奏。当然由于对java 7不太熟悉,因此同时也学习下java 7的api。

    目前支持jdk 8的ide有:

    • , 官方需要到明年java 8正式发布以后

    并非所有jdk 8的特性ide都能支持,因此需要随时更新ide以便获得更好的开发环境,推荐使用idea。


    java 8 新特性入门

    1. 时间表
    2. lambda
    3. 流式操作 – stream api
    4. 接口默认方法 – default method
    5. 日期和时间 – date & time (jsr 310)
    6. 集合扩展 – collections api
    7. 并发操作 – concurrency api additions
    8. io/nio 扩展 – io/nio api additions
    9. 反射和注解更新 – reflection and annotation changes
    10. base64
    11. 其它各种更新 – other additions

    java 7 新特性入门

    1. 字符串在switch中的使用
    2. try-with-resources 自动释放资源
    3. 泛型实例创建的类型推断
    4. 多异常catch操作
    5. 文件api扩展
    6. 集合api更新
    7. 并发编程api更新
    8. unicode 6.0的支持
    9. jdbc 4.1 支持 rowset 1.1

    [更新时间: 2013/10/16]
    [原文地址:]



    imxylz 2013-10-16 00:33 发表评论
    ]]>
    bash命令路径的缓存http://www.blogjava.net/xylz/archive/2013/10/13/path-cache-of-bash-command.htmlimxylzimxylzsun, 13 oct 2013 14:16:00 gmthttp://www.blogjava.net/xylz/archive/2013/10/13/path-cache-of-bash-command.htmlhttp://www.blogjava.net/xylz/comments/404935.htmlhttp://www.blogjava.net/xylz/archive/2013/10/13/path-cache-of-bash-command.html#feedback0http://www.blogjava.net/xylz/comments/commentrss/404935.htmlhttp://www.blogjava.net/xylz/services/trackbacks/404935.html阅读全文

    imxylz 2013-10-13 22:16 发表评论
    ]]>
    mac下批量转换png和jpeghttp://www.blogjava.net/xylz/archive/2013/10/08/404759.htmlimxylzimxylztue, 08 oct 2013 09:17:00 gmthttp://www.blogjava.net/xylz/archive/2013/10/08/404759.htmlhttp://www.blogjava.net/xylz/comments/404759.htmlhttp://www.blogjava.net/xylz/archive/2013/10/08/404759.html#feedback1http://www.blogjava.net/xylz/comments/commentrss/404759.htmlhttp://www.blogjava.net/xylz/services/trackbacks/404759.html sips的名称功能非常强大,参考。
    这里我们只用到其中的一个功能,转换图片格式。

    命令参考:
        sips -s format jpeg --out b.jpg a.png
    写一个png批量转换jpg的脚本:

        cat  
    ~/bin/png2jpg
        #
    !/bin/bash
        # convert png files to jpeg files
        # usage: png2jpg 
    <file>

        
    for f in "$@"
        
    do
            sips 
    -s format jpeg --out "${f%.*}.jpg" "$f"
        done
    同样写一个jpg批量转换png的脚本:

        cat 
    ~/bin/jpg2png
        #
    !/bin/bash
        # convert jpeg files to png files
        # usage: jpg2png 
    <file>

        
    for f in "$@"
        
    do
            sips 
    -s format png --out "${f%.*}.png" "$f"
        done
    使用例子:

        ➜ 
    ~/downloads $ png2jpg qq20131008-*.png
        
    /users/adyliu/downloads/qq20131008-2.png
          
    /users/adyliu/downloads/qq20131008-2.jpg
        
    /users/adyliu/downloads/qq20131008-3.png
          
    /users/adyliu/downloads/qq20131008-3.jpg
        
    /users/adyliu/downloads/qq20131008-4.png
          
    /users/adyliu/downloads/qq20131008-4.jpg
        ➜ 
    ~/downloads $ ll qq*
        
    -rw-r--r--  1 adyliu  staff    67k 10  8 15:43 qq20131008-2.jpg
        
    -rw-r--r--1 adyliu  staff    88k 10  8 15:31 qq20131008-2.png
        
    -rw-r--r--  1 adyliu  staff    23k 10  8 15:43 qq20131008-3.jpg
        
    -rw-r--r--1 adyliu  staff    34k 10  8 15:31 qq20131008-3.png
        
    -rw-r--r--  1 adyliu  staff    47k 10  8 15:43 qq20131008-4.jpg
        
    -rw-r--r--1 adyliu  staff    44k 10  8 15:31 qq20131008-4.png

    参考资料:

    原文地址:

    imxylz 2013-10-08 17:17 发表评论
    ]]>
    octopress加速google字体渲染http://www.blogjava.net/xylz/archive/2013/09/22/move-google-fonts-to-local-server.htmlimxylzimxylzsun, 22 sep 2013 13:42:00 gmthttp://www.blogjava.net/xylz/archive/2013/09/22/move-google-fonts-to-local-server.htmlhttp://www.blogjava.net/xylz/comments/404298.htmlhttp://www.blogjava.net/xylz/archive/2013/09/22/move-google-fonts-to-local-server.html#feedback0http://www.blogjava.net/xylz/comments/commentrss/404298.htmlhttp://www.blogjava.net/xylz/services/trackbacks/404298.html阅读全文

    imxylz 2013-09-22 21:42 发表评论
    ]]>
    jrebel 6.0.0 crack (20141216更新)http://www.blogjava.net/xylz/archive/2013/09/15/404098.htmlimxylzimxylzsun, 15 sep 2013 15:24:00 gmthttp://www.blogjava.net/xylz/archive/2013/09/15/404098.html阅读全文

    imxylz 2013-09-15 23:24 发表评论
    ]]>
    申请ssl证书及nginx支持httpshttp://www.blogjava.net/xylz/archive/2013/09/11/403965.htmlimxylzimxylzwed, 11 sep 2013 13:58:00 gmthttp://www.blogjava.net/xylz/archive/2013/09/11/403965.htmlhttp://www.blogjava.net/xylz/comments/403965.htmlhttp://www.blogjava.net/xylz/archive/2013/09/11/403965.html#feedback0http://www.blogjava.net/xylz/comments/commentrss/403965.htmlhttp://www.blogjava.net/xylz/services/trackbacks/403965.html阅读全文

    imxylz 2013-09-11 21:58 发表评论
    ]]>
    随机选择集合的子元素集合http://www.blogjava.net/xylz/archive/2013/08/17/402978.htmlimxylzimxylzsat, 17 aug 2013 09:44:00 gmthttp://www.blogjava.net/xylz/archive/2013/08/17/402978.htmlhttp://www.blogjava.net/xylz/comments/402978.htmlhttp://www.blogjava.net/xylz/archive/2013/08/17/402978.html#feedback3http://www.blogjava.net/xylz/comments/commentrss/402978.htmlhttp://www.blogjava.net/xylz/services/trackbacks/402978.html我需要一个从集合n中随机选择m个子元素的算法。 当然最好的办法是将集合打乱顺序,然后从中选择前m个元素即可。 java中现成的api可以使用:
    java.util.collections.shuffle(list)
    此算法非常简单,循环n次,每次长度减少1,随机获取其中一个元素,然后交换其对称元素。
    public static void shuffle(list list, random rnd) {
        int size = list.size();
        if (size < shuffle_threshold || list instanceof randomaccess) {
            for (int i=size; i>1; i--)
                swap(list, i-1, rnd.nextint(i));
        } else {
            object arr[] = list.toarray();

            // shuffle array
            for (int i=size; i>1; i--)
                swap(arr, i-1, rnd.nextint(i));

            // dump array back into list
            listiterator it = list.listiterator();
            for (int i=0; i             it.next();
                it.set(arr[i]);
            }
        }
    }

    有点意思的swap函数

    public static void swap(list list, int i, int j) {
        final list l = list;
        l.set(i, l.set(j, l.get(i)));
    }

    其实我们的需求很简单,在基本不变的集合中,多次重复随机获取其子集,至于子集是否有序或者随机不重要的, 重要的是原集合中的每个元素都有相似的概率出现在子集合中。

    考虑到性能以及并发访问(多线程)的需要,我想到了一个简单的算法:
    给定n个元素集合,从中选择m(0
    1. 随机选择索引k(0<=k
    2. 取有效元素n(k-i),n(k i) 加入未满子集m
    3. i =1, 重复(2) 直到子集m已满
    4. 终止
    这样取出来的元素虽然和原始集顺序有一定的关系,但是每个元素在子集里出现的概率相当,满足结果要求。 最后生成的算法如下:
    public static  list randomlist(list views, int max) {

        final int size = views.size();
        int index = randomutils.nextint(size);
        //
        list ret = new arraylist(max);
        int low = index - 1, high = index;
        while (max > 0 && (low >= 0 || high < size)) {
            if (low >= 0 && max-- > 0) {
                ret.add(views.get(low));
            }
            if (high < size && max-- > 0) {
                ret.add(views.get(high));
            }
            low--;
            high ;
        }
        return ret;
    }

    此算法满足如下特点:
    1. 足够快
    2. 线程安全(原始集合不变)
    3. 子元素出现概率相当(未经数学证明

    另外,stackoverflow上也有一些参考链接:
    • http://mcherm.com/permalinks/1/a-random-selection-algorithm
    • http://stackoverflow.com/questions/4702036/take-n-random-elements-from-a-liste

    [ 原文地址  ]


    imxylz 2013-08-17 17:44 发表评论
    ]]>捕获java线程池执行任务抛出的异常http://www.blogjava.net/xylz/archive/2013/08/05/402405.htmlimxylzimxylzmon, 05 aug 2013 08:45:00 gmthttp://www.blogjava.net/xylz/archive/2013/08/05/402405.htmlhttp://www.blogjava.net/xylz/comments/402405.htmlhttp://www.blogjava.net/xylz/archive/2013/08/05/402405.html#feedback6http://www.blogjava.net/xylz/comments/commentrss/402405.htmlhttp://www.blogjava.net/xylz/services/trackbacks/402405.htmljava中线程执行的任务接口java.lang.runnable 要求不抛出checked异常,
    public interface runnable {

        
    public abstract void run();
    }

    那么如果 run() 方法中抛出了runtimeexception,将会怎么处理了?

    通常java.lang.thread对象运行设置一个默认的异常处理方法:

    java.lang.thread.setdefaultuncaughtexceptionhandler(uncaughtexceptionhandler)

    而这个默认的静态全局的异常捕获方法时输出堆栈。

    当然,我们可以覆盖此默认实现,只需要一个自定义的java.lang.thread.uncaughtexceptionhandler接口实现即可。

    public interface uncaughtexceptionhandler {

        
    void uncaughtexception(thread t, throwable e);
    }

    而在线程池中却比较特殊。默认情况下,线程池 java.util.concurrent.threadpoolexecutor 会catch住所有异常, 当任务执行完成(java.util.concurrent.executorservice.submit(callable))获取其结果 时(java.util.concurrent.future.get())会抛出此runtimeexception。

    /**
     * waits if necessary for the computation to complete, and then
     * retrieves its result.
     *
     * 
    @return the computed result
     * 
    @throws cancellationexception if the computation was cancelled
     * 
    @throws executionexception if the computation threw an exception
     * 
    @throws interruptedexception if the current thread was interrupted while waiting
     
    */
    v get() 
    throws interruptedexception, executionexception;

    其中 executionexception 异常即是java.lang.runnable 或者 java.util.concurrent.callable 抛出的异常。

    也就是说,线程池在执行任务时捕获了所有异常,并将此异常加入结果中。这样一来线程池中的所有线程都将无法捕获到抛出的异常。 从而无法通过设置线程的默认捕获方法拦截的错误异常。

    也不同通过来完成异常的拦截。

    好在java.util.concurrent.threadpoolexecutor 预留了一个方法,运行在任务执行完毕进行扩展(当然也预留一个protected方法beforeexecute(thread t, runnable r)):

    protected void afterexecute(runnable r, throwable t) { } 

    此方法的默认实现为空,这样我们就可以通过继承或者覆盖threadpoolexecutor 来达到自定义的错误处理。

    解决办法如下:

    threadpoolexecutor threadpoolexecutor = new threadpoolexecutor(111001, timeunit.minutes, //
            new arrayblockingqueue<runnable>(10000),//
            new defaultthreadfactory()) {

        
    protected void afterexecute(runnable r, throwable t) {
            
    super.afterexecute(r, t);
            printexception(r, t);
        }
    };

    private static void printexception(runnable r, throwable t) {
        
    if (t == null && r instanceof future) {
            
    try {
                future
     future = (future) r;
                
    if (future.isdone())
                    future.get();
            } 
    catch (cancellationexception ce) {
                t 
    = ce;
            } 
    catch (executionexception ee) {
                t 
    = ee.getcause();
            } 
    catch (interruptedexception ie) {
                thread.currentthread().interrupt(); 
    // ignore/reset
            }
        }
        
    if (t != null)
            log.error(t.getmessage(), t);
    }

    此办法的关键在于,事实上 afterexecute 并不会总是抛出异常 throwable t,通过查看源码得知,异常是封装在此时的future对象中的, 而此future对象其实是一个java.util.concurrent.futuretask的实现,默认的run方法其实调用的 java.util.concurrent.futuretask.sync.innerrun()。

    void innerrun() {
        if (!compareandsetstate(0, running))
            return;
        try {
            runner = thread.currentthread();
            if (getstate() == running) // recheck after setting thread
                innerset(callable.call());
            else
                releaseshared(0); // cancel
        } catch (throwable ex) {
            innersetexception(ex);
        }
    }

    void innersetexception(throwable t) {
        for (;;) {
            int s = getstate();
            if (s == ran)
                return;
            if (s == cancelled) {
                // aggressively release to set runner to null,
                
    // in case we are racing with a cancel request
                
    // that will try to interrupt runner
                releaseshared(0);
                return;
            }
            if (compareandsetstate(s, ran)) {
                exception = t;
                result = null;
                releaseshared(0);
                done();
                return;
            }
        }
    }

    这里我们可以看到它吃掉了异常,将异常存储在java.util.concurrent.futuretask.sync的exception字段中:

    /** the exception to throw from get() */
    private throwable exception;

    当我们获取异步执行的结果时, java.util.concurrent.futuretask.get()

    public v get() throws interruptedexception, executionexception {
        
    return sync.innerget();
    }

    java.util.concurrent.futuretask.sync.innerget()

    v innerget() throws interruptedexception, executionexception {
        acquiresharedinterruptibly(
    0);
        
    if (getstate() == cancelled)
            
    throw new cancellationexception();
        
    if (exception != null)
            
    throw new executionexception(exception);
        
    return result;
    }

    异常就会被包装成executionexception异常抛出。

    也就是说当我们想线程池 threadpoolexecutor(java.util.concurrent.executorservice)提交任务时, 如果不理会任务结果(feture.get()),那么此异常将被线程池吃掉。

    <t> future<t> submit(callable<t> task);
    future
     submit(runnable task);

    而java.util.concurrent.scheduledthreadpoolexecutor是继承threadpoolexecutor的,因此情况类似。

    结论,通过覆盖threadpoolexecutor.afterexecute 方法,我们才能捕获到任务的异常(runtimeexception)。

    原文地址:



    imxylz 2013-08-05 16:45 发表评论
    ]]>
    python 基础文件操作http://www.blogjava.net/xylz/archive/2013/02/24/395677.htmlimxylzimxylzsun, 24 feb 2013 12:55:00 gmthttp://www.blogjava.net/xylz/archive/2013/02/24/395677.htmlhttp://www.blogjava.net/xylz/comments/395677.htmlhttp://www.blogjava.net/xylz/archive/2013/02/24/395677.html#feedback0http://www.blogjava.net/xylz/comments/commentrss/395677.htmlhttp://www.blogjava.net/xylz/services/trackbacks/395677.html

    blogjava-凯发k8网页登录

    学习一门语言,我总是喜欢从文件开始。文本文件的读写操作是我比较在意的基本功能。 在这方面,java语言功能比较强大,用到的设计模式也非常多。只是使用起来太过繁琐。 而python在这方面表现非常好,简洁不失功能,强大不失性能,通俗不失优雅,值得称赞。

    我们从一个最简单的开始。

    with open('/etc/resolv.conf') as f:
    print(f.read())

    这里有用到语法来关闭文件句柄。

    open()

    首先来了解下内置函数。

    open(file, mode='r', buffering=-1, encoding=none, errors=none, newline=none, closefd=true, opener=none)
    open file and return a corresponding file object. if the file cannot be opened, an oserror is raised.

    open()的参数众多,通常需要关注的是mode/encoding/errors/newline等。

    最佳实践

    (1) 读取文件必须传入字符编码encoding 
    (2) 用完的流需要关闭,推荐使用with操作
    (3) 换行符尽可能的使用unix格式(\n),尽管python可以智能转换
    (4) 如果可以的话尽可能的使用utf-8编码来处理非ascii字符,不要依赖操作系统的编码

    小贴士

    多个文件同时操作可使用with的语法:

    with open('/etc/hosts','r') as f,open('/tmp/hosts','w') as t:
    //do something

    或者

    with f=open('/etc/hosts'),t=open('/tmp/hosts','w'):
    // do something

    file object

    文件对象描述的是一种“流”操作,通常支持read()或者write()方法。 这里的文件对象是一种概念上的“文件对象”,除了常见的真是的磁盘文件,还可以是 标准输入输出文件(stdin/stdout/stderr),内存缓冲区(stringio,cstringio), socket,pipes等。

    这在模块中有具体的描述。

    文本操作和二进制操作有一些区别。分别介绍。

    text i/o

    如果中包含t(默认),那么返回的流是一个纯文本操作。

    read() 是读取文本的最简单的方法。返回的是字符串形式的结果(和参数encoding有关)。

    read(n)
    read and return at most n characters from the stream as a single str. if n is negative or none, reads until eof.

    在很多安装脚本中有:

    readme=open('./readme.md').read() 

    类似的用法。这在一个快速结束的程序中问题不大。在正式的服务中应该随时关闭文件句柄释放资源。

    小贴士:

    如果已经读取到文件末尾,read()则返回空字符串''。 

    如果要读取一行,使用readline()方法。

    readline(limit=-1)
    read until newline or eof and return a single str. if the stream is already at eof, an empty string is returned. if limit is specified, at most limit characters will be read.

    读取一行意味着和行结束符有关,这个有点复杂。

    读取多行,使用readlines()方法。这将返回一个字符串列表。readlines()也可以限制最多读取多少个字符。

    小贴士:

    readline(limit=-1)和readlines(limit=-1)对limit的描述不太一致。 
    readline(limit=-1)描述的是读取一行,最多不超过limit个字符(不是字节),因此有可能结果不是某一行的结束。
    readlines(limit=-1)描述的是读取字符,直到limit个字符所在的行结束。也就是返回的结果一定是某一行的结束(除非eof)。

    例如:
    >>> open('/tmp/x1','w').write('python真是一个好同学\n只是限制被割裂成两个版本了\n我支持python3.x')
    40
    >>> open('/tmp/x1','r').readline(10)
    'python真是一个'
    >>> open('/tmp/x1','r').readlines(10)
    ['python真是一个好同学\n']

    readlines(limit)是一个难以理解的逻辑。如果可以不要随便传输一个参数。。


    写入文本可使用write(s)方法:

    write(s) write the string s to the stream and return the number of characters written. 

    写入的是字符串,而不是字节。如果要写入多行字符串,可以使用writelines(lines)方法。

    小贴士:

    write(s)和writelines(lines)不会将行结束符写入文件流。因此需要手动写入行结束符。 

    binary i/o

    二进制流和文本流类似,只是二进制流没有encoding一说。打开二进制流需要传入参数mode中包含’b’。

    例如:

    >>> type(open('/etc/hosts','rb').read())

    对比文本流,二进制流有一些小的差别:

    • read()返回的值是字节(bytes)
    • readline()返回的值是字节(bytes),包括换行符
    • readlines()返回的值是字节(bytes)列表,包括换行符
    • write()参数可以是或者
    • readinto(b)是将内容读取到bytearray b中,返回读取的字节数。

    其它文件操作

    除了read/write方法,文件对象还有一些其它的内置方法:

    • file.close() 关闭文件
    • file.fileno() 获取文件描述符(整形值)
    • file.flush() 对于有缓冲区的写操作,刷新缓冲区
    • file.tell() 返回当前流的字节位置
    • file.seek() 移动文件流的当前位置
    • file.truncate() 截断文件大小

    将在介绍更多的知识。



    imxylz 2013-02-24 20:55 发表评论
    ]]>
    crack jrebel 5.3.1http://www.blogjava.net/xylz/archive/2012/12/26/393498.htmlimxylzimxylzwed, 26 dec 2012 04:02:00 gmthttp://www.blogjava.net/xylz/archive/2012/12/26/393498.htmlhttp://www.blogjava.net/xylz/comments/393498.htmlhttp://www.blogjava.net/xylz/archive/2012/12/26/393498.html#feedback31http://www.blogjava.net/xylz/comments/commentrss/393498.htmlhttp://www.blogjava.net/xylz/services/trackbacks/393498.html
    我一直使用5.1.0版本的jrebel,是social免费版本的。social版本会在启动时连接jrebel服务器(myrebel)获取license,同时会将一些热部署的次数、节约时间、性能等日志提交到远程服务器。
    最近中国网络抽风,连接jrebel服务器特别慢,导致每次启动的时候都需要10s以上的时间才能得到服务器的响应(加上自动更新检测)。最为一个技术控,很显然,我不能忍受这种行为。

    只好研究如何破解它。
    从4.0开始jrebel的混淆机制做得非常棒,基本上无法进行反编译修改了。好在jrebel比较厚道,一直兼容旧版本的license检测机制,翻出我2008年写的破解工程,顺利解决了5.1.0版本。
    然后下载最新的5.1.2(20121217)版本,尝试了下居然没有成功。太囧了。这是一个小版本,为何改动如此大?

    打开debug日志后发现,根本就没有加载jrebel.jar里面的license文件。反编译源码看了下,果然,从5.1.2版本开始不再加载jrebel.jar里面的license文件了,该从用户主目录,jrebel安装目录等获取license文件。这样就没法通过一个jar包分发jrebel了。
    将jrebel.lic拷贝到用户主目录的.jrebel目录即可。
    ~ $ ls ~/.jrebel/jrebel.lic 
    /users/adyliu/.jrebel/jrebel.lic

    来两张截图。
    jrebel 5.1.2 crack
    jrebel 5.1.2 crack

    下载地址


    updated 2013/03/25
        jrebel更新到5.2.0版本,所以可以放出一个低版本(我一直使用)5.1.2。5.1.3就暂时不去解决了。


    updated 2013/04/17
        jrebel 更新到5.2.2版本,所以可以放出一个低版本5.2.0。


    updated 2013/06/06
        jrebel 更新到5.3.0版本,所以可以放出一个低版本5.2.2。


    updated 2013/07/12
        jrebel 更新到5.3.1版本,所以可以放出一个低版本5.3.0。


    updated 2013/09/15
        最新版本的下载地址在:http://www.blogjava.net/xylz/archive/2013/09/15/404098.html

    ps:
         吐槽下,jrebel支持的功能越来越多,导致本身越来越大了,版本5.x已经快9m了!!!

     

    关键词: jrebel 5.3.1 crack, jrebel 5.3.0 crack, jrebel 5.2.2 crack, jrebel 5.2.0 crack, jrebel 5.1.2 crack,jrebel 5.1.0 crack, jrebel 5.x crack



    imxylz 2012-12-26 12:02 发表评论
    ]]>
    sqlite3 c语言api入门http://www.blogjava.net/xylz/archive/2012/09/25/388519.htmlimxylzimxylztue, 25 sep 2012 08:34:00 gmthttp://www.blogjava.net/xylz/archive/2012/09/25/388519.htmlhttp://www.blogjava.net/xylz/comments/388519.htmlhttp://www.blogjava.net/xylz/archive/2012/09/25/388519.html#feedback0http://www.blogjava.net/xylz/comments/commentrss/388519.htmlhttp://www.blogjava.net/xylz/services/trackbacks/388519.htmlsqlite3 c语言api入门

    下载sqlite3

    我们下载sqlite,只需要其中的sqlite3.c、sqlite.h即可。

    最简单的一个创建表操作

    #include 
    #include "sqlite3.h"

    int main(int argc,char *argv[]){
        const char *sql_create_table="create table t(id int primary key,msg varchar(128))";
        char *errmsg = 0;
        int ret = 0;

        sqlite3 *db = 0;
        ret = sqlite3_open("./sqlite3-demo.db",&db);
        if(ret != sqlite_ok){
            fprintf(stderr,"cannot open db: %s\n",sqlite3_errmsg(db));
            return 1;
        }
        printf("open database\n");

        ret = sqlite3_exec(db,sql_create_table,null,null,&errmsg);
        if(ret != sqlite_ok){
            fprintf(stderr,"create table fail: %s\n",errmsg);
        }
        sqlite3_free(errmsg);
        sqlite3_close(db);

        printf("close database\n");

        return 0;
    }



    在这个操作中我们执行了如下操作:

    • 打开数据库
    • 执行sql语句
    • 关闭数据库

    当然这中间会有一些状态的判断以及内存指针的释放等。

    打开数据库的api如下:

    int sqlite3_open(
      const char *filename,   /* database filename (utf-8) */
      sqlite3 **ppdb          /* out: sqlite db handle */
    );
    这里会引入一个非常复杂的sqlite3的数据结构。这个根据需要以后酌情了解些。

     

    打开数据库除了这种形式意外,还有sqlite3_open、sqlite3_open16、sqlite3_open_v2几种形式,基本上类似。

    大部分sql操作都可以通过sqlite3_exec来完成,它的api形式如下:

    int sqlite3_exec(
      sqlite3*,                                  /* an open database */
      const char *sql,                           /* sql to be evaluated */
      int (*callback)(void*,int,char**,char**),  /* callback function */
      void *,                                    /* 1st argument to callback */
      char **errmsg                              /* error msg written here */
    );

     

    各个参数的意义为:

    • sqlite3描述的是数据库句柄
    • sql 要执行的sql语句
    • callback回调函数
    • void *回调函数的第一个参数
    • errmsg错误信息,如果没有sql问题则值为null

    回调函数式一个比较复杂的函数。它的原型是这样的:

    int callback(void *params,int column_size,char **column_value,char **column_name){

     

    每一个参数意义如下:

    • params是sqlite3_exec传入的第四个参数
    • column_size是结果字段的个数
    • column_value是返回记录的一位字符数组指针
    • column_name是结果字段的名称

    通常情况下callback在select操作中会使用到,尤其是处理每一行记录数。返回的结果每一行记录都会调用下“回调函数”。 如果回调函数返回了非0,那么sqlite3_exec将返回sqlite_abort,并且之后的回调函数也不会执行,同时未执行的子查询也不会继续执行。

    对于更新、删除、插入等不需要回调函数的操作,sqlite3_exec的第三、第四个参数可以传入0或者null。

    通常情况下sqlite3_exec返回sqlite_ok=0的结果,非0结果可以通过errmsg来获取对应的错误描述。

    windows下编译:

    d:\home\dev\c>cl /nologo /tc sqlite3-demo.c sqlite3.c 

    gcc下编译:

    $ gcc -o sqlite3-demo.bin sqlite3-demo.c sqlite3.c 

    删除表操作

    为了防止垃圾数据,我们在加载数据库的时候删除表操作。

    简单的删除操作可以直接使用sqlite3_exec即可。这里不需要回调函数以及回调函数的参数。 当然需要可以关注sqlite3_exec返回的结果是否为sqlite_ok的值。

        const char *sql_drop_table="drop table if exists t";
        const char *sql_create_table="create table t(id int primary key,msg varchar(128))";

        sqlite3_exec(db,sql_drop_table,0,0,&errmsg);
        sqlite3_exec(db,sql_create_table,0,0,&errmsg);

     

    插入数据

    插入第一条数据

        ret = sqlite3_exec(db,"insert into t(id,msg) values(1,'ady liu')",null,null,&errmsg);
        printf("insert a record %s\n",ret == sqlite_ok ? "ok":"fail");

     

    返回值ret为sqlite_ok即操作成功。

    插入多条数据,并删除数据

        ret = sqlite3_exec(db,"insert into t(id,msg) values(1,'ady liu')",null,null,&errmsg);
        printf("insert a record %s\n",ret == sqlite_ok ? "ok":"fail");
        ret = sqlite3_exec(db,"insert into t(id,msg) values(2,'imxylz')",null,null,&errmsg);
        printf("insert a record %s\n",ret == sqlite_ok ? "ok":"fail");
        ret = sqlite3_exec(db,"delete from t where id < 3",null,null,&errmsg);
        printf("delete records: %s\n",ret == sqlite_ok ? "ok":"fail");
    插入多条数据,简单的使用sqlite3_exec进行sql执行即可。当然这里是完整的sql字符串。

     

    预编译操作

        int i = 0;
        sqlite3_stmt *stmt;
        char ca[255];

        //prepare statement
        sqlite3_prepare_v2(db,"insert into t(id,msg) values(?,?)",-1,&stmt,0);
        for(i=10;i<20;i ){
            sprintf(ca,"hello#%i",i);
            sqlite3_bind_int(stmt,1,i);
            sqlite3_bind_text(stmt,2,ca,strlen(ca),null);
            sqlite3_step(stmt);
            sqlite3_reset(stmt);
        }
        sqlite3_finalize(stmt);
    预编译操作比较麻烦的,完整的预编译操作的流程是:
    1. 通过sqlite3_prepare_v2()创建一个sqlite3_stmt对象
    2. 通过sqlite3_bind_*()绑定预编译字段的值
    3. 通过sqlite3_step()执行sql语句
    4. 通过sqlite3_reset()重置预编译语句,重复操作2多次
    5. 通过sqlite3_finalize()销毁资源

    sqlite3_prepare_v2()有个多种类似的形式,完整的api语法是:

    int sqlite3_prepare(
      sqlite3 *db,            /* database handle */
      const char *zsql,       /* sql statement, utf-8 encoded */
      int nbyte,              /* maximum length of zsql in bytes. */
      sqlite3_stmt **ppstmt,  /* out: statement handle */
      const char **pztail     /* out: pointer to unused portion of zsql */
    );

     

    各个参数的定义为:

    • db为sqlite3的句柄
    • zsql为要执行的sql语句
    • nbyte为要执行语句在zsql中的最大长度,如果是负数,那么就需要重新自动计算
    • ppstmt为预编译后的句柄
    • pztail预编译后剩下的字符串(未预编译成功或者多余的)的指针,通常没什么用,传入0或者null即可。


    绑定参数sqlite3_bind_*有多种形式,分别对应不同的数据类型:

    int sqlite3_bind_blob(sqlite3_stmt*, intconst void*, int n, void(*)(void*));
    int sqlite3_bind_double(sqlite3_stmt*, intdouble);
    int sqlite3_bind_int(sqlite3_stmt*, intint);
    int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
    int sqlite3_bind_null(sqlite3_stmt*, int);
    int sqlite3_bind_text(sqlite3_stmt*, intconst char*, int n, void(*)(void*));
    int sqlite3_bind_text16(sqlite3_stmt*, intconst void*, intvoid(*)(void*));
    int sqlite3_bind_value(sqlite3_stmt*, intconst sqlite3_value*);
    int sqlite3_bind_zeroblob(sqlite3_stmt*, intint n);

     


    预编译sql语句中可以包含如下几种形式:

    • ?
    • ?nnn
    • :vvv
    • @vvv
    • $vvv

    nnn代表数字,vvv代表字符串。

    如果是?或者?nnn,那么可以直接sqlite3_bind_*()进行操作,如果是字符串,还需要通过sqlite3_bind_parameter_index()获取对应的index,然后再调用sqlite3_bind_*()操作。这通常用于构造不定条件的sql语句(动态sql语句)。

    查询操作

    回调函数的解释参考最上面的描述。 首先声明一个回调函数。

    int print_record(void *,int,char **,char **); 


    查询代码

        //select data
        ret = sqlite3_exec(db,"select * from t",print_record,null,&errmsg);
        if(ret != sqlite_ok){
            fprintf(stderr,"query sql error: %s\n",errmsg);
        }

     

    现在定义回调函数,只是简单的输出字段值。

    int print_record(void *params,int n_column,char **column_value,char **column_name){
        int i;
        for(i=0;i         printf("\t%s",column_value[i]);
        }
        printf("\n");
        return 0;
    }

     

    不使用回调的查询操作

    定义使用的变量

     char **dbresult; int j,nrow,ncolumn,index; 

    查询操作

        //select table
        ret = sqlite3_get_table(db,"select * from t",&dbresult,&nrow,&ncolumn,&errmsg);
        if(ret == sqlite_ok){
            printf("query %i records.\n",nrow);
            index=ncolumn;
            for(i=0;i             printf("[%2i]",i);
                for(j=0;j                 printf(" %s",dbresult[index]);
                    index ;
                }
                printf("\n");
            }
        }
        sqlite3_free_table(dbresult);

     

    sqlite3_get_table的api语法:

    int sqlite3_get_table(
      sqlite3 *db,          /* an open database */
      const char *zsql,     /* sql to be evaluated */
      char ***pazresult,    /* results of the query */
      int *pnrow,           /* number of result rows written here */
      int *pncolumn,        /* number of result columns written here */
      char **pzerrmsg       /* error msg written here */
    );
    void sqlite3_free_table(char **result);

     

    其中:

    • db是sqlite3的句柄
    • zsql是要执行的sql语句
    • pazresult是执行查询操作的返回结果集
    • pnrow是记录的行数
    • pncolumn是记录的字段个数
    • pzerrmsg是错误信息

    由于sqlite3_get_table是sqlite3_exec的包装,因此返回的结果和sqlite3_exec类似。

    pazresult是一个(pnrow 1)*pncolumn结果集的字符串数组,其中前pncolumn个结果是字段的名称,后pnrow行记录是真实的字段值,如果某个字段为空,则对应值为null。

    最后需要通过sqlite3_free_table()释放完整的结果集。

    更新操作

     sqlite3_exec(db,"update t set msg='message#10' where id=10",null,null,&errmsg); 

    当然了,我们也可以使用预编译方法进行更新操作。

    受影响的记录数

    我们可以使用sqlite3_change(sqlite3 *)的api来统计上一次操作受影响的记录数。

     ret = sqlite3_exec(db,"delete from t",null,null,&errmsg); 
    if(ret == sqlite_ok){
    printf("delete records: %i\n",sqlite3_changes(db));
    }

    总结

    这里我们接触了sqlite3的13个api:

    • sqlite3_open()
    • sqlite3_exec()
    • sqlite3_close()
    • sqlite3_prepare_v2
    • sqlite3_bind_*()
    • sqlite3_bind_parameter_index()
    • sqlite3_step()
    • sqlite3_reset()
    • sqlite3_finalize()
    • sqlite3_get_table
    • sqlite3_change()
    • sqlite3_free()
    • sqlite3_free_table()

    事实上截止到sqlite3.7.14(2012/09/03) 一共提供了204个api函数(

    但最精简的api函数大概有6个:

    • sqlite3_open()
    • sqlite3_prepare()
    • sqlite3_step()
    • sqlite3_column()
    • sqlite3_finalize()
    • sqlite3_close()

    核心api也就10个(在精简api基础上增加4个):

    • sqlite3_exec()
    • sqlite3_get_table()
    • sqlite3_reset()
    • sqlite3_bind()

    因此掌握起来还是比较容易的。

    完整的源码地址:



    imxylz 2012-09-25 16:34 发表评论
    ]]>
    分布式消息系统jafka 发布1.2.0版本http://www.blogjava.net/xylz/archive/2012/06/26/381490.htmlimxylzimxylztue, 26 jun 2012 02:51:00 gmthttp://www.blogjava.net/xylz/archive/2012/06/26/381490.htmlhttp://www.blogjava.net/xylz/comments/381490.htmlhttp://www.blogjava.net/xylz/archive/2012/06/26/381490.html#feedback2http://www.blogjava.net/xylz/comments/commentrss/381490.htmlhttp://www.blogjava.net/xylz/services/trackbacks/381490.htmljafka 是一个高性能的分布式消息系统。jafka已经开源,使用github托管,凯发k8网页登录主页地址:

    jafka 发布1.2.0版本, 
    • 增加创建topic的命令 
    • 增加监控topic消费情况的工具 
    • 添加删除topic的命令 
    • 忽略intellij idea工程文件 
    • 支持密码验证某些操作 
    • 手动配置broker时支持默认分区数配置 
    • 重构发送消息的接口 
    • 添加一个默认发送字符串的消息发送者 
    • 添加生成完整完整包的脚本 
    • 添加一个导出字符串消息的脚本工具 
    • 修复消费自动分配(负载均衡)失败的问题 
    下载地址
    安装指南
    更多文档

    imxylz 2012-06-26 10:51 发表评论
    ]]>
    fedora 17 降级一把辛酸泪http://www.blogjava.net/xylz/archive/2012/06/07/380210.htmlimxylzimxylzthu, 07 jun 2012 04:13:00 gmthttp://www.blogjava.net/xylz/archive/2012/06/07/380210.htmlhttp://www.blogjava.net/xylz/comments/380210.htmlhttp://www.blogjava.net/xylz/archive/2012/06/07/380210.html#feedback9http://www.blogjava.net/xylz/comments/commentrss/380210.htmlhttp://www.blogjava.net/xylz/services/trackbacks/380210.html

    fedora 17发布,第二天立马更新了。 首先光是更新就折腾了很久,总算弄好了。结果发现一个巨大的问题。gtk2与eclipse不兼容。

    不兼容的后果是总是报这样的错误(命令行启动eclipse: eclipse -debug -consolelog):

    (eclipse:21798): glib-gio-critical **: g_dbus_proxy_new_for_bus_sync: assertion `g_dbus_is_name (name)' failed

    (eclipse:21798): glib-gio-critical **: g_dbus_proxy_new_for_bus_sync: assertion `g_dbus_is_name (name)' failed

    (eclipse:21798): glib-gio-critical **: g_dbus_proxy_new_for_bus_sync: assertion `g_dbus_is_name (name)' failed

    表现为打开编辑器后总是有很多内容无法显示,显示为空白,必须重新选定或者拖动滚动条才能显示。

    这令人崩溃啊!!!

    这下悲剧了,要知道我的开发工作就是在ecilpse下进行的。

    好吧,上网找找。发现有些人也遇到不兼容问题。但是没有一个解决办法。

    我的解决过程是这样:

    • 更新整个fedora环境(发布后官方发布了一些紧急修正包),未果
    • 重新下载最新发行版的eclipse,未果
    • 重新下载最新的测试版本eclipse,未果
    • 下载fedora18的gtk2、glibc等强制安装,未果
    • 降级gtk2、glibc等到fedora 16,未果
    • 继续google,寻找解决方法,依然未果
    • 替换最新发布的二进制swt库,未果
    • 尝试手动编译swt源码,未成功

    这样,折腾了几天,快要放弃了。

    昨天是在搞不定,尝试下载idea的社区版,使用了下还是感觉不习惯,放弃。

    今天早上突然想到,公司配的那台笔记本还是fedora 16未升级。于是想强制降级到swt所有依赖库到fedora 16看能否解决问题。

    使用了下面命令成功完成了部分依赖库的降级,这里面更是不断的尝试,在失败中成长。哭~~~

    yum list

    yum install

    yum erase

    yum --releasever=16 downgrade

    rpm -qa

    rpm -qf

    ldd

    lsof

    好在只是用了mirrors.sohu.com镜像,绑定了内网地址,下载rpm包非常快。这是是给我最大的安慰。

    这个过程经过了长达两个小时的折腾和仿佛。最终终于成功完成了以下依赖的降级。

    [adyliu@adyliu-pc jafka]$ rpm -qa|grep fc16|sort
    cscope-15.7a-9.fc16.x86_64
    dconf-0.10.0-1.fc16.x86_64
    fcitx-4.2.3-1.fc16.x86_64
    fcitx-data-4.2.3-1.fc16.noarch
    fcitx-gtk2-4.2.3-1.fc16.x86_64
    fcitx-gtk3-4.2.3-1.fc16.x86_64
    fcitx-libs-4.2.3-1.fc16.x86_64
    gdk-pixbuf2-2.24.1-1.fc16.x86_64
    gedit-3.2.6-1.fc16.x86_64
    glib2-2.30.3-1.fc16.x86_64
    glibc-2.14.90-24.fc16.7.x86_64
    glibc-common-2.14.90-24.fc16.7.x86_64
    glibc-devel-2.14.90-24.fc16.7.x86_64
    glibc-headers-2.14.90-24.fc16.7.x86_64
    glib-networking-2.30.1-2.fc16.x86_64
    gnome-disk-utility-libs-3.0.2-3.fc16.x86_64
    gnutls-2.12.14-2.fc16.x86_64
    gsettings-desktop-schemas-3.2.0-1.fc16.noarch
    gtk2-2.24.8-3.fc16.x86_64
    gtk2-immodule-xim-2.24.8-3.fc16.x86_64
    gvfs-1.10.1-3.fc16.x86_64
    libarchive-2.8.5-1.fc16.x86_64
    libbluray-0.2-0.5.20110710git51d7d60a96d06.fc16.x86_64
    libcdio-0.82-6.fc16.x86_64
    libsoup-2.36.1-2.fc16.x86_64
    mdadm-3.2.3-7.fc16.x86_64
    nautilus-3.2.1-2.fc16.x86_64
    nautilus-extensions-3.2.1-2.fc16.x86_64
    packagekit-0.6.22-2.fc16.x86_64
    packagekit-glib-0.6.22-2.fc16.x86_64
    packagekit-gtk-module-0.6.22-2.fc16.x86_64
    packagekit-yum-0.6.22-2.fc16.x86_64
    pango-1.29.4-1.fc16.x86_64
    yum-3.4.3-24.fc16.noarch

    可以看到仅仅更新gtk2/glibc是不够的。

    总结下:

    • 坚持是成功的关键(中间过程,欲哭无泪,最后我都打算重新安装fedora 16了)
    • 我还是很强的(囧)


    最后警告: 可能会有后遗症,请勿模仿,请勿尝试

    imxylz 2012-06-07 12:13 发表评论
    ]]>
    分布式消息系统jafka 发布1.1.0版本http://www.blogjava.net/xylz/archive/2012/05/27/379308.htmlimxylzimxylzsun, 27 may 2012 02:53:00 gmthttp://www.blogjava.net/xylz/archive/2012/05/27/379308.htmlhttp://www.blogjava.net/xylz/comments/379308.htmlhttp://www.blogjava.net/xylz/archive/2012/05/27/379308.html#feedback1http://www.blogjava.net/xylz/comments/commentrss/379308.htmlhttp://www.blogjava.net/xylz/services/trackbacks/379308.htmlhttps://github.com/adyliu/jafka

    jafka 发布1.1.0版本,:

    服务端

    • 增加  支持
    • 默认的编码/解码调整为字节数组 
    • 增加服务端的mbean serverinfo,描述版本信息,启动时间、运行时间等
    • 增加getoffset-console.sh脚本,获取broker的偏移量
    • 增加dumper工具,用于导出字符串消息
    • 默认zookeeper 负载均衡重试时间调整为10s
    • 将log4j.properties文件加入服务端classpath
    • 增加简单安装文档 
    • 默认服务端配置不启用zookeeper
    • 解决一些mbean重复注册问题
    • 大部分io关闭接口都继承自java.io.closeable,并提供closers工具类使用
    • 大量的注释更新以及日志友好化
    • 增加第三方依赖的

    客户端

    • 无消息消费时不更新offset 
    • 修复发送者无法收到新增加的topic分片信息问题
    • 消费消息时打开tcp nodelay特性 
    • 升级zookeeper客户端为3.3.5版本,修复zookeeper bug(961,1091)

    下载地址


    imxylz 2012-05-27 10:53 发表评论
    ]]>
    ice mini gridhttp://www.blogjava.net/xylz/archive/2012/05/22/378862.htmlimxylzimxylztue, 22 may 2012 11:47:00 gmthttp://www.blogjava.net/xylz/archive/2012/05/22/378862.htmlhttp://www.blogjava.net/xylz/comments/378862.htmlhttp://www.blogjava.net/xylz/archive/2012/05/22/378862.html#feedback0http://www.blogjava.net/xylz/comments/commentrss/378862.htmlhttp://www.blogjava.net/xylz/services/trackbacks/378862.htmlice grid 入门篇
    这篇是ice grid入门的最简单版本(不涉及到icegride node)。这里面设计到过多的概念和知识,暂且不表。

    创建slice文件

    printer.ice
     1 // **********************************************************************
     2 //
     3 // 凯发天生赢家一触即发官网 copyright (c) 2012 ady liu. all rights reserved.
     4 //
     5 // email: imxylz@gmail.com
     6 //
     7 // **********************************************************************
     8 
     9 module demo{
    10     interface printer {
    11         void printstring(string s);
    12     };
    13 };

    转换slice

    slice2cpp printer.ice 

    配置icegrid registry
    registry.cfg
    icegrid.instancename=demogrid

    ice.default.locator=demogrid/locator:default -p 4061  

    icegrid.registry.client.endpoints=tcp -p 4061
    icegrid.registry.server.endpoints=tcp
    icegrid.registry.internal.endpoints=tcp
    icegrid.registry.permissionsverifier=demogrid/nullpermissionsverifier
    icegrid.registry.adminpermissionsverifier=demogrid/nullpermissionsverifier
    icegrid.registry.sslpermissionsverifier=demogrid/nullsslpermissionsverifier
    icegrid.registry.adminsslpermissionsverifier=demogrid/nullsslpermissionsverifier
    icegrid.registry.data=./data
    icegrid.registry.dynamicregistration=1

    启动registry
    icegridregistry --ice.config=./registry.cfg &
    启动前最好创建数据目录./data
    mkdir ./data

    服务端

    printeri.h
     1 //**********************************************************************
     2 //
     3 // 凯发天生赢家一触即发官网 copyright (c) 2012 ady liu. all rights reserved.
     4 //
     5 // email: imxylz@gmail.com
     6 //
     7 //**********************************************************************
     8 
     9 #ifndef printer_i_h
    10 #define printer_i_h
    11 
    12 #include 
    13 
    14 using namespace demo;
    15 using namespace std;
    16 
    17 class printeri : public printer {
    18 public:
    19     virtual void printstring(const string& s,const ice::current&);
    20 };
    21 
    22 #endif
    23 

    printeri.cpp
     1 //**********************************************************************
     2 //
     3 // 凯发天生赢家一触即发官网 copyright (c) 2012 ady liu. all rights reserved.
     4 //
     5 // email: imxylz@gmail.com
     6 //
     7 //**********************************************************************
     8 
     9 #include 
    10 #include 
    11 
    12 using namespace std;
    13 
    14 void printeri :: printstring(const string& s,const ice::current&){
    15     cout << s << endl;
    16 }
    17 

    server.cpp
     1 #include 
     2 #include 
     3 
     4 using namespace std;
     5 
     6 class server : public ice::application {
     7 
     8     public:
     9         virtual int run(int argc,char* argv[]);
    10 };
    11 
    12 int main(int argc,char* argv[]){
    13 
    14     server app;
    15     int status = app.main(argc,argv,"server.cfg");
    16     return status;
    17 }
    18 
    19 int server::run(int argc,char* argv[]){
    20     if(argc>1){
    21         cerr< 22         return exit_failure;
    23     }
    24 
    25     ice::propertiesptr properties = communicator()->getproperties();
    26     ice::objectadapterptr adapter = communicator()->createobjectadapter("printeradapter");
    27     ice::identity id = communicator()->stringtoidentity("printer");
    28     demo::printerptr printer = new printeri();
    29     adapter->add(printer,id);
    30     adapter->activate();
    31     communicator()->waitforshutdown();
    32     return exit_success;
    33 }
    34 

    编译
    c  -i. -i$ice_home/include -c printeri.cpp printer.cpp server.cpp

    连接
    c  -o server printer.o server.o printeri.o -l$ice_home/lib -lice -liceutil -lpthread

    服务端配置
    server.cfg
    printeradapter.adapterid=printeradapter
    printeradapter.endpoints=default
    ice.default.locator=demogrid/locator:tcp -p 4061
    运行服务端
    ./server

    客户端

    client.cpp
     1 //**********************************************************************
     2 //
     3 // 凯发天生赢家一触即发官网 copyright (c) 2012 ady liu. all rights reserved.
     4 //
     5 // email: imxylz@gmail.com
     6 //
     7 //**********************************************************************
     8 
     9 #include 
    10 #include 
    11 #include 
    12 
    13 using namespace std;
    14 using namespace demo;
    15 
    16 int main(int argc,char* argv[]){
    17     int status = 0;
    18     ice::communicatorptr ic;
    19     printerprx printer;
    20     try{
    21         ic = ice::initialize(argc,argv);
    22         cout<<"printer proxy=>"<stringtoproxy("printer@printeradapter")< 23 
    24         try{
    25            printer = printerprx::checkedcast(ic->stringtoproxy("printer@printeradapter"));
    26         }catch(const ice::notregisteredexception&){
    27             icegrid::queryprx query = icegrid::queryprx::checkedcast(ic->stringtoproxy("demogrid/query"));
    28             printer = printerprx::checkedcast(query->findobjectbytype("::demo::printer"));
    29         }
    30         if(!printer){
    31             cerr<<": could't find a `::demo::printer` object."< 32             if(ic){
    33                 ic->destroy();
    34             }
    35             return exit_failure;
    36         }
    37         printer->printstring("hello world!");
    38     }catch(const ice::exception& ex){
    39         cerr << ex << endl;
    40         status = 1;
    41     }catch(const char* msg){
    42         cerr << msg << endl;
    43         status = 2;
    44     }
    45     if(ic){
    46         ic->destroy();
    47     }
    48     return status;
    49 }
    50 

    编译
    c  -i. -i$ice_home/include -c printer.cpp client.cpp

    连接
    c  -o client printer.o client.o -l$ice_home/lib -lice -liceutil -licegrid -lglacier2 -lpthread

    客户端配置
    client.cfg
    ice.default.locator=demogrid/locator:default -p 4061

    运行客户端
    ./client --ice.config=./client.cfg


    所有文件

    grid
    ├── client.cfg
    ├── client.cpp
    ├── printer.cpp
    ├── printer.h
    ├── printeri.cpp
    ├── printeri.h
    ├── registry.cfg
    ├── server.cfg
    └── server.cpp


    所有文件下载: 

    imxylz 2012-05-22 19:47 发表评论
    ]]>
    分布式消息系统jafka快速起步http://www.blogjava.net/xylz/archive/2012/05/11/377938.htmlimxylzimxylzfri, 11 may 2012 10:48:00 gmthttp://www.blogjava.net/xylz/archive/2012/05/11/377938.htmlhttp://www.blogjava.net/xylz/comments/377938.htmlhttp://www.blogjava.net/xylz/archive/2012/05/11/377938.html#feedback4http://www.blogjava.net/xylz/comments/commentrss/377938.htmlhttp://www.blogjava.net/xylz/services/trackbacks/377938.html阅读全文

    imxylz 2012-05-11 18:48 发表评论
    ]]>
    jafka - 一个高性能的消息系统http://www.blogjava.net/xylz/archive/2012/05/10/377759.htmlimxylzimxylzthu, 10 may 2012 02:08:00 gmthttp://www.blogjava.net/xylz/archive/2012/05/10/377759.htmlhttp://www.blogjava.net/xylz/comments/377759.htmlhttp://www.blogjava.net/xylz/archive/2012/05/10/377759.html#feedback0http://www.blogjava.net/xylz/comments/commentrss/377759.htmlhttp://www.blogjava.net/xylz/services/trackbacks/377759.htmljafka 是一个高性能的分布式消息系统。jafka已经开源,使用github托管,凯发k8网页登录主页地址:
    jafka 1.0版本已经发布,同步到maven中央仓库。

    jafka是由apache孵化的kafka(由linkedin捐助给apache)克隆而来。jafka 1.0完整遵循kafka 0.7的规范,几乎是kafka的克隆版(有一些改进和调整)。
    jafka有几个吸引人的特性:

    • 消息持久化非常快,服务端存储消息的开销为o(1),并且基于文件系统,能够持久化tb级的消息而不损失性能
    • 吞吐量很大,在我的单机dell e6220(现已经停产)、fedora 16 x86_64下单cpu内核运行,使用jafka内置的python客户端,吞吐量能够达到300k/s
    • 完全的分布式系统,broker、producer、consumer都原生自动支持分布式。自动实现复杂均衡。
    • 内核非常小,整个系统(包括服务端和客户端)只有一个272kb的jar包,内部机制也不复杂,适合进行内嵌或者二次开发 。整个服务端加上依赖组件共3.5mb。
    • 消息格式以及通信机制非常简单,适合进行跨语言开发。目前自带的python 3.x的客户端支持发送消息和接收消息。
    另外,这里有一个分享的ppt资源。
    view more from
    如果感兴趣,fork在github上的源码,进行二次开发或者按照自己喜欢的方式进行改进。如果有好的特性或者发现bug请友情提醒我。 另外,友情支持淘宝内部使用的kafka克隆版,内部做了大量的改进和附加组件。如果你需要一个全功能的“复杂”系统,可以试试metaq.

    imxylz 2012-05-10 10:08 发表评论
    ]]>
    [深入浅出jetty 05] jetty 模块化http://www.blogjava.net/xylz/archive/2012/04/12/372999.htmlimxylzimxylzthu, 12 apr 2012 01:39:00 gmthttp://www.blogjava.net/xylz/archive/2012/04/12/372999.htmlhttp://www.blogjava.net/xylz/comments/372999.htmlhttp://www.blogjava.net/xylz/archive/2012/04/12/372999.html#feedback3http://www.blogjava.net/xylz/comments/commentrss/372999.htmlhttp://www.blogjava.net/xylz/services/trackbacks/372999.html

    inside in jetty 8.x带有一个默认的test环境。我们从这个默认的环境入手。

    首先,来分析下start.ini里面的配置,这个配置决定启动了哪些模块。

    $ grep -v "#" start.ini|grep -v "^$"
    options=server,jsp,jmx,resources,websocket,ext,plus,annotations
    etc/jetty.xml
    etc/jetty-annotations.xml
    etc/jetty-deploy.xml
    etc/jetty-webapps.xml
    etc/jetty-contexts.xml
    etc/jetty-testrealm.xml
    

    利用上节学到的只是,我们先来分析下用到了那些模块。

    java -jar start.jar --list-options
    

    查找server,jsp,jmx,resources,websocket,ext,plus,annotations这些对应的模块有:

    global option (appended entries) (*)
    -------------------------------------------------------------
     0:      8.1.2.v20120308 | ${jetty.home}/lib/jetty-util-8.1.2.v20120308.jar
     1:      8.1.2.v20120308 | ${jetty.home}/lib/jetty-io-8.1.2.v20120308.jar
    
    option [server] (aggregate)
    -------------------------------------------------------------
     0:      8.1.2.v20120308 | ${jetty.home}/lib/jetty-xml-8.1.2.v20120308.jar
     1:  3.0.0.v201112011016 | ${jetty.home}/lib/servlet-api-3.0.jar
     2:      8.1.2.v20120308 | ${jetty.home}/lib/jetty-http-8.1.2.v20120308.jar
     3:      8.1.2.v20120308 | ${jetty.home}/lib/jetty-continuation-8.1.2.v20120308.jar
     4:      8.1.2.v20120308 | ${jetty.home}/lib/jetty-server-8.1.2.v20120308.jar
     5:      8.1.2.v20120308 | ${jetty.home}/lib/jetty-security-8.1.2.v20120308.jar
     6:      8.1.2.v20120308 | ${jetty.home}/lib/jetty-servlet-8.1.2.v20120308.jar
     7:      8.1.2.v20120308 | ${jetty.home}/lib/jetty-webapp-8.1.2.v20120308.jar
     8:      8.1.2.v20120308 | ${jetty.home}/lib/jetty-deploy-8.1.2.v20120308.jar
     9:      8.1.2.v20120308 | ${jetty.home}/lib/jetty-servlets-8.1.2.v20120308.jar
    
    option [jsp]
    -------------------------------------------------------------
     0:  2.2.0.v201108011116 | ${jetty.home}/lib/jsp/com.sun.el-2.2.0.v201108011116.jar
     1:  2.2.0.v201108011116 | ${jetty.home}/lib/jsp/javax.el-2.2.0.v201108011116.jar
     2:  1.2.0.v201105211821 | ${jetty.home}/lib/jsp/javax.servlet.jsp.jstl-1.2.0.v201105211821.jar
     3:  2.2.0.v201112011158 | ${jetty.home}/lib/jsp/javax.servlet.jsp-2.2.0.v201112011158.jar
     4:  2.2.2.v201112011158 | ${jetty.home}/lib/jsp/org.apache.jasper.glassfish-2.2.2.v201112011158.jar
     5:  1.2.0.v201112081803 | ${jetty.home}/lib/jsp/org.apache.taglibs.standard.glassfish-1.2.0.v201112081803.jar
     6: 3.7.0.m20110909-1335 | ${jetty.home}/lib/jsp/org.eclipse.jdt.core-3.7.1.jar
    
    option [jmx]
    -------------------------------------------------------------
     0:      8.1.2.v20120308 | ${jetty.home}/lib/jetty-jmx-8.1.2.v20120308.jar
    
    option [resources]
    -------------------------------------------------------------
     0:                (dir) | ${jetty.home}/resources
    
    option [websocket]
    -------------------------------------------------------------
     0:      8.1.2.v20120308 | ${jetty.home}/lib/jetty-websocket-8.1.2.v20120308.jar
    
    option [ext]
    -------------------------------------------------------------
    empty option, no classpath entries active.
    
    option [plus]
    -------------------------------------------------------------
     0:      8.1.2.v20120308 | ${jetty.home}/lib/jetty-jndi-8.1.2.v20120308.jar
     1:      8.1.2.v20120308 | ${jetty.home}/lib/jetty-plus-8.1.2.v20120308.jar
     2:  1.1.0.v201105071233 | ${jetty.home}/lib/jndi/javax.activation-1.1.0.v201105071233.jar
     3:  1.4.1.v201005082020 | ${jetty.home}/lib/jndi/javax.mail.glassfish-1.4.1.v201005082020.jar
    
    option [annotations]
    -------------------------------------------------------------
     0:      8.1.2.v20120308 | ${jetty.home}/lib/jetty-annotations-8.1.2.v20120308.jar
     1:  1.1.0.v201108011116 | ${jetty.home}/lib/annotations/javax.annotation-1.1.0.v201108011116.jar
     2:  3.1.0.v200803061910 | ${jetty.home}/lib/annotations/org.objectweb.asm-3.1.0.v200803061910.jar
    

    从上一节中我们知道,这些模块相当于将那些组件加入classpath中,jetty在启动时也会装载这些模块。

    $java -jar start.jar --dry-run|awk '{print $4}'|sed 's/:/\n/g'
    /opt/apps/jetty8/lib/jetty-xml-8.1.2.v20120308.jar
    /opt/apps/jetty8/lib/servlet-api-3.0.jar
    /opt/apps/jetty8/lib/jetty-http-8.1.2.v20120308.jar
    /opt/apps/jetty8/lib/jetty-continuation-8.1.2.v20120308.jar
    /opt/apps/jetty8/lib/jetty-server-8.1.2.v20120308.jar
    /opt/apps/jetty8/lib/jetty-security-8.1.2.v20120308.jar
    /opt/apps/jetty8/lib/jetty-servlet-8.1.2.v20120308.jar
    /opt/apps/jetty8/lib/jetty-webapp-8.1.2.v20120308.jar
    /opt/apps/jetty8/lib/jetty-deploy-8.1.2.v20120308.jar
    /opt/apps/jetty8/lib/jetty-servlets-8.1.2.v20120308.jar
    /opt/apps/jetty8/lib/jetty-annotations-8.1.2.v20120308.jar
    /opt/apps/jetty8/lib/annotations/javax.annotation-1.1.0.v201108011116.jar
    /opt/apps/jetty8/lib/annotations/org.objectweb.asm-3.1.0.v200803061910.jar
    /opt/apps/jetty8/lib/jetty-jmx-8.1.2.v20120308.jar
    /opt/apps/jetty8/lib/jsp/com.sun.el-2.2.0.v201108011116.jar
    /opt/apps/jetty8/lib/jsp/javax.el-2.2.0.v201108011116.jar
    /opt/apps/jetty8/lib/jsp/javax.servlet.jsp.jstl-1.2.0.v201105211821.jar
    /opt/apps/jetty8/lib/jsp/javax.servlet.jsp-2.2.0.v201112011158.jar
    /opt/apps/jetty8/lib/jsp/org.apache.jasper.glassfish-2.2.2.v201112011158.jar
    /opt/apps/jetty8/lib/jsp/org.apache.taglibs.standard.glassfish-1.2.0.v201112081803.jar
    /opt/apps/jetty8/lib/jsp/org.eclipse.jdt.core-3.7.1.jar
    /opt/apps/jetty8/lib/jetty-jndi-8.1.2.v20120308.jar
    /opt/apps/jetty8/lib/jetty-plus-8.1.2.v20120308.jar
    /opt/apps/jetty8/lib/jndi/javax.activation-1.1.0.v201105071233.jar
    /opt/apps/jetty8/lib/jndi/javax.mail.glassfish-1.4.1.v201005082020.jar
    /opt/apps/jetty8/resources
    /opt/apps/jetty8/lib/jetty-websocket-8.1.2.v20120308.jar
    /opt/apps/jetty8/lib/jetty-util-8.1.2.v20120308.jar
    /opt/apps/jetty8/lib/jetty-io-8.1.2.v20120308.jar
    

    在总结下,不同的option决定了启动不同的模块(也就是不同的组件和classpath)。另外,对于start.config里面的不同的option可能有相同的模块依赖。

    默认的test.war启动了如下模块:

    • server: 一个标准的servlet容器
    • jsp: jsp模块
    • jmx: jmx支持
    • resources: 允许从${jetty.home}/resources中读取类资源(实际上是配置log4j.properties)
    • websocket: 支持websocket的例子
    • ext: 由于${jetty.home}/lib/ext目录为空,实际上什么都做。其实此特性是为了装载自定义的组件依赖。
    • plus: 一些扩展支持,从上面classpath中猜测,应该是jndi、java认证以及java mail的组件。
    • annotations: java注解以及字节码的支持。

    test.war配置

    再来看看加载jetty配置。 test.war模块默认加载了6个配置组件。

    etc/jetty.xml
    etc/jetty-annotations.xml
    etc/jetty-deploy.xml
    etc/jetty-webapps.xml
    etc/jetty-contexts.xml
    etc/jetty-testrealm.xml
    

    inside in jetty.xml

    默认的jetty.xml负责配置设置服务器的参数,包括绑定的地址、线程池大小以及一些默认的处理器(handler)等。

    
        
          
            10
            200
            false
          
        
        
          
              
                inside in jetty.host" />
                inside in jetty.port" default="8080"/>
                300000
                2
                false
                8443
        20000
        5000
              
          
        
        
          
            
             
               
                 
               
               
                 
               
             
            
          
        
        true
        true
        true
        1000
        false
        false
    
    

    可以看出默认的线程池大小是最小线程10个,最大线程200个。绑定在所有网卡的8080端口。其它配置以后再分析。

    inside in jetty-annotation.xml

    inside in jetty-annotation.xml配置应该是描述支持哪些注解配置方式。

        
          org.eclipse.jetty.webapp.configuration
          
              
                   org.eclipse.jetty.webapp.webinfconfiguration
                   org.eclipse.jetty.webapp.webxmlconfiguration
                   org.eclipse.jetty.webapp.metainfconfiguration
                   org.eclipse.jetty.webapp.fragmentconfiguration
                   org.eclipse.jetty.annotations.annotationconfiguration
                   org.eclipse.jetty.webapp.jettywebxmlconfiguration
              
          
        
    

    inside in jetty-deploy.xml

    inside in jetty-deploy.xml配置web发布方式。

        
          
            
              
                
              
              
                org.eclipse.jetty.server.webapp.containerincludejarpattern
                .*/servlet-api-[^/]*\.jar$
                        
            
          
        
    

    事实上这里没有定义要发布的目录或者应用位置,因此jetty-deploy依赖于jetty-contexts.xml或者jetty-webapps.xml。

    inside in jetty-webapps.xml

    inside in jetty-webapps.xml定义要发布的内容,通常是要发布应用或者应用的定义。默认是存放于${jetty.home}/webapps下的应用以及${jetty.home}/contexts下的xml定义。

        
              
                
                  
                    inside in jetty.home" default="." />/webapps
                    inside in jetty.home" default="."/>/etc/webdefault.xml
                    1
                    inside in jetty.home" default="." />/contexts
    true
                  
                
              
        
    

    inside in jetty-contexts.xml

    inside in jetty-contexts.xml定义一些预置规则。类似于一些拦截器。例如可以讲某些uri rewrite或者静态资源cache配置等。

    这会自动扫描${jetty.home}/contexts下面的xml配置。

        
          
            
              
                inside in jetty.home" default="." />/contexts
                1
              
            
          
        
    

    inside in jetty-testrealm.xml

    inside in jetty-testrealm.xml用于test.war的特定配置,用于配置一些认证信息。

        
          
            
              test realm
              inside in jetty.home" default="."/>/etc/realm.properties
              0
            
          
        
    

    test.xml

    事实上这么模块的配置都是在节点配置下。 因此可以合并成一个大的xml。这样做的好处是在一个xml包含所有配置,方便灵活定义。当然,坏处就是复用率低。

    
    
        
          
          
            10
            200
            false
          
        
        
          
              
                inside in jetty.host" />
                inside in jetty.port" default="8080"/>
                300000
                2
                false
                8443
        20000
        5000
              
          
        
        
          
            
             
               
                 
               
               
                 
               
             
            
          
        
        true
        true
        true
        1000
        false
        false
        
          org.eclipse.jetty.webapp.configuration
          
              
    org.eclipse.jetty.webapp.webinfconfiguration
    org.eclipse.jetty.webapp.webxmlconfiguration
    org.eclipse.jetty.webapp.metainfconfiguration
    org.eclipse.jetty.webapp.fragmentconfiguration
    org.eclipse.jetty.annotations.annotationconfiguration
    org.eclipse.jetty.webapp.jettywebxmlconfiguration
              
          
        
        
          
            
              
                
              
              
                org.eclipse.jetty.server.webapp.containerincludejarpattern
                .*/servlet-api-[^/]*\.jar$
              
            
          
        
        
              
                
                  
                    inside in jetty.home" default="." />/webapps
                    inside in jetty.home" default="."/>/etc/webdefault.xml
                    1
                    inside in jetty.home" default="." />/contexts
    true
                  
                
              
        
    
      
    
      
    inside in jetty.home" default="." />/contexts
    1
      
    
      
    
    
      
    
      test realm
      inside in jetty.home" default="."/>/etc/realm.properties
      0
    
      
    
    
    

    我们将test.xml放入etc目录下面。这是保持start.ini文件不存在,也就是不使用start.ini里面的配置。

    手动运行它。

    java -jar start.jar options=server,jsp,jmx,resources,websocket,ext,plus,annotations etc/test.xml
    

    这时候的启动就和默认启动是一样的了。

    这时候就可以访问了。

    inside in jetty statistics

    这一部分,我们利用学习到的只是来部署一个jetty统计模块。

    修改设置

    将连接计数参数打开:

        
          
              
                inside in jetty.host" />
                inside in jetty.port" default="8080"/>
                300000
                2
                true
              
          
        
    

    设置servlet

    为了不影响默认的test.war环境,我们增加一个最简单的war环境。

    根据前面学到的知识,只需要将war环境放到webapps目录下即可。可以是一个war包,也可以是一个以.war结尾的目录。

    $tree webapps/demo.war/
    webapps/demo.war/
    `-- web-inf
        |-- inside in jetty-web.xml
        `-- web.xml
    1 directory, 2 files
    
    $cat webapps/demo.war/web-inf/jetty-web.xml 
    
    
    
      /demo
    
    
    $cat webapps/demo.war/web-inf/web.xml
    
    
     
      static demo
      
        statistic
        org.eclipse.jetty.servlet.statisticsservlet
        1
        
            restricttolocalhostfalse
        
      
      
        statistic
        /statistic/*
      
    
    

    说明几点:

    • 为了不和test.war的contextpath混淆,这里强制修改为/demo。
    • 增加一个jetty内置的统计servlet(org.eclipse.jetty.servlet.statisticsservlet)
    • 将servlet的参数restricttolocalhost修改为false,否则默认情况下只能通过本机访问,不能远程访问

    运行demo

    保持test.war不变增加一个统计配置。

    $java -jar start.jar etc/jetty-stats.xml
    

    执行效果

    使用浏览器访问

    http://127.0.0.1:8080/demo/statistic/
    

    效果如下:

    统计结果包含6个部分:

    1. 统计结果收集时间
    2. 请求数详情(当前请求数、最大请求数、总共请求数、请求时间等)
    3. 请求分发详情(和请求数不同的是,这是jetty内部分发请求的数量,包括forward/include等)
    4. 响应状态详情(1xx/2xx/3xx/4xx/5xx以及总共发送的字节数)
    5. 连接数详情 (当前连接数、最大连接数、连接持续时间等)
    6. 内存状况(堆内存和非堆内存使用状况,非堆内存通常也称永久代内存)

    小结

    inside in jetty 8.x已经将各个模块拆分非常详细了。每一个模块的命名都非常有规律。通常从名称上就能够猜测出模块的作用。

    部分模块可能还需要对应的配置。${jetty.home}/etc下面有大量的配置,这些零散的配置拆分是为了可复用。 如果一个jetty要想启动多个java进程,那么只需要指定不同的配置即可。甚至为了方便定制化,可能为每一个java进程创建一个完整的jetty.xml配置,而不需要${jetty.home}/etc下面的配置。



    imxylz 2012-04-12 09:39 发表评论
    ]]>
    [深入浅出jetty] 文章索引http://www.blogjava.net/xylz/archive/2012/04/12/371612.htmlimxylzimxylzthu, 12 apr 2012 01:38:00 gmthttp://www.blogjava.net/xylz/archive/2012/04/12/371612.htmlhttp://www.blogjava.net/xylz/comments/371612.htmlhttp://www.blogjava.net/xylz/archive/2012/04/12/371612.html#feedback0http://www.blogjava.net/xylz/comments/commentrss/371612.htmlhttp://www.blogjava.net/xylz/services/trackbacks/371612.html
    1. [深入浅出jetty 01] jetty 8.x 安装
    2. [深入浅出jetty 02] jetty 8.x 简单试用
    3. [深入浅出jetty 03] 简单的restful入门
    4. [深入浅出jetty 04] jetty的启动方式
    5. [深入浅出jetty 05] jetty 模块化


    imxylz 2012-04-12 09:38 发表评论
    ]]>
    [深入浅出jetty 04]jetty的启动方式http://www.blogjava.net/xylz/archive/2012/03/28/372923.htmlimxylzimxylzwed, 28 mar 2012 11:02:00 gmthttp://www.blogjava.net/xylz/archive/2012/03/28/372923.htmlhttp://www.blogjava.net/xylz/comments/372923.htmlhttp://www.blogjava.net/xylz/archive/2012/03/28/372923.html#feedback2http://www.blogjava.net/xylz/comments/commentrss/372923.htmlhttp://www.blogjava.net/xylz/services/trackbacks/372923.html
    除了极大方便嵌入式启动之外,从程序外部也非常好容易启动jetty。

    [原文:http://www.blogjava.net/xylz/archive/2012/03/28/372923.html]

    运行方式

    运行方法1

    首先我们以一个标准的jar程序启动来看待这个问题.
    [adyliu@adyliu-pc jetty8]$ cat run.sh 
    #!/bin/bash


    jetty_classpath="./start.jar"
    for f in `find ./lib -name "*.jar"`
    do
        jetty_classpath=$jetty_classpath:$f
    done

    #echo $jetty_classpath
    java -cp $jetty_classpath $*

    然后运行查看下
    [adyliu@adyliu-pc jetty8]$ sh run.sh org.eclipse.jetty.start.main
    2012-03-28 16:00:57.532:info:oejs.server:jetty-8.1.2.v20120308
    2012-03-28 16:00:57.578:info:oejs.abstractconnector:started selectchannelconnector@0.0.0.0:8080

    由于没有任何web环境,因此此时访问任何地址应该都是404。测试一下:
    [adyliu@adyliu-pc jetty8]$ curl -v http://127.0.0.1:8080
    * about to connect() to 127.0.0.1 port 8080
    *   trying 127.0.0.1 connected
    * connected to 127.0.0.1 (127.0.0.1) port 8080
    > get / http/1.1
    > user-agent: curl/7.15.5 (x86_64-redhat-linux-gnu) libcurl/7.15.5 openssl/0.9.8b zlib/1.2.3 libidn/0.6.5
    > host: 127.0.0.1:8080
    accept: */*

    < http/1.1 404 not found
    < date: wed, 28 mar 2012 08:15:27 gmt
    < content-type: text/html
    < content-length618
    < server: jetty(8.1.2.v20120308)


    error <span style="color: #800000; ">404</span> - not found

    error 404 - not found.

    运行方法2

    另外上述运行等价于:
    [adyliu@adyliu-pc jetty8]$ sh run.sh org.eclipse.jetty.xml.xmlconfiguration etc/jetty.xml
    2012-03-28 16:31:16.481:info:oejs.server:jetty-8.1.2.v20120308
    2012-03-28 16:31:16.518:info:oejs.abstractconnector:started selectchannelconnector@0.0.0.0:8080

    运行方法3

    第三种方法就是使用封装好的start.jar,这个jar包封装了一些常规的配置。

    在开始之前,我们先重命名下默认的start.ini,因为默认的配置文件会启动一个test.war环境。
    mv start.ini start.ini.default
    [adyliu@adyliu-pc jetty8]$ java -jar start.jar
    2012-03-28 16:35:21.941:info:oejs.server:jetty-8.1.2.v20120308
    2012-03-28 16:35:21.992:info:oejs.abstractconnector:started selectchannelconnector@0.0.0.0:8080

    可以看出这个方式和第一种、第二种完全相同。
    另外start.jar提供了一种可以查看当前运行参数的命令:
    java -jar start.jar --dry-run

    可能输出:
    /opt/apps/jdk/bin/java -djetty.home=/opt/apps/jetty8 -cp /opt/apps/jetty8/resources:\
    /opt/apps/jetty8/lib/jetty-xml-8.1.2.v20120308.jar:/opt/apps/jetty8/lib/servlet-api-3.0.jar:\
    /opt/apps/jetty8/lib/jetty-http-8.1.2.v20120308.jar:/opt/apps/jetty8/lib/jetty-continuation-8.1.2.v20120308.jar:\
    /opt/apps/jetty8/lib/jetty-server-8.1.2.v20120308.jar:/opt/apps/jetty8/lib/jetty-security-8.1.2.v20120308.jar:\
    /opt/apps/jetty8/lib/jetty-servlet-8.1.2.v20120308.jar:/opt/apps/jetty8/lib/jetty-webapp-8.1.2.v20120308.jar:\
    /opt/apps/jetty8/lib/jetty-deploy-8.1.2.v20120308.jar:/opt/apps/jetty8/lib/jetty-servlets-8.1.2.v20120308.jar:\
    /opt/apps/jetty8/lib/jetty-util-8.1.2.v20120308.jar:/opt/apps/jetty8/lib/jetty-io-8.1.2.v20120308.jar \
    org.eclipse.jetty.xml.xmlconfiguration /tmp/start1059041541723976621.properties /opt/apps/jetty8/etc/jetty.xml

    有意思的是这里有一个临时文件:/tmp/start1059041541723976621.properties,里面记录了所有系统属性,也就是类似system.getproperties()。
    除非是嵌入式开发,否则我们都是用start.jar来启动jetty。

    命令参数

    start.jar提供了大量的参数来负责启动jvm。
    下面命令列出所有的命令行参数:
    java -jar start.jar --help

    现在问题来了,这些默认的参数都是哪来的?例如,如果想改变${jetty.home}又怎样?
    jetty内部默认提供了一个默认的配置文件来解决此问题。
    默认情况下start.jar里面带有一个默认的start.config文件,这个文件有一些预置的定义。
    [adyliu@adyliu-pc jetty8]$ jar tvf start.jar | grep start.config
      8669 fri mar 09 00:13:12 cst 2012 org/eclipse/jetty/start/start.config
     文件内容非常大,其中大部分是注释。

    start.config的作用有以下几个:

    • 定义jetty.home属性
    • 定义jetty启动类
    • 定义jetty启动的默认配置文件
    • 定义options
    • 根据options来定义classpath

    上面特别提到options。什么是options?

    options

    由于jetty是高度可定制的,因此jetty将各个模块拆分成各个非常细小的模块。每一个模块(实际上是一个个的jar包),我们可以简单的看出是一个option。而每一个option都会对应于实际的jar,这就决定了这些jar包是否需要加入classpath,并且在jetty启动的时候是否需要做一些额外的事情。

    start.config文件的语法也挺有意思的。支持一些简单的逻辑判断,例如文件是否存在、命令行参数是否存在等。

    默认情况下有如下配置:

    • path参数的值加入classpath
    • lib参数的值作为目录搜索jar包,其中的jar/zip包加入classpath
    • 默认的启动类是org.eclipse.jetty.xml.xmlconfiguration.class,除非定义了start.class属性
    • 默认的jetty配置文件是$(jetty.home)/etc/jetty.xml,除非传入的参数不为空
    • 默认${jetty.home}目录是当前目录(不一定是start.jar所在路径)。${jetty.home}属性搜索顺序有:
      • $(jetty.home) 参数或者系统属性(包括环境变量)
      • . 当前路径
      • .. 当前路径的父路径
      • jetty-distribution/src/main/resources 当前路径的发行版子路径
      • ../jetty-distribution/src/main/resources 当前路径的父路径的发行版子路径
    • 默认的classpath有:
      • resources
      • lib/jetty-xml-8.1.2.v20120308.jar
      • lib/servlet-api-3.0.jar
      • lib/jetty-http-8.1.2.v20120308.jar
      • lib/jetty-continuation-8.1.2.v20120308.jar
      • lib/jetty-server-8.1.2.v20120308.jar
      • lib/jetty-security-8.1.2.v20120308.jar
      • lib/jetty-servlet-8.1.2.v20120308.jar
      • lib/jetty-webapp-8.1.2.v20120308.jar
      • lib/jetty-deploy-8.1.2.v20120308.jar
      • lib/jetty-servlets-8.1.2.v20120308.jar
      • lib/jetty-util-8.1.2.v20120308.jar
      • lib/jetty-io-8.1.2.v20120308.jar

    start.jar参数

    我们再来看start.jar支持的参数:

    [adyliu@adyliu-pc jetty8]# java -jar start.jar --help
    usage: java -jar start.jar [options] [properties] [configs]

    options

    其中options列表(这指的是命令行参数,不是模块,由此可见jetty将内置的options定义为模块多好)有:

    • --version 列出版本号
    • --list-options 列出当前start.config支持的所有options
    • --list-config 列出当前start.config内容(文本内容)
    • --dry-run 列出当前配置要启动的java进程完整参数(不启动jetty服务)
    • --exec 启动子进程(只有启动子进程才能修改-x,-d等参数,因为start.jar本身就是依靠java进程启动的,不能在运行时改变)
    • --stop 停止运行的jetty实例
    • --daemon 后台运行jetty,启动将stdout/stderr记录到${jetty.log}/start.log中(好了,这个变量jetty.log没有默认配置说明,估计是${jetty.home}/logs目录)
    • --config= 指定特别的start.config,以便覆盖内置的start.config.(经过测试,如果指定此文件,那么内置的配置将不再读取,这导致必须将所有配置写全,包括mainclass/jetty config/options等)
    • --ini= 从配置文件中装载命令行参数。上面参数以及下面提到的参数是在太多,可以从配置文件中一次性加载,默认的配置文件是${jetty.home}/start.ini。
    • --pre= 指定特别的jetty运行配置文件,这个配置文件在后面提高的配置文件前面运行,相当于改变默认的装载机制。

    properties

    属性分成两种,一种是会传递给系统属性(java.lang.system#getproperty(string)),一种只是作为jetty的启动参数。

    如果要传递给系统属性,则格式是: -dname=value,和java进程系统属性类似。

    jetty也有一些默认的系统属性:

    属性类型描述
    org.eclipse.jetty.util.log.class class jetty日志记录,默认为:org.eclipse.jetty.util.log.slf4jlog
    org.eclipse.jetty.util.log.debug boolean 调试日志输出地方,默认为stderr和java内置的logger,如果是其他日志则需要设置为true,默认为false
    org.eclipse.jetty.util.log.ignored boolean 是否记录一些忽略的错误日志,默认为false
    org.eclipse.jetty.util.log.source boolean 记录错误日志行号?位置?默认为false
    com.sun.management.jmxremote   启动jmx管理

    jetty的启动参数属性,格式是: name=value,注意这里没有-d了。这些参数不会传递给系统属性。

    所有参数列表:

    • path=[directory]: 传递额外的classpath,参考上面默认的start.config配置
    • lib=[directory]: 传递额外classpath搜索jar/zip的目录
    • stop.port=[number]: 停止jetty的端口(远程管理)
    • stop.key=[alphanumeric]: 停止jetty的密码(远程管理)
    • debug=true: 是否启动调试模式,同时会设置org.eclipse.jetty.util.log.debug属性为true,默认为false
    • options=[option,option...]: option列表,也就是要启动的模块列表。

    在内置的start.config中默认的options列表有:

    • all
    • client
    • server
    • ajp
    • annotations
    • client
    • default
    • deploy
    • ext
    • jmx
    • jndi
    • jsp
    • jta
    • monitor
    • overlay
    • overlays
    • plus
    • policy
    • resources
    • rewrite
    • security
    • server
    • servlet
    • servlets
    • setuid
    • webapp
    • websocket
    • xml

    configs

    jetty运行需要一些配置文件,这些配置文件对应于不同的option所需要的配置。

    默认的jetty配置存在都存在于${jetty.home}/etc中,所有配置文件列表有:

    • etc/jetty-ajp.xml
    • etc/jetty-annotations.xml
    • etc/jetty-bio-ssl.xml
    • etc/jetty-bio.xml
    • etc/jetty-contexts.xml
    • etc/jetty-debug.xml
    • etc/jetty-deploy.xml
    • etc/jetty-fileserver.xml
    • etc/jetty-ipaccess.xml
    • etc/jetty-jmx.xml
    • etc/jetty-logging.xml
    • etc/jetty-monitor.xml
    • etc/jetty-overlay.xml
    • etc/jetty-plus.xml
    • etc/jetty-policy.xml
    • etc/jetty-proxy.xml
    • etc/jetty-requestlog.xml
    • etc/jetty-rewrite.xml
    • etc/jetty-ssl.xml
    • etc/jetty-stats.xml
    • etc/jetty-testrealm.xml
    • etc/jetty-webapps.xml
    • etc/jetty-xinetd.xml
    • etc/jetty.xml

    这么多配置,如何记得住?该使用哪些配置?

    下一个章节中介绍配置文件。


    参考资源:


    imxylz 2012-03-28 19:02 发表评论
    ]]>
    一次简单却致命的错误http://www.blogjava.net/xylz/archive/2012/03/15/371966.htmlimxylzimxylzthu, 15 mar 2012 10:30:00 gmthttp://www.blogjava.net/xylz/archive/2012/03/15/371966.htmlhttp://www.blogjava.net/xylz/comments/371966.htmlhttp://www.blogjava.net/xylz/archive/2012/03/15/371966.html#feedback16http://www.blogjava.net/xylz/comments/commentrss/371966.htmlhttp://www.blogjava.net/xylz/services/trackbacks/371966.html我看到机器的负载都超过20了,查看java进程线程栈,找到了出问题的代码。

    下面是其代码片段,实际情况错误处理比这更坏。
     1 package demo;
     2 
     3 import java.io.bufferedreader;
     4 import java.io.inputstream;
     5 import java.io.inputstreamreader;
     6 import java.net.httpurlconnection;
     7 import java.net.url;
     8 import java.net.urlconnection;
     9 import org.apache.commons.lang.stringutils;
    10 
    11 /**
    12  * @author adyliu (imxylz#gmail.com)
    13  * @since 2012-3-15
    14  */
    15 public class faultdemo {
    16 
    17     /**
    18      * @param args
    19      */
    20     public static void main(string[] args) throws exception {
    21         final string tudou = "http://v.youku.com/v_playlist/f17170661o1p9.html";
    22 
    23         url url = new ;
    24         httpurlconnection conn = (httpurlconnection) url.openconnection();
    25         conn.connect();
    26         try {
    27             inputstream in = conn.getinputstream();
    28             bufferedreader br = new bufferedreader(new inputstreamreader(in, "utf-8"));
    29             stringbuilder buf = new stringbuilder();
    30             string line = null;
    31             while ((line = br.readline()) != null) {
    32                 if (stringutils.isnotempty(buf.tostring())) {
    33                     buf.append("\r\n");
    34                 }
    35                 buf.append(line);
    36             }
    37             //do something with 'buf'
    38 
    39         } finally {
    40             conn.disconnect();
    41         }
    42 
    43     }
    44 
    45 }
    46 

    思考下,这段代码有什么致命问题么?(这里不追究业务逻辑处理的正确性以及细小的瑕疵)
    .
    ..
    ...
    现在回来。
    我发现线程栈里面的线程都runnable在32行。
    这一行看起来有什么问题呢?stringbuilder.tostring()不是转换成string么?apache commons-lang里面的stringutils.isnotempty使用也没问题啊?
    看代码,人家的逻辑其实是判断是否是第一行,如果不是第一行那么就增加一个换行符。

    既然cpu在这里运行,那么就说明这个地方一定存在非常耗费cpu的操作,导致cpu非常繁忙,从而系统负载过高。
    看详细堆栈,其实cpu在进行内存的拷贝动作。
    看下面的源码。
    java.lang.stringbuilder.tostring()
        public string tostring() {
            // create a copy, don't share the array
        return new string(value, 0, count);
        }
    接着看java.lang.string的构造函数:
        public string(char value[], int offset, int count) {
            if (offset < 0) {
                throw new stringindexoutofboundsexception(offset);
            }
            if (count < 0) {
                throw new stringindexoutofboundsexception(count);
            }
            // note: offset or count might be near -1>>>1.
            if (offset > value.length - count) {
                throw new stringindexoutofboundsexception(offset   count);
            }
            this.offset = 0;
            this.count = count;
            this.value = arrays.copyofrange(value, offset, offset count);
        }

    看出来了么?
    问题的关键在于string构造函数的最后一行,value并不是直接指向的,而是重新生成了一个新的字符串,使用系统拷贝函数进行内存复制。
    java.util.arrays.copyofrange(char[], int, int)
        public static char[] copyofrange(char[] original, int from, int to) {
            int newlength = to - from;
            if (newlength < 0)
                throw new illegalargumentexception(from   " > "   to);
            char[] copy = new char[newlength];
            system.arraycopy(original, from, copy, 0,
                             math.min(original.length - from, newlength));
            return copy;
        }

    好了,再回头看逻辑代码32行。
    if (stringutils.isnotempty(buf.tostring())) {
        buf.append("\r\n");
    }
    这里有问题的地方在于每次循环一行的时候都生成一个新的字符串。也就是说如果http返回的结果输入流中有1000行的话,将额外生成1000个字符串(不算stringbuilder扩容生成的个数)。每一个字符串还比前一个字符串大。


    我们来做一个简单的测试,我们在原来的代码上增加几行计数代码。
        int lines =0;
        int count = 0;
        int malloc = 0;
        while ((line = br.readline()) != null) {
            lines ;
            count =line.length();
            malloc  = count;
            if (stringutils.isnotempty(buf.tostring())) {
                buf.append("\r\n");
            }
            buf.append(line);
        }
        system.out.println(lines " -> " count " -> " malloc);
    我们记录下行数lines以及额外发生的字符串拷贝大小malloc。
    这是一次输出的结果。
    1169 -> 66958 -> 39356387
    也就是1169行的网页,一共是66958字节(65kb),结果额外生成的内存大小(不算stringbuilder扩容占用的内存大小)为39356387字节(37.5mb)!!!
    试想一下,cpu一直频繁于进行内存分配,机器的负载能不高么?我们线上服务器是2个cpu 16核,内存24g的redhat enterprise linux 5.5,负载居然达到几十。这还是只有访问量很低的时候。这就难怪服务频繁宕机了。

    事实上我们有非常完善和丰富的基于apache commons-httpclient的封装,操作起来也非常简单。对于这种简单的请求,只需要一条命令就解决了。
    string platform.utils.httpclientutils.getresponse(string)
    string platform.utils.httpclientutils.postresponse(string, map)

    即使非要自造轮子,处理这种简单的输入流可以使用下面的代码,就可以很好的解决问题。
        inputstream in = 
        bytearrayoutputstream baos = new bytearrayoutputstream(8192);
        int len = -1;
        byte[] b = new byte[8192];//8k
        while ((len = in.read(b)) > 0) {
            baos.write(b, 0, len);
        }
        baos.close();//ignore is ok
        string response =  new string(baos.tobytearray(), encoding);

    当然了,最后紧急处理线上问题最快的方式就是将有问题的代码稍微变通下即可。
        if (buf.length() > 0) {
            buf.append("\r\n");
        }


    这个问题非常简单,只是想表达几个观点:
    • 团队更需要合作,按照规范来进行。自造轮子不是不可以,但是生产环境还是要限于自己熟悉的方式。
    • 即使非常简单的代码,也有可能有致命的陷阱在里面。善于思考才是王道。
    • 学习开源的代码和常规思路,学习解决问题的常规做法。这个问题其实非常简单,熟悉输入输出流的人非常熟练就能解决问题。


    imxylz 2012-03-15 18:30 发表评论
    ]]>
    [深入浅出jetty 03]简单的restful入门http://www.blogjava.net/xylz/archive/2012/03/09/371598.htmlimxylzimxylzfri, 09 mar 2012 09:52:00 gmthttp://www.blogjava.net/xylz/archive/2012/03/09/371598.htmlhttp://www.blogjava.net/xylz/comments/371598.htmlhttp://www.blogjava.net/xylz/archive/2012/03/09/371598.html#feedback0http://www.blogjava.net/xylz/comments/commentrss/371598.htmlhttp://www.blogjava.net/xylz/services/trackbacks/371598.html
    项目地址: 

    文件列表


    包含如下文件:

    • git忽略文件
    • readme文件
    • pom文件
    • 一个简单的controller文件
    • 一个log4j的配置文件
    • 一个简单的spring mvc配置
    • 一个简单的web.xml

    maven配置

    为了能够方便从jetty:run来启动web容器,使用jetty的maven插件。
    需要特别注意的是,从jetty7.5.3开始就必须用maven 3了,以前使用的maven 2不能使用了,就为了这问题,我跟踪了很久,大囧。
    这里使用jetty最新的maven插件,同样会启动最新的jetty8.1.1 来测试。

        
            
                org.mortbay.jetty
                jetty-maven-plugin
                8.1.1.v20120215
            

        

    web.xml

    这是一个简单的web.xml配置,主要配置spring servlet。当然这里也辅助配置了一个log4j,方便查看日志输出,不配置也没关系。
    另外也没有使用servlet 3.0的配置。

    xml version="1.0" encoding="utf-8"?>
    <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
        xsi:schemalocation
    ="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
        version
    ="2.4">
        <display-name>jetty-rest-demodisplay-name>
        <context-param>
            <param-name>log4jconfiglocationparam-name>
            <param-value>classpath:log4j.propertiesparam-value>
        context-param>
        <listener>
            <listener-class>org.springframework.web.util.log4jconfiglistenerlistener-class>
        listener>
        <servlet>
            <servlet-name>dispatcherservlet-name>
            <servlet-class>org.springframework.web.servlet.dispatcherservletservlet-class>
            <load-on-startup>1load-on-startup>
        servlet>
        <servlet-mapping>
            <servlet-name>dispatcherservlet-name>
            <url-pattern>/*url-pattern>
        servlet-mapping>
    web-app>

    dispatcher-servlet.xml

    接下来是spring mvc的配置。
    包含三部分:要扫描的住解包,mvc注解驱动以及jsp的渲染映射(其实这个例子中没有用到)。
    xml version="1.0" encoding="utf-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
        xmlns:context
    ="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc"
        xsi:schemalocation
    ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
                http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd"
    >
        <context:component-scan base-package="info.imxylz.study.jetty.rest" />
        <mvc:annotation-driven />
        <bean class="org.springframework.web.servlet.view.internalresourceviewresolver">
            <property name="prefix" value="/web-inf/pages/">property>
            <property name="suffix" value=".jsp">property>
            <property name="viewclass" value="org.springframework.web.servlet.view.jstlview">property>
        bean>
    beans>

    controller

    下载开始写第一个controller,当然这个controller稍微有一点点别扭。
    直接返回字符串,另外将索引页映射到一个字符串上。(也不对中文进行处理)

    package info.imxylz.study.jetty.rest.controller;

    import org.springframework.stereotype.controller;
    import org.springframework.web.bind.annotation.pathvariable;
    import org.springframework.web.bind.annotation.requestmapping;
    import org.springframework.web.bind.annotation.responsebody;

    /**
     * a rest demo (spring 3.x)
     * 
     * 
    @author adyliu (imxylz@gmail.com)
     * 
    @since 2012-3-9
     
    */
    @controller
    public class democontroller {

        @responsebody
        @requestmapping("/index/{name}/")
        public string index(@pathvariable("name") string name) {
            return "welcome, "   name;
        }
        @responsebody
        @requestmapping("")
        public string index() {
            return "this is a rest demo";
        }
    }

    access

    现在该是打开浏览器显示下了。
    http://localhost:8080/index/ady/
    http://localhost:8080/index/ady liu/
    http://localhost:8080/

    好了,这算是一个最简单的入门例子了。
    下面的参考资源中有git的源码。

    resources

    • source code: git@github.com:adyliu/jetty-rest-demo.git (branch: v1.0-helloworld)
    • jetty maven plugin: 
    • spring mvc: 


    imxylz 2012-03-09 17:52 发表评论
    ]]>
    ice mini guidehttp://www.blogjava.net/xylz/archive/2012/02/29/370971.htmlimxylzimxylzwed, 29 feb 2012 02:44:00 gmthttp://www.blogjava.net/xylz/archive/2012/02/29/370971.htmlhttp://www.blogjava.net/xylz/comments/370971.htmlhttp://www.blogjava.net/xylz/archive/2012/02/29/370971.html#feedback0http://www.blogjava.net/xylz/comments/commentrss/370971.htmlhttp://www.blogjava.net/xylz/services/trackbacks/370971.htmlice中间件。

    ice作为一个异构平台,提供了高性能的rpc凯发天生赢家一触即发官网的解决方案。全年指定的架构计划中就是将现有的内部通讯方式迁移到ice 的组合方案中。
    我们尽可能的利用的配置管理,创建更透明的客户端代理,同时也是降低开发的难度。
    我们慢慢尝试,寻找更适合我们的分布式通讯中间件。

    下面的slide是一篇简短的入门介绍。目前为止,我们的开发还是仅限于java语言的服务端。以后视情况提供一些其它语言的服务端吧。
    view more from
    关键字:ice "the internet communications engine" rpc "protocol buffers"

    imxylz 2012-02-29 10:44 发表评论
    ]]>
    搜狐技术部长期招聘java工程师/高级工程师/初级架构师/项目经理/技术主管http://www.blogjava.net/xylz/archive/2012/02/16/366663.htmlimxylzimxylzthu, 16 feb 2012 03:10:00 gmthttp://www.blogjava.net/xylz/archive/2012/02/16/366663.htmlhttp://www.blogjava.net/xylz/comments/366663.htmlhttp://www.blogjava.net/xylz/archive/2012/02/16/366663.html#feedback10http://www.blogjava.net/xylz/comments/commentrss/366663.htmlhttp://www.blogjava.net/xylz/services/trackbacks/366663.html业务发展需要,对人才的渴望,对事业的追求,搜狐技术部需要一些高级人才。
    今年社招努力不再拘于形式,只要是人才,双方有意愿的,我们都努力去争取。

    北京地点:北京 五道口
    工作经验:不限,应届生都可以,我们有工作十年以上的人才,也需要这种人才。
    待遇方面:努力跟上物价的水平。常规在10k~30k。
    技术要求:以java语言为主,要求对基本的技术、概念、理论、框架都需要有一定的深度。根据经验,仅仅是靠忽悠和项目数量是不行的。
    产品要求:要求对主流的互联网产品都有认识,对用户体验有一定的理解。对于非应届生,我们更偏重于用互联网技术经验(不是企业web系统方面)。
    扩展要求:要求有gmail/twitter/stackoverflow/github帐号。有开源贡献的特别考虑。
    创新要求:能够掌握python/ruby/perl/erlang等一两种脚本语言为佳。
    工作领域:我们有挑战的领域有大规模数据集群、高性能异步通讯、海量数据处理、分布式存储与缓存、并行计算、高并发处理等。


    我们欢迎有志向于互联网的同学加入。技术要求不高,但要有思想、有深度、热爱互联网。
    有兴趣发送简历到:已过期


    我们长期招聘这类人才,只要是人才,我们都愿意提供相适应的环境。
    另外,也非常需要一个前端主管,负责管理整个团队的前端技术人才和基础架构。
    【最后更新时间:2012/11/01】



    imxylz 2012-02-16 11:10 发表评论
    ]]>
    spring framework 3.1 reference chmhttp://www.blogjava.net/xylz/archive/2012/02/08/369608.htmlimxylzimxylzwed, 08 feb 2012 08:41:00 gmthttp://www.blogjava.net/xylz/archive/2012/02/08/369608.htmlhttp://www.blogjava.net/xylz/comments/369608.htmlhttp://www.blogjava.net/xylz/archive/2012/02/08/369608.html#feedback1http://www.blogjava.net/xylz/comments/commentrss/369608.htmlhttp://www.blogjava.net/xylz/services/trackbacks/369608.html
    去掉了发生错误的javascript(网络原因,你懂的),索引排序重命名,稍微排版了下。

    没有改动任何内容。毫无疑问,这是英文版的,因为没有人翻译。

    截图如下。





    imxylz 2012-02-08 16:41 发表评论
    ]]>
    [深入浅出jetty 02] jetty 8.x 简单试用http://www.blogjava.net/xylz/archive/2012/01/29/368970.htmlimxylzimxylzsun, 29 jan 2012 08:41:00 gmthttp://www.blogjava.net/xylz/archive/2012/01/29/368970.htmlhttp://www.blogjava.net/xylz/comments/368970.htmlhttp://www.blogjava.net/xylz/archive/2012/01/29/368970.html#feedback4http://www.blogjava.net/xylz/comments/commentrss/368970.htmlhttp://www.blogjava.net/xylz/services/trackbacks/368970.htmljetty 8.x 简单试用

    运行

    安装好了以后,在jetty的主目录下,运行起来。

    java -jar start.jar 

    如果仔细看的话还有一个start.ini,这是典型的eclipse启动方式。事实上jetty8是按照eclipse的osgi启动模型来运行的。

    远程访问

    默认情况下jetty使用8080端口,访问下看看。

    http://adyliu-pc:8080 

    出现了点问题。启动后居然是jetty7后的描述信息。看来jetty8发布的时候比较粗糙,这些细节都没有处理好。事实上,官方站点上的文章都是和jetty7.x有关的,没有更新到8.x版本。

    好在有一行提示说,如果要远程访问的话,需要开启一个设置。好吧,按照说明,将默认test.war的远程访问模式打开。 修改文件$jetty_home/contexts/test.d/override-web.xml中的如下部分

      <filter>
        <filter-name>testfilterfilter-name>
        <filter-class>com.acme.testfilterfilter-class>
        <init-param>
          <param-name>remoteparam-name>
          <param-value>trueparam-value>
        init-param>
      filter>


    这里已经将默认remote的属性值false改为了true。然后再试试。


    显然,这样就已经支持远程访问了。

    servlet访问

    test.war模块里面有一个dump的servlet,它可以查看当前请求的request/session/cookie信息。我们简单看一下request请求。

    这里面的信息非常丰富,这为以后调试当前请求信息提供了很方便的样例。

    comet模型

    jetty8.x里面有两种comet模型,一种是常见的长连接(long polling), 另一种就是html5支持的websocket模型。

    我们先来简单看一下long polling模型。在这种方式下,浏览器定时发起一个长连接,等待服务器返回。一次请求完了以后仍然会发起一个新的请求,总是有一个连接保持双方的通讯。 下图描述了此效果。

    而websocket模型显然不是所有浏览器都支持的。高版本的chrome就支持,比如我的chrome 18.0的开发版本就能很好的支持websocket。

    有意思的是,这里的请求头和响应头有一些特殊的标识。以后涉及到websocket的时候再来研究。

    经测试,我机器上的chrome 18.0,firefox 8.0都支持websocket的,而ie9仍然不支持。




    imxylz 2012-01-29 16:41 发表评论
    ]]>
    [深入浅出jetty 01] jetty 8.x 安装http://www.blogjava.net/xylz/archive/2012/01/29/368969.htmlimxylzimxylzsun, 29 jan 2012 08:34:00 gmthttp://www.blogjava.net/xylz/archive/2012/01/29/368969.htmlhttp://www.blogjava.net/xylz/comments/368969.htmlhttp://www.blogjava.net/xylz/archive/2012/01/29/368969.html#feedback0http://www.blogjava.net/xylz/comments/commentrss/368969.htmlhttp://www.blogjava.net/xylz/services/trackbacks/368969.htmljetty从7.x已经迁移到eclipse下了,从eclipse的下载目录开始安装吧。

    最新的发布版本是8.1.0.v20120127,我们从这个版本开始。

    jetty_version=8.1.0.v20120127
    wget http://download.eclipse.org/jetty/$jetty_version/dist/jetty-distribution-$jetty_version.tar.gz
    tar xfz jetty-distribution-$jetty_version.tar.gz
    cd jetty-distribution-$jetty_version
    java -jar start.jar

    附录

    • 下载地址:
    • 更多下载安装方式:


    imxylz 2012-01-29 16:34 发表评论
    ]]>
    深入浅出 java concurrency (40): 并发总结 part 4 性能与伸缩性http://www.blogjava.net/xylz/archive/2011/12/31/367641.htmlimxylzimxylzsat, 31 dec 2011 06:13:00 gmthttp://www.blogjava.net/xylz/archive/2011/12/31/367641.htmlhttp://www.blogjava.net/xylz/comments/367641.htmlhttp://www.blogjava.net/xylz/archive/2011/12/31/367641.html#feedback5http://www.blogjava.net/xylz/comments/commentrss/367641.htmlhttp://www.blogjava.net/xylz/services/trackbacks/367641.html性能与伸缩性

    使用线程的一种说法是为了提高性能。多线程可以使程序充分利用闲置的资源,提高资源的利用率,同时能够并行处理任务,提高系统的响应性。 但是很显然,引入线程的同时也引入了系统的复杂性。另外系统的性能并不是总是随着线程数的增加而总是提高。

    性能与伸缩性

    性能的提升通常意味着可以用更少的资源做更多的事情。这里资源是包括我们常说的cpu周期、内存、网络带宽、磁盘io、数据库、web服务等等。 引入多线程可以充分利用多核的优势,充分利用io阻塞带来的延迟,也可以降低网络开销带来的影响,从而提高单位时间内的响应效率。

    为了提高性能,需要有效的利用我们现有的处理资源,同时也要开拓新的可用资源。例如,对于cpu而言,理想状况下希望cpu能够满负荷工作。当然这里满负荷工作是指做有用的事情,而不是无谓的死循环或者等待。受限于cpu的计算能力,如果cpu达到了极限,那么很显然我们充分利用了计算能力。对于io而言(内存、磁盘、网络等),如果达到了其对于的带宽,这些资源的利用率也就上去了。理想状况下所有资源的能力都被用完了,那么这个系统的性能达到了最大值。

    为了衡量系统的性能,有一些指标用于定性、定量的分析。例如服务时间、等待时间、吞吐量、效率、可伸缩性、生成量等等。服务时间、等待时间等用于衡量系统的效率,即到底有多快。吞吐量、生成量等用于衡量系统的容量,即能够处理多少数据。除此之外,有效服务时间、中断时间等用于能力系统的可靠性和稳定性等。

    可伸缩性的意思是指增加计算资源,吞吐量和生产量相应得到的改进。 从算法的角度讲,通常用复杂度来衡量其对应的性能。例如时间复杂度、空间复杂度等。

    amdahl定律

    并行的任务增加资源显然能够提高性能,但是如果是串行的任务,增加资源并不一定能够得到合理的性能提升。 描述的在一个系统中,增加处理器资源对系统行的提升比率。 假定在一个系统中,f是必须串行化执行的比重,n是处理器资源,那么随着n的增加最多增加的加速比:

    理论上,当n趋近于无穷大时,加速比最大值无限趋近于1/f。 这意味着如果一个程序的串行化比重为50%,那么并行化后最大加速比为2倍。

    加速比除了可以用于加速的比率外,也可以用于衡量cpu资源的利用率。如果每一个cpu的资源利用率为100%,那么cpu的资源每次翻倍时,加速比也应该翻倍。 事实上,在拥有10个处理器的系统中,程序如果有10%是串行化的,那么最多可以加速1/(0.1 (1-0.1)/10)=5.3倍,换句话说cpu的利用率只用5.3/10=53%。而如果处理器增加到100倍,那么加速比为9.2倍,也就是说cpu的利用率只有个9.3%。

    显然增加cpu的数量并不能提高cpu的利用率。下图描述的是随着cpu的数量增加,不同串行化比重的系统的加速比。

    很显然,串行比重越大,增加cpu资源的效果越不明显。

    性能提升

    性能的提升可以从以下几个方面入手。

    系统平台的资源利用率

    一个程序对系统平台的资源利用率是指某一个设备繁忙且服务于此程序的时间占所有时间的比率。从物理学的角度讲类似于有用功的比率。简单的说就是:资源利用率=有效繁忙时间/总耗费时间。

    也就说尽可能的让设备做有用的功,同时榨取其最大值。无用的循环可能会导致cpu 100%的使用率,但不一定是有效的工作。有效性通常难以衡量,通常只能以主观来评估,或者通过被优化的程序的行为来判断是否提高了有效性。

    延迟

    延迟描述的是完成任务所耗费的时间。延迟有时候也成为响应时间。如果有多个并行的操作,那么延迟取决于耗费时间最大的任务。

    多处理

    多处理是指在单一系统上同时执行多个进程或者多个程序的能力。多处理能力的好处是可以提高吞吐量。多处理可以有效利用多核cpu的资源。

    多线程

    多线程描述的是同一个地址空间内同时执行多个线程的过程。这些线程都有不同的执行路径和不同的栈结构。我们说的并发性更多的是指针对线程。

    并发性

    同时执行多个程序或者任务称之为并发。单程序内的多任务处理或者多程序间的多任务处理都认为是并发。

    吞吐量

    吞吐量衡量系统在单位之间内可以完成的工作总量。对于硬件系统而言,吞吐量是物理介质的上限。在没有达到物理介质之前,提高系统的吞吐量也可以大幅度改进性能。同时吞吐量也是衡量性能的一个指标。

    瓶颈

    程序运行过程中性能最差的地方。通常而言,串行的io、磁盘io、内存单元分配、网络io等都可能造成瓶颈。某些使用太频繁的算法也有可能成为瓶颈。

    可扩展性

    这里的可扩展性主要是指程序或系统通过增加可使用的资源而增加性能的能力。

    线程开销

    假设引入的多线程都用于计算,那么性能一定会有很大的提升么? 其实引入多线程以后也会引入更多的开销。

    切换上下文

    如果可运行的线程数大于cpu的内核数,那么os会根据一定的调度算法,强行切换正在运行的线程,从而使其它线程能够使用cpu周期。

    切换线程会导致上下文切换。线程的调度会导致cpu需要在操作系统和进程间花费更多的时间片段,这样真正执行应用程序的时间就减少了。另外上下文切换也会导致缓存的频繁进出,对于一个刚被切换的线程来说,可能由于高速缓冲中没有数据而变得更慢,从而导致更多的io开销。

    内存同步

    不同线程间要进行数据同步,synchronized以及volatile提供的可见性都会导致缓存失效。线程栈之间的数据要和主存进行同步,这些同步有一些小小的开销。如果线程间同时要进行数据同步,那么这些同步的线程可能都会受阻。

    阻塞

    当发生锁竞争时,失败的线程会导致阻塞。通常阻塞的线程可能在jvm内部进行自旋等待,或者被操作系统挂起。自旋等待可能会导致更多的cpu切片浪费,而操作系统挂起则会导致更多的上下文切换。

    了解了性能的提升的几个方面,也了解性能的开销后,应用程序就要根据实际的场景进行取舍和评估。没有一劳永逸的优化方案,不断的进行小范围改进和调整是提高性能的有效手段。当前一些大的架构调整也会导致较大的性能的提升。

    简单的原则是在保证逻辑正确的情况小,找到性能瓶颈,小步改进和优化。

    参考资料

    • amdahl's law: 
    • gustafson's law: 
    • sun-ni law: 
    • 多核系统中三种典型锁竞争的加速比分析 
    • 阿姆达尔定律和gustafson定律的等价性 

     



    imxylz 2011-12-31 14:13 发表评论
    ]]>
    深入浅出 java concurrency (39): 并发总结 part 3 常见的并发陷阱http://www.blogjava.net/xylz/archive/2011/12/30/367592.htmlimxylzimxylzfri, 30 dec 2011 09:25:00 gmthttp://www.blogjava.net/xylz/archive/2011/12/30/367592.htmlhttp://www.blogjava.net/xylz/comments/367592.htmlhttp://www.blogjava.net/xylz/archive/2011/12/30/367592.html#feedback0http://www.blogjava.net/xylz/comments/commentrss/367592.htmlhttp://www.blogjava.net/xylz/services/trackbacks/367592.html常见的并发陷阱

    volatile

    volatile只能强调数据的可见性,并不能保证原子操作和线程安全,因此volatile不是万能的。参考指令重排序

    volatile最常见于下面两种场景。

    a. 循环检测机制

    volatile boolean done = false;


        while( ! done ){
            dosomething();
        }


    b. 单例模型 (http://www.blogjava.net/xylz/archive/2009/12/18/306622.html)

    public class doublelocksingleton {

        
    private static volatile doublelocksingleton instance = null;

        
    private doublelocksingleton() {
        }

        
    public static doublelocksingleton getinstance() {
            
    if (instance == null) {
                
    synchronized (doublelocksingleton.class) {
                    
    if (instance == null) {
                        instance 
    = new doublelocksingleton();
                    }
                }
            }
            
    return instance;
        }
    }

     


    synchronized/lock

    看起来lock有更好的性能以及更灵活的控制,是否完全可以替换synchronized?

    锁的一些其它问题中说过,synchronized的性能随着jdk版本的升级会越来越高,而lock优化的空间受限于cpu的性能,很有限。另外jdk内部的工具(线程转储)对synchronized是有一些支持的(方便发现死锁等),而对lock是没有任何支持的。

    也就说简单的逻辑使用synchronized完全没有问题,随着机器的性能的提高,这点开销是可以忽略的。而且从代码结构上讲是更简单的。简单就是美。

    对于复杂的逻辑,如果涉及到读写锁、条件变量、更高的吞吐量以及更灵活、动态的用法,那么就可以考虑使用lock。当然这里尤其需要注意lock的正确用法。

    lock lock = 
    lock.lock();
    try{
        //do something
    }finally{
        lock.unlock();
    }


    一定要将lock的释放放入finally块中,否则一旦发生异常或者逻辑跳转,很有可能会导致锁没有释放,从而发生死锁。而且这种死锁是难以排查的。

    如果需要synchronized无法做到的尝试锁机制,或者说担心发生死锁无法自恢复,那么使用trylock()是一个比较明智的选择的。

    lock lock = 
    if(lock.trylock()){
        try{
            //do something
        }finally{
            lock.unlock();
        }
    }

     

    甚至可以使用获取锁一段时间内超时的机制lock.trylock(long,timeunit)。 锁的使用可以参考前面文章的描述和建议。

    锁的边界

    一个流行的错误是这样的。

    concurrentmap map = new concurrenthashmap();

    if(!map.containskey(key)){
        map.put(key,value);
    }


    看起来很合理的,对于一个线程安全的map实现,要存取一个不重复的结果,先检测是否存在然后加入。 其实我们知道两个原子操作和在一起的指令序列不代表就是线程安全的。 割裂的多个原子操作放在一起在多线程的情况下就有可能发生错误。

    实际上concurrentmap提供了putifabsent(k, v)的“原子操作”机制,这等价于下面的逻辑:

    if(map.containskey(key)){
        return map.get(key);
    }else{
        return map.put(k,v);
    }


    除了putifabsent还有replace(k, v)以及replace(k, v, v)两种机制来完成组合的操作。

    提到map,这里有一篇谈hashmap读写并发的问题。

    构造函数启动线程

    下面的实例是在构造函数中启动一个线程。

    public class runner{
       int x,y;
       thread thread;
       public runner(){
          this.x=1;
          this.y=2;
          this.thread=new mythread();
          this.thread.start();
       }
    }


    这里可能存在的陷阱是如果此类被继承,那么启动的线程可能无法正确读取子类的初始化操作。

    因此一个简单的原则是,禁止在构造函数中启动线程,可以考虑但是提供一个方法来启动线程。如果非要这么做,最好将类设置为final,禁止继承。

    丢失通知的问题

    这篇文章里面提到过notify丢失通知的问题。

    对于wait/notify/notifyall以及await/singal/singalall,如果不确定到底是否能够正确的收到消息,担心丢失通知,简单一点就是总是通知所有。

    如果担心只收到一次消息,使用循环一直监听是不错的选择。

    非常主用性能的系统,可能就需要区分到底是通知单个还是通知所有的挂起者。

    线程数

    并不是线程数越多越好,在下一篇文章里面会具体了解下性能和可伸缩性。 简单的说,线程数多少没有一个固定的结论,受限于cpu的内核数,io的性能以及依赖的服务等等。因此选择一个合适的线程数有助于提高吞吐量。

    对于cpu密集型应用,线程数和cpu的内核数一致有助于提高吞吐量,所有cpu都很繁忙,效率就很高。 对于io密集型应用,线程数受限于io的性能,某些时候单线程可能比多线程效率更高。但通常情况下适当提高线程数,有利于提高网络io的效率,因为我们总是认为网络io的效率比较低。

    对于线程池而言,选择合适的线程数以及任务队列是提高线程池效率的手段。

    public threadpoolexecutor(
        int corepoolsize,
        int maximumpoolsize,
        long keepalivetime,
        timeunit unit,
        blockingqueue workqueue,
        threadfactory threadfactory,
        rejectedexecutionhandler handler)

     


    对于线程池来说,如果任务总是有积压,那么可以适当提高corepoolsize大小;如果机器负载较低,那么可以适当提高maximumpoolsize的大小;任务队列不长的情况下减小keepalivetime的时间有助于降低负载;另外任务队列的长度以及任务队列的拒绝策略也会对任务的处理有一些影响。

     



    imxylz 2011-12-30 17:25 发表评论
    ]]>
    深入浅出 java concurrency (38): 并发总结 part 2 常见的并发场景http://www.blogjava.net/xylz/archive/2011/12/29/367480.htmlimxylzimxylzthu, 29 dec 2011 08:31:00 gmthttp://www.blogjava.net/xylz/archive/2011/12/29/367480.htmlhttp://www.blogjava.net/xylz/comments/367480.htmlhttp://www.blogjava.net/xylz/archive/2011/12/29/367480.html#feedback0http://www.blogjava.net/xylz/comments/commentrss/367480.htmlhttp://www.blogjava.net/xylz/services/trackbacks/367480.html
    并发最常见用于线程池,显然使用线程池可以有效的提高吞吐量。
    最常见、比较复杂一个场景是web容器的线程池。web容器使用线程池同步或者异步处理http请求,同时这也可以有效的复用http连接,降低资源申请的开销。通常我们认为http请求时非常昂贵的,并且也是比较耗费资源和性能的,所以线程池在这里就扮演了非常重要的角色。
    在线程池的章节中非常详细的讨论了线程池的原理和使用,同时也提到了,线程池的配置和参数对性能的影响是巨大的。不尽如此,受限于资源(机器的性能、网络的带宽等等)、依赖的服务,客户端的响应速度等,线程池的威力也不会一直增长。达到了线程池的瓶颈后,性能和吞吐量都会大幅度降低。
    一直增加机器的性能或者增大线程的个数,并不一定能有效的提高吞吐量。高并发的情况下,机器的负载会大幅提升,这时候机器的稳定性、服务的可靠性都会下降。
    尽管如此,线程池依然是提高吞吐量的一个有效措施,配合合适的参数能够有效的充分利用资源,提高资源的利用率。  阅读全文

    imxylz 2011-12-29 16:31 发表评论
    ]]>
    深入浅出 java concurrency (37): 并发总结 part 1 死锁与活跃度http://www.blogjava.net/xylz/archive/2011/12/29/365149.htmlimxylzimxylzthu, 29 dec 2011 06:04:00 gmthttp://www.blogjava.net/xylz/archive/2011/12/29/365149.htmlhttp://www.blogjava.net/xylz/comments/365149.htmlhttp://www.blogjava.net/xylz/archive/2011/12/29/365149.html#feedback2http://www.blogjava.net/xylz/comments/commentrss/365149.htmlhttp://www.blogjava.net/xylz/services/trackbacks/365149.html
    前面谈了很多并发的特性和工具,但是大部分都是和锁有关的。我们使用锁来保证线程安全,但是这也会引起一些问题。
    锁顺序死锁(lock-ordering deadlock):多个线程试图通过不同的顺序获得多个相同的资源,则发生的循环锁依赖现象。
    动态的锁顺序死锁(dynamic lock order deadlocks):多个线程通过传递不同的锁造成的锁顺序死锁问题。
    资源死锁(resource deadlocks):线程间相互等待对方持有的锁,并且谁都不会释放自己持有的锁发生的死锁。也就是说当现场持有和等待的目标成为资源,就有可能发生此死锁。这和锁顺序死锁不一样的地方是,竞争的资源之间并没有严格先后顺序,仅仅是相互依赖而已。  阅读全文

    imxylz 2011-12-29 14:04 发表评论
    ]]>
    编程语言大战http://www.blogjava.net/xylz/archive/2011/12/06/365658.htmlimxylzimxylztue, 06 dec 2011 03:25:00 gmthttp://www.blogjava.net/xylz/archive/2011/12/06/365658.htmlhttp://www.blogjava.net/xylz/comments/365658.htmlhttp://www.blogjava.net/xylz/archive/2011/12/06/365658.html#feedback8http://www.blogjava.net/xylz/comments/commentrss/365658.htmlhttp://www.blogjava.net/xylz/services/trackbacks/365658.html


    非常令人吃惊的是c 语言依然不够坚挺,由于windows 7/windows 8的发力,c#很快就会抢占c 的市场,估计很快就会将c 从前三名中挤下去。



    iphone/ipad的热销让object c继续火热,前十的位置还是可以持续很久的,这一点毋庸置疑。移动设备开发的高端人才现在是高薪难求,如果有时间我也要继续关注下。  阅读全文

    imxylz 2011-12-06 11:25 发表评论
    ]]>
    处理zookeeper的session过期问题http://www.blogjava.net/xylz/archive/2011/12/05/365578.htmlimxylzimxylzmon, 05 dec 2011 05:57:00 gmthttp://www.blogjava.net/xylz/archive/2011/12/05/365578.htmlhttp://www.blogjava.net/xylz/comments/365578.htmlhttp://www.blogjava.net/xylz/archive/2011/12/05/365578.html#feedback8http://www.blogjava.net/xylz/comments/commentrss/365578.htmlhttp://www.blogjava.net/xylz/services/trackbacks/365578.htmlsession失效问题

    通常客户端主动关闭连接认为是一次session失效。另外也有可能因为其它未知原因,例如网络超时导致的session失效问题。在服务端看来,无法区分session失效是何种情况,一次一旦发生session失效,一定时间后就会将session持有的所有watcher以及瞬时节点删除。
    而对于zookeeper客户端而言,一旦发生失效不知道是否该重连,这涉及到watcher和瞬时节点问题,因此zookeeper客户端认为,一旦发生了seesion失效,那么就认为客户端死掉了。从而所有操作都不能够进行。参考 how should i handle session  阅读全文

    imxylz 2011-12-05 13:57 发表评论
    ]]>
    redis 2.2.x 升级到2.4.xhttp://www.blogjava.net/xylz/archive/2011/11/21/364457.htmlimxylzimxylzmon, 21 nov 2011 08:48:00 gmthttp://www.blogjava.net/xylz/archive/2011/11/21/364457.htmlhttp://www.blogjava.net/xylz/comments/364457.htmlhttp://www.blogjava.net/xylz/archive/2011/11/21/364457.html#feedback1http://www.blogjava.net/xylz/comments/commentrss/364457.htmlhttp://www.blogjava.net/xylz/services/trackbacks/364457.html

    有人说redis的作者是一个勤奋的人,深表同意!


    本来升级是为了增加批量操作从而提高性能,没想到内存占用节省了很多。

    对于32位的操作系统而言,节省内存62%,对于64位操作系统而言节省73%。非常可观。  阅读全文

    imxylz 2011-11-21 16:48 发表评论
    ]]>
    兑现http://www.blogjava.net/xylz/archive/2011/10/10/360915.htmlimxylzimxylzmon, 10 oct 2011 14:44:00 gmthttp://www.blogjava.net/xylz/archive/2011/10/10/360915.htmlhttp://www.blogjava.net/xylz/comments/360915.htmlhttp://www.blogjava.net/xylz/archive/2011/10/10/360915.html#feedback3http://www.blogjava.net/xylz/comments/commentrss/360915.htmlhttp://www.blogjava.net/xylz/services/trackbacks/360915.html

    我承认写技术博客是一件特别辛苦和痛苦的事情。


    写一篇技术博客需要大量的技术储备,同时自动亲自动手去实践,证实想表示的,发现要回避的问题,还需要将自己体验的过程记录下来,以便后来人能够避免类似的问题。


    而这一切显然不是写一篇杂记或者转载一篇文章那么容易。


    两年前写一个技术专题,断断续续写了两年,到今天依然没有完成。每次总是希望自己能够很认真、很努力的完成,甚至都有答应网友尽快完成的冲动。可是真正开始时才发现我的注意力明显没有当初那么集中了。


    而我现在更喜欢更新那种wiki式的技术判断,作为点滴的积累。没有压力,没有负担,随心随意。


    也许需要更多的兴趣和毅力才能坚持下去,不管怎么说,今年还是希望能够有更多的技术文章出来,两年前的承诺也应该勇敢的兑现。



    imxylz 2011-10-10 22:44 发表评论
    ]]>
    ganglia安装指南 (基于centos 5.6)http://www.blogjava.net/xylz/archive/2011/07/21/354744.htmlimxylzimxylzwed, 20 jul 2011 16:34:00 gmthttp://www.blogjava.net/xylz/archive/2011/07/21/354744.htmlhttp://www.blogjava.net/xylz/comments/354744.htmlhttp://www.blogjava.net/xylz/archive/2011/07/21/354744.html#feedback7http://www.blogjava.net/xylz/comments/commentrss/354744.htmlhttp://www.blogjava.net/xylz/services/trackbacks/354744.html

    ganglia安装指南 (基于centos 5.6)

    安装依赖

    rpm -ivh http://mirrors.sohu.com/centos/5/os/x86_64/centos/zlib-devel-1.2.3-3.x86_64.rpm
    rpm -ivh http://mirrors.sohu.com/centos/5/os/x86_64/centos/freetype-devel-2.2.1-28.el5_5.1.x86_64.rpm
    rpm -ivh http://mirrors.sohu.com/centos/5/os/x86_64/centos/libart_lgpl-devel-2.3.17-4.x86_64.rpm
    rpm -ivh http://mirrors.sohu.com/centos/5/os/x86_64/centos/libpng-devel-1.2.10-7.1.el5_5.3.x86_64.rpm
    

    如果上述安装失败,可能需要安装以下库依赖

    yum install zlib freetype libart_lgpl libpng
    

    安装rrdtools

    http://oss.oetiker.ch/rrdtool/pub/rrdtool-1.2.27.tar.gz
    tar zxvf rrdtool-1.2.27.tar
    cd rrdtool-1.2.27
    ./configure --prefix=/usr/local/rrdtool
    make
    make install
    

    执行下命令,看是否安装成功

    /usr/local/rrdtool/bin/rrdtool
    

    安装expat依赖

    http://downloads.sourceforge.net/project/expat/expat/2.0.1/expat-2.0.1.tar.gz?use_mirror=cdnetworks-kr-2
    tar zxvf expat-2.0.1.tar.gz
    ./configure --prefix=/usr/local/expat
    make
    make install
    

    对于64位操作系统,需要手动的拷贝下动态链接库到lib64下

    mkdir /usr/local/expat/lib64
    cp -a /usr/local/expat/lib/* /usr/local/expat/lib64/
    

    安装apr以及apr-util

    http://labs.renren.com/apache-mirror/apr/apr-1.4.5.tar.gz
    tar xvjf apr-1.3.2.tar.bz2
    ./configure --prefix=/usr/local/apr
    make
    make install
    
    http://labs.renren.com/apache-mirror/apr/apr-util-1.3.12.tar.gz
    tar xvjf apr-util-1.3.2.tar.bz2
    ./configure --with-apr=/usr/local/apr --with-expat=/usr/local/expat
    make
    make install
    

    同样64位机器需要拷贝动态链接库

    /bin/cp -f /usr/local/apr/include/apr-1/* /usr/local/apr/include/
    mkdir -p /usr/local/apr/lib64
    /bin/cp -a -f /usr/local/apr/lib/* /usr/local/apr/lib64/
    

    安装confuse

    http://download.savannah.gnu.org/releases/confuse/confuse-2.7.tar.gz
    tar zxvf confuse-2.6.tar.gz
    ./configure cflags=-fpic --disable-nls --prefix=/usr/local/confuse
    make
    make install
    

    拷贝动态链接库

    mkdir -p /usr/local/confuse/lib64
    /bin/cp -a -f /usr/local/confuse/lib/* /usr/local/confuse/lib64/
    

    安装ganglia

    现在才是安装ganglia的开始,如果提示需要pcre的话,安装下 yum install pcre 下载ganglia-3.2.0,解压,安装

    ./configure --prefix=/usr/local/ganglia --with-librrd=/usr/local/rrdtool --with-libapr=/usr/local/apr --with-libexpat=/usr/local/expat \
    --with-libconfuse=/usr/local/confuse --with-gmetad --enable-gexec --enable-status --sysconfdir=/etc/ganglia
    make
    make install
    

    服务端配置

    创建rrdtool数据目录,看$ganglia-3.2.0/web/conf.php里面的gmetad_root变量,并根据apache的运行用户创建权限,例如apache运行于apache用户上 。

    mkdir -p /var/lib/ganglia/rrds
    mkdir -p /var/lib/ganglia/dwoo
    chown -r apache;apache /var/lib/ganglia
    

    配置一个数据源,修改/etc/ganglia/gmetad.conf文件,同时将运行用户设置为rrdtool的目录权限用户,例如apache用户

    data_source "suc" localhost
    setuid_username "apache"
    

    其中suc是数据源的名称,客户端分组会依赖此名称,后面会提到。 添加自启动脚本

    /bin/cp -f gmetad/gmetad.init /etc/init.d/gmetad
    /bin/cp -f /usr/local/ganglia/sbin/gmetad /usr/sbin/gmetad
    chkconfig -add gmetad
    

    启动gmetad服务

    service gmetad start
    

    看见starting ganglia gmetad: [ ok ]就代表运行正常了。

    客户端配置(gmond节点)

    本机安装如下:

    /bin/cp -f gmond/gmond.init /etc/init.d/gmond
    /bin/cp -f /usr/local/ganglia/sbin/gmond/usr/sbin/gmond
    chkconfig -add gmond
    gmond --default_config > /etc/ganglia/gmond.conf
    

    对于生成的默认配置文件需要做适当的修改

    cluster {
    name="suc"
    owner="apache"
    latlong="unspecified"
    url="unspecified"
    }
    

    其中name是将要在服务端进行的分组,是服务端的数据源。接下来开启服务

    service gmond start
    

    看见starting ganglia gmetad: [ ok ]代表启动成功。如果有失败,可以讲gmond.conf中的debug有0改为100,看更多的日志,然后进行排查。

    globals {
    daemonize = yes
    setuid = yes
    user = nobody
    debug_level = 100
    }
    

    非本机客户端配置需要安装服务端安装一样进行配置,运行,非常麻烦,这里使用本机安装好的文件进行安装。 使用下面的脚本进行安装deploy-ganglia.sh

    i=$1
    scp /usr/sbin/gmond $i:/usr/sbin/gmond
    ssh $i mkdir -p /etc/ganglia/
    ssh $i mkdir -p /usr/local/ganglia/lib64
    ssh $i mkdir -p /usr/local/expat/lib
    scp /etc/ganglia/gmond.conf $i:/etc/ganglia/
    scp /etc/init.d/gmond $i:/etc/init.d/
    scp -r /usr/local/ganglia/lib64/* $i:/usr/local/ganglia/lib64/
    scp /usr/local/expat/lib/libexpat.so.1 $i:/usr/local/expat/lib/libexpat.so.1
    scp /usr/lib64/libapr-1.so.0 $i:/usr/lib64/
    

    实际上就是将本机安装好(编译好)的动态链接库拷贝到其它机器上,使用如下命令拷贝即可

    sh deploy-ganglia.sh 10.1.11.2
    

    服务端的web配置

    php程序需要依赖apache来运行,因此需要安装如下依赖

    yum install php-common php-cli php php-gd httpd
    

    安装web程序,这里假定apache的root路径在/var/www/html下面。

    mkdir /var/www/html/ganglia
    cp -a -f ganglia-3.2.0/web/* /var/www/html/ganglia
    

    禁用selinux setenforce 0 修改rrdtool的路径,文件/var/www/html/ganglia/conf.php中的rrdtool

    define("rrdtool", "/usr/local/rrdtool/bin/rrdtool");
    

    重启httpd服务器即可看到效果 service httpd restart

    更多参考 http://www.imxylz.info/wiki/ganglia/ganglia


    imxylz 2011-07-21 00:34 发表评论
    ]]>
    深入浅出 java concurrency (36): 线程池 part 9 并发操作异常体系http://www.blogjava.net/xylz/archive/2011/07/12/354206.htmlimxylzimxylztue, 12 jul 2011 15:15:00 gmthttp://www.blogjava.net/xylz/archive/2011/07/12/354206.htmlhttp://www.blogjava.net/xylz/comments/354206.htmlhttp://www.blogjava.net/xylz/archive/2011/07/12/354206.html#feedback3http://www.blogjava.net/xylz/comments/commentrss/354206.htmlhttp://www.blogjava.net/xylz/services/trackbacks/354206.html并发包引入的工具类很多方法都会抛出一定的异常,这些异常描述了任务在线程池中执行时发生的例外情况,而通常这些例外需要应用程序进行捕捉和处理。

    例如在future接口中有如下一个api:

     

    java.util.concurrent.future.get(long, timeunit) throws interruptedexception, executionexception, timeoutexception;

     

    前面的章节中描述了future类的具体实现原理。这里不再讨论,但是比较好奇的抛出的三个异常。

    这里有一篇文章()描述了interruptedexception的来源和处理方式。简单的说就是线程在执行的过程中被自己或者别人中断了。这时候为了响应中断就需要处理当前的异常。

    对于java.lang.thread而言,interruptedexception也是一个很诡异的问题。

    中断一个线程thread.interrupt()时会触发下面一种情况:

    如果线程在调用 object 类的 wait()、wait(long) 或 wait(long, int) 方法,或者该类的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法过程中受阻,则其中断状态将被清除,它还将收到一个 interruptedexception。

    检测一个线程的中断状态描述是这样的thread.interrupted():

    测试当前线程是否已经中断。线程的中断状态 由该方法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回 false(在第一次调用已清除了其中断状态之后,且第二次调用检验完中断状态前,当前线程再次中断的情况除外)。 

    也就是说如果检测到一个线程已经被中断了,那么线程的使用方(挂起、等待或者正在执行)都将应该得到一个中断异常,同时将会清除异常中断状态。

     

    v innerget(long nanostimeout) throws interruptedexception, executionexception, timeoutexception {
        
    if (!tryacquiresharednanos(0, nanostimeout))
            
    throw new timeoutexception();
        
    if (getstate() == cancelled)
            
    throw new cancellationexception();
        
    if (exception != null)
            
    throw new executionexception(exception);
        
    return result;
    }

     

    上面获取任务结果的方法实现中,将在获取锁的过程中得到一个中断异常。代码java.util.concurrent.locks.abstractqueuedsynchronizer.tryacquiresharednanos(int, long)描述了这种情况:

        public final boolean tryacquiresharednanos(int arg, long nanostimeout) throws interruptedexception {
        
    if (thread.interrupted())
            
    throw new interruptedexception();
        
    return tryacquireshared(arg) >= 0 ||
            doacquiresharednanos(arg, nanostimeout);
        }

     


    这里在获取锁的时候检测线程中断情况,如果被中断则清除中断位,同时抛出一个中断异常。为什么如此做?因为我们的线程在线程池中是被重复执行的,所以一旦线程被中断后并不会退出线程,而是设置中断位,等候任务队列自己处理线程,从而达到线程被重复利用的目的。有兴趣的可以参考代码java.util.concurrent.threadpoolexecutor.worker.runtask(runnable)。这里在关闭线程池时就会导致中断所有线程。

    除了interruptedexception 异常我们还发现了一个全新的异常java.util.concurrent.timeoutexception,此异常是用来描述任务执行时间超过了期望等待时间,也许是一直没有获取到锁,也许是还没有执行完成。

    在innerget代码片段中我们看到,如果线程在指定的时间无法获取到锁,那么就会得到一个超时异常。这个很好理解,比如如果执行一个非常耗时的网络任务,我们不希望任务一直等待从而占用大量的资源,可能在一定时间后就会希望取消此操作。此时超时异常很好的描述了这种需求。

    与此同时,如果取消了一个任务,那么再次从任务中获取执行结果,那么将会得到一个任务被取消的异常java.util.concurrent.cancellationexception。

    除了上述异常外,还将得到一个java.util.concurrent.executionexception异常,

    这是因为我们的提交的任务java.util.concurrent.callable在call()方法中允许抛出任何异常,另外常规的线程执行也可能抛出一个runtimeexception,所以这里简单包装了下所有异常,当作执行过程中发生的异常executionexception抛出。

    以上就是整个异常体系,所有并发操作的异常都可以归结于上述几类。

    很多情况下处理时间长度都是用java.util.concurrent.timeunit,这是一个枚举类型,用来描述时间长度。其中内置了一些长度的单位。其中包括纳秒、微秒、毫秒、秒、分、时、天。例如超时操作5秒,可以使用

    future.get(5,timeunit.seconds) 或者 future.get(5000l,timeunit.milliseconds)

    当然一种单位的时间转换成另一种单位的时间也是非常方便的。另外还有线程的sleep/join以及对象的wait操作的便捷操作。

     



    imxylz 2011-07-12 23:15 发表评论
    ]]>
    享受热部署的好处http://www.blogjava.net/xylz/archive/2011/06/17/352476.htmlimxylzimxylzfri, 17 jun 2011 01:25:00 gmthttp://www.blogjava.net/xylz/archive/2011/06/17/352476.htmlhttp://www.blogjava.net/xylz/comments/352476.htmlhttp://www.blogjava.net/xylz/archive/2011/06/17/352476.html#feedback3http://www.blogjava.net/xylz/comments/commentrss/352476.htmlhttp://www.blogjava.net/xylz/services/trackbacks/352476.html

    你还在为频繁部署服务器而烦恼么?

    亲,试试jrebel吧。更多jrebel的介绍参考这里。

    啊?免费版只能使用30天?花钱?十个人的团队使用一年的企业版license是2891$!你没看错,是真真正正的美帝国的钱!

    好吧,我等穷人使用不起,只好“自己动手/丰衣足食”。

    这里提供了一个完整功能的企业版,免费大甩送了,有木有!!!

    http://www.blogjava.net/xylz/archive/2011/06/12/352109.html

     

    怎么使用,最简单方式,在resin的启动文件,例如httpd.sh中增加:

    resin 3.1 版本:

    exec $java_exe -javaagent:/opt/apps/resin/jrebel4.0-crack.jar -jar ${resin_home}/lib/resin.jar $*

    resin 3.0-版本:

    args=”-j-javaagent:/opt/apps/resin/jrebel4.0-crack.jar

    tomcat?jetty? jboss? weblogic? websphere? maven? eclipse? and more?

    ok,参考这里文档吧:

    亲,不要钱的,试试吧!

    有木有更简单,更nb的热部署秘籍啊?

    有的,亲!

    如果你的linux x86 (x86_64位目前没有)的glibc是2.4 版本,试试吧!windows 32/64位同样有相应的版本啊!



    imxylz 2011-06-17 09:25 发表评论
    ]]>
    crack jrebel 4.0,无需重启jvm,热部署凯发天生赢家一触即发官网的解决方案http://www.blogjava.net/xylz/archive/2011/06/12/352109.htmlimxylzimxylzsat, 11 jun 2011 16:24:00 gmthttp://www.blogjava.net/xylz/archive/2011/06/12/352109.htmlhttp://www.blogjava.net/xylz/comments/352109.htmlhttp://www.blogjava.net/xylz/archive/2011/06/12/352109.html#feedback36http://www.blogjava.net/xylz/comments/commentrss/352109.htmlhttp://www.blogjava.net/xylz/services/trackbacks/352109.html  www.zeroturnaround.com最近又接触到一点web应用,想到resin服务器重启需要花费比较多的时间(spring将web服务搞得越来越复杂,越来越臃肿了),所以又想到了08年那时候用javarebel了。一段时间不用人家居然改名为javarebel了。
    如果不熟悉的可以搜索下jrebel/javarebel,这里是官方网站:
    www.zeroturnaround.com。
    最近刚发布了4.0版本,功能更强大,配置也更加简单了。价格不菲。
    官方提供30天试用版,可以先体验下再决定是否购买。

    看到里面的代码混淆让我很崩溃,没有深入研究混淆后的运行机制。比如下面居然有两个名称相同,参数相同,但是返回值不同的静态方法,不知是如何执行的。
    public static void a(string s)和 public static string a(string),以及
    private static void c()和private static string c()。
    猜测是在运行的时候自己进行jvm指令的执行。这样的代码反编译后都不知道怎么写回去,想到崩溃,因为两个方法居然都有地方调用了。



    提供了一个4.0的破解版,我很好奇,咨询了下,居然还是以前的rsa签名算法。

    好吧,翻出08年写的javarebel 2.0-m1的破解程序,重新生成一个license文件,修改公钥,替换license文件,居然运行正常。这么多年了,签名算法和步骤居然一点都没变,嗯,人家真执着!
    当然是无限制版,所有功能可用,也没有时间限制。


    #############################################################

     jrebel 
    4.0 (201105311152)
       with enterprise add
    -on! (see http://jrebel.com/enterprise)
     (c) 凯发天生赢家一触即发官网 copyright zeroturnaround ou, estonia, tartu.

     over the last 
    1 days jrebel prevented 
     at least 
    0 redeploys/restarts saving you about 0 hours.

     this product is licensed to www.imxylz.info
     
    for unlimited number of developer seats on site.
     
    == cracked by imxylz (imxylz#gmail.com) from javarebel 2.0-m1, 2008 ==

    #############################################################

    伟大领袖毛主席,指引我们向前进!
    jrebel cracked by imxylz
    伟大领袖毛主席,指引我们向前进!
    jrebel cracked by imxylz
    jrebel: reloading class 'reloadclass'.change 
    伟大领袖毛主席,指引我们向前进!
    class!

    破解思路很简单,替换公钥,使用自己私钥生成签名license文件。
    如果想屏蔽版本更新提示,有以下几种思路:
    (1)修改调用更新坚持的类(难道有点大,因为混淆比较严重,不容易反编译)
    (2)修改更新服务器的地址,将地址修改,可以使用二进制工具直接修改字符串,比如我就将update改为updatt,无法解析域名就不能获取最新版本了。
    (3)增加-drebel.disable_update=true参数即可。(这种方法最简单)。

    当然了,为了“保护知识产权”,不会将破解文件放出来,有需求的可以留言联系。(所谓的“计算机条例”是允许为了学习、研究而进行相关逆向工程的,哈哈)。

    好吧,架不住国人的热情,这里是下载地址,需要翻x,你懂得!
      

    [关键字: jrebel, javarebel, jrebel crack, jrebel license, javarebel license]


    imxylz 2011-06-12 00:24 发表评论
    ]]>
    网站地图