OSGI服务发布和导入的自主实现

             —OSGI+Spring+Hibernate+...完美解决方案[非SpringDM]之二


 

 

 

 

 

 

 

《OSGI+Spring+Hibernate+...完美解决方案[非SpringDM]》一文中,我提出了非SpringDM的OSGI下使用Spring的解决方案。

本文是该文的姐妹篇,讲解在“OSGI+Spring+Hibernate+...完美解决方案[非SpringDM]”下的OSGI服务的发布和导入的实现。

 

 

 

OSGI服务的发布

OSGI下服务的发布,仍然和SpringDM下的相同。

如:

<service ref="beanToPublish" interface="com.xyz.MessageService"/>
 
<service id="myServiceRegistration" ref="beanToPublish"
interface="com.xyz.MessageService"/>
 
<osgi:service interface="com.xyz.MessageService">
<bean class="SomeClass">
...
</bean>
</osgi:service>
 
<osgi:service ref="beanToBeExported" interface="com.xyz.MessageService"/>
<bean id="beanToBeExported" scope="bundle" class="com.xyz.MessageServiceImpl"/>

    完全相同。不需改变。

 

 

我一向不喜欢自制Spring标签,如上面的osgi:service

自制Spring标签,虽然看上去挺酷,很专业。但是确实增加了我们用户的学习强度。你必须看文档才能知道该怎样使用这些千奇百怪的标签。

 

我还是喜欢直接使用<bean>标签。实际上,SpringDM中负责注册服务的类是:org.springframework.osgi.service.exporter.support.OsgiServiceFactoryBean类。

因此,我们可以这样注册OSGI服务:

 

例1

<bean  id="userBySessionServiceOsgiService" class="org.springframework.osgi.service.exporter.support.OsgiServiceFactoryBean"> 
  
       <property name="target"> 
  
          <ref bean="userBySessionService"/> 
  
       </property> 
  
       <property name="interfaces"> 
  
          <util:list> 
  
             <value>com.withub.gis.server.login.IUserBySessionService</value> 
  
          </util:list> 
  
       </property> 
  
   </bean>

 

例2

<bean  id="loginWSSecurityOsgiService" class="org.springframework.osgi.service.exporter.support.OsgiServiceFactoryBean"> 
  
       <property name="target"> 
  
          <ref bean="loginWSSecurity"/> 
  
       </property> 
  
       <property name="interfaces"> 
  
          <util:list> 
  
             <value>com.withub.gis.server.login.ILoginWSSecurity</value> 
  
          </util:list> 
  
       </property> 
  
   </bean>

 

 

 

  

 

OSGI服务的导入

在我的解决方案下,再使用SpringDM的导入服务的方式就不行了,会报错。这应该是SpringDM内部实现造成的。

SpringDM下的org.springframework.osgi.service.importer.support. OsgiServiceProxyFactoryBean导入一个服务。

OsgiServiceCollectionProxyFactoryBean导入多个服务。

 

我们需要编写自己的导入OSGI服务的类

 

   

导入OSGI Service的类

    这是自己独立于SpringDM的OSGI服务导入类。

/**
 * 
 */
package com.withub.gis.osgi.util.springSupport.importService;
 
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
 
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
 
/**
 * @author 沈东良 Edward Shen shendl_s@hotmail.com
 *
 */
public class ImportOsgiServiceFactory implements IImportOsgiServiceFactory {
       /* (non-Javadoc)
        * @see com.withub.gis.osgi.util.springSupport.importService.IImportOsgiServiceFactory#getService()
        */
       public Object getService(){
              Object[] services=this.getServices();
              if(services.length>=1){
                     return services[0];
              }else{
                     return null;
              }             
       }
       
       public static int DefaultRetryTimes=1;
       public static int DefaultWaitTime=1000;
       
       private int retryTimes=DefaultRetryTimes;
       private int waitTime=DefaultWaitTime;
       public int getRetryTimes() {
              return retryTimes;
       }
 
