隨筆 - 1  文章 - 37  trackbacks - 0
          <2025年6月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          293012345

          留言簿(16)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          test

          搜索

          •  

          最新評(píng)論

          一、契子

            很早以前就開(kāi)始構(gòu)思可動(dòng)態(tài)部署的Web應(yīng)用,模塊化應(yīng)用無(wú)疑是一種趨勢(shì),Portal應(yīng)用可謂是一個(gè)小革新,它的功能引起了很多人的注意,OSGi 無(wú)疑會(huì)為這帶來(lái)本質(zhì)上的升級(jí)。

          二、目標(biāo)

          這篇blog中的例子從JPetStoreOsgi衍生,通過(guò)擴(kuò)展(修改)Spring mvc中的某些對(duì)象,實(shí)現(xiàn)模塊的動(dòng)態(tài)部署,當(dāng)然,這只是很簡(jiǎn)單的案例,不過(guò)足以達(dá)到我的預(yù)期目標(biāo):有2個(gè)非常簡(jiǎn)單的模塊module1和module2,它們都有自己的Spring mvc配置文件,可以在運(yùn)行時(shí)簡(jiǎn)單的通過(guò)OSGi控制臺(tái),安裝它們,并完成它們各自的功能。


          三、準(zhǔn)備工作

          [點(diǎn)擊這里下載 DynamicModule 工程包
          由于整個(gè)Workspace太大,所以僅僅只是把更新的5個(gè)Bundle的Project上傳了,先 下載JPetStoreOsgi ,然后將所有關(guān)于JPetStore的Project刪除,導(dǎo)入這5個(gè)Project

          四、Spring MVC

          目前還沒(méi)有用于OSGi環(huán)境的MVC框架,所以選用Spring MVC做為演示框架

          org.phrancol.osgi.demo.mvc.springmvc 是整個(gè)應(yīng)用的MVC Bundle,以下簡(jiǎn)稱 MVCBundle

          1. org.phrancol.osgi.demo.mvc.springmvc.core.HandlerRegister
            public interface HandlerRegister {
                
                
            /**
                 * 當(dāng)bundle的ApplicationContext生成后,獲取HandlerMapping,并注冊(cè)
                 * 
            @param context Spring為Bundle生成的ApplicationContext
                 * 
            @param bundle
                 
            */

                
            public void registerHandler(ApplicationContext context, Bundle bundle);
                
                
            /**
                 * 當(dāng)Bundle被停止或是卸載的時(shí)候,注銷這個(gè)bundle的HandlerMapping
                 * 當(dāng)然這個(gè)功能沒(méi)有實(shí)現(xiàn)(它可以實(shí)現(xiàn)),因?yàn)樗粚儆谘菔痉秶?br />      * 
            @param bundle
                 
            */

                
            public void unRegisterHandler(Bundle bundle);

            }

          2. 擴(kuò)展DispatcherServlet - org.phrancol.osgi.demo.mvc.springmvc.core.OsgiDispatcherServlet
            同時(shí),它還充當(dāng)一個(gè)HandlerMapping注冊(cè)管理器的角色,通過(guò)一個(gè)BundleHandlerMappingManager來(lái)管理bundle的HandlerMapping,包括動(dòng)態(tài)添加/刪除等,它會(huì)重寫DispatcherServlet 的getHandler方法,從BundleHandlerMappingManager獲取Handler.....這里的代碼比較簡(jiǎn)單,一看就能明白。BundleHandlerMappingManager只是一個(gè)Map的簡(jiǎn)單操作,代碼省略
            public class OsgiDispatcherServlet extends DispatcherServlet implements
                    HandlerRegister 
            {

                
            private static final Log log = LogFactory
                        .getLog(OsgiDispatcherServlet.
            class);
                
                
            /* HandlerMapping管理對(duì)象 */
                
            private BundleHandlerMappingManager bundleHandlerMappingManager;

                
            private BundleContext bundleContext;

                
            public OsgiDispatcherServlet(BundleContext bundleContext) {
                    
            this.bundleContext = bundleContext;
                    
            this.bundleHandlerMappingManager = new BundleHandlerMappingManager();
                }


                
            protected WebApplicationContext createWebApplicationContext(
                        WebApplicationContext parent) 
            throws BeansException {
                    ClassLoader contextClassLoader 
            = Thread.currentThread()
                            .getContextClassLoader();
                    
            try {
                        ClassLoader cl 
            = BundleDelegatingClassLoader
                                .createBundleClassLoaderFor(bundleContext.getBundle(),
                                        getClass().getClassLoader());
                        Thread.currentThread().setContextClassLoader(cl);
                        LocalBundleContext.setContext(bundleContext);

                        ConfigurableWebApplicationContext wac 
            = new OSGiXmlWebApplicationContext(
                                bundleContext);
                        wac.setParent(parent);
                        wac.setServletContext(getServletContext());
                        wac.setServletConfig(getServletConfig());
                        wac.setNamespace(getNamespace());
                        
            if (getContextConfigLocation() != null{
                            wac
                                    .setConfigLocations(StringUtils
                                            .tokenizeToStringArray(
                                                    getContextConfigLocation(),
                                                    ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS));
                        }

                        wac.addApplicationListener(
            this);
                        wac.refresh();
                        
            return wac;
                    }
             finally {
                        Thread.currentThread().setContextClassLoader(contextClassLoader);
                    }

                }


                
            /**
                 * 重寫這個(gè)方法是很有必要的
                 
            */

                
            protected HandlerExecutionChain getHandler(HttpServletRequest request,
                        
            boolean cache) throws Exception {
                    
                    HandlerExecutionChain handler 
            = (HandlerExecutionChain) request
                            .getAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE);
                    
            if (handler != null{
                        
            if (!cache) {
                            request.removeAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE);
                        }

                        
            return handler;
                    }


                    
            for (Iterator _it = this.bundleHandlerMappingManager
                            .getBundlesHandlerMapping().values().iterator(); _it.hasNext();) 
            {
                        List _handlerMappings 
            = (List) _it.next();

                        
            for (Iterator it = _handlerMappings.iterator(); it.hasNext();) {
                            
                            HandlerMapping hm 
            = (HandlerMapping) it.next();
                            
            if (logger.isDebugEnabled()) {
                                logger.debug(
            "Testing handler map [" + hm
                                        
            + "] in OsgiDispatcherServlet with name '"
                                        
            + getServletName() + "'");
                            }

                            handler 
            = hm.getHandler(request);
                            
            if (handler != null{
                                
            if (cache) {
                                    request.setAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE,
                                            handler);
                                }

                                
            return handler;
                            }

                        }

                    }

                    
            return null;
                }


                
            /**
                 * 這個(gè)功能實(shí)現(xiàn)起來(lái)有點(diǎn)牽強(qiáng),但是以演示為主,一笑而過(guò)
                 
            */

                
            protected View resolveViewName(String viewName, Map model, Locale locale,
                        HttpServletRequest request) 
            throws Exception {
                    
            long bundleId = this.bundleHandlerMappingManager.getBundleId(request);
                    Bundle bundle 
            = this.bundleContext.getBundle(bundleId);
                    ViewResolver viewResolver 
            = new OsgiInternalResourceViewResolver(
                            bundle, getWebApplicationContext(), viewName);
                    View view 
            = viewResolver.resolveViewName(viewName, locale);
                    
            return view;
                }


                
            public void registerHandler(ApplicationContext context, Bundle bundle) {
                    Map matchingBeans 
            = BeanFactoryUtils.beansOfTypeIncludingAncestors(
                            context, HandlerMapping.
            classtruefalse);
                    
            if (!matchingBeans.isEmpty()) {
                        List _list 
            = new ArrayList(matchingBeans.values());
                        String bundleId 
            = new Long(bundle.getBundleId()).toString();
                        
            this.bundleHandlerMappingManager.registerHandlerMapping(bundleId,
                                _list);
                    }

                }

                
                
            public void unRegisterHandler(Bundle bundle){
                    String bundleId 
            = new Long(bundle.getBundleId()).toString();
                    
            this.bundleHandlerMappingManager.unRegisterHandlerMapping(bundleId);
                }

            }

          3. 擴(kuò)展InternalResourceViewResolver - org.phrancol.osgi.demo.mvc.springmvc.core.OsgiInternalResourceViewResolver
            為了方便,這部份的代碼寫得有些不地道(演示為主~),重寫getPrefix()方法,主要是為了獲取jsp文件
            public class OsgiInternalResourceViewResolver extends
                    InternalResourceViewResolver 
            {
                
                
            private static final Log log = LogFactory.getLog(OsgiInternalResourceViewResolver.class);
                
                
            private static final String PREFIX = "/web/jsp/spring/";
                
                
            private static final String SUFFIX = ".jsp";
                
                
            private String viewName;
                
                
            private Bundle bundle;
                
                
            public OsgiInternalResourceViewResolver(Bundle bundle, ApplicationContext applicationContext , String viewName){
                    
            this.bundle = bundle;
                    setPrefix(PREFIX);
                    setSuffix(SUFFIX);
                    setViewClass(
            new JstlView().getClass());
                    setApplicationContext(applicationContext);
                    
                    
            this.bundle = bundle;
                    
            this.viewName = viewName;
                    
                }

                
                
            protected String getPrefix() {
                    String _prefix
            = "/"+bundle.getSymbolicName()+PREFIX;
                    
            return _prefix;
                }
                

            }

          4. MVCBundle需要設(shè)置一個(gè)Activator,用于將OsgiDispatcherServlet注冊(cè)為OSGi Service
            public void start(BundleContext bundleContext) throws Exception {
                    DispatcherServlet ds 
            = new OsgiDispatcherServlet(bundleContext);
                    bundleContext.registerService(DispatcherServlet.
            class.getName(), ds,
                            
            null);
                }

          5. MVCBundle中的SpringmvcHttpServiceRegister還是需要的,它需要生成一個(gè)所謂的容器Context
            public class SpringmvcHttpServiceRegister implements HttpServiceRegister {
                
            public void serviceRegister(BundleContext context,
                        ApplicationContext bundleApplicationContext) 
            {
                    
            try {

                        ServiceReference sr 
            = context.getServiceReference(HttpService.class
                                .getName());
                        HttpService httpService 
            = (HttpService) context.getService(sr);
                        HttpContext defaultContext 
            = httpService.createDefaultHttpContext();
                        Dictionary
            <String, String> initparams = new Hashtable<String, String>();
                        initparams.put(
            "load-on-startup""1");
                        
            /**/
                        ContextLoaderServlet contextloaderListener = new BundleContextLoaderServlet(
                                context, bundleApplicationContext);
                        httpService.registerServlet("/initContext", contextloaderListener,
                                initparams, defaultContext);
                        /*
            */

                        DispatcherServlet dispatcherServlet 
            = (DispatcherServlet) context
                                .getService(context
                                        .getServiceReference(DispatcherServlet.
            class
                                                .getName()));
                        
            /* 這里給了 DispatcherServlet 一個(gè)空的配置文件,可以節(jié)省好多代碼*/
                        dispatcherServlet
                                .setContextConfigLocation(
            "META-INF/dispatcher/DynamicModule-servlet.xml");
                        initparams 
            = new Hashtable<String, String>();
                        initparams.put(
            "servlet-name""DynamicModule");
                        initparams.put(
            "load-on-startup""2");
                        httpService.registerServlet(
            "/*.do", dispatcherServlet, initparams,
                                defaultContext);
                    }
             catch (Exception e) {
                        e.printStackTrace(System.out);
                    }

                }

            }

          通過(guò)以上工作,Spring MVC就被簡(jiǎn)單的改造完了......當(dāng)然他僅僅只是能實(shí)現(xiàn)我所要演示的功能

          五、模塊

          新建一個(gè)模塊bundle - org.phrancol.osgi.demo.mvc.springmvc.module2  ,Bundle-SymbolicName設(shè)置為module2
          先看看它的bean配置

          <beans>

              
          <bean id="module2Register"
                  class
          ="org.phrancol.osgi.demo.mvc.util.BundleServiceRegister">
                  
          <constructor-arg>
                      
          <bean
                          
          class="org.phrancol.osgi.demo.mvc.springmvc.module2.SpringmvcHttpServiceRegister" />
                  
          </constructor-arg>
              
          </bean>

              
          <!-- ========================= DEFINITIONS OF PUBLIC CONTROLLERS ========================= -->

              
          <bean id="module2HandlerMapping"
                  class
          ="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />

              
          <bean name="/DynamicModule/module2.do"
                  class
          ="org.phrancol.osgi.demo.mvc.springmvc.module2.TheSecondModuleController">
              
          </bean>

          </beans>

           

          也使用了一個(gè)SpringmvcHttpServiceRegister,它就是用來(lái)注冊(cè)這個(gè)bundle 中的jsp和資源的

          public class SpringmvcHttpServiceRegister implements HttpServiceRegister {
              
          public void serviceRegister(BundleContext context,
                      ApplicationContext bundleApplicationContext) 
          {
                  
          try {

                      ServiceReference sr 
          = context.getServiceReference(HttpService.class
                              .getName());
                      
          /* 在上一個(gè)例子中,HttpContext的用法不對(duì),這個(gè)用法才是正確的 */
                      HttpService httpService 
          = (HttpService) context.getService(sr);
                      HttpContext defaultContext 
          = httpService.createDefaultHttpContext();
                      httpService.registerResources(
          "/module2""/module2",
                              defaultContext);
                      
          /*
                       * 這個(gè)JspServlet對(duì)象中的參數(shù)"module2/web",可以理解為 The root path of module
                       * application,它是干什么用的,請(qǐng)參考它的JavaDoc,建議從Eclipse的CVS中準(zhǔn)備一份Equinox的源代碼
                       
          */

                      JspServlet jspServlet 
          = new JspServlet(context.getBundle(),
                              
          "/module2/web");
                      httpService.registerServlet(
          "/module2/*.jsp", jspServlet, null,
                              defaultContext);

                      HandlerRegister dispatcherServlet 
          = (HandlerRegister) context
                              .getService(context
                                      .getServiceReference(DispatcherServlet.
          class
                                              .getName()));
                      dispatcherServlet.registerHandler(bundleApplicationContext, context
                              .getBundle());

                  }
           catch (Exception e) {
                      e.printStackTrace(System.out);
                  }

              }

          }

          來(lái)看看org.phrancol.osgi.demo.mvc.springmvc.module2.TheSecondModuleController ,只有很簡(jiǎn)單的一個(gè)輸出

          public class TheSecondModuleController implements Controller {
              
              
          private static final String VIEWSTRING = "Hello, this is the second module !";

              
          public ModelAndView handleRequest(HttpServletRequest request,
                      HttpServletResponse response) 
          throws Exception {
                  Map model 
          = new HashMap();
                  model.put(
          "viewString", VIEWSTRING);
                  ModelAndView mv 
          = new ModelAndView("Success", model);
                  
          return mv;
              }


          }

          目錄結(jié)構(gòu)也有一點(diǎn)變化 /module1/web/jsp/spring/ *.jsp

          模塊1和模塊2是一樣的

           

          六、運(yùn)行

          將模塊二導(dǎo)出為bundle jar包,放到C盤根目錄下,啟動(dòng)這個(gè)應(yīng)用(當(dāng)然不要啟動(dòng)modure2),在瀏覽器看看module1的運(yùn)行情況


          現(xiàn)在安裝一下module2



          試著訪問(wèn)一下module2




          404,正常,啟動(dòng)一下這個(gè)bundle再看看


          顯示出來(lái)了,現(xiàn)在可以動(dòng)態(tài)的操作這2個(gè)模塊了......


          七、擴(kuò)展

          通過(guò)這個(gè)演示,可以領(lǐng)略到OSGi帶給我們的一小部分功能,做一些擴(kuò)展看看
          1.  當(dāng)然是各種框架的支持。
          2.  強(qiáng)大的bundle資源庫(kù)
          3.  絕對(duì)動(dòng)態(tài)的部署框架,可以通過(guò)UI界面來(lái)操作。
          4.  可以從URL來(lái)安裝bundle,  install http://www.domain.com/sampleBundle.jar ,如果是這樣的,服務(wù)網(wǎng)關(guān)就能體現(xiàn)出來(lái)了,你提供一個(gè)服務(wù)框架,別人可以通過(guò)你的框架運(yùn)行自己的服務(wù)。
          5.   個(gè)人猜測(cè),它將取代Portal的運(yùn)行模式
          6.  ..........


          八、結(jié)束語(yǔ)

          OSGi在Web應(yīng)用中還有很長(zhǎng)的路要走,它到底會(huì)發(fā)展成什么樣子,就目前的功能還真不好推測(cè)。
          現(xiàn)在不管是MVC還是持久層都還沒(méi)有框架對(duì)OSGi的支持,我個(gè)人準(zhǔn)備用業(yè)余時(shí)間研究一下這方面,順便也可以練練手,希望傳說(shuō)中的強(qiáng)人能開(kāi)發(fā)這樣的框架并不吝開(kāi)源~


          九、相關(guān)資源

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

          Struts2有一個(gè)OSGi的插件,但是我看了看,并不能達(dá)到預(yù)期效果,不過(guò)可以看一看
          http://cwiki.apache.org/S2PLUGINS/osgi-plugin.html

          在持久層方面,db4o似乎有這個(gè)打算,不做評(píng)論
          http://www.db4o.com/osgi/
          另外它的合作伙伴prosyst已經(jīng)開(kāi)發(fā)出了一個(gè)基于Equinox的OSGi Server,還有個(gè)專業(yè)版,好像要收費(fèi),所以也就沒(méi)下載,不知道是個(gè)什么樣子。
          http://www.prosyst.com/
          posted on 2007-11-01 15:09 Phrancol Yang 閱讀(6279) 評(píng)論(5)  編輯  收藏 所屬分類: OSGI

          FeedBack:
          # re: 構(gòu)建模塊化的動(dòng)態(tài)Web應(yīng)用(演示版) 2007-12-03 14:47 ky
          petStoreOsgi的包下不到啊,是不是鏈接失效了?Thanks!  回復(fù)  更多評(píng)論
            
          # re: 構(gòu)建模塊化的動(dòng)態(tài)Web應(yīng)用(演示版) 2007-12-11 09:54 Phrancol Yang
          可以下載啊,不要用 Firefox 訪問(wèn)那個(gè)下載頁(yè)面  回復(fù)  更多評(píng)論
            
          # re: 構(gòu)建模塊化的動(dòng)態(tài)Web應(yīng)用(演示版) 2008-02-14 17:51 s
          啟動(dòng)出現(xiàn)錯(cuò)誤org.springframework.ejb.config.JeeNamespaceHandler not found
          是什么原因,謝謝!  回復(fù)  更多評(píng)論
            
          # re: 構(gòu)建模塊化的動(dòng)態(tài)Web應(yīng)用(演示版) 2008-02-15 09:14 Phrancol Yang
          @s
          http://forum.springframework.org/showthread.php?t=33474
          看看這個(gè),如果還不能解決你的問(wèn)題,請(qǐng)將問(wèn)題發(fā)詳細(xì)一些~  回復(fù)  更多評(píng)論
            
          # re: 構(gòu)建模塊化的動(dòng)態(tài)Web應(yīng)用(演示版) 2008-07-11 18:04 亞龍
          太好了,幫你頂!!  回復(fù)  更多評(píng)論
            
          主站蜘蛛池模板: 双峰县| 克什克腾旗| 泰来县| 花莲市| 保定市| 陕西省| 京山县| 河间市| 水富县| 行唐县| 兰考县| 哈密市| 杨浦区| 遂平县| 綦江县| 韩城市| 阳城县| 闽侯县| 若羌县| 汤原县| 广丰县| 隆化县| 伊通| 朝阳市| 五寨县| 故城县| 肃南| 乐东| 北海市| 曲阜市| 临安市| 普陀区| 榆社县| 民权县| 阳城县| 丹东市| 于都县| 冕宁县| 宁晋县| 福贡县| 安化县|