恰巧现在项目中正在使用OSGi框架,并需要结合使用Struts2框架,下面记录下改造过程。
在OSGi的浪潮下,struts2也湿鞋了,从2.1.8版开始Struts也有用于支持OSGi的插件了。
想了解正统struts2 OSGi插件的同学可以通过阅读这篇文章《使用 Felix 和 Struts2 开发 Web 应用》
下面言归正传,由于项目要求所有模块都包含在OSGi容器里,而struts提供的OSGi插件是通过struts启动OSGi容器的方式,并不满足我们的要求,那只能改Struts OSGi插件了。
传统的系统中插件的jar包和struts的jar包是分离的,OSGi中这种分离带来的后果是互相间交流的困难,为了回避这种问题,我们采用Struts Bundle包含Struts OSGi插件代码的方式。
Bundle Context是OSGi环境中极为重要的,注册服务和获得服务都需要它,监听Bundle的启停也需要它。由于在Struts原版Bundle中没有Activator类,需要存储BundleContext可以为Struts Bundle添加Activator类通过静态类变量的方式存储BundleContext实例。
为了实现根据bundle的启停动态加载卸载Struts配置及Action,需要修改OsgiConfigurationProvider类。由于在项目中需呀结合SpringDM一起使用,在这里通过监听org.springframework.context.ApplicationContext这个服务的启停来达到目的。因为在通过spring配置发布服务的Bundle都会向外界提供ApplicationContext这个服务。下面是通过ServiceTracker来实现服务监听的实例
private class ApplicationContextTracker extends ServiceTracker {
private BundleContext context;
public ApplicationContextTracker(BundleContext context) {
super(context, ApplicationContext.class.getName(), null);
this.context = context;
}
public Object addingService(ServiceReference reference) {
Bundle bundle = reference.getBundle();
String bundleName = bundle.getSymbolicName();
if (bundleName != null && shouldProcessBundle(bundle) && bundleName.indexOf("需要监控bundle包含的特殊单词") >= 0) {
LOG.trace("The bundlde has been activated and will be scanned for struts configuration, bundleName = " + bundleName);
loadConfigFromBundle(bundle);
}
return context.getService(reference);
}
public void removedService(ServiceReference reference, Object service) {
Bundle bundle = reference.getBundle();
String bundleName = bundle.getSymbolicName();
if (bundleName != null && shouldProcessBundle(bundle)) {
onBundleStopped(bundle);
}
super.removedService(reference, service);
}
}
通过上面几步就可以完成Struts的改造。