       public void setRetryTimes(int retryTimes) {
              this.retryTimes = retryTimes;
       }
       public int getWaitTime() {
              return waitTime;
       }
 
 
       public void setWaitTime(int waitTime) {
              this.waitTime = waitTime;
       }
 
 
       /* (non-Javadoc)
        * @see com.withub.gis.osgi.util.springSupport.importService.IImportOsgiServiceFactory#getServices()
        */
       public Object[] getServices(){
              List<ServiceReference> all=new ArrayList<ServiceReference>();
           String interface0=this.interfaces[0];
                     ServiceTracker serviceTracker=new ServiceTracker(this.bundleContext,interface0 , null);
                     serviceTracker.open();
                     
                     ServiceReference[] serviceReferences=serviceTracker.getServiceReferences();
                     
                     if(serviceReferences==null && this.retryTimes>0){
                            this.retryTimes--;
                            try {
                                   Thread.sleep(this.getWaitTime());
                            } catch (InterruptedException e) {
                                   // TODO Auto-generated catch block
                                   e.printStackTrace();
                            }
                            this.getServices();
                     }
                      
                     for(ServiceReference serviceReference:serviceReferences){
                            String[] objectClasses=(String[]) serviceReference.getProperty(Constants.OBJECTCLASS);
                            if(equal(this.interfaces,objectClasses)){
                                   all.add(serviceReference);
                            }
                     }
                     
                     
                     if(this.map!=null){
                            for(ServiceReference serviceReference:all){
                                   boolean upToGrade=true;
                                    Set<Map.Entry<String,Object>> entrySet=map.entrySet();
                                    for(Map.Entry<String,Object> entry:entrySet){
                                           if(serviceReference.getProperty(entry.getKey())==null){
                                                  if(entry.getValue()!=null){
                                                         upToGrade=false;
                                                         break;
                                                  }
                                           }else{
                                           
                                              if(!serviceReference.getProperty(entry.getKey()).equals(entry.getValue())){
                                                     upToGrade=false;
                                                     break;
                                              }
                                           }
                                           
                                    }
                                   if(upToGrade==false){
                                          all.remove(serviceReference);
                                          
                                   }
                            }
                            
                     }
                     
                     List allServices=new ArrayList();
                for(ServiceReference serviceReference:all){
                       allServices.add(this.bundleContext.getService(serviceReference)); 
                       
                }  
       
              return allServices.toArray();
       }
       
       
       private boolean equal(String[] interfaces, String[] objectClasses) {
              // TODO Auto-generated method stub
              
              for(String interface0:interfaces){
                     boolean yes=false;
                     for(String clazz:objectClasses){
                            if(interface0.equals(clazz)){
                                   yes=true;
                                   break;
                            }
                            
                     }
                     if(!yes){
                            return false;
                     }
              }
              
              
              
              
              return true;
              
              
              
       }
 
       private BundleContext bundleContext;
       private Map<String,Object> map;
 
       
       /**
        * 
        */
       private String[] interfaces;
       
 
       /**
        * 
        */
       public ImportOsgiServiceFactory() {
              // TODO Auto-generated constructor stub
       }
       public ImportOsgiServiceFactory(BundleContext bundleContext,String[] interfaces,Map<String,Object> map) {
              // TODO Auto-generated constructor stub
              this.bundleContext=bundleContext;
              this.interfaces=interfaces;
              this.map=map;
       }
 
       /**
        * @param args
        */
       public static void main(String[] args) {
              // TODO Auto-generated method stub
 
       }
 
       public BundleContext getBundleContext() {
              return bundleContext;
       }
 
       public void setBundleContext(BundleContext bundleContext) {
              this.bundleContext = bundleContext;
       }
 
       public String[] getInterfaces() {
              return interfaces;
       }
 
       public void setInterfaces(String[] interfaces) {
              this.interfaces = interfaces;
       }
 
       public Map getMap() {
              return map;
       }
 
       public void setMap(Map map) {
              this.map = map;
       }
 
       
 
}

 

使用的方法

下面给出一个使用的例子

 

1,使用Activator

package com.withub.gis.client.app.plugin;
 
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
import org.springframework.osgi.context.DelegatedExecutionOsgiBundleApplicationContext;
 
import com.withub.gis.client.app.context.GISApplicationContext;
import com.withub.gis.osgi.util.springSupport.StandAloneOsgiApplicationContextCreator;
import com.withub.gis.server.startDependency.WithubGISServicStartDependency;
 
