一、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 閱讀(2341)
評論(1) 編輯 收藏 所屬分類:
OSGI