<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Chasing an mobile web vision

    闖蕩在移動(dòng)互聯(lián)網(wǎng)的世界中

    OSGi介紹(五)兩個(gè)bundle

    (四)中提到的直接型改造法實(shí)際上和一個(gè)傳統(tǒng)的java應(yīng)用程序沒(méi)有區(qū)別。因此客戶(hù)的需求發(fā)生變化,通常是牽一發(fā)而動(dòng)全身。
    那么我們現(xiàn)在就看看如果在osgi framework中,用多個(gè)bundle來(lái)實(shí)現(xiàn)的效果吧。
    我的想法是用兩個(gè)bundle來(lái)配合實(shí)現(xiàn)“扶貧助手”的功能。一個(gè)bundle專(zhuān)門(mén)負(fù)責(zé)錄入和顯示紀(jì)錄,一個(gè)bundle專(zhuān)門(mén)負(fù)責(zé)紀(jì)錄的數(shù)據(jù)結(jié)構(gòu)和對(duì)數(shù)據(jù)的處理,用時(shí)下時(shí)髦的說(shuō)法就是使用了mvc,只是我的m和c放到了一起。
    先看看mc的bundle實(shí)現(xiàn)代碼片斷:

    package com.wukong.test.family.control;
    import java.util.*;
    import com.wukong.test.family.control.impl.*;
    public interface FamilyInfoDatabase {
        
    public static class FamilyFactory {
            
    private static FamilyInfoDatabase database;
            
    public static FamilyInfoDatabase getDatabaseInstance(){
                
    if(database == null){
                    database 
    = new FamilyDatabase();
                }

                
    return database;
            }

        }

        
    public String[] getColumns();
        
    public Object getValueAt(int row, int column);
        
    public String[] getSortingFields();
        
    public int getRowCount();
        
        
    public void sort(String sortField) throws IllegalArgumentException;
        
        
    public void addEntry(List columns, List values) throws IllegalArgumentException;
        
    public void deleteEntry(String familyName);
        
    public void update(String familyName,List columns, List values)throws IllegalArgumentException;
    }



    這個(gè)interface是用來(lái)描述一個(gè)數(shù)據(jù)庫(kù)所具備的基本功能。注意,這個(gè)interface被放到了package com.wukong.test.family.control中。
    另外,這個(gè)interface還提供了一個(gè)內(nèi)嵌類(lèi),用來(lái)專(zhuān)門(mén)提供一個(gè)工廠(chǎng)方法來(lái)產(chǎn)生唯一的一個(gè)數(shù)據(jù)庫(kù)實(shí)例。
    對(duì)于這個(gè)數(shù)據(jù)庫(kù)的實(shí)現(xiàn),代碼片斷如下(增加,刪除和修改的代碼都被省略了,只給出排序的代碼):
    package com.wukong.test.family.model.impl;
    public class FamilyInfoEntry {
        
    private String familyName;
        
    private int population;
        
    private int incomePerYear;
        
        FamilyInfoEntry(String familyName,
    int population,int income){
            
    this.familyName = familyName;
            
    this.population = population;
            
    this.incomePerYear = income;
        }

        
        
        String getFamilyName() 
    {
            
    return familyName;
        }

        
    int getIncomePerYear() {
            
    return incomePerYear;
        }

        
    int getPopulation() {
            
    return population;
        }

    }


    package com.wukong.test.family.control.impl;
    import com.wukong.test.family.control.FamilyInfoDatabase;
    import java.util.*;
    public class FamilyDatabase implements FamilyInfoDatabase {
        
    private LinkedList familyEntryList = new LinkedList();
        
    private Object[] sortedValues = null;
        
    public FamilyDatabase() {
            
    this.familyEntryList.add(new FamilyInfoEntry("Zhang",3,1200));
            
    this.familyEntryList.add(new FamilyInfoEntry("Li",6,1800));
            
    this.familyEntryList.add(new FamilyInfoEntry("Liu",4,1500));
            
    this.sortedValues = this.familyEntryList.toArray();
        }

        
    public String[] getColumns() {
            
    return new String[] "Family Name""Family Population""Income" };
        }

        
    public Object getValueAt(int row, int column) {
            FamilyInfoEntry entry 
    = (FamilyInfoEntry)this.sortedValues[row];
            
    switch (column) {
            
    case 0:
                
    return entry.getFamilyName();
            
    case 1:
                
    return new Integer(entry.getPopulation());
            
    case 2:
                
    return new Integer(entry.getIncomePerYear());
            
    default:
                
    throw new IllegalArgumentException("Invalid column index.");
            }

        }

        
    public String[] getSortingFields() {
            
    return new String[] "FamilyName","Income" };
        }

        
    public int getRowCount() {
            
    return this.familyEntryList.size();
        }

        
    public void addEntry(List columns, List values)
                
    throws IllegalArgumentException {
        }

        
    public void deleteEntry(String familyName) {
        }

        
    public void update(String familyName, List columns, List values)
                
    throws IllegalArgumentException {
        }


        
    public void sort(String sortField) throws IllegalArgumentException{
            
    if(sortField.equals("FamilyName")){
                
    this.sortedValues = this.familyEntryList.toArray();
                Arrays.sort(
    this.sortedValues,new SortedByName());
                
            }

            
    if(sortField.equals("Income")){
                
    this.sortedValues = this.familyEntryList.toArray();
                Arrays.sort(
    this.sortedValues,new SortedByIncome());
            }

     
    throw new IllegalArgumentException("Sorting enties by field '" + sortField + "' is not supported."); 
        }

        
        
    class SortedByName implements Comparator{
            
    public int compare(Object entry1,Object entry2) {
                
    if (entry1 == entry2) {
                    
    return 0;
                }

                FamilyInfoEntry en1 
    = (FamilyInfoEntry) entry1;
                FamilyInfoEntry en2 
    = (FamilyInfoEntry) entry2;
                
                
    return en1.getFamilyName().compareTo(en2.getFamilyName());
            }

            
        }

        
        
    class SortedByIncome implements Comparator {
            
    public int compare(Object entry1, Object entry2) {
                
    if (entry1 == entry2) {
                    
    return 0;
                }

                FamilyInfoEntry en1 
    = (FamilyInfoEntry) entry1;
                FamilyInfoEntry en2 
    = (FamilyInfoEntry) entry2;
                
    return en1.getIncomePerYear() - en2.getIncomePerYear();
            }

        }

    }



    同樣需要注意的是我們把這個(gè)實(shí)現(xiàn)放到了package com.wukong.test.family.control.impl中
     
    下面看看v的bundle實(shí)現(xiàn)。

    package com.wukong.test.family.gui;
    import org.osgi.framework.*;
    import javax.swing.*;
    import javax.swing.table.*;
    import java.awt.*;
    import java.awt.event.*;
    import com.wukong.test.family.control.*;
    public class FamilyInfoGui implements BundleActivator, ActionListener,ItemListener {
        
    private JFrame mainFrame;
        
    private JPanel contentPanel;
        
    private JTable familiesTable;
        
    private JScrollPane familiesTableScrollPane;
        
    private JPanel sortedByPanel = new JPanel(new GridLayout(12));
        
    private JLabel sortedByLabel = new JLabel("Sorted By: ");
        
    private JComboBox sortedByList = null;
        
    private JPanel commandPanel = new JPanel(new GridLayout(13));
        
    private JButton addEntry = new JButton("Add");
        
    private JButton deleteEntry = new JButton("Delete");
        
    private JButton updateEntry = new JButton("Update");
        
        FamilyInfoDatabase database 
    = null;
        
    public void start(BundleContext context) throws Exception {
            Runnable r 
    = new Runnable() {
                
    public void run() {
                    contentPanel 
    = new JPanel();
                    familiesTableScrollPane 
    = new JScrollPane();
                    database 
    = FamilyInfoDatabase.FamilyFactory
                            .getDatabaseInstance();
                    familiesTable 
    = new JTable(new FamilyInfoTableModel(database));
                    familiesTableScrollPane.setViewportView(familiesTable);
                    
                    String[] sortedFields 
    = database.getSortingFields();
                    
                    sortedByList 
    = new JComboBox(sortedFields);
                    
                    sortedByList.addItemListener(FamilyInfoGui.
    this);
                    sortedByPanel.add(sortedByLabel);
                    sortedByPanel.add(sortedByList);
                    commandPanel.add(addEntry);
                    commandPanel.add(deleteEntry);
                    commandPanel.add(updateEntry);
                    contentPanel.add(sortedByPanel, BorderLayout.NORTH);
                    contentPanel.add(familiesTableScrollPane, BorderLayout.CENTER);
                    contentPanel.add(commandPanel, BorderLayout.SOUTH);
                    mainFrame 
    = new JFrame();
                    mainFrame.setContentPane(contentPanel);
                    mainFrame.setSize(
    new Dimension(500600));
                    mainFrame.show();
                }

            }
    ;
            Thread t 
    = new Thread(r);
            t.start();
        }

        
    public void stop(BundleContext context) throws Exception {
            
    this.mainFrame.dispose();
        }

        
    public void actionPerformed(ActionEvent event) {
        }

        
        
        
    public void itemStateChanged(ItemEvent event) {
            
    if(event.getSource() == this.sortedByList){
                String sortingField 
    = (String)event.getItem();
                
    this.database.sort(sortingField);
                
    this.familiesTable.repaint();
            }

        }

        
    class FamilyInfoTableModel extends AbstractTableModel {
            
    private FamilyInfoDatabase database;
            FamilyInfoTableModel(FamilyInfoDatabase database) 
    {
                
    this.database = database;
            }

            
    public String getColumnName(int col) {
                
    return database.getColumns()[col];
            }

            
    public boolean isCellEditable(int row, int col) {
                
    return false;
            }

            
    public int getColumnCount() {
                
    return database.getColumns().length;
            }

            
    public int getRowCount() {
                
    return database.getRowCount();
            }

            
    public Object getValueAt(int row, int col) {
                
    return database.getValueAt(row, col);
            }

        }

    }


    v的實(shí)現(xiàn)基本是界面的構(gòu)造,而關(guān)于數(shù)據(jù)庫(kù),它只能看到interface FamilyInfoDatabase,因?yàn)樗籭mport com.wukong.test.family.control.*,然后通過(guò)FamilyInfoDatabase內(nèi)嵌靜態(tài)類(lèi)的靜態(tài)工廠(chǎng)方法獲得數(shù)據(jù)庫(kù)的實(shí)例,這樣它完全不用關(guān)心數(shù)據(jù)庫(kù)如何實(shí)現(xiàn)。
     
    源碼編譯后得到class文件后,下一步我們的工作就要來(lái)構(gòu)造這兩個(gè)bundle。最關(guān)鍵的步驟就是為每個(gè)bundle寫(xiě)它的manifest文件
    我們先給出mc bundle的manifest文件(familycontrol.mf):
    Manifest-Version: 1.0
    Bundle-SymbolicName: com.wukong.test.family.control
    Bundle-Name: family control
    Bundle-Version: 
    1.0
    Bundle-Vendor: LiMing
    Export-Package: com.wukong.test.family.control


    非常簡(jiǎn)單,但請(qǐng)大家注意這行
    Export-Package: com.wukong.test.family.control
    它告訴framework,這個(gè)bundle提供com.wukong.test.family.control這個(gè)包。
    所謂“bundle A提供某個(gè)包”意思,通俗簡(jiǎn)單的理解是如果bundle B在manifest文件中說(shuō)明要使用這個(gè)包(通過(guò)Import-Package這個(gè)關(guān)鍵字,下面會(huì)在v bundle中有說(shuō)明)那么bundle B運(yùn)行時(shí),當(dāng)使用到這個(gè)包中的類(lèi)時(shí),framework將告訴B的class loader這個(gè)類(lèi)的定義是來(lái)自bundle A,從而不會(huì)發(fā)生ClassNotFoundException。另外值得一提的是我們并沒(méi)有把com.wukong.test.family.control.impl這個(gè)包加進(jìn)來(lái),這樣做的目的也是為了隱藏具體實(shí)現(xiàn)。將來(lái)只要interface不變,我們可以使用不同的實(shí)現(xiàn)來(lái)替換現(xiàn)有實(shí)現(xiàn),大大提高擴(kuò)展性。
     
    還有一點(diǎn),細(xì)心的話(huà),你會(huì)發(fā)現(xiàn)這個(gè)bundle沒(méi)有activator。這是允許的,這種bundle就像動(dòng)態(tài)連接庫(kù),只提供接口和方法以及實(shí)現(xiàn),等待其他實(shí)體的調(diào)用,而本身不能運(yùn)行。
    再來(lái)看看v bundle的manifest文件(family.mf):

    Manifest-Version: 1.0
    Bundle-SymbolicName: com.wukong.test.family.gui
    Bundle-Name: family gui
    Bundle-Version: 
    1.0
    Bundle-Vendor: LiMing
    Bundle-Activator: com.wukong.test.family.gui.FamilyInfoGui
    Import-Package: org.osgi.framework
    ;version=1.3,com.wukong.test.family.control


    正如上面曾經(jīng)提到過(guò)的一樣,我們?cè)贗mport-Package:關(guān)鍵字中指定該bundle需要使用com.wukong.test.family.control包。在v bundle的源代碼中,我們也看到這個(gè)bundle的確使用了com.wukong.test.family.control包中的FamilyInfoDatabase。更深入一點(diǎn),我們可以簡(jiǎn)單的這樣理解,當(dāng)v bundle運(yùn)行的時(shí)候,framework通過(guò)匹配bundle間的Import-Package和Export-Package,
    然后告訴v bundle,F(xiàn)amilyInfoDatabase這個(gè)類(lèi)型的定義和裝載實(shí)際上是由mc bundle完成的。這樣,v bundle就會(huì)使用mc bundle的class loader來(lái)加在這個(gè)類(lèi)型。另外,按照osgi framework的spec規(guī)定,javax.swing;javax.swing.table;java.awt;java.awt.event這4個(gè)包都都不屬于framework的必備包,所以應(yīng)該在Import-Package中指定。為了不用在Import-Package中指定這4個(gè)包,這個(gè)例子要求運(yùn)行在sun的j2se的jvm(比如version 1.4.2_04),這樣4個(gè)包都作為java api由bootstrap classloader加載,每個(gè)bundle都可以直接使用了。
     
    有了manifest文件,我們最后就是打jar包了。
    比如在windows下,你把兩個(gè)manifest文件放在包的根目錄,然后執(zhí)行以下命令
    jar -cvfm family.jar family.mf com\wukong\test\family\gui\*.class
    jar -cvfm familycontrol.jar familycontrol.mf com\wukong\test\family\control
    這樣,我們就可以認(rèn)為family.jar是我們的v bundle而familycontrol.jar是我們的mc bundle。
    下面,我們就來(lái)安裝運(yùn)行這兩個(gè)bundle吧。
    我將首先簡(jiǎn)單介紹一個(gè)我自己編寫(xiě)的osgi framework,然后結(jié)合這個(gè)demo framework來(lái)部署和運(yùn)行新的“扶貧助手”。
    本人編寫(xiě)的osgi framework基本上完成了spec r4的核心規(guī)范,但是與安全相關(guān)的功能都沒(méi)有實(shí)現(xiàn)。
    啟動(dòng)這個(gè)framework后,它的shell提供了如下簡(jiǎn)單的framework管理功能命令:
    bl 即bundle list,查看所有已經(jīng)安裝的bundle
    dl 即detailed bundle list,用來(lái)查看某個(gè)bundle的詳細(xì)信息
    sl 即service list,用來(lái)查看所有已經(jīng)注冊(cè)的service
    ls 即list setting,用來(lái)查看所有設(shè)置的系統(tǒng)屬性(System.getProperties)和framework當(dāng)前的active start level
    in 即install bundle,通過(guò)指定bundle文件的url來(lái)安裝該bundle
    up 即update bundle,通過(guò)指定bundle id來(lái)升級(jí)指定的bundle
    un 即uninstall bundle,通過(guò)指定bundle id來(lái)卸載指定的bundle
    stt 即start bundle,通過(guò)指定bundle id來(lái)啟動(dòng)指定的bundle
    stp 即stop bundle,通過(guò)指定bundle id來(lái)停止指定bundle的運(yùn)行
    rst 即restart bundle,通過(guò)指定bundle id來(lái)重新啟動(dòng)指定的bundle
    rfr 即refresh package,當(dāng)某些bundle被更新或卸載后,如果不執(zhí)行這個(gè)命令,那么被更新或卸載的bundle的Export-Package(如果有的話(huà))將繼續(xù)服役,
    也就是說(shuō),之前使用這些包的bundle不會(huì)因?yàn)檫@個(gè)bundle被更新或者卸載而發(fā)生變化。而執(zhí)行這個(gè)命令后,受影響的bundle將被重新解析
    rest 即restart,重新啟動(dòng)framework,屬于“熱起”
    shut 即shutdown,停止整個(gè)framework的運(yùn)行
    set 用來(lái)設(shè)置framework的active startlevel或者某個(gè)bundle的start level
    log 用來(lái)查看系統(tǒng)的日志信息
    現(xiàn)在我們來(lái)假設(shè)運(yùn)行環(huán)境如下:
    OS: window
    jvm: j2se 1.4.2_04
    family.jar和familycontrol.jar這兩個(gè)文件放在D:/framework/bundles目錄下
    第一步:安裝bundle
    輸入以下兩條命令:
    in file:D:/framework/bundles/familycontrol.jar
    in file:D:/framework/bundles/family.jar
    然后用bl命令查看結(jié)果,其中得到如下顯示結(jié)果:
    Bundle Id Bundle Name Bundle State Start Level Bundle Location     Bundle Symbolic Name
    0  OSGiFramework Active  0  System Bundle     system.bundle
    .
    .(省略部分結(jié)果顯示)
    .
    16  family control Installed 1  file:D:/framework/bundles/familycontrol.jar com.wukong.test.family.control
    17  family gui Installed 1  file:D:/framework/bundles/family.jar  com.wukong.test.family.gui
    說(shuō)明兩個(gè)bundle安裝成功,其中mc bundle的id是16, v bundle的id是17
    第二步:?jiǎn)?dòng)bundle
    可以輸入以下命令
    stt 16,17
    然后我們就可以看到一個(gè)JFrame顯示出來(lái),里面顯示了3條記錄,沒(méi)有任何順序(其順序?qū)嶋H上是在程序中添加到LinkedList的順序)。我們可以在Sorted By的列表中看到有兩個(gè)選擇“FamilyName”和“Income”,當(dāng)選擇“Income”時(shí),你將發(fā)現(xiàn)3條記錄按年收入由小到大排列起來(lái)。程序的運(yùn)行完全符合我們的意圖。
    這時(shí)如果我們?cè)儆胋l命令查看,將得到如下結(jié)果:
    Bundle Id Bundle Name Bundle State Start Level Bundle Location     Bundle Symbolic Name
    0  OSGiFramework Active  0  System Bundle     system.bundle
    .
    .(省略部分結(jié)果顯示)
    .
    16  family control Resolved 1  file:D:/framework/bundles/familycontrol.jar com.wukong.test.family.control
    17  family gui Active  1  file:D:/framework/bundles/family.jar  com.wukong.test.family.gui
    注意:由于mc bundle沒(méi)有Activator,所以啟動(dòng)這個(gè)bundle只會(huì)使其進(jìn)入Resolved狀態(tài)。

    有了這樣的結(jié)構(gòu),程序變得靈活些了。現(xiàn)在假設(shè)客戶(hù)提出需要增加一個(gè)字段,即人均年收入,并且提供按人均年收入排列紀(jì)錄。看看framework框架下,這樣的變動(dòng)是如何的簡(jiǎn)單!
    首先,我們通過(guò)分析,發(fā)現(xiàn)只要更改mc bundle的代碼,使得數(shù)據(jù)庫(kù)的實(shí)現(xiàn)中增加這個(gè)字段以及相應(yīng)的排序方法即可。更新后的代碼如下:

    package com.wukong.test.family.control.impl;
    import com.wukong.test.family.control.FamilyInfoDatabase;
    import java.util.*;
    public class FamilyDatabase implements FamilyInfoDatabase {
        
    private LinkedList familyEntryList = new LinkedList();
        
    private Object[] sortedValues = null;
        
    public FamilyDatabase() {
            
    this.familyEntryList.add(new FamilyInfoEntry("Zhang",3,1260));
            
    this.familyEntryList.add(new FamilyInfoEntry("Li",6,1800));
            
    this.familyEntryList.add(new FamilyInfoEntry("Liu",4,1500));
            
    this.sortedValues = this.familyEntryList.toArray();
        }

        
    public String[] getColumns() {
            
    return new String[] "Family Name""Family Population""Income" ,"IncomePerPerson"};//添加了“IncomePerPerson”字段
        }

        
    public Object getValueAt(int row, int column) {
            FamilyInfoEntry entry 
    = (FamilyInfoEntry)this.sortedValues[row];
            
    switch (column) {
            
    case 0:
                
    return entry.getFamilyName();
            
    case 1:
                
    return new Integer(entry.getPopulation());
            
    case 2:
                
    return new Integer(entry.getIncomePerYear());
            
    case 3:
                
    return new Integer(entry.getIncomePerYear()/entry.getPopulation());//計(jì)算人均年收入
            default:
                
    throw new IllegalArgumentException("Invalid column index.");
            }

        }

        
    public String[] getSortingFields() {
        }

        
    public int getRowCount() {
            
    return this.familyEntryList.size();
        }

        
    public void addEntry(List columns, List values)
                
    throws IllegalArgumentException {
            
    // TODO Auto-generated method stub
        }

        
    public void deleteEntry(String familyName) {
            
    // TODO Auto-generated method stub
        }

        
    public void update(String familyName, List columns, List values)
                
    throws IllegalArgumentException {
            
    // TODO Auto-generated method stub
        }

        
    public void sort(String sortField) throws IllegalArgumentException{
            
    if(sortField.equals("FamilyName")){
                
    this.sortedValues = this.familyEntryList.toArray();
                Arrays.sort(
    this.sortedValues,new SortedByName());
                
            }

            
    if(sortField.equals("Income")){
                
    this.sortedValues = this.familyEntryList.toArray();
                Arrays.sort(
    this.sortedValues,new SortedByIncome());
            }

            
    if(sortField.equals("IncomePerPerson")){//對(duì)紀(jì)錄按人均年收入進(jìn)行排序
                this.sortedValues = this.familyEntryList.toArray();
                Arrays.sort(
    this.sortedValues,new SortedByIPP());
                
            }

        }

        
        
    class SortedByName implements Comparator{
            
    public int compare(Object entry1,Object entry2) {
                
    if (entry1 == entry2) {
                    
    return 0;
                }

                FamilyInfoEntry en1 
    = (FamilyInfoEntry) entry1;
                FamilyInfoEntry en2 
    = (FamilyInfoEntry) entry2;
                
                
    return en1.getFamilyName().compareTo(en2.getFamilyName());
            }

            
        }

        
        
    class SortedByIncome implements Comparator {
            
    public int compare(Object entry1, Object entry2) {
                
    if (entry1 == entry2) {
                    
    return 0;
                }

                FamilyInfoEntry en1 
    = (FamilyInfoEntry) entry1;
                FamilyInfoEntry en2 
    = (FamilyInfoEntry) entry2;
                
    return en1.getIncomePerYear() - en2.getIncomePerYear();
            }

        }

        
        
    class SortedByIPP implements Comparator {//人均年收入的排序標(biāo)準(zhǔn)。
            public int compare(Object entry1, Object entry2) {
                
    if (entry1 == entry2) {
                    
    return 0;
                }

                FamilyInfoEntry en1 
    = (FamilyInfoEntry) entry1;
                FamilyInfoEntry en2 
    = (FamilyInfoEntry) entry2;
                
    return (en1.getIncomePerYear()/en1.getPopulation()) - (en2.getIncomePerYear()/en2.getPopulation());
            }

            
        }

    }




    編譯完畢后,我們把mc bundle的manifest文件改為如下:

    Manifest-Version: 1.0
    Bundle-SymbolicName: com.wukong.test.family.control
    Bundle-Name: family control
    Bundle-Version: 
    2.0 //由1.0改為2.0
    Bundle-Vendor: LiMing
    Export-Package: com.wukong.test.family.control


    然后使用jar工具打包,并把產(chǎn)生的新的familycontrol.jar依舊放在D:/framework/bundles目錄下。
    這時(shí),我們只要執(zhí)行下面的命令,framework就完成對(duì)mc bundle的升級(jí)工作:
    up 16
    升級(jí)完畢后,你會(huì)發(fā)現(xiàn)v bundle的顯示依舊沒(méi)有任何變化。這時(shí)我們需要執(zhí)行一個(gè)refresh package命令,來(lái)更新bundle的解析:
    rfr
    這時(shí),你會(huì)發(fā)現(xiàn)原來(lái)的JFrame被關(guān)閉了,然后又一個(gè)JFrame顯示出來(lái),里面的紀(jì)錄多了一列“IncomePerPerson”,而且在“Sorted By”里面也
    多了“IncomePerPerson”,而且,排序的結(jié)果也很正確。
    瞧,framework為應(yīng)用程序提供了強(qiáng)大的動(dòng)態(tài)更新功能,非常方便。甚至都不用重新啟動(dòng)framework,更不用說(shuō)JVM了。您也許會(huì)說(shuō),最終用戶(hù)根本不可能幫你輸入這些什么in,up晦澀的命令。還有,讓用戶(hù)拷貝新版本到本地似乎也不是什么好主意。嗯,這個(gè)問(wèn)題說(shuō)得很對(duì)。其實(shí)我是偷懶了,這些操作framework都留有接口,我們只要再編寫(xiě)一個(gè)專(zhuān)門(mén)管理這兩個(gè)bundle升級(jí)的第三個(gè)bundle就可以了,這個(gè)bundle將提供友好的界面來(lái)告訴最終用戶(hù)如何升級(jí)。這樣就能夠提供比較好的解決方案了。至于第二個(gè)問(wèn)題,別忘了bundle的location是一個(gè)url,只要jvm注冊(cè)了相應(yīng)的url handler完全可以支持http,ftp等豐富的url,例如,升級(jí)的時(shí)候,framework自動(dòng)連接到供應(yīng)商的http下載服務(wù)器獲取最新版本進(jìn)行更新,當(dāng)然,我們也可以把更強(qiáng)大更靈活的升級(jí)功能及選項(xiàng)加入到上面提到的第三個(gè)bundle中,從而極大提高了程序的易用性,而且極大降低了軟件提供商的維護(hù)成本。
     
    到此為止,我已經(jīng)想不出再多好話(huà)了,但是,還可以更好!下一節(jié),將采用service的方式來(lái)實(shí)現(xiàn),嘿嘿,情況又會(huì)不一樣了,到時(shí)候我會(huì)對(duì)比一下這兩種實(shí)現(xiàn)方式的優(yōu)劣。
     
    題外話(huà):抱歉沒(méi)有拿某個(gè)著名的產(chǎn)品或者open source的產(chǎn)品來(lái)舉例,我打算把自己的實(shí)現(xiàn)也opensource,有興趣參與嗎?不管怎樣,過(guò)兩天就把實(shí)現(xiàn)上傳上來(lái),歡迎拍磚。

    posted on 2006-02-14 16:02 勤勞的蜜蜂 閱讀(4391) 評(píng)論(3)  編輯  收藏

    評(píng)論

    # re: OSGi介紹(五)兩個(gè)bundle 2007-06-22 10:27 hata

    這章講的比較長(zhǎng),要耐心看,有點(diǎn)遺憾的是沒(méi)有把工具放上來(lái)我測(cè)試不鳥(niǎo)。在eclipse里的equinox插件里只能看到bundle啟動(dòng)與否的提示,看不到運(yùn)行結(jié)果,很是郁悶。希望快點(diǎn)把實(shí)現(xiàn)傳上來(lái)啊!
    我分析下我的看法,看對(duì)不對(duì)啊:
    我有2個(gè)bundle:bundleA & bundleB
    bundleA里我寫(xiě)入: interface,pojo,iterfaceImpl
    (在manifese里:Export-Package對(duì)外提供接口)
    bundleB里我寫(xiě)入: 一系列的業(yè)務(wù)方法.
    (在manifese里:Import-Package獲取bundleA的服務(wù))
    那么這個(gè)時(shí)候就能運(yùn)用到OSGI的功能了?我即時(shí)更新bundleA的話(huà)那么bundleB會(huì)相應(yīng)發(fā)生變化!這就完成了最基本的OSGI的功能?
    ===>
    附錄:針對(duì)OSGI實(shí)戰(zhàn)上的例子,那么功能基本相同,只是擴(kuò)展了bundleB,多寫(xiě)了2個(gè)bundleC,bundleD?只是里面用到了servlet和service,我想我要看看你下面寫(xiě)的才知道怎么應(yīng)用到上面.估計(jì)理解完后調(diào)通例子也就能進(jìn)一步了解了.
    ===>
    我們做J2EE,只是想把接口放在OSGI里,經(jīng)理也只是這么說(shuō),希望能用這個(gè)做吧....期待你更多的OSGI的資料,我想你這個(gè)blog也算國(guó)內(nèi)討論osgi少有的好地方,加油加油!  回復(fù)  更多評(píng)論   

    # re: OSGi介紹(五)兩個(gè)bundle[未登錄](méi) 2009-07-24 10:04 han

    有點(diǎn)長(zhǎng)。。現(xiàn)在也不干活了。。天天看OSGI。。呵呵  回復(fù)  更多評(píng)論   

    # re: OSGi介紹(五)兩個(gè)bundle[未登錄](méi) 2009-07-24 17:26 han

    我想問(wèn)一下:FamilyInfoEntry 這個(gè)類(lèi)不放到mc bundle的manifest文件中嗎?
    這個(gè)要怎么處理?  回復(fù)  更多評(píng)論   


    只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 男女拍拍拍免费视频网站| 亚洲精品无码永久在线观看你懂的| 亚洲 暴爽 AV人人爽日日碰| 国产91色综合久久免费分享| 亚洲精品午夜视频| 免费A级毛片无码A∨免费| 久久久亚洲裙底偷窥综合| 亚洲精品视频免费在线观看| 亚洲精品成人网站在线播放| 国产精品久久久久久久久免费| 亚洲女人18毛片水真多| 无码一区二区三区免费视频| 国内精品久久久久影院亚洲 | 亚洲第一中文字幕| 无码人妻一区二区三区免费n鬼沢 无码人妻一区二区三区免费看 | 免费一区二区三区四区五区| 黄床大片30分钟免费看| 亚洲福利在线播放| 99在线免费视频| 亚洲AV无码乱码在线观看裸奔 | 噼里啪啦免费观看高清动漫4| 亚洲色欲色欲www| 日本免费福利视频| 国产成人高清亚洲一区91| 亚洲无码精品浪潮| 光棍天堂免费手机观看在线观看| 亚洲大片在线观看| 很黄很黄的网站免费的| 亚洲欧美中文日韩视频| 免费大学生国产在线观看p| 国产国产人免费人成成免视频 | 6080午夜一级毛片免费看6080夜福利 | 丁香花在线观看免费观看图片| 国产亚洲AV无码AV男人的天堂 | 国产又黄又爽又大的免费视频| 亚洲电影免费在线观看| 日本妇人成熟免费中文字幕| 亚洲av中文无码字幕色不卡| 亚洲国产婷婷综合在线精品| 免费91麻豆精品国产自产在线观看| 亚洲首页在线观看|