<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆 - 1  文章 - 37  trackbacks - 0
    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    留言簿(16)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    test

    搜索

    •  

    最新評論

    一、契子

      很早以前就開始構思可動態部署的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

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

          
      public void registerHandler(ApplicationContext context, Bundle bundle);
          
          
      /**
           * 當Bundle被停止或是卸載的時候,注銷這個bundle的HandlerMapping
           * 當然這個功能沒有實現(它可以實現),因為他不屬于演示范圍
           * 
      @param bundle
           
      */

          
      public void unRegisterHandler(Bundle bundle);

      }

    2. 擴展DispatcherServlet - org.phrancol.osgi.demo.mvc.springmvc.core.OsgiDispatcherServlet
      同時,它還充當一個HandlerMapping注冊管理器的角色,通過一個BundleHandlerMappingManager來管理bundle的HandlerMapping,包括動態添加/刪除等,它會重寫DispatcherServlet 的getHandler方法,從BundleHandlerMappingManager獲取Handler.....這里的代碼比較簡單,一看就能明白。BundleHandlerMappingManager只是一個Map的簡單操作,代碼省略
      public class OsgiDispatcherServlet extends DispatcherServlet implements
              HandlerRegister 
      {

          
      private static final Log log = LogFactory
                  .getLog(OsgiDispatcherServlet.
      class);
          
          
      /* HandlerMapping管理對象 */
          
      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);
              }

          }


          
      /**
           * 重寫這個方法是很有必要的
           
      */

          
      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;
          }


          
      /**
           * 這個功能實現起來有點牽強,但是以演示為主,一笑而過
           
      */

          
      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. 擴展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需要設置一個Activator,用于將OsgiDispatcherServlet注冊為OSGi Service
      public void start(BundleContext bundleContext) throws Exception {
              DispatcherServlet ds 
      = new OsgiDispatcherServlet(bundleContext);
              bundleContext.registerService(DispatcherServlet.
      class.getName(), ds,
                      
      null);
          }

    5. MVCBundle中的SpringmvcHttpServiceRegister還是需要的,它需要生成一個所謂的容器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 一個空的配置文件,可以節省好多代碼*/
                  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);
              }

          }

      }

    通過以上工作,Spring MVC就被簡單的改造完了......當然他僅僅只是能實現我所要演示的功能

    五、模塊

    新建一個模塊bundle - org.phrancol.osgi.demo.mvc.springmvc.module2  ,Bundle-SymbolicName設置為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>

     

    也使用了一個SpringmvcHttpServiceRegister,它就是用來注冊這個bundle 中的jsp和資源的

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

                ServiceReference sr 
    = context.getServiceReference(HttpService.class
                        .getName());
                
    /* 在上一個例子中,HttpContext的用法不對,這個用法才是正確的 */
                HttpService httpService 
    = (HttpService) context.getService(sr);
                HttpContext defaultContext 
    = httpService.createDefaultHttpContext();
                httpService.registerResources(
    "/module2""/module2",
                        defaultContext);
                
    /*
                 * 這個JspServlet對象中的參數"module2/web",可以理解為 The root path of module
                 * application,它是干什么用的,請參考它的JavaDoc,建議從Eclipse的CVS中準備一份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);
            }

        }

    }

    來看看org.phrancol.osgi.demo.mvc.springmvc.module2.TheSecondModuleController ,只有很簡單的一個輸出

    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;
        }


    }

    目錄結構也有一點變化 /module1/web/jsp/spring/ *.jsp

    模塊1和模塊2是一樣的

     

    六、運行

    將模塊二導出為bundle jar包,放到C盤根目錄下,啟動這個應用(當然不要啟動modure2),在瀏覽器看看module1的運行情況


    現在安裝一下module2



    試著訪問一下module2




    404,正常,啟動一下這個bundle再看看


    顯示出來了,現在可以動態的操作這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 閱讀(6276) 評論(5)  編輯  收藏 所屬分類: OSGI

    FeedBack:
    # re: 構建模塊化的動態Web應用(演示版) 2007-12-03 14:47 ky
    petStoreOsgi的包下不到啊,是不是鏈接失效了?Thanks!  回復  更多評論
      
    # re: 構建模塊化的動態Web應用(演示版) 2007-12-11 09:54 Phrancol Yang
    可以下載啊,不要用 Firefox 訪問那個下載頁面  回復  更多評論
      
    # re: 構建模塊化的動態Web應用(演示版) 2008-02-14 17:51 s
    啟動出現錯誤org.springframework.ejb.config.JeeNamespaceHandler not found
    是什么原因,謝謝!  回復  更多評論
      
    # re: 構建模塊化的動態Web應用(演示版) 2008-02-15 09:14 Phrancol Yang
    @s
    http://forum.springframework.org/showthread.php?t=33474
    看看這個,如果還不能解決你的問題,請將問題發詳細一些~  回復  更多評論
      
    # re: 構建模塊化的動態Web應用(演示版) 2008-07-11 18:04 亞龍
    太好了,幫你頂!!  回復  更多評論
      
    主站蜘蛛池模板: 九九九精品成人免费视频| 亚洲午夜激情视频| 亚洲AV日韩AV一区二区三曲| 国产中文字幕免费| 国产在线精品免费aaa片| 亚洲免费二区三区| 亚洲AV无码一区二三区 | 99亚洲男女激情在线观看| 亚洲综合AV在线在线播放| 国产91免费视频| j8又粗又长又硬又爽免费视频| 91亚洲国产成人久久精品网站| 免费国产a国产片高清| 免费h视频在线观看| 国产精品亚洲AV三区| 久久夜色精品国产噜噜亚洲AV| 免费A级毛片无码A| 免费成人福利视频| 国产99久久久久久免费看| 亚洲av成人一区二区三区| 久久精品国产亚洲沈樵| 免费看大黄高清网站视频在线| 性无码免费一区二区三区在线| 亚洲av日韩精品久久久久久a| 亚洲国产成人久久综合碰碰动漫3d | 亚洲福利精品电影在线观看| 亚洲精品视频在线免费| 精品一区二区三区免费视频| 亚洲成av人片在www鸭子| 99亚洲精品高清一二区| 国产亚洲精午夜久久久久久| 毛片A级毛片免费播放| 日韩免费高清大片在线| jizz免费观看| 国产成人亚洲精品电影| 亚洲欧洲日本在线观看 | 豆国产96在线|亚洲| 亚洲娇小性色xxxx| 亚洲日本一区二区三区| 在线日韩日本国产亚洲| 亚洲男人在线无码视频|