OSGI服务发布和导入的自主实现
—OSGI+Spring+Hibernate+...完美解决方案[非SpringDM]之二
在《OSGI+Spring+Hibernate+...完美解决方案[非SpringDM]》一文中,我提出了非SpringDM的OSGI下使用Spring的解决方案。
本文是该文的姐妹篇,讲解在“OSGI+Spring+Hibernate+...完美解决方案[非SpringDM]”下的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>
在我的解决方案下,再使用SpringDM的导入服务的方式就不行了,会报错。这应该是SpringDM内部实现造成的。
SpringDM下的org.springframework.osgi.service.importer.support. OsgiServiceProxyFactoryBean导入一个服务。
OsgiServiceCollectionProxyFactoryBean导入多个服务。
这是自己独立于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 [email protected]
*
*/
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;
}
}
下面给出一个使用的例子
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;
}
}
/**
*
*/
package com.withub.gis.client.app.context;
import java.util.HashMap;
import java.util.Map;
import org.osgi.framework.BundleContext;
/**
* @author 沈东良 Edward Shen [email protected]
*
*/
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;
}
}
/**
*
*/
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 [email protected]
*
*/
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
}
}
<?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>
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);
这行代码也不需要。
这里介绍一个Spring的小技巧。
Spring对于静态类的静态工厂方法,这个类单例在外部也可以使用!是同一的。
这是很好的外部代码插入Spring管理的代码的途径!
我的代码中使用GISApplicationContext类的单例拿到BundleContext的实例,插进Spring中就是使用了这个技巧。
还有一个问题,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服务的引用正确!