14.OSGI企业应用开发-整合Spring、Mybatis、Spring MVC

作为一个企业级的Web应用,MVC框架是必不可少的。Spring MVC目前使用也比较广泛,本文就来介绍一下如何在OSGI应用中实现Spring、Mybatis、Spring MVC框架的整合,其中Spring MVC的整合比较困难,原因是Spring整合到OSGI中后,每个Bundle都拥有一个孤立的ApplicationContext,也就是说不同Bundle中实例化的Bean之间的依赖注入就存在一定的问题,前面文章中提到过,这个问题可以通过Bean的注册和引用机制解决。

而实例化Spring MVC框架中的org.springframework.web.servlet.DispatcherServlet类时也需要指定Bean的配置文件,Spring MVC框架启动后会实例化配置文件中的Bean(例如Controller实例),Spring MVC框架启动后实例化的Bean与Bundle中实例化的Bean属于不同的类加载器,所以Bundle中实例化的Bean无法注入到Spring MVC框架启动时实例化的Bean,比较直接的例子就是Mybatis操作数据库的SqlSession实例无法注入到Spring MVC的Controller中,网上比较多的解决方案是使用Virgo,笔者经过一番钻研,解决了Spring MVC框架与OSGI应用的整合,如果发现有什么问题,可以一起探讨下_

接下来就介绍OSGI应用中Spring、Mybatis、Spring MVC框架的整合,我们依然使用前面文章中已经搭建好的工作空间。

首先新建一个Bundle,名称为com.csdn.osgi.user.web,整个工作空间结构如下图所示:
这里写图片描述
由于OSGI应用中资源与Servlet都需要注册后才能被客户端访问,我们可以编写几个类专门用于注册Web资源。

首先是图片、CSS、JS等静态资源的注册,在com.csdn.osgi.user.web这个Bundle中新建一个类,名称为com.csdn.osgi.user.web.registry.ResourceRegistry,代码如下:

package com.csdn.osgi.user.web.registry;
 
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
 
import org.eclipse.gemini.blueprint.context.BundleContextAware;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.http.HttpContext;
import org.osgi.service.http.HttpService;
import org.osgi.service.http.NamespaceException;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
 
public class ResourceRegistry implements ApplicationContextAware,
        BundleContextAware {
 
    Map resMapping;
 
    BundleContext bundleContext;
 
    ApplicationContext applicationContext;
 
    @Override
    public void setBundleContext(BundleContext bundleContext) {
        this.bundleContext = bundleContext;
    }
 
    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        this.applicationContext = applicationContext;
    }
 
    public void setResMapping(Map resMapping) {
        this.resMapping = resMapping;
    }
 
    public void init() {
        ServiceReference serviceReference = bundleContext.getServiceReference(HttpService.class.getName());
        HttpService httpService = (HttpService) bundleContext.getService(serviceReference);
        HttpContext commonContext = httpService.createDefaultHttpContext();
 
        try {
            Set keySet = resMapping.keySet();
            Iterator<String> it = keySet.iterator();
            while(it.hasNext()){
                String key = it.next();
                String value = (String) resMapping.get(key);
                httpService.registerResources(key, value, commonContext);
            }
        } catch (NamespaceException e) {
            e.printStackTrace();
        }
    }
}

我们可以通过Spring来实例化这个类,Bean的配置如下:

    <bean name="resourceRegistry" class="com.csdn.osgi.user.web.registry.ResourceRegistry" init-method="init">
        <property name="resMapping">
            <map>  
                <entry key="/js" value="/WebContent/js"/>  
                <entry key="/css" value="/WebContent/css"/>
                <entry key="/images" value="/WebContent/images"/>
            </map> 
        </property>
    </bean>

这样就可以完成静态资源的注册,这种方式比较灵活,如果有新的资源类型,只需要在map标签中增加一个新的entry标签即可。

接下来是JSP的注册,我们在com.csdn.osgi.user.web这个Bundle中新建一个类,名称为 com.csdn.osgi.user.web.registry.JspRegistry,代码如下:

package com.csdn.osgi.user.web.registry;
 
import java.util.Dictionary;
import java.util.Hashtable;
 
import javax.servlet.ServletException;
 
import org.eclipse.equinox.jsp.jasper.JspServlet;
import org.eclipse.gemini.blueprint.context.BundleContextAware;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.http.HttpContext;
import org.osgi.service.http.HttpService;
import org.osgi.service.http.NamespaceException;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
 
