美文网首页程序员
工作阶段总结

工作阶段总结

作者: 御街打码 | 来源:发表于2018-05-07 09:12 被阅读0次

    程序整体框架概述

    所接触的是数据采集方面的任务,整个数据采集模块主框架被封装在一个a.jar包之中,程序入口common通过启动命令指定,使用nohuo与&指令将服务运行在后台:

     nohup java -cp 'pwd'/a.jar main.common [args]>>nohup.out &
    

    进入common继续往下看:
    首先关注启动命令中所指定的args参数,此参数指定配置文件路径,(程序启动后,a.jar文件所在目录即为根目录,指定路径以此为基础)。通过jar包sysconfig类中定义的静态方法,读取cfg配置文件内容,依次赋值给sysconfig类中的静态变量,作后续使用。
    之后利用jar包Server类中的ServerRun静态方法,通过读取上述sysconfig类中的port静态变量,使用mina框架提供的socket通信方法,监听本机端口。

    public static void ServerRun(int PORT) throws Exception {
    
            SocketAcceptor acceptor = new NioSocketAcceptor();
            acceptor.setReuseAddress(true);
    
            DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();
            chain.addLast("threadPool", new ExecutorFilter(Executors.newFixedThreadPool(sysconfig.socket_poolsize)));
    
            acceptor.setHandler(new Server());
            acceptor.getSessionConfig().setUseReadOperation(true);
            acceptor.getSessionConfig().setReadBufferSize(30000);
            acceptor.bind(new InetSocketAddress(PORT));
            
            System.out.println("Listening on port " + PORT);
            for (;;) {
                Thread.sleep(1000);
            }
        }
    

    如此一来,通过telnet连接至指定端口,就可以做到与程序进行交互。Server类继承mina框架的IoHandAdapter类,便于管理连接,[mian Iohander事件触发机制可以参考该博文]
    (https://blog.csdn.net/boonya/article/details/51583823)
    当消息被接收到时,messageReceived事件被触发,这是应用程序需要处理输入信息的地方。这里将首次与外部js文件产生调用,(关于java与js的相互调用,大家可自行查阅相关资料)而后续大量的操作均需要通过外部js代码进行完成,如此重要的操作自然需要一个专门的类进行封装。js类概要功能如下:

    import javax.script.*;
    public class js {
        public ScriptEngine engine = null;
        public static ScriptEngineManager manager = new ScriptEngineManager();
        public js(String args) throws Exception {
            m_args = args;
            engine = manager.getEngineByName("JavaScript");
            engine.put("engine", engine);
            engine.put("core", this);
            engine.put("args", args);
            ...
            m_files.add(sysconfig.js_run_path + sysconfig.entry_js);
        }
        public Object runfile(String filename) throws Exception {
            java.io.FileReader reader = null;
            try { 
                reader = new java.io.FileReader(filename); 
                return engine.eval(reader);
            } finally {
                try{ reader.close(); } catch(Exception e){}
            }
        }
        public Object include(String filename) throws Exception{
            return this.runfile(sysconfig.js_run_path + filename);
        }
    }
    
    

    简单地说,就是通过getEngineByName初始化一个ScriptEngine,然后通过put()对变量赋值,通过eval执行js程序。
    了解了js类的主要方法,回过头继续看messageReceived方法中所作的处理。

    public class Server extends IoHandlerAdapter {
        @Override
        public void messageReceived(IoSession session, Object message) throws UnsupportedEncodingException {
            String buf = new String(((IoBuffer) message).array(), sysconfig.socket_recv_encode);
            buf = buf.trim();
            if (buf.length() > 0) {
                try {
                        js jengine = new js(buf);
                        jengine.engine.put("client", new Requ(session));
                        jengine.include(sysconfig.entry_js);
                    }
                    jengine.engine.put("input_0_0_0", buf);
                    jengine.engine.eval("main(input_0_0_0)");
                } catch (Exception ex) {
                    ex.printStackTrace();
                    Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                    session.closeOnFlush();
                }
            }
        }
    }
    

    这里首先生成一个js对象,之后通过put方法将一个Requ对象与client字符串绑定,Requ对象即为负责与telnet进行通信的实现对象,包括send和recv方法。(在后续程序中通过client.send(“msg”)即可往控制台输出内容,方便了解程序交互运行的过程)。
    紧接着调用include方法调用执行一个外部js文件(sysconfig.entry_js在配置文件中的值为main.js,通过include方法拼凑出文件路径,进一步调用runfile方法执行main.js)。而事实上,mian.js里面仅仅定义了一个main(args)函数,因此在jengine.engine.put("input_0", buf);jengine.engine.eval("main(input_0)");这两句代码的作用仅仅是将接收到的buf数据传输给main(args)执行,其中由telnet传输的args[0]此处一般为js文件名,args[1]为后续参数。通过main(args)函数继续调用args[0]执行各类操作。(这么做显得main.js多此一举,完全可以在Server类中做同样处理,但我想既然存在,自然是有一定的道理,毕竟架构师的经验要丰富的多)。
    到此处,基本的架构逻辑捋顺,接下来就是在此基础上各种具体应用,如果有人愿意看,下一篇就选取一个常用的数据库指标采集进行详细的陈述。

    所思所得

    java与js文件的互相调用配合,架构师的作用

    在java程序中通过js类封装了ScriptEngine,并将core与当前js对象绑定。之后在执行的各js文件中,通过core.include("*.js"),就可以继续调用执行其他js程序。js类中还有一个重要的方法newobject(String classname),这个方法实现在js脚本程序中初始化jar包中封装的类。

        public Object newobject(String classname) throws Exception {
            return Class.forName(classname).newInstance();
        }
    

    这样在js脚本程序中通过Object_classname= core.newobject(classname);就可以得到classname的实例对象。
    如此一来,将主要功能模块封装在jar包中,具体使用时则通过js程序来调用,这种设计使得程序的灵活性大大提高,程序后期的扩展性也得到了保障。(ps:在学校也曾读过一两本关于设计模式的书,浅尝辄止,只能在以后的工作中多花功夫了)

    java与telnet之间的命令传输

    在java程序中通过Server类启动并监听PORT端口,当有一个远程端口接入,就生成一个Requ对象负责通信,而根据约定,远程端口发送的命令格式为js文件名+" "+参数列表,解析命令字符串,通过core.include与runfile方法就可以实现执行js程序并传参的功能预期。

    js奇妙体验

    以前对js没怎么研究过,只是初步知道是解释型语言,原生支持json,语法简单了解过。在这一个月的"使用"过程中,深深体会到它的便捷与易用性,最简单的如编写一个js文件,代码仅仅是一个方法,甚至只是几个变量的初始化,而当被eval()执行过后,该方法就被加载到了内存中,之后就可以在其它地方直接调用执行,产生一种C#扩展方法的错觉。

    所遇到的一个问题

    问题描述

    在添加对postgresql数据库指标的采集功能时,发现无法采集数据,经排查发现原因在于无法连接至postgresql数据库。

    解决问题过程中的所见所得

    为什么无法连接postgresql数据库?明明代码什么的都没问题,自己编写的数据库连接测试的小程序也可以成功连接,不得不请教技术专家来解决。问题描述清楚后,老师键指如飞,我一个初出茅庐的小兵是眼花缭乱,再也插不上一句话。几分钟后老师排查出问题所在,原因很简单,jar包没有自动引用postgresql数据库驱动包。事后通过查看历史命令,将大致排查过程简单还原如下:

    starce 命令跟踪---查到数据库连接不通
    ps -ef | grep *.jar---得到程序pid
    cd /proc/pid/fd ---进入程序文件描述符文件夹
    ll -h | grep *.jar---查看引用的所有jar包---发现没有引用postgresql驱动jar包
    

    解决方案

    为了进一步确认驱动包是否可用,在测试环境下进行了一次破坏性试验。

    cd /'home'/lib/
    for name in `ls | grep *.jar$`;do `jar -xvf $name`;done
    rm -rf *.jar
    jar -cvf ojdbc14.jar *
    

    由于ojdbc14.jar是一定会被引用,所以将所有的jar包解包后全部压入ojdbc14.jar中。重新运行程序,发现已经可以正常连接至postgresql数据库。技术与经验的差距,仅仅不到10分钟,不仅排查了问题,还给出一个临时的试验解决方案,当然最终的解决是重新编译打包程序。
    事后尝试直接改写jar包中的META-INF/MANIFEST.MF文件,在其Class-Path后加上postgresql的包地址,但并不起作用(格式没问题),所以请读到此文的各位博友不吝赐教。

    目前水平较低,难免对各种各样的问题理解不够深彻,还是希望各位博友多多留言交流。

    相关文章

      网友评论

        本文标题:工作阶段总结

        本文链接:https://www.haomeiwen.com/subject/xpqmrftx.html