基於 Jython 的大型應用系統動態實現

伴隨着 Jython 的出現,使 Java 代碼和 Python 代碼做到了無縫交互。而 Python 自身強大的字符處理能力和動態執行能力更佳彌補了大型 J2EE 應用的一些先天缺陷。本文將分爲幾個章節,配合生動的實例,着重闡述如何利用 Jython 讓我們的大型 Java 應用系統更加靈活。

引言

伴隨信息時代的的迅猛發展,互聯網已經全面滲透到電子商務,金融,電信,物流,資源等各個領域並逐漸成爲其不可或缺的一部分。

信息時代,時間就意味着金錢。伴隨着各種大型應用系統的普及,人們對於系統的穩定性,對與零宕機硬件不斷的提出更高要求,卻往往會忽視應用系統自身升級所帶來的問題。

什麼是 Jython

Jython 是一種完整的語言,而不是一個簡單的 Java 翻譯器或 Python 編譯器,它是 Python 在 Java 中的完整實現。由於 Jython 繼承了 Java 和 Python 二者的特性從而使其顯得很獨特。

看到這裏讀者一定會問,那 Jython,Java 以及 Python 之間的關係到底是怎麼樣的呢?其實,我理解 Jython 說簡單一些,就是用 Java 語言實現的 Python 解釋器,這種關係也就意味着你可以用 Python 語言編寫程序而同時使用 Java 庫。

在這裏我不想大篇幅的闡述 Jython 是什麼,如果各位讀者感興趣,請參閱 Jython 介紹

發現問題

大型的應用系統從不同的應用層面大致可以分爲 :

  • UI 層

該層應該說是比較穩定的,或者說它的變化對於整個系統的運行不會帶來特別嚴重的影響。

  • 接口層

該層與上層的 UI 以及底層的實現,都有着緊密的聯繫,所謂牽一髮而動全身。作爲一位大型應用系統的架構師或是系統設計人員,往往會出於維護成本以及開發成本的考慮,儘可能會讓這個層面的設計與定義相對靈活。

  • 實現層

該層可以說是系統最核心的層面,整個系統的核心處理邏輯都會放在這一層面上。而往往該層,在實際使用過程中也是最不穩定的,最容易從需求角度發生變化。

  • 數據層

該層其實說簡單一些就是數據庫層,用於用戶數據的查詢、組裝、更新等等,提供持久的數據服務,我們可以認爲它也是個比較穩定的層面。

問題焦點似乎發現了,如何讓我們的實現層更加靈活成爲核心問題所在。那麼如何能讓我們系統的核心“與時俱進”呢?

分析問題

接下來,讓我們看看一個系統的實現層都可能會幹哪些事情:

  1. 接收通過接口傳遞過來的用戶數據
  2. 依據一定的業務邏輯,處理用戶數據
  3. 將處理結果更新到數據庫中(可選)
  4. 將處理結果響應給 UI 層並渲染出來

分析到這裏。我們對於實現層的內部數據流向又有了更進一步直觀的認識。而我們對於實現層定義的所謂變數所在,也就比較明顯了,如何實現業務處理邏輯的分離成爲我們的目標。

解決問題

動態算法核心

本段以一個簡單的 Python 方法爲例,介紹如何藉助 Jython 的動態執行能力來實現系統核心算法,以供 Java 代碼調用。

Java 層代碼片段

 PythonInterpreter interpreter=new PythonInterpreter();              
 PySystemState sys = Py.getSystemState(); 

 <em>// 將 Jython 庫加入系統的 classpath 中或直接通過這種方式動態引入</em>
 sys.path.add("D:\\jython2.5.2\\Lib");  

 <em>// 執行算法所在的 python 文件</em>
 interpreter.execfile("impl/demo.py");

Jython 層代碼片段

def getValue(o): 
    result = 0 
    if o < 2: 
      return -1 
    else: 
      for i in range(o): 
       		result +=i 
    return result

該方法很簡單,當用戶數據小於 2 時返回運算結果 -1,當用戶數據大於等於 2 時,返回從 0 到輸入數據的和。

Java 調用

 PyFunction pyFunction = (PyFunction)interpreter.get("getValue",PyFunction.class ); 

 System.<em>out</em>.println("Result: "+pyFunction.__call__(new PyInteger(100)));

通過 PyFunction 對象的內置方法 __call__() 傳入用戶數據。因爲 Python 文件本身具備動態編譯執行能力,所以我們只需要更新算法核心部分的 Python 代碼,就可以達到動態改變系統底層算法的目的,而不需要更新 jar 包或重新部署應用而重啓應用系統。