/**
 * The activator class controls the plug-in life cycle
沈东良
 */
public class Activator extends AbstractUIPlugin {
 
       // The plug-in ID
       public static final String PLUGIN_ID = "com.withub.gis.client.app";
 
       // The shared instance
       private static Activator plugin;
         private DelegatedExecutionOsgiBundleApplicationContext applicationContext;
 
              public DelegatedExecutionOsgiBundleApplicationContext getApplicationContext() {
                     return applicationContext;
              }
       /**
        * The constructor
        */
       public Activator() {
       }
 
       /*
        * (non-Javadoc)
        * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
        */
       public void start(BundleContext context) throws Exception {
              super.start(context);
              plugin = this;
              /**
               * WithubGISServicStartDependency这个类是依赖的插件Service发布出来的一个类。
               * 如果使用这个类,就意味着Service插件必须被启动。
               * 这就使Service插件先发布我们需要的OSGI Service。保证了使用。
               */
              WithubGISServicStartDependency withubGISServicStartDependency=new WithubGISServicStartDependency();
              System.out.println(Activator.PLUGIN_ID+" Startup!!");
              GISApplicationContext.getInstance().setBundleContext(context);
              
              String[] configFiles = new String[] { "spring/bean.xml", "classpath:spring/osgi.xml" };
 
              StandAloneOsgiApplicationContextCreator standAloneOsgiApplicationContextCreator = new StandAloneOsgiApplicationContextCreator(
                            configFiles);
              try {
                     this.applicationContext = standAloneOsgiApplicationContextCreator.createApplicationContext(context);
                     //applicationContext.refresh();
              } catch (Exception e1) {
                     // TODO Auto-generated catch block
                     e1.printStackTrace();
              }
 
              System.out.println("Spring ApplicationContext  Startup!!");
       }
 
       /*
        * (non-Javadoc)
        * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
        */
       public void stop(BundleContext context) throws Exception {
              plugin = null;
              super.stop(context);
              System.out.println(Activator.PLUGIN_ID+"  Shutdown!!");
       }
 
       /**
        * Returns the shared instance
        *
        * @return the shared instance
        */
       public static Activator getDefault() {
              return plugin;
       }
       private ClassLoader classLoader = this.getClass().getClassLoader();
       private Log log = LogFactory.getLog(this.getClass());
       
       
 
 
       public ClassLoader getClassLoader() {
              return classLoader;
       }
 
       public void setClassLoader(ClassLoader classLoader) {
              this.classLoader = classLoader;
       }
 
}

 

 

2,无关的支持类

/**
 * 
 */
package com.withub.gis.client.app.context;
 
import java.util.HashMap;
import java.util.Map;
 
import org.osgi.framework.BundleContext;
 
 
 
/**
 * @author 沈东良 Edward Shen shendl_s@hotmail.com
 *
 */
public class GISApplicationContext {
 
       /**
        * 
        */
       public GISApplicationContext() {
              // TODO Auto-generated constructor stub
       }
 
       /**
        * @param args
        */
       public static void main(String[] args) {
              // TODO Auto-generated method stub
 
       }
       private static GISApplicationContext instance=null;
       private static Object lockInstance=new Object();
    private String  username="";
    private String  password="";
    private String sessionId;
    
    
    private BundleContext  bundleContext;
    private ClassLoader classLoader;
  
    private Map<String,Object> map=new HashMap<String,Object>();
    /**
     * 
     * @return
     */
    public static GISApplicationContext getInstance(){
         if(GISApplicationContext.instance==null){
                synchronized(GISApplicationContext.lockInstance){
                       if(GISApplicationContext.instance==null){
                              GISApplicationContext.instance=new GISApplicationContext();
                       }
                       
                }
                
         } 
          return GISApplicationContext.instance;
    }
   public String getUsername() {
              return username;
       }
 
       public void setUsername(String username) {
              this.username = username;
       }
 
       public String getPassword() {
              return password;
       }
 
       public void setPassword(String password) {
              this.password = password;
       }
 
       public String getSessionId() {
              return sessionId;
       }
 