public class JspRegistry implements ApplicationContextAware,
        BundleContextAware {
 
 
    BundleContext bundleContext;
 
    ApplicationContext appContext;
 
    @Override
    public void setBundleContext(BundleContext bundleContext) {
        this.bundleContext = bundleContext;
    }
 
    @Override
    public void setApplicationContext(ApplicationContext appContext)
            throws BeansException {
        this.appContext = appContext;
    }
 
    public void init() {
 
        ServiceReference serviceReference = bundleContext.getServiceReference(HttpService.class.getName());
        HttpService httpService = (HttpService) bundleContext.getService(serviceReference);
        HttpContext commonContext = httpService.createDefaultHttpContext();
 
 
        Dictionary initparams = new Hashtable<String, String>();
 
        JspServlet jspServlet = new JspServlet(bundleContext.getBundle(), "/WebContent/WEB-INF/jsp", "/jsp");
        try {
            httpService.registerServlet("/jsp", jspServlet, initparams, commonContext);
        } catch (ServletException e) {
            e.printStackTrace();
        } catch (NamespaceException e) {
            e.printStackTrace();
        }
    }
}

同样,也是在Spring中实例化JspRegistry,Bean的配置如下:

<bean name="jspRegistry" class="com.csdn.osgi.user.web.registry.JspRegistry" init-method="init">
</bean>

最后就是Servlet资源的注册了,使用Spring MVC框架,我们需要实例化一个DispatcherServlet对象,需要注意的是,DispatcherServlet对象不能通过new关键字创建,应该由Spring框架实例化,在com.csdn.osgi.user.web这个Bundle中新建一个类,名称为com.csdn.osgi.user.web.registry.DispatcherServletRegistry,代码如下:

package com.csdn.osgi.user.web.registry;
 
import java.util.Dictionary;
import java.util.Hashtable;
 
import javax.servlet.ServletException;
 
import org.eclipse.gemini.blueprint.context.BundleContextAware;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.http.HttpContext;
import org.osgi.service.http.HttpService;
import org.osgi.service.http.NamespaceException;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.web.servlet.DispatcherServlet;
 
public class DispatcherServletRegistry implements ApplicationContextAware, BundleContextAware {
 
    String urlPattern;
 
    String servletName;
 
    BundleContext bundleContext;
 
    ApplicationContext applicationContext;
 
    DispatcherServlet dispatcherServlet;
 
    @Override
    public void setBundleContext(BundleContext bundleContext) {
        this.bundleContext = bundleContext;
    }
 
    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        this.applicationContext = applicationContext;
    }
 
    public void setServletName(String servletName) {
        this.servletName = servletName;
    }
 
    public void setUrlPattern(String urlPattern) {
        this.urlPattern = urlPattern;
    }
 
    public void setDispatcherServlet(DispatcherServlet dispatcherServlet) {
        this.dispatcherServlet = dispatcherServlet;
    }
 
    public void init() {
 
        ServiceReference serviceReference = bundleContext.getServiceReference(HttpService.class.getName());
        HttpService httpService = (HttpService) bundleContext.getService(serviceReference);
        HttpContext commonContext = httpService.createDefaultHttpContext();
 
 
        Dictionary<String, String> initparams = new Hashtable<String, String>();
        initparams.put("load-on-startup", "1");
        initparams.put("servlet-name", servletName);
        try {
            httpService.registerServlet(urlPattern, dispatcherServlet, initparams, commonContext);
        }
        catch (ServletException e) {
            e.printStackTrace();
        } catch (NamespaceException e)
        {
            e.printStackTrace();
        }
    }
}

