<dfn id="w48us"></dfn><ul id="w48us"></ul>
  • <ul id="w48us"></ul>
  • <del id="w48us"></del>
    <ul id="w48us"></ul>
  • Java中的動態(tài)代碼編程

    時間:2024-06-27 15:06:03 JAVA認證 我要投稿
    • 相關推薦

    Java中的動態(tài)代碼編程

      Java不是解決動態(tài)層問題的理想語言,這些動態(tài)層問題包括原型設計、腳本處理等。

      公司的項目主要基于Java平臺,在實踐中發(fā)現主要有兩種方式可以實現:

      統(tǒng)一表達式語言

      動態(tài)語言,如Groovy

      JUEL(Java 統(tǒng)一表達式語言)

      Java*統(tǒng)一表達式語言(英語:Unified Expression Language,簡稱JUEL*)是一種特殊用途的編程語言,主要在Java Web應用程序用于將表達式嵌入到web頁面。Java規(guī)范制定者和Java Web領域技術專家小組制定了統(tǒng)一的表達式語言。JUEL最初包含在JSP 2.1規(guī)范JSR-245中,后來成為Java EE 7的一部分,改在JSR-341中定義。

      主要的開源實現有:OGNL ,MVEL ,SpEL ,JUEL ,Java Expression Language (JEXL) ,JEval,Jakarta JXPath 等。這里主要介紹在實踐中使用較多的MVEL、OGNL和SpEL。

      OGNL(Object Graph Navigation Library)

      在Struts 2 的標簽庫中都是使用OGNL表達式訪問ApplicationContext中的對象數據,OGNL主要有三個重要因素:

      Expression

      Expression是整個OGNL的核心內容,所有的OGNL操作都是針對表達式解析后進行的。通過Expression來告知OGNL操作到 底要干些什么。因此,Expression其實是一個帶有語法含義的字符串,整個字符串將規(guī)定操作的類型和內容。OGNL表達式支持大量 Expression,如“鏈式訪問對象”、表達式計算、甚至還支持Lambda表達式。

      Root對象:

      OGNL的Root對象可以理解為OGNL的操作對象。當我們指定了一個表達式的時候,我們需要指定這個表達式針對的是哪個具體的對象。而 這個具體的對象就是Root對象,這就意味著,如果有一個OGNL表達式,那么我們需要針對Root對象來進行OGNL表達式的計算并且返回結果。

      ApplicationContext

      有個Root對象和Expression,我們就可以使用OGNL進行簡單的操作了,如對Root對象的賦值與取值操作。但是,實際上在OGNL的 內部,所有的操作都會在一個特定的數據環(huán)境中運行。這個數據環(huán)境就是ApplicationContext(上下文環(huán)境)。OGNL的上下文環(huán)境是一個 Map結構,稱之為OgnlContext。Root對象也會被添加到上下文環(huán)境當中去。

      Foo foo = new Foo();foo.setName("test");Map context = new HashMap();context.put("foo",foo);String expression = "foo.name == 'test'";try {

      Boolean result = (Boolean) Ognl.getValue(expression,context);

      System.out.println(result);} catch (OgnlException e) {

      e.printStackTrace();}

      這段代碼就是判斷對象foo的name屬性是否為test。

      OGNL的具體語法參見OGNL language guide 。

      MVEL

      MVEL最初作為Mike Brock創(chuàng)建的 Valhalla項目的表達式計算器(expression evaluator)。Valhalla本身是一個早期的類似 Seam 的“開箱即用”的Web 應用框架,而 Valhalla 項目現在處于休眠狀態(tài), MVEL則成為一個繼續(xù)積極發(fā)展的項目。相比最初的OGNL、JEXL和JUEL等項目,而它具有遠超它們的性能、功能和易用性 – 特別是集成方面。它不會嘗試另一種JVM語言,而是著重解決嵌入式腳本的問題。

      MVEL特別適用于受限環(huán)境 – 諸如由于內存或沙箱(sand-boxing)問題不能使用字節(jié)碼生成。它不是試圖重新發(fā)明Java,而是旨在提供一種Java程序員熟悉的語法,同時還加入了簡短的表達式語法。

      MVEL主要使用在Drools,是Drools規(guī)則引擎不可分割的一部分。

      MVEL語法較為豐富,不僅包含了基本的屬性表達式,布爾表達式,變量復制和方法調用,還支持函數定義,詳情參見MVEL Language Guide 。

      MVEL在執(zhí)行語言時主要有解釋模式(Interpreted Mode)和編譯模式(Compiled Mode )兩種:

      解釋模式(Interpreted Mode)是一個無狀態(tài)的,動態(tài)解釋執(zhí)行,不需要負載表達式就可以執(zhí)行相應的腳本。

      編譯模式(Compiled Mode)需要在緩存中產生一個完全規(guī)范化表達式之后再執(zhí)行。

      解釋模式

      //解釋模式Foo foo = new Foo();foo.setName("test");Map context = new HashMap();String expression = "foo.name == 'test'";VariableResolverFactory functionFactory = new MapVariableResolverFactory(context);context.put("foo",foo);Boolean result = (Boolean) MVEL.eval(expression,functionFactory);System.out.println(result);

      編譯模式

      //編譯模式Foo foo = new Foo();foo.setName("test");Map context = new HashMap();String expression = "foo.name == 'test'";VariableResolverFactory functionFactory = new MapVariableResolverFactory(context);context.put("foo",foo);Serializable compileExpression = MVEL.compileExpression(expression);Boolean result = (Boolean) MVEL.executeExpression(compileExpression, context, functionFactory);

      SpEL

      SpEl(Spring表達式語言)是一個支持查詢和操作運行時對象導航圖功能的強大的表達式語言。 它的語法類似于傳統(tǒng)EL,但提供額外的功能,最出色的就是函數調用和簡單字符串的模板函數。SpEL類似于Struts2x中使用的OGNL表達式語言, 能在運行時構建復雜表達式、存取對象圖屬性、對象方法調用等等,并且能與Spring功能完美整合,如能用來配置Bean定義。

      SpEL主要提供基本表達式、類相關表達式及集合相關表達式等,詳細參見Spring 表達式語言 (SpEL) 。

      類似與OGNL,SpEL具有expression(表達式),Parser(解析器),EvaluationContext(上下文)等基本概念;類似與MVEL,SpEl也提供了解釋模式和編譯模式兩種運行模式。

      //解釋器模式Foo foo = new Foo();foo.setName("test");// Turn on:// - auto null reference initialization// - auto collection growingSpelParserConfiguration config = new SpelParserConfiguration(true,true);ExpressionParser parser = new SpelExpressionParser(config);String expressionStr = "#foo.name == 'test'";StandardEvaluationContext context = new StandardEvaluationContext();context.setVariable("foo",foo);Expression expression = parser.parseExpression(expressionStr);Boolean result = expression.getValue(context,Boolean.class);//編譯模式config = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, RunSpel.class.getClassLoader());parser = new SpelExpressionParser(config);context = new StandardEvaluationContext();context.setVariable("foo",foo);expression = parser.parseExpression(expressionStr);result = expression.getValue(context,Boolean.class);

      Groovy

      Groovy除了Gradle 上的廣泛應用之外,另一個大范圍的使用應該就是結合Java使用動態(tài)代碼了。Groovy的語法與Java非常相似,以至于多數的Java代碼也是正確的Groovy代碼。Groovy代碼動態(tài)的被編譯器轉換成Java字節(jié)碼。由于其運行在JVM上的特性,Groovy可以使用其他Java語言編寫的庫。

      Groovy可以看作給Java靜態(tài)世界補充動態(tài)能力的語言,同時Groovy已經實現了java不具備的語言特性:

      函數字面值;

      對集合的一等支持;

      對正則表達式的一等支持;

      對xml的一等支持;

      Groovy作為基于JVM的語言,與表達式語言存在語言級的不同,因此在語法上比表達還是語言更靈活。Java在調用Groovy時,都需要將Groovy代碼編譯成Class文件。

      Groovy 可以采用GroovyClassLoader、GroovyShell、GroovyScriptEngine和JSR223 等方式與Java語言集成。

      GroovyClassLoader

      GroovyClassLoader是一個定制的類裝載器,負責解釋加載Java類中用到的Groovy類,也可以編譯,Java代碼可通過其動態(tài)加載Groovy腳本并執(zhí)行。

      class FooCompare{

      boolean compare(String toCompare){

      Foo foo = new Foo();

      foo.name = "test";

      return foo.name == toCompare;

      }}

      GroovyClassLoader loader = new GroovyClassLoader();Class groovyClass = null;try {

      String path = "FooCompare.groovy";

      groovyClass = loader.parseClass(new File(path));} catch (IOException e) {

      e.printStackTrace();}GroovyObject groovyObject = null;try {

      groovyObject = (GroovyObject) groovyClass.newInstance();} catch (InstantiationException e) {

      e.printStackTrace();} catch (IllegalAccessException e) {

      e.printStackTrace();}result = groovyObject.invokeMethod("compare", "test");assert result.equals(Boolean.TRUE);System.out.print(result);

      GroovyShell

      GroovyShell允許在Java類中(甚至Groovy類)求任意Groovy表達式的值。可以使用Binding對象輸入參數給表達式,并最終通過GroovyShell返回Groovy表達式的計算結果。

      Foo foo = new Foo();foo.setName("test");Binding binding = new Binding();binding.setVariable("foo",foo);GroovyShell shell = new GroovyShell(binding);String expression = "foo.name=='test'";Object result = shell.evaluate(expression);assert result.equals(Boolean.TRUE);

      GroovyScriptEngine

      GroovyShell多用于推求對立的腳本或表達式,如果換成相互關聯(lián)的多個腳本,使用GroovyScriptEngine會更好些。 GroovyScriptEngine從您指定的位置(文件系統(tǒng),URL,數據庫,等等)加載Groovy腳本,并且隨著腳本變化而重新加載它們。如同 GroovyShell一樣,GroovyScriptEngine也允許您傳入參數值,并能返回腳本的值。

      FooScript.groovy

      package blog.brucefeng.info.groovy

      foo.name=="test";

      Foo foo = new Foo();foo.setName("test");Binding binding = new Binding();binding.setVariable("foo",foo);String[] paths = {"/demopath/"}GroovyScriptEngine gse = new GroovyScriptEngine(paths);try {

      result = gse.run("FooScript.groovy", binding);} catch (ResourceException e) {

      e.printStackTrace();} catch (ScriptException e) {

      e.printStackTrace();}assert result.equals(Boolean.TRUE);

      JSR223

      JSR223 是Java 6提供的一種從Java內部執(zhí)行腳本編寫語言的方便、標準的方式,并提供從腳本內部訪問Java 資源和類的功能,可以使用其運行多種腳本語言如JavaScript和Groovy等。

      Foo foo = new Foo();foo.setName("test");ScriptEngineManager factory = new ScriptEngineManager();ScriptEngine engine1 = factory.getEngineByName("groovy");engine1.put("foo",foo);try {

      result = engine1.eval(expression);} catch (javax.script.ScriptException e) {

      e.printStackTrace();}assert result.equals(Boolean.TRUE);

      使用中經常出現的問題

      因此Java每次調用Groovy代碼都會將Groovy編譯成Class文件,因此在調用過程中會出現JVM級別的問題。如使用 GroovyShell的parse方法導致perm區(qū)爆滿的問題,使用GroovyClassLoader加載機制導致頻繁gc問題和 CodeCache用滿,導致JIT禁用問題等,相關問題可以參考Groovy與Java集成常見的坑 。

      性能對比

      在這里簡單對上面介紹到的OGNL、MVEL、SpEL和Groovy2.4 的性能進行大致的性能測試(簡單測試):

    實現方式 耗時(MS)
    Java 13
    OGNL 2958
    MVEL 225
    SpEL 1023
    Groovy 99

      通過這個簡單測試發(fā)現,Groovy 2.4的性能已經足夠的好,而MVEL的性能依然保持強勁,不過已經遠遠落后與Groovy,在對性能有一定要求的場景下已經不建議使用OGNL和SpEL。

      不過動態(tài)代碼的執(zhí)行效率還是遠低于Java,因此在高性能的場景下慎用。

      以下是測試代碼:

      package blog.brucefeng.info.performanceclass GroovyCal{

      Integer cal(int x,int y,int z){

      return x + y*2 - z;

      }}

      package blog.brucefeng.info.performance;public class RunPerform {

      public static void main(String[] args) {

      try {

      int xmax = 100,ymax = 100,zmax= 10;

      runJava(xmax, ymax, zmax);

      runOgnl(xmax, ymax, zmax);

      runMvel(xmax, ymax, zmax);

      runSpel(xmax, ymax, zmax);

      runGroovyClass(xmax, ymax, zmax);

      } catch (Exception e) {

      e.printStackTrace();

      }

      }

      public static void runJava(int xmax, int ymax, int zmax) {

      Date start = new Date();

      Integer result = 0;

      for (int xval = 0; xval < xmax; xval++) {

      for (int yval = 0; yval < ymax; yval++) {

      for (int zval = 0; zval <= zmax; zval++) {

      result += xval + yval * 2 - zval;

      }

      }

      }

      Date end = new Date();

      System.out.println("time is : " + (end.getTime() - start.getTime()) + ",result is " + result);

      }

      public static void runOgnl(int xmax, int ymax, int zmax) throws OgnlException {

      String expression = "x + y*2 - z";

      Map context = new HashMap();

      Integer result = 0;

      Date start = new Date();

      for (int xval = 0; xval < xmax; xval++) {

      for (int yval = 0; yval < ymax; yval++) {

      for (int zval = 0; zval <= zmax; zval++) {

      context.put("x", xval);

      context.put("y", yval);

      context.put("z", zval);

      Integer cal = (Integer) Ognl.getValue(expression, context);

      result += cal;

      }

      }

      }

      Date end = new Date();

      System.out.println("Ognl:time is : " + (end.getTime() - start.getTime()) + ",result is " + result);

      }

      public static void runMvel(int xmax, int ymax, int zmax) {

      Map context = new HashMap();

      String expression = "x + y*2 - z";

      Serializable compileExpression = MVEL.compileExpression(expression);

      Integer result = 0;

      Date start = new Date();

      for (int xval = 0; xval < xmax; xval++) {

      for (int yval = 0; yval < ymax; yval++) {

      for (int zval = 0; zval <= zmax; zval++) {

      context.put("x", xval);

      context.put("y", yval);

      context.put("z", zval);

      VariableResolverFactory functionFactory = new MapVariableResolverFactory(context);

      Integer cal = (Integer) MVEL.executeExpression(compileExpression, context, functionFactory);

      result += cal;

      }

      }

      }

      Date end = new Date();

      System.out.println("MVEL:time is : " + (end.getTime() - start.getTime()) + ",result is " + result);

      }

      public static void runSpel(int xmax, int ymax, int zmax) {

      SpelParserConfiguration config;

      ExpressionParser parser;

      config = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, RunSpel.class.getClassLoader());

      parser = new SpelExpressionParser(config);

      StandardEvaluationContext context = new StandardEvaluationContext();

      Integer result = 0;

      String expressionStr = "#x + #y*2 - #z";

      Date start = new Date();

      for (Integer xval = 0; xval < xmax; xval++) {

      for (Integer yval = 0; yval < ymax; yval++) {

      for (Integer zval = 0; zval <= zmax; zval++) {

      context.setVariable("x", xval);

      context.setVariable("y", yval);

      context.setVariable("z", zval);

      Expression expression = parser.parseExpression(expressionStr);

      Integer cal = expression.getValue(context, Integer.class);

      result += cal;

      }

      }

      }

      Date end = new Date();

      System.out.println("SpEL:time is : " + (end.getTime() - start.getTime()) + ",result is " + result);

      }

      public static void runGroovyClass(int xmax, int ymax, int zmax) {

      GroovyClassLoader loader = new GroovyClassLoader();

      Class groovyClass = null;

      try {

      groovyClass = loader.parseClass(new File(

      "GroovyCal.groovy"));

      } catch (IOException e) {

      e.printStackTrace();

      }

      GroovyObject groovyObject = null;

      try {

      groovyObject = (GroovyObject) groovyClass.newInstance();

      } catch (InstantiationException e) {

      e.printStackTrace();

      } catch (IllegalAccessException e) {

      e.printStackTrace();

      }

      Integer result = 0;

      Date start = new Date();

      for (int xval = 0; xval < xmax; xval++) {

      for (int yval = 0; yval < ymax; yval++) {

      for (int zval = 0; zval <= zmax; zval++) {

      Object[] args = {xval,yval,zval};

      Integer cal = (Integer) groovyObject.invokeMethod("cal", args);

      result += cal;

      }

      }

      }

      Date end = new Date();

      System.out.println("Groovy Class:time is : " + (end.getTime() - start.getTime()) + ",result is " + result);

      }}

    【Java中的動態(tài)代碼編程】相關文章:

    在Java中執(zhí)行JavaScript代碼04-01

    數控編程代碼大全03-09

    數控編程M代碼大全04-24

    Java基本編程技巧03-31

    如何讓JAVA代碼更高效03-20

    Java代碼的基本知識02-27

    java證書的加密與解密代碼02-26

    Java編程常見問題匯總02-28

    java非對稱加密的源代碼(rsa)03-30

    主站蜘蛛池模板: 精品无人区无码乱码大片国产| 亚洲AV永久无码精品| 无码乱码观看精品久久| 国产精品99久久精品| 亚洲第一永久AV网站久久精品男人的天堂AV | 精品久久久久久国产牛牛app| 久久国产精品一国产精品金尊| 国产综合免费精品久久久| 国产精品久久久久久一区二区三区| 亚洲日韩精品射精日| 国产午夜精品一区二区| 青青草国产精品欧美成人| 国产精品无码a∨精品| 亚洲精品无码乱码成人| 鲸鱼传媒绿头鱼实验室之炮机测评日韩精品一级毛 | 国产午夜福利精品一区二区三区 | 欧洲精品久久久av无码电影| 久久这里有精品视频| 国产精品麻豆VA在线播放| 黑人精品videos亚洲人| 国产精品99精品无码视亚| 漂亮人妻被黑人久久精品| 亚洲线精品一区二区三区| 午夜肉伦伦影院久久精品免费看国产一区二区三区 | 一色屋精品视频在线观看| 人妻无码久久精品| 精品亚洲欧美中文字幕在线看| 国产成人久久精品麻豆一区| 亚洲国产精品热久久| 久久精品这里热有精品| 精品久久久久久久| 久久er热视频在这里精品| 国产成人精品免费视| 国产精品内射后入合集| 国产精品白浆在线观看免费| 国产精品一久久香蕉国产线看观看 | 香港三级精品三级在线专区 | 久久亚洲AV永久无码精品| 精品久久久久久无码中文字幕 | 欧美肥屁VIDEOSSEX精品| 日韩av无码久久精品免费|