       public void setSessionId(String sessionId) {
              this.sessionId = sessionId;
       }
 
       public Map<String, Object> getMap() {
              return map;
       }
 
       public BundleContext getBundleContext() {
              return bundleContext;
       }
 
       public void setBundleContext(BundleContext bundleContext) {
              this.bundleContext = bundleContext;
       }
 
       public ClassLoader getClassLoader() {
              return classLoader;
       }
 
       public void setClassLoader(ClassLoader classLoader) {
              this.classLoader = classLoader;
       }

}

 

 

3,IApplication的实现类,这是RCP程序的入口点。应该在其他Activator启动后执行。这里是Spring的消费者。

/**
 * 
 */
package com.withub.gis.client.app.eclipse.application;
 
 
import java.awt.Rectangle;
import java.rmi.server.UID;
import java.util.Iterator;
import java.util.Set;
 
import javax.units.SI;
 
import net.refractions.udig.internal.ui.JaiErrorDialog;
import net.refractions.udig.internal.ui.UDIGWorkbenchAdvisor;
import net.refractions.udig.internal.ui.UiPlugin;
 
import org.eclipse.core.runtime.Platform;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.application.WorkbenchAdvisor;
import org.geotools.referencing.FactoryFinder;
import org.springframework.osgi.context.DelegatedExecutionOsgiBundleApplicationContext;
 
import com.withub.gis.client.app.context.GISApplicationContext;
import com.withub.gis.client.app.plugin.Activator;
import com.withub.gis.osgi.util.springSupport.StandAloneOsgiApplicationContextCreator;
import com.withub.gis.server.login.ILoginWSSecurity;
import com.withub.gis.ui.dialog.LoginDialog;
 
/**
 * @author 沈东良 Edward Shen shendl_s@hotmail.com
 *
 */
public class GISApplication implements IApplication {
    private ILoginWSSecurity loginWSSecurity;
       public ILoginWSSecurity getLoginWSSecurity() {
              return loginWSSecurity;
       }
 
       public void setLoginWSSecurity(ILoginWSSecurity loginWSSecurity) {
              this.loginWSSecurity = loginWSSecurity;
       }
 
       /**
        * 
        */
       public GISApplication() {
              // TODO Auto-generated constructor stub
       }
        
    protected WorkbenchAdvisor createWorkbenchAdvisor() {
           return new UDIGWorkbenchAdvisor();
          /*
        return new UDIGWorkbenchAdvisor() {
            @Override
            public String getInitialWindowPerspectiveId() {
                return "net.refractions.udig.tutorials.customapp.perspective";
            }
        };
        */
    }
    
    
    /**
     * Override to perform your own security check.
     * 
     * @return true to indicate a successful login
     */
    public  boolean checkLogin() {
        LoginDialog loginDialog = new LoginDialog(
                "登陆WithubGIS系统",
                "请输入用户名和密码:" );
        
        boolean login= false;
       
        while( !login ){
             loginDialog.clearUserNamePassword();
            int result = loginDialog.open();                    
            if( result == MessageDialog.OK){
                try {
                   Activator activator=Activator.getDefault();
                   DelegatedExecutionOsgiBundleApplicationContext applicationContext=activator.getApplicationContext();
                   
                    ILoginWSSecurity loginWSSecurity=       (ILoginWSSecurity)applicationContext.getBean("loginWSSecurityOsgiReference");
                   //loginWSSecurity.login(loginDialog.getUser(), loginDialog.getPassword());
                   //login =loginService.checkLogin( loginDialog.getUser(), loginDialog.getPassword() );
                   String sessionId=loginWSSecurity.login(loginDialog.getUser(), loginDialog.getPassword());
                    GISApplicationContext.getInstance().setSessionId(sessionId);
                   login=true;
                                   
                } catch (Throwable connectionProblem) {
                   System.err.println(connectionProblem.getMessage());
                   MessageDialog.openError(null, "登录错误", "用户名或者密码错误,请重新登陆!");
                   // MessageDialog.openInformation(null, "不能连接服务器,请检查网络", connectionProblem.toString() );
                    
                   // return false; // probably should prompt user here?
                }
            }
            else {
                return false; // user cancelled
            }
        }
       // WithubGISApplicationContext.getInstance().getMap().put("loginService", loginService);
       
        return true;
    }
  
 
    /**
     * Starts GIS application with the given context and returns a result. This method must not exit
     * until the application is finished and is ready to exit. The content of the context is
     * unchecked and should conform to the expectations of the application being invoked.
     * <p>
     * Applications can return any object they like. If an <code>Integer</code> is returned it is
     * treated as the program exit code if Eclipse is exiting.
     * <p>
     * Note: This method is called by the platform; it is not intended to be called directly by
     * clients.
     * </p>
     * 
     * @return the return value of the application
     * @see #EXIT_OK
     * @see #EXIT_RESTART
     * @see #EXIT_RELAUNCH
     * @param context the application context to pass to the application
     * @exception Exception if there is a problem running this application.
     */
    public Object start( IApplicationContext context ) throws Exception {
          
          
          
        WorkbenchAdvisor workbenchAdvisor = createWorkbenchAdvisor();
        Display display = PlatformUI.createDisplay();
 
        boolean isInitalized = init();
        if (!isInitalized) {
            return EXIT_OK;
        }
        int returnCode = EXIT_OK;
        try {
            returnCode = PlatformUI.createAndRunWorkbench(display, workbenchAdvisor);
        } catch (Throwable t) {
            UiPlugin.log("Messages.UDIGApplication_error", t);
        } finally {
            Platform.endSplash();
            display.dispose();
        }
        if (returnCode == PlatformUI.RETURN_RESTART) {
            return EXIT_RESTART;
        }
        return EXIT_OK;
    }
 
   
 