DispatcherServletRegistry 类的实例化也是通过Spring来完成,Bean的配置如下:

    <bean name="dispatcherServlet" class="org.springframework.web.servlet.DispatcherServlet">
        <property name="contextConfigLocation">
            <value>/META-INF/spring/*.xml</value>
        </property>
    </bean>    
 
    <bean name="servletRegistry" class="com.csdn.osgi.user.web.registry.DispatcherServletRegistry" init-method="init">
        <property name="urlPattern" value="/*.do"></property>
        <property name="servletName" value="dispatcherServlet"></property>
        <property name="dispatcherServlet" ref="dispatcherServlet"></property>
    </bean>

接下来在com.csdn.osgi.user.web这个Bundle中,新建META-INF/spring/registry.xml文件,用于配置注册Web资源的Bean,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:osgix="http://www.springframework.org/schema/osgi-compendium"
   xmlns:ctx="http://www.springframework.org/schema/context"
   xmlns:osgi="http://www.eclipse.org/gemini/blueprint/schema/blueprint"
   xsi:schemaLocation="
    http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context 
      http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/osgi-compendium 
      http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd
      http://www.eclipse.org/gemini/blueprint/schema/blueprint 
       http://www.eclipse.org/gemini/blueprint/schema/blueprint/gemini-blueprint.xsd">
 
    <bean name="dispatcherServlet" class="org.springframework.web.servlet.DispatcherServlet">
        <property name="contextConfigLocation">
            <value>/META-INF/spring/*.xml</value>
        </property>
    </bean>    
 
    <bean name="servletRegistry" class="com.csdn.osgi.user.web.registry.DispatcherServletRegistry" init-method="init">
        <property name="urlPattern" value="/*.do"></property>
        <property name="servletName" value="dispatcherServlet"></property>
        <property name="dispatcherServlet" ref="dispatcherServlet"></property>
    </bean>
 
    <bean name="resourceRegistry" class="com.csdn.osgi.user.web.registry.ResourceRegistry" init-method="init">
        <property name="resMapping">
            <map>  
                <entry key="/js" value="/WebContent/js"/>  
                <entry key="/css" value="/WebContent/css"/>
                <entry key="/images" value="/WebContent/images"/>
            </map> 
        </property>
    </bean>
 
    <bean name="jspRegistry" class="com.csdn.osgi.user.web.registry.JspRegistry" init-method="init">
    </bean>
 
</beans>

然后新建一个META-INF/spring/dmconfig.xml文件,用于引用其他Bundle中注册的Bean,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:osgix="http://www.springframework.org/schema/osgi-compendium"
   xmlns:ctx="http://www.springframework.org/schema/context"
   xmlns:osgi="http://www.eclipse.org/gemini/blueprint/schema/blueprint"
   xsi:schemaLocation="
    http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context 
      http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/osgi-compendium 
      http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd
      http://www.eclipse.org/gemini/blueprint/schema/blueprint 
       http://www.eclipse.org/gemini/blueprint/schema/blueprint/gemini-blueprint.xsd">
 
   <osgi:reference  id="sqlMapService" interface="org.apache.ibatis.session.SqlSession" />
 
</beans>

然后还需要新建一个META-INF/spring/controllers.xml文件,实例化Spring MVC中的Controller及ViewResolver等,配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:osgix="http://www.springframework.org/schema/osgi-compendium"
   xmlns:ctx="http://www.springframework.org/schema/context"
   xmlns:osgi="http://www.eclipse.org/gemini/blueprint/schema/blueprint"
   xsi:schemaLocation="
    http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context 
      http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/osgi-compendium 
      http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd
      http://www.eclipse.org/gemini/blueprint/schema/blueprint 
       http://www.eclipse.org/gemini/blueprint/schema/blueprint/gemini-blueprint.xsd">
 
 
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
 
    <bean name="/test.do" class="com.csdn.osgi.web.controllers.TestController">
    </bean>
 
</beans>

上面配置中,我们实例化了一个TestController对象,用于测试Spring MVC框架是否整合成功,TestController代码如下:

package com.csdn.osgi.web.controllers;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
 
public class TestController implements Controller{
 
    @Override
    public ModelAndView handleRequest(HttpServletRequest req,
            HttpServletResponse resp) throws Exception {
 
        System.out.println("Test Controller");
        ModelAndView mv = new ModelAndView();
        mv.setViewName("test");
        return mv;
    }
 
}

接下来还需要增加一个WebContent/WEB-INF/jsp/test.jsp页面,代码如下:

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<title>Spring MVC测试页面</title>
</head>
<body>
<h1>这是Spring MVC测试页面!</h1>
</body>
</html>

到此为止Spring MVC框架已经整合完毕,同时我们实例化了一个用于测试的TestController对象,整个工程结构如下图所示:
这里写图片描述

最后,启动OSGI容器,打开浏览器,访问http://localhost:8080/test.do,如下图所示:
这里写图片描述

可以发现Spring MVC已经成功整合到OSGI应用中,下篇文章,笔者带领大家基于Spring、Mybatis、Spring MVC实现一个简单的登录功能。

注意:不需要启动前面文章演示使用的com.csdn.osgi.test.web这个Bundle,否则JSP注册时指定的URL会有冲突。

本文源码地址:http://download.csdn.net/detail/rongbo_j/9753640

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值