上邊這個例子其實很簡單,我們假設這個簡單的 Jython 方法就是我們的業務邏輯,它會返回處理結果供上層渲染,但當業務邏輯發生了變化,比如當用戶輸入等於 2 時也要求返回值是 -1,此時對於這樣一個簡單的需求,我們只需要修改 Jython 代碼就好了,並不需要更新 Java 層的東西。

動態配置文件

本段着重介紹,當系統中配置文件中若該項的數值需要發生變化時,我們如何來解決動態獲取最新配置的問題。

配置文件 ( demo.properties )

假設我們爲每一次查詢結果定義了最大的返回數目爲 100

 MaxValue=100 
…

Java 層代碼片段

 PythonInterpreter interpreter=new PythonInterpreter();              
 PySystemState sys = Py.getSystemState(); 
 sys.path.add("D:\\jython2.5.2\\Lib"); 

 <em>//‘re’是 Python 自身提供的正則表達式庫,在 Python 方法中我們需要用到這個庫中的方法,所以需要提前導入進來</em>
 interpreter.exec("import re"); 

 interpreter.execfile("impl/demo.py"); 
 PyFunction pyFunction = (PyFunction)interpreter.get("getconfig",PyFunction.class );

Jython 層代碼片段

import re
def getconfig(flag):
    result=''
    f=open('demo.properties','r')
    for i in f:
        g=re.findall(flag+'.*=.*',i)
        if len(g)>0:
            al=g[0].split('=')            
            result=al[1].strip()
            break    
return result

這個方法很簡單根據我們傳入的條目名稱,獲取配置文件中對應條目的定義數值。

Java 調用

System.out.println("Config value: "+pyFunction.__call__(new PyString("MaxValue")));

藉助 Python 強大的文本處理能力,由 Python 作爲 Java 代碼和配置文件之間的橋樑,從而動態的獲取最新配置項數值。

相比純 Java 內存操作的實現方式,這種實現機制從運行速度上可能沒有什麼優勢,但是卻可以給我們帶來一種新的理念。也許我們可以將這兩種方式融合起來找到某種平衡,既不影響系統的運行效率又保留了 Python 動態的運行機制,達到雙贏的目的。

動態後臺實現

前邊已經提到了系統接口定義層和實現層之間的關係。那麼我們是否可以藉助 Jython 來幫助我們動態實現定義的接口呢?答案很明顯,當然可以。

這裏我就以一個簡單的例子,介紹一下如何藉助 Jython 實現可插拔式的後臺實現。利用 Jython 來實現 Java 定義的接口。從而可以被其他的 Java 方法調用。

Java 接口定義

 package com; 
 public interface Worker { 
 public String getFirstName(); 
    public String getLastName(); 
    public String getId(); 
    public 
				 void setId(); 
 }

上邊是一個簡單的人員接口,接口的實現類中我們就需要實現這裏定義的 4 個方法。

Jython 層代碼片段 ( 實現接口 )

 from com import Worker 
 class Worker(Worker): 
    def __init__(self): 
        self.first = "FirstName"
        self.last  = "LastName"

    def getFirstName(self): 
        return self.first 

    def getLastName(self): 
        return self.last 

    def getId(self): 
        return self.Id 

    def setId(self, newId): 
        self.Id = newId

我們在 Worker 類的構造函數中爲該類的兩個私有成員賦值,當調用 getFirstName() 或 getLastName() 方法時我們返回這兩個私有成員的當前值。

Java 層代碼片段

 Object javaObject; 
 PythonInterpreter interpreter=new PythonInterpreter();              
 PySystemState sys = Py.getSystemState(); 
 sys.path.add("D:\\jython2.5.2\\Lib");  
 interpreter.execfile("impl/demo.py"); 
 interpreter.exec("worker=Worker()"); 
 PyObject pyObject = interpreter.get("worker"); 
 pyObject.invoke("setId",new PyString("8888")); 
 try { 
     Class Interface = Class.forName(interfaceName); 
     javaObject = pyObject.__tojava__(Interface); 
 } catch (ClassNotFoundException e) { 
     e.printStackTrace(); 
 }

Java 調用

 Worker worker = (Worker) javaObject; 
 System.out.println("Name:"+worker.getFirstName()+worker.getLastName()); 
 System.out.println("ID:"+worker.getId());

看到這裏就不必多說了,只需要動態的替換 Python 實現部分的代碼,就可以實現可插拔式後臺實現啦。而對於調用這個接口的 Java 對象來說,並不知道這個實現類是否發生了變化。

轉載:基於 Jython 的大型應用系統動態實現

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章