一、Spring Framework
通常Spring的web应用结构层次:
1,ContextLoaderServlet,创建一个ContextLoader做为整个web应用的Loader,它会为自己创建一个web应用级别的WebApplicationContext,接着默认加载applicationContext.xml里面的bean
2,DispatcherServlet,同样创建一个WebApplicationContext,加载dispatch-bean,它会将ContextLoader的WebApplicationContext做为自己的父ApplicationContext
二、Spring-OSGI
通过Spring-osgi规范可以了解到spring-osgi会为每一个有spring-bean配置文件的bundle创建一个ApplicationContext,spring-bean配置文件里面的bean则被它加载,所以Dispatch-bean-loader无法找到spring-osgi-bean
三、RESOLVER
首先要先得到bundle的ApplicationContext,然后创建一个自定义的ContextLoader-BundleContextLoader,不加载配置文件,重写loadParentContext方法,将父ApplicationContext设置成bundle的ApplicationContext,然后生成一个自定义的WebApplicationContext-BundleWebApplicationContext,里面的bean信息直接从parentApplicationContext里面获取。本来spring规范里面写着
org.springframework.osgi.context.support.WebApplicationContext
,但是找个底朝天,也没找到,可能还没出呢吧,于是只能自己写了。
bundle的ApplicationContext可通过org.springframework.context.ApplicationContextAware.setApplicationContext(ApplicationContext applicationContext)得到
四、BundleContextLoaderServlet
在org.phrancol.osgi.jpetstore.springmvc里新建类BundleContextLoaderServlet
public class BundleContextLoaderServlet extends ContextLoaderServlet {
private final ApplicationContext applicationContext;
private BundleContext ctx;
public BundleContextLoaderServlet(BundleContext ctx,
ApplicationContext appContext) {
this.ctx = ctx;
this.applicationContext = appContext;
}
/** *//**
* 重写该方法,用于构造一个自定义的BundleContextLoader
*/
protected ContextLoader createContextLoader() {
return new BundleContextLoader(applicationContext, ctx);
}
}
五、BundleContextLoader
在org.phrancol.osgi.jpetstore.springmvc里新建类BundleContextLoader
public class BundleContextLoader extends ContextLoader {
private final ApplicationContext applicationContext;
private BundleContext bundleContext;
public BundleContextLoader(ApplicationContext appContext, BundleContext ctx) {
this.applicationContext = appContext;
this.bundleContext = ctx;
}
/** *//**
* 重写该方法,让其返回的ParentContext是Bundle里的那个ApplicationContext
*/
protected ApplicationContext loadParentContext(ServletContext servletContext)
throws BeansException {
return applicationContext;
}
/** *//**
* 生成一个自定义的BundleWebApplicationContext,返回的bean信息直接从Parent获取
* 这里的代码请参考org.springframework.osgi.extender.support.ApplicationContextCreator.run()方法里的代码
*/
protected WebApplicationContext createWebApplicationContext(
ServletContext servletContext, ApplicationContext parent)
throws BeansException {
ClassLoader contextClassLoader = Thread.currentThread()
.getContextClassLoader();
try {
ClassLoader cl = BundleDelegatingClassLoader
.createBundleClassLoaderFor(bundleContext.getBundle(), getClass()
.getClassLoader());
Thread.currentThread().setContextClassLoader(cl);
LocalBundleContext.setContext(bundleContext);
return new BundleWebApplicationContext(parent, servletContext);
} finally {
Thread.currentThread().setContextClassLoader(contextClassLoader);
}
}
}
六、BundleWebApplicationContext
在org.phrancol.osgi.jpetstore.springmvc里面新建类BundleWebApplicationContext,所有的方法都返回parent的方法返回值
public class BundleWebApplicationContext implements WebApplicationContext {
private final ApplicationContext parentApplicationContext;
private ServletContext servletContext;
public BundleWebApplicationContext(ApplicationContext parentApplicationContext,
ServletContext servletContext){
this.parentApplicationContext = parentApplicationContext;
this.servletContext = servletContext;
}
public ServletContext getServletContext() {
// TODO Auto-generated method stub
return servletContext;
}
public AutowireCapableBeanFactory getAutowireCapableBeanFactory()
throws IllegalStateException {
// TODO Auto-generated method stub
return parentApplicationContext.getAutowireCapableBeanFactory();
}
public String getDisplayName() {
// TODO Auto-generated method stub
return parentApplicationContext.getDisplayName();
}
.
}
七、修改
1,修改接口HttpServiceRegister.serviceRegister(BundleContext context),改成
serviceRegister(BundleContext context, ApplicationContext bundleApplicationContext);
2,修改SpringmvcHttpServiceRegister.serviceRegister(BundleContext context),改成
serviceRegister(BundleContext context, ApplicationContext bundleApplicationContext)
3,SpringmvcHttpServiceRegister.serviceRegister方法修改一下
public void serviceRegister(BundleContext context, ApplicationContext bundleApplicationContext) {
try {
ServiceReference sr = context.getServiceReference(HttpService.class
.getName());
HttpService httpService = (HttpService) context.getService(sr);
httpService.registerResources("/", "/web", null);
httpService.registerServlet("/*.jsp", new JspServlet(context
.getBundle(), "/web"), null, null);
Dictionary<String, String> initparams = new Hashtable<String, String>();
initparams.put("load-on-startup", "1");
/* 编辑器的问题,这4行代码不是注释。。。 */
ContextLoaderServlet contextloaderListener = new BundleContextLoaderServlet(
context, bundleApplicationContext);
httpService.registerServlet("/ContextLoader",
contextloaderListener, initparams, null);
/* */
DispatcherServlet dispatcherServlet = new DispatcherServlet();
dispatcherServlet
.setContextConfigLocation("META-INF/dispatcher/petstore-servlet.xml");
initparams = new Hashtable<String, String>();
initparams.put("servlet-name", "petstore");
initparams.put("load-on-startup", "2");
httpService.registerServlet("/*.do", dispatcherServlet, initparams,
null);
} catch (Exception e) {
e.printStackTrace(System.out);
}
}
OK,这下应该没问题了,启动看看效果
倒,还是报错。。。。。。
八、HttpContext
来看看org.osgi.service.http.HttpService.registerServlet的代码
* Servlets registered with the same <code>HttpContext</code> object will
* share the same <code>ServletContext</code>.
原来是这样,注册了2个servlet,于是生成了2个不同的HttpContext,那就只生成一个试试
HttpContext defaultContext = new DefaultHttpContext(context.getBundle());
httpService.registerServlet("/init-context-loader-petsore-web",
contextloaderListener, initparams, defaultContext);
httpService.registerServlet("/*.do", dispatcherServlet, initparams,
defaultContext);
再启动,一切顺利,访问页面也正常。
九、打完收工
将org.phrancol.osgi.jpetstore.springmvc/METS-INF/dispatcher/petstore-servlet.xml里面的bean补全(注意还有2个bean需要注册和引用),再运行,就OK了。
posted on 2007-09-07 18:15
Phrancol Yang 阅读(2331)
评论(1) 编辑 收藏 所属分类:
OSGI