Tomcat集成OSGi,首先要选择OSGI服务器,我这里采用的是equinox.jar.
第一步开发OSGI的bundle,这里就不说明了.
第二步构建OSGi在Tomcat下的目录结构如图${Tomcat_Home}/lib
第三步配置OSGI启动项,配置文件[config.ini]内容如下:
osgi.noShutdown=true
osgi.bundles=reference\:file\:bundles/org.apache.commons.logging_1.0.4.v201101211617.jar@start,reference\:file\:bundles/org.eclipse.osgi.services_3.3.0.v20110513.jar@start,reference\:file\:bundles/DictQuery_1.0.0.jar@start,reference\:file\:bundles/RomoteDictQuery_1.0.0.jar@start,reference\:file\:bundles/LocalDictQuery_1.0.0.jar@start
osgi.bundles.defaultStartLevel=4
第四步关键了,我们把OSGI的生命周期集成到Tomcat容器来管理.
package standard.osgi.jndi;
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleListener;
import org.eclipse.core.runtime.adaptor.EclipseStarter;
import org.osgi.dictquery.query.QueryService;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
public class OsgiListener implements LifecycleListener {
private static Logger log = Logger.getLogger(OsgiListener.class.getName());
private String osgiType = "Equinox";
private BundleContext bundleContext;
private static OsgiListener listener = null;
public static OsgiListener getInstance(){
return listener;
}
public BundleContext getBundleContext() {
return bundleContext;
}
public void setBundleContext(BundleContext bundleContext) {
this.bundleContext = bundleContext;
}
@Override
public void lifecycleEvent(LifecycleEvent event) {
if (Lifecycle.AFTER_INIT_EVENT.equals(event.getType())) {
log.info("The osgi content is initialized. Using osgi content:"+ osgiType);
try {
// initContent();
} catch (Exception e) {
log.log(Level.SEVERE, "初始化osgi失败"+e.getCause());
}
} else if (Lifecycle.START_EVENT.equals(event.getType())) {
try {
log.info("Starting osgi service.");
EclipseStarter.run(new String[] { "-console" }, null);
initContent();
log.info("Starting osgi service invoke.");
//获取服务
//this interface is not the osgi's interface.
// QueryService queryService = null;
Object queryService = null;
ServiceReference serviceRef = bundleContext.getServiceReference(QueryService.class.getName());
if(null != serviceRef){
queryService = bundleContext.getService(serviceRef);
}
Method method = queryService.getClass().getDeclaredMethod("queryWorld", String.class);
Object result = method.invoke(queryService, "sky");
System.out.println("11Result is " +new String(result.toString().getBytes(),"GB2312"));
} catch (Exception e) {
e.printStackTrace();
log.info("Starting the osgi content occured error. "
+ e.getMessage());
}
} else if (Lifecycle.STOP_EVENT.equals(event.getType())) {
try {
log.info("Stopping osgi service.");
EclipseStarter.shutdown();
} catch (Exception e) {
log.info("Stopping the osgi content occured error. "
+ e.getMessage());
}
}
}
/**
* 初始化osgi
*/
private void initContent() {
bundleContext = EclipseStarter.getSystemBundleContext();
listener = this;
}
}
在web容器启动的时候,启动osgi容量,这里提供了一个简单的调用,通过bundleContext可以获取服务,通过反映可以调用osgi方法,并返回结果.[osgi classLoader is not the web classloader].
启动Tomcat,你会发现启动成功,并成功启动osgi容器,调用成功osgi容量的方法.
当然,这里的bundleContext是可以通过JNDI开放到Tomcat容器下的其他web应用使用的.
那么如何把OSGI包装成JNDI开放出去呢
第一步,开发InitialContext
package standard.osgi.jndi;
import java.util.HashMap;
import java.util.Hashtable;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class MyInitialContext extends InitialContext {
private static HashMap<String, Object> map = new HashMap<String, Object>();
public MyInitialContext() throws NamingException {
super();
}
public MyInitialContext(Hashtable<?,?> environment) throws NamingException {
super(environment);
}
@Override
public void bind(String name, Object obj) throws NamingException {
map.put(name, obj);
}
@Override
public void unbind(String name) throws NamingException {
map.remove(name);
}
@Override
public Object lookup(String name) throws NamingException {
return map.get(name);
}
}
第二步,开发InitialContextFactory
package standard.osgi.jndi;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.spi.InitialContextFactory;
public class MyInitialContextFactory implements InitialContextFactory{
@Override
public Context getInitialContext(Hashtable<?, ?> environment)
throws NamingException {
return new MyInitialContext();
}
}
第三步,使用我们自定义的JNDI注册我们的OSGI服务,修改上面的initContext方法
/**
* 初始化osgi
*/
private void initContent() {
bundleContext = EclipseStarter.getSystemBundleContext();
try {
Hashtable env = new Hashtable();
//env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");
env.put(Context.INITIAL_CONTEXT_FACTORY, "standard.osgi.jndi.MyInitialContextFactory");
Context ctx = new InitialContext(env);
ctx.bind("init/context", bundleContext);
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
第四步,这样我们的osgi的bundleContext已经注册到Jndi中了,我们要web中,只需要获取我们自定义的JNDI,获取bundleContext就可以了.
Hashtable env = new Hashtable();
//env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");
env.put(Context.INITIAL_CONTEXT_FACTORY, "standard.osgi.jndi.MyInitialContextFactory");
Context ctx = new InitialContext(env);
BundleContext bundleContextJndi = (BundleContext)ctx.lookup("init/context");
Object queryService = null;
ServiceReference serviceRef = bundleContextJndi.getServiceReference(QueryService.class.getName());
if(null != serviceRef){
queryService = bundleContextJndi.getService(serviceRef);
}
Method method = queryService.getClass().getDeclaredMethod("queryWorld", String.class);
Object result = method.invoke(queryService, "sky");
System.out.println("jndi Result is " +new String(result.toString().getBytes(),"GB2312"));
这里没作太多的封装,不过成功的把OSGI封装到Tomcat,再把OSGI通过JNDI开放到各个web应用。