<listener> <listener-class>org.apache.felix.http.proxy.ProxyListener</listener-class> </listener>
路由开发通过上面的配置,只是将OSGI容器加载到了Web应用中。还需要修改Web应用程序路由的代码。
在Bundle加载到OSGI容器中后,可以通过bundleContext.getBundles()方法获取到OSGI容器中的所有已经加载的Bundle。
可以调用Bundle的bundle.getRegisteredServices()方法获取到该Bundle对外提供的所有服务服务。getRegisteredServices方法返回ServiceReference的数组。前文中我们调用context.registerService(Servlet.class, new DispatcherServlet(), props)我们已经注册了一个服务,getRegisteredServices返回的数据只有一个ServiceReference对象。
获取Bundle所能提供的服务
可以通过ServiceReference对象的getProperty方法获取context.registerService中传入的props中的值。这样我们就能通过调用ServiceReference.getProperty方法获取到该Bundle所能提供的服务。
通过上面提供的接口,我们可以将Bundle对应ServiceReference以及Bundle对应的servlet-pattern进行缓存。当用户请求进入到应用服务器后,通过缓存的servlet-pattern可以判断Bundle是否能提供用户所请求的服务,如果可以提供通过下面的方式,来调用Bundle所提供的服务。
ServiceReference sr = cache.get(bundleName); HttpServlet servlet = (HttpServlet) this.bundleContext.getService(sr); servlet.service(request, response);
Bundle自动加载在Apache Felix例子中提供的ProvisionActivator,只会在系统启动时加载/WEB-INF/bundles/目录下的Bundle。当文件夹下的Bundle文件有更新时,并不会自动更新OSGI容器中的Bundle。所以Bundle自动加载的逻辑,需要我们自己增加。下面提供实现的思路:
在第一次加载文件夹下的Bundle时,记录Bundle包所对应的最后的更新时间。
在程序中创建一个独立线程,用以扫描/WEB-INF/bundles/目录,逐个的比较Bundle的更新时间。如果与内存中的不相符合,则从OSGI中获取Bundle对象然后调用其stop以及uninstall方法,将其从OSGI容器中卸载。
卸载后,再调用bundleContext.installBundle以及bundle.start将最新的Bundle加载到OSGI容器中
BundleListener最后一个问题,通过上面的方式,可以实现Bundle的自动加载。但是刚才我们介绍了,在路由程序中,我们会缓存OSGI容器中所有的Bundle所对应的ServiceReference以及所有Bundle所对应的servlet-pattern。所以Bundle自动更新后,我们还需要将路由程序中的缓存同步的进行更新。
可以通过向bundleContext中注册BundleListener,当OSGI容器中的Bundle状态更新后,会调用BundleListener的bundleChanged回调方法。然后我们可以在bundleChanged回调方法中书写更新路由缓存的逻辑
this.bundleContext.addBundleListener(new BundleListener() { @Override public void bundleChanged(BundleEvent event) { if (event.getType() == BundleEvent.STARTED) { initBundle(event.getBundle()); } else if (event.getType() == BundleEvent.UNINSTALLED) { String name = event.getBundle().getSymbolicName(); indexes.remove(name); } } });