    /**
     * Forces this running application to exit. This method should wait until the running
     * application is ready to exit. The {@link #start(IApplicationContext)} should already have
     * exited or should exit very soon after this method exits
     * <p>
     * This method is only called to force an application to exit. This method will not be called if
     * an application exits normally from the {@link #start(IApplicationContext)} method.
     * <p>
     * Note: This method is called by the platform; it is not intended to be called directly by
     * clients.
     * </p>
     */
    public void stop() {
        final IWorkbench workbench = PlatformUI.getWorkbench();
        if (workbench == null){
            return;
        }
        final Display display = workbench.getDisplay();
        display.syncExec(new Runnable(){
            public void run() {
                if (!display.isDisposed()){
                    workbench.close();
                }
            }
        });
    };
 
    /**
     * Called before the workbench is created.
     * <p>
     * The following checks are performed:
     * <ul>
     * <li>checkForJAI(): optional - Dig will work with reduced functionality if JAI is not
     * available
     * <li>checkForGDI(): required - uDig will not function on WIN_32 if GDI is not present
     * </ul>
     * This method also loads some commonly used objects; subclasses may override this method (say
     * to ask the user to login)
     * 
     * @return <code>true </code> on successful startup; false to exit the application with an
     *         error.
     */
    protected boolean init() {
        checkForJAI();
        boolean required = checkForGDI();
 
        if (!required) {
            // we could not meet our requirements; please exit!
            return false;
        }
 
        loadCommonlyUsedObject();
 
        boolean login = checkLogin();
        if (!login) {
            return false;
        }
        return true;
    }
 
    /**
     * Forces the class loader to load several troublesome classes; mostly focused on FactorySPI
     * plugins used by the GeoTools library.
     */
    private void loadCommonlyUsedObject() {
        // potential fix for win32 (occasionally blocks in Drawing.feature(Point/etc) during first
        // render)
        new UID(); // seed the random number generator
 
        load(FactoryFinder.getCoordinateOperationAuthorityFactories());
        load(FactoryFinder.getCoordinateOperationAuthorityFactories());
        load(FactoryFinder.getCRSFactories());
        load(FactoryFinder.getCSFactories());
        load(FactoryFinder.getDatumAuthorityFactories());
        load(FactoryFinder.getDatumFactories());
        load(FactoryFinder.getMathTransformFactories());
        @SuppressWarnings("unused")
        Object o = SI.BIT;
        o = SI.GRAM;
        o = SI.KILOGRAM;
        o = SI.METER;
        o = SI.RADIAN;
        o = SI.SECOND;
        o = SI.STERADIAN;
    }
 
