OSGi實戰總結


  1、類加載問題ClassNotFoundException

  在OSGi環境中,ClassNotFoundException是最常見的,主要是因為在OSGi環境,每一個Bundle都有自己獨立的ClassLoader,而Bundle之間的通信交互是通過依賴關系(import/export)來控制,隨着系統越來越復雜,依賴關系也就越來越復雜(尤其是在一些沒有嚴格控制依賴的系統中),因此,出現這種異常的頻率非常高。類似的,也經常會出現NoClassDefDoundErr、ClassCastException異常。

  遇到這類問題,直接從異常日志是很難精確定位根源的,必須打開OSGi提供的調試日志(詳細調試選項可以參考OSGi項目的Debug.java類),這樣從日志就可以看出是哪個Bundle加載哪個類遇到什么問題。

  但是,如果我們在啟動服務的時候就打開這些調試日志,系統啟動會非常慢,因為輸出了很多的日志,運行期也同樣非常慢。那么,就需要一個可以動態開關調試日志的功能。我們可以通過擴展OSGi的CommandProvider,實現一個自己的命令,然后可以動態的修改Debug.java屬性值來達到目的。

例如修改調試參數的命令:

public class DebugCommandProvider implements CommandProvider {
    public void _debug(CommandInterpreter ci) {
        String debug_field = ci.nextArgument();
        String tip = ci.nextArgument();
        if (null != debug_field && debug_field.trim().length() > 0) {
            if (null != tip && tip.trim().length() > 0) {
                try {
                    debug_field = debug_field.trim().toUpperCase();
                    Field field = Debug.class.getDeclaredField(debug_field);
                    boolean flag = tip.trim().toUpperCase().equals("ON");
                    field.set(null, flag);
                    ci.print("設置Debug參數:[" + debug_field + "=" + flag + "]\r\n");
                } catch (Exception e) {
                    ci.print("設置Debug參數時出現異常:" + e.getMessage() + "\r\n");
                }
            } else {
                ci.println("未指定參數,例如: debug debug_loader <on|off>");
            }
        } else {
            ci.println("未指定參數,例如: debug debug_loader <on|off>");
        }
    }
    ...
}    

 

  2、OSGi調試環境擴展

  為了讓開發人員能知道OSGi容器里面的方方面面,框架本身提供了一個調試控制台,通過命令可以查看容器裝載的Bundle、服務、依賴等所有需要知道的系統服務信息。

  在開發環境下,通過JVM參數-console開啟,直接在Eclipse控制台就可以輸入命令;如果不希望命令輸出和控制台日志混合的話,可以單獨指定一個端口。

  通常,生產環境就會指定一個端口來隔離應用日志,然后telnet進去操作命令。

  例如生產環境開啟控制台的配置:

<servlet-class>org.eclipse.equinox.servletbridge.BridgeServlet</servlet-class>    
  <init-param>
    <param-name>enableFrameworkControls</param-name>
    <param-value>true</param-value>    
  </init-param>
  <init-param>
    <param-name>commandline</param-name>
    <param-value>-console 9999</param-value>    
  </init-param>
</servlet>

  但是,這個配置不能用在集群下,會端口沖突,動態web配置顯得麻煩。

  然后,一個Web形式的OSGi控制台就應該出來了,主要實現就是提供一個命令的重定向,將輸入的命令重定向到OSGi控制台,然后將命令結果輸出到web頁面。核心就是圍繞org.eclipse.osgi.framework.internal.core.FrameworkConsole類傳參,並指定好PrintWriter。

  3、服務異常自動分析報告

  無論什么好東西,如果不好好的使用的話,時間久了都會把它玩爛。OSGi就是如此,如果模塊、依賴起初沒有嚴格規划好,越到后面,遇到的問題就越多,也越復雜,維護成本非常高。

  但是,有些問題可以根據經驗和具體實現來自動分析,然后得出一份異常分析報告並給出相應的解決方案,好處就是根據分析報告可以快速定位解決問題。

  報告可以包括參數配置信息、Bundle依賴校驗結果、Bundle啟動異常、bean異常、上下文發布異常、資源注冊信息等

  值得一提的是Bundle依賴校驗,通常都是采用eclipse自帶的依賴校驗功能,可以直接看出不滿足的依賴信息。但是,生成環境在沒有eclipse的情況就沒那么簡單了。雖然OSGi會將依賴校驗不滿足的信息寫到一個日志文件里面,但是太冗余,對於問題定位很多時候都沒什么幫助。

  舉個例子,如果有一個依賴鏈涉及很多的Bundle,而處於這個鏈中間的某個Bundle依賴有問題導致不能正常解析,結果就導致依賴它的Bundle(包括間接的)都不能解析。笨辦法就是操作控制台,一個一個排查(通過diag命令可以看未滿足約束信息),簡單的情況可以整出結果來,稍微復雜的情況就繞不出來了。最后實在不行就只有將項目拷貝到eclipse中看校驗結果。

  該問題的終極解決辦法就是在框架裝載完Bundle后自動輸出校驗結果,而且只輸出依賴鏈的葉子節點信息,這樣就可以一目了然的發現是哪個Bundle導致的依賴問題。核心就是圍繞org.eclipse.osgi.service.resolver.State類,它有一個方法getResolverErrors()可以根據BundleDescription來獲取解析錯誤信息,然后對這些信息進行分析得出結果。

  4、分層啟動

  如果一個系統比較龐大,並且模塊依賴比較規范,比如系統分了平台層、業務層,只有業務層能依賴平台層,這樣就可以優先啟動平台層,然后再啟動業務層。通過這樣的啟動可以減少服務依賴的等待時間,並且如果平台層啟動發現問題時,可以停止后續的啟動過程,對於問題的定位效率也是非常大的提升。

  OSGi有一個StartLevel的服務,首先約定Bundle的啟動級別,然后通過調整框架級別就可以實現分層啟動了。

  5、OSGi與Spring的整合問題

  可以通過SpringDM進行整合。

  但是也有一些優化,比如在對Bundle的Class進行掃描的時候,同時會對它依賴的Bundle進行掃描,其實這是多余的,只關心當前Bundle的類,其他的即使掃描出來也沒有任何用處,但是該操作又比較耗時。

  6、OSGi部署優化

  在集群環境下,部署的web應用都會同步到各個節點,如果應用較大的話,同步操作也比較耗時。

  如果節點都在同一個機器上的話,可以讓所有節點都從同一個Bundle插件目錄讀取,然后將里面的Bundle安裝到OSGi框架。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM