java动态模块开发,构建模块化的动态Web应用(演示版)

一、契子

很早以前就开始构思可动态部署的Web应用,模块化应用无疑是一种趋势,Portal应用可谓是一个小革新,它的功能引起了很多人的注意,OSGi 无疑会为这带来本质上的升级。

二、目标

这篇blog中的例子从JPetStoreOsgi衍生,通过扩展(修改)Spring mvc中的某些对象,实现模块的动态部署,当然,这只是很简单的案例,不过足以达到我的预期目标:有2个非常简单的模块module1和module2,它们都有自己的Spring mvc配置文件,可以在运行时简单的通过OSGi控制台,安装它们,并完成它们各自的功能。

三、准备工作

[点击这里下载 DynamicModule 工程包]

由于整个Workspace太大,所以仅仅只是把更新的5个Bundle的Project上传了,先 下载JPetStoreOsgi ,然后将所有关于JPetStore的Project删除,导入这5个Project

四、Spring MVC

目前还没有用于OSGi环境的MVC框架,所以选用Spring MVC做为演示框架

org.phrancol.osgi.demo.mvc.springmvc 是整个应用的MVC Bundle,以下简称 MVCBundle

org.phrancol.osgi.demo.mvc.springmvc.core.HandlerRegister

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gifpublicinterfaceHandlerRegister9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png    

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/** *//**d18c02628675d0a2c816449d98bda930.png     * 当bundle的ApplicationContext生成后,获取HandlerMapping,并注册

d18c02628675d0a2c816449d98bda930.png     *@paramcontext Spring为Bundle生成的ApplicationContext

d18c02628675d0a2c816449d98bda930.png     *@parambundle

ecedf933ec37d714bd4c2545da43add2.png*/d18c02628675d0a2c816449d98bda930.pngpublicvoidregisterHandler(ApplicationContext context, Bundle bundle);

d18c02628675d0a2c816449d98bda930.png    

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/** *//**d18c02628675d0a2c816449d98bda930.png     * 当Bundle被停止或是卸载的时候,注销这个bundle的HandlerMapping

d18c02628675d0a2c816449d98bda930.png     * 当然这个功能没有实现(它可以实现),因为他不属于演示范围

d18c02628675d0a2c816449d98bda930.png     *@parambundle

ecedf933ec37d714bd4c2545da43add2.png*/d18c02628675d0a2c816449d98bda930.pngpublicvoidunRegisterHandler(Bundle bundle);

d18c02628675d0a2c816449d98bda930.png

8f1ba5b45633e9678d1db480c16cae3f.png}

扩展DispatcherServlet - org.phrancol.osgi.demo.mvc.springmvc.core.OsgiDispatcherServlet

同时,它还充当一个HandlerMapping注册管理器的角色,通过一个BundleHandlerMappingManager来管理bundle的HandlerMapping,包括动态添加/删除等,它会重写DispatcherServlet 的getHandler方法,从BundleHandlerMappingManager获取Handler.....这里的代码比较简单,一看就能明白。BundleHandlerMappingManager只是一个Map的简单操作,代码省略

4f1150b881333f12a311ae9ef34da474.pngpublicclassOsgiDispatcherServletextendsDispatcherServletimplements1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif        HandlerRegister9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png

d18c02628675d0a2c816449d98bda930.pngprivatestaticfinalLog log=LogFactory

d18c02628675d0a2c816449d98bda930.png            .getLog(OsgiDispatcherServlet.class);

d18c02628675d0a2c816449d98bda930.png    

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/**//*HandlerMapping管理对象*/d18c02628675d0a2c816449d98bda930.pngprivateBundleHandlerMappingManager bundleHandlerMappingManager;

d18c02628675d0a2c816449d98bda930.png

d18c02628675d0a2c816449d98bda930.pngprivateBundleContext bundleContext;

d18c02628675d0a2c816449d98bda930.png

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicOsgiDispatcherServlet(BundleContext bundleContext)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngthis.bundleContext=bundleContext;

d18c02628675d0a2c816449d98bda930.pngthis.bundleHandlerMappingManager=newBundleHandlerMappingManager();

ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png

d18c02628675d0a2c816449d98bda930.pngprotectedWebApplicationContext createWebApplicationContext(

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif            WebApplicationContext parent)throwsBeansException9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png        ClassLoader contextClassLoader=Thread.currentThread()

d18c02628675d0a2c816449d98bda930.png                .getContextClassLoader();

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.giftry9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png            ClassLoader cl=BundleDelegatingClassLoader

d18c02628675d0a2c816449d98bda930.png                    .createBundleClassLoaderFor(bundleContext.getBundle(),

d18c02628675d0a2c816449d98bda930.png                            getClass().getClassLoader());

d18c02628675d0a2c816449d98bda930.png            Thread.currentThread().setContextClassLoader(cl);

d18c02628675d0a2c816449d98bda930.png            LocalBundleContext.setContext(bundleContext);

d18c02628675d0a2c816449d98bda930.png

d18c02628675d0a2c816449d98bda930.png            ConfigurableWebApplicationContext wac=newOSGiXmlWebApplicationContext(

d18c02628675d0a2c816449d98bda930.png                    bundleContext);

d18c02628675d0a2c816449d98bda930.png            wac.setParent(parent);

d18c02628675d0a2c816449d98bda930.png            wac.setServletContext(getServletContext());

d18c02628675d0a2c816449d98bda930.png            wac.setServletConfig(getServletConfig());

d18c02628675d0a2c816449d98bda930.png            wac.setNamespace(getNamespace());

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifif(getContextConfigLocation()!=null)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                wac

d18c02628675d0a2c816449d98bda930.png                        .setConfigLocations(StringUtils

d18c02628675d0a2c816449d98bda930.png                                .tokenizeToStringArray(

d18c02628675d0a2c816449d98bda930.png                                        getContextConfigLocation(),

d18c02628675d0a2c816449d98bda930.png                                        ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS));

ecedf933ec37d714bd4c2545da43add2.png            }d18c02628675d0a2c816449d98bda930.png            wac.addApplicationListener(this);

d18c02628675d0a2c816449d98bda930.png            wac.refresh();

d18c02628675d0a2c816449d98bda930.pngreturnwac;

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif        }finally9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png            Thread.currentThread().setContextClassLoader(contextClassLoader);

ecedf933ec37d714bd4c2545da43add2.png        }ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/** *//**d18c02628675d0a2c816449d98bda930.png     * 重写这个方法是很有必要的

ecedf933ec37d714bd4c2545da43add2.png*/d18c02628675d0a2c816449d98bda930.pngprotectedHandlerExecutionChain getHandler(HttpServletRequest request,

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifbooleancache)throwsException9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png        

d18c02628675d0a2c816449d98bda930.png        HandlerExecutionChain handler=(HandlerExecutionChain) request

d18c02628675d0a2c816449d98bda930.png                .getAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE);

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifif(handler!=null)9b8a8a44dd1c74ae49c20a7cd451974e.png{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifif(!cache)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                request.removeAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE);

ecedf933ec37d714bd4c2545da43add2.png            }d18c02628675d0a2c816449d98bda930.pngreturnhandler;

ecedf933ec37d714bd4c2545da43add2.png        }d18c02628675d0a2c816449d98bda930.png

d18c02628675d0a2c816449d98bda930.pngfor(Iterator _it=this.bundleHandlerMappingManager

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif                .getBundlesHandlerMapping().values().iterator(); _it.hasNext();)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png            List _handlerMappings=(List) _it.next();

d18c02628675d0a2c816449d98bda930.png

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.giffor(Iterator it=_handlerMappings.iterator(); it.hasNext();)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                

d18c02628675d0a2c816449d98bda930.png                HandlerMapping hm=(HandlerMapping) it.next();

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifif(logger.isDebugEnabled())9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                    logger.debug("Testing handler map ["+hm

d18c02628675d0a2c816449d98bda930.png+"] in OsgiDispatcherServlet with name '"d18c02628675d0a2c816449d98bda930.png+getServletName()+"'");

ecedf933ec37d714bd4c2545da43add2.png                }d18c02628675d0a2c816449d98bda930.png                handler=hm.getHandler(request);

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifif(handler!=null)9b8a8a44dd1c74ae49c20a7cd451974e.png{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifif(cache)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                        request.setAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE,

d18c02628675d0a2c816449d98bda930.png                                handler);

ecedf933ec37d714bd4c2545da43add2.png                    }d18c02628675d0a2c816449d98bda930.pngreturnhandler;

ecedf933ec37d714bd4c2545da43add2.png                }ecedf933ec37d714bd4c2545da43add2.png            }ecedf933ec37d714bd4c2545da43add2.png        }d18c02628675d0a2c816449d98bda930.pngreturnnull;

ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/** *//**d18c02628675d0a2c816449d98bda930.png     * 这个功能实现起来有点牵强,但是以演示为主,一笑而过

ecedf933ec37d714bd4c2545da43add2.png*/d18c02628675d0a2c816449d98bda930.pngprotectedView resolveViewName(String viewName, Map model, Locale locale,

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif            HttpServletRequest request)throwsException9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pnglongbundleId=this.bundleHandlerMappingManager.getBundleId(request);

d18c02628675d0a2c816449d98bda930.png        Bundle bundle=this.bundleContext.getBundle(bundleId);

d18c02628675d0a2c816449d98bda930.png        ViewResolver viewResolver=newOsgiInternalResourceViewResolver(

d18c02628675d0a2c816449d98bda930.png                bundle, getWebApplicationContext(), viewName);

d18c02628675d0a2c816449d98bda930.png        View view=viewResolver.resolveViewName(viewName, locale);

d18c02628675d0a2c816449d98bda930.pngreturnview;

ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicvoidregisterHandler(ApplicationContext context, Bundle bundle)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png        Map matchingBeans=BeanFactoryUtils.beansOfTypeIncludingAncestors(

d18c02628675d0a2c816449d98bda930.png                context, HandlerMapping.class,true,false);

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifif(!matchingBeans.isEmpty())9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png            List _list=newArrayList(matchingBeans.values());

d18c02628675d0a2c816449d98bda930.png            String bundleId=newLong(bundle.getBundleId()).toString();

d18c02628675d0a2c816449d98bda930.pngthis.bundleHandlerMappingManager.registerHandlerMapping(bundleId,

d18c02628675d0a2c816449d98bda930.png                    _list);

ecedf933ec37d714bd4c2545da43add2.png        }ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png    

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicvoidunRegisterHandler(Bundle bundle)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png        String bundleId=newLong(bundle.getBundleId()).toString();

d18c02628675d0a2c816449d98bda930.pngthis.bundleHandlerMappingManager.unRegisterHandlerMapping(bundleId);

ecedf933ec37d714bd4c2545da43add2.png    }8f1ba5b45633e9678d1db480c16cae3f.png}

扩展InternalResourceViewResolver - org.phrancol.osgi.demo.mvc.springmvc.core.OsgiInternalResourceViewResolver

为了方便,这部份的代码写得有些不地道(演示为主~),重写getPrefix()方法,主要是为了获取jsp文件

4f1150b881333f12a311ae9ef34da474.pngpublicclassOsgiInternalResourceViewResolverextends1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif        InternalResourceViewResolver9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png    

d18c02628675d0a2c816449d98bda930.pngprivatestaticfinalLog log=LogFactory.getLog(OsgiInternalResourceViewResolver.class);

d18c02628675d0a2c816449d98bda930.png    

d18c02628675d0a2c816449d98bda930.pngprivatestaticfinalString PREFIX="/web/jsp/spring/";

d18c02628675d0a2c816449d98bda930.png    

d18c02628675d0a2c816449d98bda930.pngprivatestaticfinalString SUFFIX=".jsp";

d18c02628675d0a2c816449d98bda930.png    

d18c02628675d0a2c816449d98bda930.pngprivateString viewName;

d18c02628675d0a2c816449d98bda930.png    

d18c02628675d0a2c816449d98bda930.pngprivateBundle bundle;

d18c02628675d0a2c816449d98bda930.png    

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifpublicOsgiInternalResourceViewResolver(Bundle bundle, ApplicationContext applicationContext , String viewName)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngthis.bundle=bundle;

d18c02628675d0a2c816449d98bda930.png        setPrefix(PREFIX);

d18c02628675d0a2c816449d98bda930.png        setSuffix(SUFFIX);

d18c02628675d0a2c816449d98bda930.png        setViewClass(newJstlView().getClass());

d18c02628675d0a2c816449d98bda930.png        setApplicationContext(applicationContext);

d18c02628675d0a2c816449d98bda930.png        

d18c02628675d0a2c816449d98bda930.pngthis.bundle=bundle;

d18c02628675d0a2c816449d98bda930.pngthis.viewName=viewName;

d18c02628675d0a2c816449d98bda930.png        

ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png    

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gifprotectedString getPrefix()9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png        String _prefix="/"+bundle.getSymbolicName()+PREFIX;

d18c02628675d0a2c816449d98bda930.pngreturn_prefix;

ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png

8f1ba5b45633e9678d1db480c16cae3f.png}

MVCBundle需要设置一个Activator,用于将OsgiDispatcherServlet注册为OSGi Service

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gifpublicvoidstart(BundleContext bundleContext)throwsException9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png        DispatcherServlet ds=newOsgiDispatcherServlet(bundleContext);

d18c02628675d0a2c816449d98bda930.png        bundleContext.registerService(DispatcherServlet.class.getName(), ds,

d18c02628675d0a2c816449d98bda930.pngnull);

8f1ba5b45633e9678d1db480c16cae3f.png    }

MVCBundle中的SpringmvcHttpServiceRegister还是需要的,它需要生成一个所谓的容器Context

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gifpublicclassSpringmvcHttpServiceRegisterimplementsHttpServiceRegister9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngpublicvoidserviceRegister(BundleContext context,

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif            ApplicationContext bundleApplicationContext)9b8a8a44dd1c74ae49c20a7cd451974e.png{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.giftry9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png

d18c02628675d0a2c816449d98bda930.png            ServiceReference sr=context.getServiceReference(HttpService.classd18c02628675d0a2c816449d98bda930.png                    .getName());

d18c02628675d0a2c816449d98bda930.png            HttpService httpService=(HttpService) context.getService(sr);

d18c02628675d0a2c816449d98bda930.png            HttpContext defaultContext=httpService.createDefaultHttpContext();

d18c02628675d0a2c816449d98bda930.png            Dictionaryinitparams=newHashtable();

d18c02628675d0a2c816449d98bda930.png            initparams.put("load-on-startup","1");

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/** *//**/

d18c02628675d0a2c816449d98bda930.png            ContextLoaderServlet contextloaderListener = new BundleContextLoaderServlet(

d18c02628675d0a2c816449d98bda930.png                    context, bundleApplicationContext);

d18c02628675d0a2c816449d98bda930.png            httpService.registerServlet("/initContext", contextloaderListener,

d18c02628675d0a2c816449d98bda930.png                    initparams, defaultContext);

ecedf933ec37d714bd4c2545da43add2.png            /**/d18c02628675d0a2c816449d98bda930.png            DispatcherServlet dispatcherServlet=(DispatcherServlet) context

d18c02628675d0a2c816449d98bda930.png                    .getService(context

d18c02628675d0a2c816449d98bda930.png                            .getServiceReference(DispatcherServlet.classd18c02628675d0a2c816449d98bda930.png                                    .getName()));

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/**//*这里给了 DispatcherServlet 一个空的配置文件,可以节省好多代码*/d18c02628675d0a2c816449d98bda930.png            dispatcherServlet

d18c02628675d0a2c816449d98bda930.png                    .setContextConfigLocation("META-INF/dispatcher/DynamicModule-servlet.xml");

d18c02628675d0a2c816449d98bda930.png            initparams=newHashtable();

d18c02628675d0a2c816449d98bda930.png            initparams.put("servlet-name","DynamicModule");

d18c02628675d0a2c816449d98bda930.png            initparams.put("load-on-startup","2");

d18c02628675d0a2c816449d98bda930.png            httpService.registerServlet("/*.do", dispatcherServlet, initparams,

d18c02628675d0a2c816449d98bda930.png                    defaultContext);

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif        }catch(Exception e)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png            e.printStackTrace(System.out);

ecedf933ec37d714bd4c2545da43add2.png        }ecedf933ec37d714bd4c2545da43add2.png    }8f1ba5b45633e9678d1db480c16cae3f.png}

通过以上工作,Spring MVC就被简单的改造完了......当然他仅仅只是能实现我所要演示的功能

五、模块

新建一个模块bundle - org.phrancol.osgi.demo.mvc.springmvc.module2  ,Bundle-SymbolicName设置为module2

先看看它的bean配置

4f1150b881333f12a311ae9ef34da474.png4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.png        class="org.phrancol.osgi.demo.mvc.util.BundleServiceRegister">4f1150b881333f12a311ae9ef34da474.png4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngclass="org.phrancol.osgi.demo.mvc.springmvc.module2.SpringmvcHttpServiceRegister"/>4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.png 4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.png4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.png        class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.png        class="org.phrancol.osgi.demo.mvc.springmvc.module2.TheSecondModuleController">4f1150b881333f12a311ae9ef34da474.png4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.png

也使用了一个SpringmvcHttpServiceRegister,它就是用来注册这个bundle 中的jsp和资源的

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gifpublicclassSpringmvcHttpServiceRegisterimplementsHttpServiceRegister9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngpublicvoidserviceRegister(BundleContext context,

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif            ApplicationContext bundleApplicationContext)9b8a8a44dd1c74ae49c20a7cd451974e.png{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.giftry9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png

d18c02628675d0a2c816449d98bda930.png            ServiceReference sr=context.getServiceReference(HttpService.classd18c02628675d0a2c816449d98bda930.png                    .getName());

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/**//*在上一个例子中,HttpContext的用法不对,这个用法才是正确的*/d18c02628675d0a2c816449d98bda930.png            HttpService httpService=(HttpService) context.getService(sr);

d18c02628675d0a2c816449d98bda930.png            HttpContext defaultContext=httpService.createDefaultHttpContext();

d18c02628675d0a2c816449d98bda930.png            httpService.registerResources("/module2","/module2",

d18c02628675d0a2c816449d98bda930.png                    defaultContext);

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/**//*d18c02628675d0a2c816449d98bda930.png             * 这个JspServlet对象中的参数"module2/web",可以理解为 The root path of module

d18c02628675d0a2c816449d98bda930.png             * application,它是干什么用的,请参考它的JavaDoc,建议从Eclipse的CVS中准备一份Equinox的源代码

ecedf933ec37d714bd4c2545da43add2.png*/d18c02628675d0a2c816449d98bda930.png            JspServlet jspServlet=newJspServlet(context.getBundle(),

d18c02628675d0a2c816449d98bda930.png"/module2/web");

d18c02628675d0a2c816449d98bda930.png            httpService.registerServlet("/module2/*.jsp", jspServlet,null,

d18c02628675d0a2c816449d98bda930.png                    defaultContext);

d18c02628675d0a2c816449d98bda930.png

d18c02628675d0a2c816449d98bda930.png            HandlerRegister dispatcherServlet=(HandlerRegister) context

d18c02628675d0a2c816449d98bda930.png                    .getService(context

d18c02628675d0a2c816449d98bda930.png                            .getServiceReference(DispatcherServlet.classd18c02628675d0a2c816449d98bda930.png                                    .getName()));

d18c02628675d0a2c816449d98bda930.png            dispatcherServlet.registerHandler(bundleApplicationContext, context

d18c02628675d0a2c816449d98bda930.png                    .getBundle());

d18c02628675d0a2c816449d98bda930.png

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif        }catch(Exception e)9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png            e.printStackTrace(System.out);

ecedf933ec37d714bd4c2545da43add2.png        }ecedf933ec37d714bd4c2545da43add2.png    }8f1ba5b45633e9678d1db480c16cae3f.png}

来看看org.phrancol.osgi.demo.mvc.springmvc.module2.TheSecondModuleController ,只有很简单的一个输出

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gifpublicclassTheSecondModuleControllerimplementsController9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png    

d18c02628675d0a2c816449d98bda930.pngprivatestaticfinalString VIEWSTRING="Hello, this is the second module !";

d18c02628675d0a2c816449d98bda930.png

d18c02628675d0a2c816449d98bda930.pngpublicModelAndView handleRequest(HttpServletRequest request,

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif            HttpServletResponse response)throwsException9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png        Map model=newHashMap();

d18c02628675d0a2c816449d98bda930.png        model.put("viewString", VIEWSTRING);

d18c02628675d0a2c816449d98bda930.png        ModelAndView mv=newModelAndView("Success", model);

d18c02628675d0a2c816449d98bda930.pngreturnmv;

ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png

8f1ba5b45633e9678d1db480c16cae3f.png}

目录结构也有一点变化 /module1/web/jsp/spring/ *.jsp

模块1和模块2是一样的

六、运行

将模块二导出为bundle jar包,放到C盘根目录下,启动这个应用(当然不要启动modure2),在浏览器看看module1的运行情况

module1.gif

现在安装一下module2

module2_install.gif

试着访问一下module2

module2_404.gif

404,正常,启动一下这个bundle再看看

module2.gif

显示出来了,现在可以动态的操作这2个模块了......

七、扩展

通过这个演示,可以领略到OSGi带给我们的一小部分功能,做一些扩展看看

1.  当然是各种框架的支持。

2.  强大的bundle资源库

3.  绝对动态的部署框架,可以通过UI界面来操作。

4.  可以从URL来安装bundle,  install http://www.domain.com/sampleBundle.jar ,如果是这样的,服务网关就能体现出来了,你提供一个服务框架,别人可以通过你的框架运行自己的服务。

5.   个人猜测,它将取代Portal的运行模式

6.  ..........

八、结束语

OSGi在Web应用中还有很长的路要走,它到底会发展成什么样子,就目前的功能还真不好推测。

现在不管是MVC还是持久层都还没有框架对OSGi的支持,我个人准备用业余时间研究一下这方面,顺便也可以练练手,希望传说中的强人能开发这样的框架并不吝开源~

九、相关资源

就我目前能找到的一些资源,列出如下:

Struts2有一个OSGi的插件,但是我看了看,并不能达到预期效果,不过可以看一看

http://cwiki.apache.org/S2PLUGINS/osgi-plugin.html

在持久层方面,db4o似乎有这个打算,不做评论

http://www.db4o.com/osgi/

另外它的合作伙伴prosyst已经开发出了一个基于Equinox的OSGi Server,还有个专业版,好像要收费,所以也就没下载,不知道是个什么样子。

http://www.prosyst.com/

posted on 2007-11-01 15:09 Phrancol Yang 阅读(6123) 评论(5)  编辑  收藏 所属分类: OSGI

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值