    @SuppressWarnings("unchecked")
    private void load( Set coordinateOperationAuthorityFactories ) {
        for( Iterator iter = coordinateOperationAuthorityFactories.iterator(); iter.hasNext(); ) {
            iter.next();
        }
    }
 
    /**
     * Ensures that GDI is available for the windows inclined. GDI is used by SWT to perform matrix
     * operations; uDIG cannot function without GDI on windows.
     * 
     * @return false if GDI is needed and not found.
     */
    public  boolean checkForGDI() {
        if (Platform.getOS().equals(Platform.OS_WIN32)) {
            // test to make sure that GDI+ is installed
              org.eclipse.swt.graphics.Image image = null;
              org.eclipse.swt.graphics.Path path = null;
            try {
                image = new  org.eclipse.swt.graphics.Image(Display.getCurrent(), 10, 10);
                path = net.refractions.udig.ui.graphics.SWTGraphics.convertToPath(new Rectangle(0, 0, 8, 8), Display.getCurrent());
            } catch (Exception e) {
                MessageDialog
                        .openError(
                                Display.getCurrent().getActiveShell(),
                                net.refractions.udig.ui.internal.Messages.UDIGApplication_title,
                                net.refractions.udig.ui.internal.Messages.UDIGApplication_error1
                                        + net.refractions.udig.ui.internal.Messages.UDIGApplication_error2
                                        + "http://www.microsoft.com/downloads/details.aspx?FamilyID=6A63AB9C-DF12-4D41-933C-BE590FEAA05A&displaylang=en"); //$NON-NLS-1$
                return false;
            } finally {
                if (image != null)
                    image.dispose();
                if (path != null)
                    path.dispose();
            }
        }
        return true;
    }
 
    /**
     * Ensures Java Advanced Imaging is installed into the JRE being used.
     * <p>
     * If JAI is not available a dialog will be displayed and false is returned. JAI is not required
     * for everything; currently rasters will not function without JAI; but many simple vector
     * formats will.
     * </p>
     * 
     * @return true if JAI is available.
     */
    public  boolean checkForJAI() {
        try {
            Class.forName("javax.media.jai.operator.OrDescriptor"); //$NON-NLS-1$
            return true;
        } catch (Throwable th) {
            JaiErrorDialog.display();
            return false;
        }
    }
 
       /**
        * @param args
        */
       public static void main(String[] args) {
              // TODO Auto-generated method stub
 
       }
 
}

 

 

 

4,Spring配置

<?xml version="1.0" encoding="UTF-8"?> 
  
