熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> JSP教程 >> 正文

克服J2SE 1.3 ~ 1.4不兼容問題 HK2000c

2013-11-15 11:43:47  來源: JSP教程 

  概要
  如果你要實現JavaAPI中的一個那麼可能是件比較痛苦的事情你經常會需要實現許多交叉依賴的接口對新特性的需求促成了升級現有的JavaAPI這就造成了提供這些API的供應商對他們的相關實現不斷的升級以維持相關功能隨著這些API的升級更改越來越頻繁API代碼的不兼容使你不得不分別維護新舊版本的代碼庫這直接到導致了你維護成本和難度的增加本文演示了解決此問題的技術揭示了如何僅使用一個代碼庫編譯不同JavaAPI版本的代碼
  
  現在非常多的API被加入到到Java的標准庫中比如JDBC這樣做的好處是Java可選包在部署時不必被綁定到相關的部署應用中去這些API由專門的專業開發小組實現在實際的使用當中這些API變得越來越受歡迎使用的深度及廣度也在不斷的增加但是有時候對一些API升級會變得使一些類及方法不可用開發小組寧願讓這些API包成為可選組件而不是作為Java標准支持庫的形式來發布但是一旦加入標准庫中的API包就像是和用戶簽定了終生契約想再成為可選包是不可能的所以作為用戶的你可能會突然發現你一下子自己的代碼庫變成了不兼容的個代碼庫一個是使用新API的代碼庫另一個是使用舊API的代碼庫你可能會以為情況不像你想象的那樣糟糕我這裡舉一個簡單的例子JSE中由於對JDBC中的一些API的升級使的javasqlConnection 不能同時被 版本編譯通過你可能會遇到我這樣的困境我可能需要實現javasqlConnection這個接口但是我的代碼需要同時通過 得編譯但是我不想同時維護個版本的代碼庫所以我開始尋找更好的解決方法
  
  如果你依賴於javac來編譯你的應用的話那麼很不幸Java著名的一次編寫到處運行(WORA)並不包括WOCA(一次編寫到處編譯^_^;)
  
  不過別太沮喪編碼的反射技巧以及編譯的Ant技巧是你能夠安然過關我能夠僅僅使用一組Java文件以及Ant工具就能使一個版本同時編譯在 版本下面別急在我結識解決辦法之前讓我先詳細的解釋一下問題的描述
  
  可憐人的連接池(PS:Poor mans connection pool 很有意思的一句話)
  兩年前我的公司需要一個連接池但是又不肯出錢買一個當時並沒有什麼免費的東東可以使用所以我們自己寫了一個連接池為了能更好的跟蹤在整個應用中連接的情況我們寫了一個comicentrissqlConnectionWrapper類它實現了javasqlConnection 接口以及其他的一些包裝類(實現了另外的一些的javasql 接口)這些包裝類僅僅是跟蹤我們應用中的數據庫使用以及通過方法調用真正的數據庫資源
  當JSE來的時候我們自然而然的想到升級我們提供給客戶的應用使這些應用的性能得到很多提升當然我們也需要保留版本因為有些客戶根本不需要升級到我們氣惱的發現如果我們不修改我們的ConnectionWrapper 以及其他JDBC封裝類根本通不過JSE的編譯
  
  為了文章的簡明我通過使用ConnectionWrapper 這個類來演示我對所有其他不能夠通過JSE的類所使用的技術如果我按照新的API標准那麼我不得不添加幾個方法到ConnectionWrapper中去接下來個大問題擺在了面前
  
  因為我的包裝類需要經歷方法調用我將不得不調用在JSE sql類中並不存在的方法
  因為一些新的方法涉及到一些新出現的類我將不得不在編譯中面對那些在JSE中並不存在的類
  
  反射提供了援助
  一些代碼可以很方便的解釋第一個問題但是我的ConnectionWrapper 封裝了javasqlConnection 所有的我的例子
  依賴於在構造方法中的變量 realConnection
  
  private javasqlConnection realConnection = null;
  
  public ConnectionWrapper(javasqlConnection connection) {
  realConnection = connection;
  }
  
  為了看清楚我怎麼做到解決版本不兼容問題讓我們仔細看一下setHoldability(int)(這個在JSE被聲明的新方法)
  public void setHoldability(int holdability) throws SQLException {
  realConnectionsetHoldability( holdability );
  }
  
  很不幸這個方法在JSE中顯然通不過編譯這就陷入了難的尴尬境地為了解決這一情況我假定setHoldability() 將只會在JSE
  下面被調用所以我使用了反射機制來調用該方法
  
  public void setHoldability(int holdability) throws SQLException {
  Class[] argTypes = new Class[] { IntegerTYPE };
  Object[] args = new Object[] {new Integer(holdability)};
  callJavaMethod(setHoldability realConnection argTypes args);
  }
  
  public static Object callJavaMethod(String methodName Object instance
  Class[] argTypes Object[] args)
  throws SQLException
  {
  try {
  Method method = instancegetClass()getMethod(methodName argTypes);
  return methodinvoke(instance args );
  } catch (NoSuchMethodException e) {
  eprintStackTrace();
  throw new SQLException(Error Invoking method ( + methodName + ):
  + e);
  } catch (IllegalAccessException e) {
  eprintStackTrace();
  throw new SQLException(Error Invoking method ( + methodName + ):
  + e);
  } catch (InvocationTargetException e) {
  eprintStackTrace();
  throw new SQLException(Error Invoking method ( + methodName + ):
  + e);
  }
  }
  
  現在我有了setHoldability() 方法因此能順利通過JSE的編譯原理是我並不直接調用JSE中間javasqlConnection並不存在的方法
  而是轉為通過讓setHoldability調用callJavaMethod這個通用方法來調用然後在一個SQLException 裡封裝所有的異常這樣就達到我預期的效果
  現在所有的在JSE中新方法都工作的很好在JSE的老版本下也能順利編譯而且工作正常現在我來著手解決第二個問題
  就是如何在應用中能夠找到一個方法能夠使用JSE中並不存在的新的類
  
  Ant 是答案
  在JSEjavasqlConnection 依賴於一個新的類javasqlSavepoint因為這個類在javasql 包中所以你不可能把它加入到JSE中去Java不允許任何的第三方擴展包加入它的核心包(java* 以及 javax* )中去 因此挑戰來了在JSE下調用這個新的javasqlSavepoint 類但同時需要代碼能夠在JSE下面得到編譯以及能夠運行很簡單不是嗎?所有回答Yes的人都會得到一個榛仁巧克力餅(PS:哈哈我回答了可是沒有P)至少現在我找到了答案使問題變得很簡單了
  首先我插入了下面一條有條件的import語句
  // Comment_next_line_to_compile_with_Java_
  import javasqlSavepoint;
  
  然後我找到了一個能夠在JSE下面注釋掉import的方法非常簡單使用如下Ant 語句就可以了
  <replace>
  <replacetoken>Comment_next_line_for_Java_
  </replacetoken>
  <replacevalue>Comment_next_line_for_Java_
  //</replacevalue>
  </replace>
  
  這個Ant 的 replace 標簽 有好幾個標簽選項在以後我給出的全部例子裡有很多在這裡面最重要的是使用<replacevalue>來替換<replacetoken>
  在XML裡面的意思是換行在JSE沒什麼會發生 但是在JSE下面一個import聲明被注釋掉了
  // Comment_next_line_to_compile_with_Java_
  //import javasqlSavepoint;
  
  但是我在代碼中Savepoint仍在使用public Savepoint setSavepoint(String name) throws SQLException { }不過我只在JSE使用這些方法類在JSE中只要能編譯就可以了我發現只要我有一個我自己的Savepoint 類在我的包中我的代碼就能夠通過編譯而且不用任何的import包但是我又要同時在這條import 語句不被注釋的同時我自己的Savepoint類被忽略掉因此我造了一個空的comicentrissqlSavepoint類這個可能(除了JavaDoc)是最短的有效類
  package comicentrissql;
  
  /** Dummy class to allow ConnectionWrapper to implement javasqlConnection
  * and still compile under JSE and JSE When compiled
  * under JSE this class compiles as a placeholder instead of the
  * missing javasqlSavepoint (not in JSE ) When compiled
  * under JSE this class is ignored and ConnectionWrapper uses the
  * javasqlSavepoint that is new in JSE
  */
  public class Savepoint {}
  
  在JSE下我能夠正確的import javasqlSavepoint類而在JSE下面Ant注釋了這條import語句因此這個Savepoint就被替換成了我這個包裡面寫的一個空的Savepoint類所以我現在就能加入任何引用到Savepoint類的方法同樣的在這些新方法中使用剛才所說的反射方法
  // Comment_next_line_to_compile_with_Java_
  import javasqlSavepoint;
  
  
  public Savepoint setSavepoint() throws SQLException {
  Class[] argTypes = new Class[];
  Object[] args = new Object[];<
From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19513.html
  • 上一篇文章:

  • 下一篇文章:
  • 推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.