一、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 阅读(2365) 
评论(1)  编辑  收藏  所属分类: 
OSGI