最近重新设计一个程序,这个程序有一个功能是监视其他进程的内存使用情况,并且在满足一定条件的时候促发警告给用户。一般的条件是,内存超过某个阀值。可是如果希望这个条件可以复杂些,譬如超过2G时并且持续增长2天,就告警;或者如果小于1G,并且在10天以内总体趋势是增长的,也告警。总之,这个条件可以支持很复杂的条件,并且需要动态修改(主模块不重启的情况下),所以我的选择是结合Java和Jython。其实Java上面可以选用JRuby, Scala, Groovy或者Javascript,选择Jython的理由有以下几点:
[1] 单位有一些项目已经使用了Python;
[2] Scala和Groovy会的人太少,太前卫了;
[3] Javascript很好,不过考虑到也许今后所有Java的程序扩展都会使用一种脚本语言,明显Javascript系统的交互能力太差。譬如链接数据库,处理文件啊
[4] Ruby是我太难割舍的,因为我喜欢Ruby,其实Ruby企业版已经比较稳定了,而且JRuby也有官方的支持。只不过,单位中已经有项目使用了Python,如果冒然的引入Ruby,势必会增加系统的复杂度。
[5] 即使有JPerl,JTcl,我也不会选用。原因很简单,我需要更好的模块化面向对象的脚本,面向对象不是银弹,可是大家都很熟悉面向对象了,而且实践证明面向对象鼓励大家写出好维护的代码(结合设计模式)。
[6] C++可以和Python集成(Boost.Python)(当然了,Lua更方便与C++集成,可是Lua会的人也太少)。
[7] 可以用Java写,然后用反射,可以做。不过我觉得脚本更好,省掉了编译的过程。(因为在现场,不能保证你的Unix上面装了JDK,只能保证一定有JRE)。
[8] 使用的是Java5,不是Java6,所以JSR233(好像是这个吧)不是直接可以用的。
因为这个项目是单位的项目,所以我把我做得Prestudy的小程序拿出来和大家共享一下解决方案。
我总喜欢用计算器这样的小例子来做PreStudy,呵呵。
首先设计一个计算器的接口ICalc(用Java写的), 如下:
package com.gmail.at.ankyhe.calc;
public interface ICalc {
void pushData(int[] data);
int getResult();
}
package com.gmail.at.ankyhe.calc;
public interface ICalc {
void pushData(int[] data);
int getResult();
}
很显然,这个接口里面有两个函数。第一个函数是pushData,主模块调用这个函数把数据送给具体的Calc类(这个用Jython实现),然后通过getResult()得到结果,思路很简单。为了能够动态的发现更新的文件,我们把送数据给Calc并且从Calc得到结果的任务放到一个独立的线程里面,如下:
package com.gmail.at.ankyhe.calc;
import java.util.Arrays;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.TimeUnit;
public class CalcTask implements Runnable {
public CalcTask(ICalc aCalc) {
calc = aCalc;
rand = new Random((new Date()).getTime());
arr = new int[3];
}
public ICalc setCalc(ICalc aCalc) {
ICalc tmp = calc;
synchronized(this) {
calc = aCalc;
}
return tmp;
}
public void run() {
while (true) {
for(int i = 0 ; i < arr.length; ++i) {
arr[i] = rand.nextInt() % 50;
}
int rst = 0;
synchronized (this) {
calc.pushData(arr);
rst = calc.getResult();
}
System.out.println(String.format("Input: %s --- Output: %d",
Arrays.toString(arr), rst));
try {
TimeUnit.SECONDS.sleep(50);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
private ICalc calc;
private Random rand;
private int[] arr;
}
然后主线程里面负责扫描Jython脚本和加载它,如下:
package com.gmail.at.ankyhe.calc;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.python.util.PythonInterpreter;
public class Main {
public static ICalc getCalc() {
Reader file = null;
file = null;
try {
file = new FileReader(filename);
} catch(FileNotFoundException ex) {
System.out.println("Can't find the file.");
System.exit(1);
}
try {
Reader in = new BufferedReader(file);
PythonInterpreter interpreter = new PythonInterpreter();
org.python.core.PyObject code = interpreter.compile(in);
interpreter.exec(code);
ICalc calc = (ICalc)interpreter.get("calc", ICalc.class);
return calc;
} finally {
try {
file.close();
} catch(IOException ex) {
System.out.print("Fail to close file");
System.exit(1);
}
}
}
public static long getLastModified() {
long rst = 0L;
File f = null;
try {
f = new File(filename);
rst = f.lastModified();
} catch(NullPointerException ex) {
ex.printStackTrace();
rst = -1;
}
return rst;
}
public static void main(String[] args) throws InterruptedException {
// initialization
if (args.length == 0) {
System.out.println("Usage java -jar calc.jar <scriptfile>.");
System.exit(1);
}
filename = args[0];
ICalc calc = null;
if (lastmodified == 0) {
lastmodified = getLastModified();
if (lastmodified == -1) {
System.out
.println(String.format("The file %s doesn't exit.", filename));
}
calc = getCalc();
}
if(calc == null) {
System.out.print(String.format("The script file has no valid calc.",
filename));
System.exit(2);
}
// launch calc task
CalcTask ct = new CalcTask(calc);
ExecutorService es = Executors.newCachedThreadPool();
es.execute(ct);
es.shutdown();
// main thread check the new script every 10 seconds
while(true) {
long modified = getLastModified();
if (modified <= lastmodified) {
// do nothing
}
else {
lastmodified = getLastModified();
ICalc newCalc = getCalc();
if (newCalc == null) {
System.out.print(String.format("The new script file has no valid calc.",
filename));
}
else {
System.out.println("Ready to use new script file.");
ct.setCalc(newCalc);
System.out.println("Use new script file.");
}
}
TimeUnit.SECONDS.sleep(10);
}
}
public static String filename = null;
public static long lastmodified = 0;
}
核心的加载代码就是下面这一段:
PythonInterpreter interpreter = new PythonInterpreter();
org.python.core.PyObject code = interpreter.compile(in);
interpreter.exec(code);
ICalc calc = (ICalc)interpreter.get("calc", ICalc.class);
注意,在Jython脚本中的calc一定是一个ICalc子类的对象,否则上面最后一句会抛出异常。Jython代码如下:
import sys
# add sys path
def addSysPath():
sys.path.append("/Users/AnkyHe/proj/java/CalcPlugin/icalc.jar")
addSysPath()
from com.gmail.at.ankyhe.calc import ICalc
class MyCalc(ICalc):
def __init__(self):
pass
def pushData(self, arr):
self.arr = arr
def getResult(self):
return sum(self.arr)
#return min(self.arr)
calc = MyCalc()
'''
if __name__ == '__main__':
mycalc = MyCalc()
arr = [1, -100, 20]
mycalc.pushData(arr)
if sum(arr) == mycalc.getResult():
print('true')
else:
print('false')
print(mycalc.getResult())
'''
sys.path.append是把接口ICalc的jar文件加入到Jython的使用环境中,这样才可以import ICalc。注意最后的if __name__ == '__main__', 这里体现了用Jython的一个优点,可以通过Jython做测试。因为这只是一个Presutdy,主要任务是验证一下这个流程,所以可能有一些错误处理没有写得很全面。源代码和可执行文件(我在Mac上编译运行通过了)如附件,执行的时候请用:
java -cp ./icalc.jar -jar calcplugin.jar script/mycalc.py
编译的时候使用把icalc.jar和jython.jar加入到classpath中。
然后你修改mycalc.py,可以看到输出结果的改变。
分享到:
相关推荐
java中jython操作把python数据类型转成java类型 例如list->List dict->Map set->Set 以及一些基本操作的包装整合
java与Jython的相互调用,对初学者很有帮助
Jython for Java Programmers.chm Java程序员学习Jython的教程。
Jython is an open source implementation of the high-level, dynamic, object-oriented scripting language Python seamlessly integrated with the Java platform. The predecessor to Jython, JPython, is ...
由于 Jython 继承了 Java 和 Python 二者的特性从而使其显得很独特。那 Jython,Java 以及 Python 之间的关系到底是怎么样的呢?其实,Jython 说简单一些,就是用 Java 语言实现的 Python 解释器,这种关系也就意味...
主要介绍了Java实现调用jython执行python文件的方法,结合实例形式分析了Java调用jython执行python文件的常见操作技巧及相关问题解决方法,需要的朋友可以参考下
json和jython
一个将Python代码转换成Java代码的编译器,能够将自己用Python代码写的类库用在Java程序里,有需要的可以下载,亲测可用。 如果windows的用户安装插件有问题的,尝试一下换这个jython: Jython官网: ...
java调用python脚本所需jar包,最新的版本,亲测可用,希望对你有帮助。jython-standalone-2.7.0.jar,jython-standalone-2.7.0.jar,
Jython是一种完整的语言,而不是一个Java翻译器或仅仅是一个Python编译器,它是一个Python语言在Java中的完全实现。Jython也有很多从CPython中继承的模块库。最有趣的事情是Jython不像CPython或其他任何高级语言,它...
该资源包含jython2.5.4.jar和jython2.7.0.jar,jython的版本要与jdk的版本要对应,这样可以解决“Unsupported major.minor version 51.0”问题。其中,对于jdk1.6.x的版本,请使用jython2.5.4.jar jdk1.7.x的版本,...
这允许程序员使用Jython来实验和调试任何Java系统。 快速应用程序开发——Python程序通常比等效Java程序短2-10倍。这直接转化为程序员生产力的提高。Python和Java之间的无缝交互允许开发人员在开发过程中和产品交付...
Jython - Python的Java语言实现 jython_installer-2.5.2rc2.zip 注意,需要先安装JDK 1, 解压到某处 2, 进入该解压目录, 执行jython.bat
Jython for Java Programmers
本文详细介绍了Jython在Eclipse中的配置和使用,利用Java运行Python脚本和运行Python语言。文中使用了一个简单的例子,容易上手,便于理解!
jython-standalone-2.7.2.jar,java应用调用Python。
Scientific Data Analysis using Jython Scripting and Java
jython官方正版资源 为了省去大家找Jython安装包的时间,附上此Jython版本。 Jython是一种完整的语言,而不是一个Java翻译器或仅仅是一个Python编译器,它是一个Python语言在Java中的完全实现。
NULL 博文链接:https://yinxvxv.iteye.com/blog/811328