<beans xmlns="http://www.springframework.org/schema/beans" 
  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  
    xmlns:aop="http://www.springframework.org/schema/aop" 
  
    xmlns:context="http://www.springframework.org/schema/context" 
  
    xmlns:flow="http://www.springframework.org/schema/webflow-config" 
  
    xmlns:jee="http://www.springframework.org/schema/jee" 
  
    xmlns:jms="http://www.springframework.org/schema/jms" 
  
    xmlns:lang="http://www.springframework.org/schema/lang" 
  
    xmlns:osgi="http://www.springframework.org/schema/osgi" 
  
    xmlns:osgi-compendium="http://www.springframework.org/schema/osgi-compendium" 
  
    xmlns:p="http://www.springframework.org/schema/p" 
  
    xmlns:tx="http://www.springframework.org/schema/tx" 
  
    xmlns:util="http://www.springframework.org/schema/util" 
  
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
  
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd 
  
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd 
  
       http://www.springframework.org/schema/webflow-config http://www.springframework.org/schema/webflow-config/spring-webflow-config-1.0.xsd 
  
       http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd 
  
       http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms.xsd 
  
       http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd 
  
       http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd 
  
       http://www.springframework.org/schema/osgi-compendium http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd 
  
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd 
  
       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> 
  
 
    <bean id="gISApplicationContext" class="com.withub.gis.client.app.context.GISApplicationContext"  factory-method="getInstance" > 
  
   
  
  </bean> 
  
  <bean id="bundleContext" factory-bean="gISApplicationContext"  factory-method="getBundleContext"></bean> 
  
 
  <bean id="userBySessionServiceOsgiReference" factory-bean="userBySessionServiceOsgiReferenceFactory"  factory-method="getService">       
  
   </bean> 
  
   <bean id="userBySessionServiceOsgiReferenceFactory" class="com.withub.gis.osgi.util.springSupport.importService.ImportOsgiServiceFactory"> 
  
      
  
      <property name="bundleContext"> 
  
         <ref  bean="bundleContext"/> 
  
      </property> 
  
        
  
      <property name="interfaces"> 
  
         <list> 
  
            <value>com.withub.gis.server.login.IUserBySessionService</value> 
  
         </list>       
  
      </property> 
  
       
  
      
  
   </bean> 
  
     
  
    
  
   <bean id="loginWSSecurityOsgiReference" factory-bean="loginWSSecurityOsgiReferenceFactory"  factory-method="getService">       
  
   </bean> 
  
   <bean id="loginWSSecurityOsgiReferenceFactory" class="com.withub.gis.osgi.util.springSupport.importService.ImportOsgiServiceFactory"> 
  
        
  
      <property name="bundleContext"> 
  
          <ref  bean="bundleContext"/> 
  
      </property> 
  
        
  
      <property name="interfaces"> 
  
         <list> 
  
            <value>com.withub.gis.server.login.ILoginWSSecurity</value> 
  
         </list>       
  
      </property> 
  
       
  
      <property name="retryTimes"> 
  
          <value>5</value> 
  
      </property> 
  
      <property name="waitTime"> 
  
         <value>1000</value> 
  
      </property> 
  
   </bean> 
  
  
  
</beans>

 

 

代码说明

1,已内建bundleContext这个Bean

OsgiBundleXmlApplicationContext创建Application时,会创建一个Bean,名字叫bundleContext,类型是BundleContext。

由于我们的方案中,内部和SpringDM一样都使用了OsgiBundleXmlApplicationContext,因此,我们的Spring内部也有bundleContext这个Bean。

因此,Spring配置中
<bean id="gISApplicationContext" class="com.withub.gis.client.app.context.GISApplicationContext"  factory-method="getInstance" > 
  
   
  
  </bean> 
  
  <bean id="bundleContext" factory-bean="gISApplicationContext"  factory-method="getBundleContext"></bean> 
  
   这2个Bean可以不用。
   Activator类的start()方法中
GISApplicationContext.getInstance().setBundleContext(context);

             

    这行代码也不需要。

 

2,外部对象插入Spring的技巧

这里介绍一个Spring的小技巧。

Spring对于静态类的静态工厂方法,这个类单例在外部也可以使用!是同一的。

这是很好的外部代码插入Spring管理的代码的途径!

 

我的代码中使用GISApplicationContext类的单例拿到BundleContext的实例,插进Spring中就是使用了这个技巧。

 

3,解决服务注册和导入先后次序的问题的独创方法

还有一个问题,B插件发布服务,A插件导入服务。就像我的例子那样,A插件依赖于B插件。

但是很有可能B插件发布服务的时间远远慢于A插件导入服务的时间。

这就会出现问题。特别是我这里的例子,A插件还是RCP程序的入口,IApplicaiton接口的实现类所在的插件。

这意味着A插件会很快启动,一般是比B插件先启动的。

 

可以设置OSGI的Start Level,保证提供服务的插件先启动。

 

 

但我这里推荐的是一种自创的方法,仅在Eclipse下测试成功,不保证在所有OSGI环境下都能成功。

有使用其他OSGI环境经验的朋友可以帮忙测试一下这招是否有效。测好了,把结果告诉我好吗!谢谢!

 

 

首先,在提供OSGI服务的插件中发布一个Package。

然后,在导入OSGI服务的插件的Activator类的start()方法中new一个提供服务插件的发布Package中的类。

然后再创建ApplicationContext。

这可以保证在创建ApplicationContext之前,提供OSGI服务的插件已启动。

 

    另外,ImportOsgiServiceFactory类也提供了重试的机制,可以让用户配置重试的次数和每次间隔的时间,以保证OSGI服务的引用正确!