设为首页 收藏本站
查看: 457|回复: 0

[经验分享] 扩展Tomcat支持OSGi应用服务(2)

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2017-1-28 06:19:48 | 显示全部楼层 |阅读模式
3.实现步骤
  有了以上的分析和设计思路,我们接下来详细描述实现过程及需要注意的地方。
3.1扩展Tomcat,集成OSGi平台
  Step1.创建java项目com.dinstone.tomcat.osgi,创建OsgiLifecycleListener类:
  package com.dinstone.tomcat.osgi;
  
  imp<wbr>ort</wbr> java.util.logging.Logger;
  
  imp<wbr>ort</wbr> org.apache.catalina.Lifecycle;
  imp<wbr>ort</wbr> org.apache.catalina.LifecycleEvent;
  imp<wbr>ort</wbr> org.apache.catalina.LifecycleListener;
  
  imp<wbr>ort</wbr> com.dinstone.osgi.OsgiServices;
  
  publicclass OsgiLifecycleListenerimplements LifecycleListener {
  
   privatestatic Loggerlog = Logger.getLogger(OsgiLifecycleListener.class
  .getName());
  
   privatestatic OsgiLifecycleListenerlistener =null;
  
   /**theosgiTypedefaultvalueis'Equixox'.*/
   private StringosgiType = "Equinox";
  
   private OsgiContentosgiContent =null;
  
   public OsgiLifecycleListener() {
   }
  
   publicstatic OsgiLifecycleListener getInstance() {
   returnlistener;
   }
  
   @Override
   publicvoid lifecycleEvent(LifecycleEvent event) {
   if (Lifecycle.INIT_EVENT.equals(event.getType())) {
  log.info("The osgi content is initialized. Using osgi content:"
  + osgiType);
  try {
  initContent();
  } catch (Exception e) {
  e.printStackTrace();
  }
   } elseif (Lifecycle.START_EVENT.equals(event.getType())) {
  try {
  log.info("Starting osgi service.");
  osgiContent.start();
  } catch (Exception e) {
  e.printStackTrace();
  log.info("Starting the osgi content occured error. "
  + e.getMessage());
  }
   } elseif (Lifecycle.STOP_EVENT.equals(event.getType())) {
  try {
  log.info("Stopping osgi service.");
  osgiContent.stop();
  } catch (Exception e) {
  e.printStackTrace();
  log.info("Stopping the osgi content occured error. "
  + e.getMessage());
  }
   }
   }
  
   privatevoid initContent()throws Exception {
   listener = this;
   osgiContent = OsgiContentFactory.getInstance().getOsgiContent(osgiType);
   }
  
   public String getOsgiType() {
   returnosgiType;
   }
  
   publicvoid setOsgiType(String osgiType) {
   this.osgiType = osgiType;
   }
  
   public OsgiServices getOsgiServices() {
   returnosgiContent;
   }
  
   publicvoid setOsgiContent(OsgiContent osgiContent) {
   this.osgiContent = osgiContent;
   }
  }
  
  Step2.打开${Tomcat_Home}/conf/server.xml.${Tomcat_Home}Tomcat安装目录,下同。
  添加红色部分:
  <Server port="8005" shutdown="SHUTDOWN">
   <!--APR library loader. Documentation at /docs/apr.html -->
   <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
   <!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html -->
   <Listener className="org.apache.catalina.core.JasperListener" />
   <!-- JMX Support for the Tomcat server. Documentation at /docs/non-existent.html -->
   <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
   <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
   <!-- OSGi support for the Tomcat server -->
  <Listener className="com.dinstone.tomcat.osgi.OsgiLifecycleListener" osgiType="felix"/>
  
  
  Step3. 打开${Tomcat_Home}/conf/catalina.properties。修改红色部分:
  #
  #
  # List of comma-separated paths defining the contents of the "common"
  # classloader. Prefixes should be used to define what is the repository type.
  # Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute.
  # If left as blank,the JVM system loader will be used as Catalina's "common"
  # loader.
  # Examples:
  # "foo": Add this folder as a class repository
  # "foo/*.jar": Add all the JARs of the specified folder as class
  # repositories
  # "foo/bar.jar": Add bar.jar as a class repository
  # ${catalina.home}/osgi/equinox/plugins,${catalina.home}/osgi/equinox/plugins/*.jar,
  common.loader=${catalina.home}/lib,${catalina.home}/lib/*.jar,${catalina.home}/osgi/felix/bin/*.jar
  Step4.构建equinox环境。
  新建目录:${Tomcat_Home}/osgi/equinox/plugins/,org.eclipse.osgi_3.3.2.R33x_v20080105.jar放于该目录下。
  Step5.构建felix环境。
  新建目录:${Tomcat_Home}/osgi/felix/,将下载的felix-1.6.0.zip解压到该目录。最终的目录结构如图:
   DSC0000.jpg
  
  
  Step5.创建服务接口:
  package com.dinstone.osgi;
  
  publicinterfaceOsgiServices {
  
   public Object getOSGiService(String serviceName);
  
   public Class<?> getBundleClass(String bundleName, String className)
  throws ClassNotFoundException;
  }
  
3.2 发布OSGi服务到JNDI
  Step6.创建资源工厂类:
  package com.dinstone.tomcat.osgi;
  
  imp<wbr>ort java.util.Enumeration;</wbr>
  imp<wbr>ort java.util.Hashtable;</wbr>
  imp<wbr>ort java.util.logging.Logger;</wbr>
  
  imp<wbr>ort javax.naming.Context;</wbr>
  imp<wbr>ort javax.naming.Name;</wbr>
  imp<wbr>ort javax.naming.RefAddr;</wbr>
  imp<wbr>ort javax.naming.Reference;</wbr>
  imp<wbr>ort javax.naming.spi.ObjectFactory;</wbr>
  
  imp<wbr>ort com.dinstone.osgi.OsgiServices;</wbr>
  
  public class OsgiServicesFactory implements ObjectFactory {
  
   private static Logger log = Logger.getLogger(OsgiServicesFactory.class
   .getName());
  
   private OsgiServices osgiServices;
  
   @Override
   public Object getObjectInstance(Object obj, Name name, Context nameCtx,
   Hashtable<?, ?> environment) throws Exception {
  
   // Customize the bean properties from our attributes
   Reference ref = (Reference) obj;
   Enumeration<RefAddr> addrs = ref.getAll();
   while (addrs.hasMoreElements()) {
   RefAddr addr = addrs.nextElement();
   String attrName = addr.getType();
   String value = (String) addr.getContent();
   log.info("the attribute is (" + attrName + " == " + value);
   }
  
   initContext();
   return osgiServices;
   }
  
   private void initContext() {
   if (osgiServices == null) {
   OsgiLifecycleListener osgilcl = OsgiLifecycleListener.getInstance();
   osgiServices = osgilcl.getOsgiServices();
   }
   }
  
  }
  Step7.打开${Tomcat_Home}/conf/context.xml。添加以下内容:
  <Resourcename="osgi/services"auth="Container"
   type="com.dinstone.osgi.OsgiServices"
   factory="com.dinstone.tomcat.osgi.OsgiServicesFactory"/>
  
  说明:
  1. OsgiLifecycleListener为单例对象,主要功能为根据配置信息osgiType来加载不同的OSGi平台,根据事件类型来启动和停止OSGi平台。
  2. osgiType必须有get/set方法,Tomcat会注入配置信息。
  3.com.dinstone.tomcat.osgi工程编译打包成com.dinstone.tomcat.osgi_1.12.4.jar,将jar放于${Tomcat_Home}/lib目录下。
  4.step7中的配置方式意味着所有的应用都可以引用"osgi/services"资源。另外一种方式可以在web应用的发布文件中配置,具体参见其它相关文档。
3.3 Web应用引用JNDI资源
   Web应用为了引用JNDI资源,需要使用java的反射机制来调用资源服务。首先我们建立web端得JNDI资源应用API
  Step1.创建java项目com.dinsotne.web.osgi,创建JndiOsgiServicesFactory类,负责在JNDI中查找OsgiServices服务。
  package com.dinsotne.web.osgi;
  
  imp<wbr>ort javax.naming.Context;</wbr>
  imp<wbr>ort javax.naming.InitialContext;</wbr>
  imp<wbr>ort javax.naming.NamingException;</wbr>
  
  imp<wbr>ort com.dinstone.osgi.OsgiServices;</wbr>
  
  public class JndiOsgiServicesFactory implements OsgiServicesFactory {
  
   /** JNDI prefix used in a J2EE container */
   private static final String CONTAINER_PREFIX = "java:comp/env/";
  
   private String jndiName;
  
   public String getJndiName() {
   return jndiName;
   }
  
   public void setJndiName(String jndiName) {
   this.jndiName = jndiName;
   }
  
   public OsgiServices getOsgiServices() {
   return (OsgiServices) lookup(getJndiName());
   }
  
   private Object lookup(String jndiName) {
   String convertedName = convertJndiName(jndiName);
   Object jndiObject = null;
   try {
   Context context = new InitialContext();
   jndiObject = context.lookup(convertedName);
   } catch (NamingException e) {
   throw new IllegalServiceException(
   "The JNDI OSGi services name is error.", e);
   } catch (Exception e) {
   throw new IllegalServiceException(
   "The JNDI OSGi services can not be initialed.", e);
   }
  
   return jndiObject;
   }
  
   private String convertJndiName(String jndiName) {
   if (!jndiName.startsWith(CONTAINER_PREFIX)
   && jndiName.indexOf(':') == -1) {
   jndiName = CONTAINER_PREFIX + jndiName;
   }
   return jndiName;
   }
  }
  
  Step2.web应用的web.xml中添加如下内容:
  <resource-env-ref>
   <description>osgi services</description>
   <resource-env-ref-name>osgi/services</resource-env-ref-name>
   <resource-env-ref-type>
  com.dinstone.osgi.OsgiServices
   </resource-env-ref-type>
  </resource-env-ref>
  
3.4 Web应用调用OSGi服务
  
  Step3.有了OsgiServices服务后,我们创建OsgiServiceFactory类,负责获取OSGi平台的动态服务。
  package com.dinsotne.web.osgi;
  
  imp<wbr>ort</wbr> com.dinstone.osgi.OsgiServices;
  
  publicclassOsgiServiceFactory {
  
   private OsgiServicesservices;
  
   public OsgiServiceFactory(OsgiServices services) {
   this.services = services;
   }
  
   public OsgiServiceFactory() {
   }
  
   public <T> T getOsgiService(Class<T> serviceType, String serviceName) {
   OsgiServiceInvocationHandler handler = new OsgiServiceInvocationHandler(
  services, serviceName);
   return JavaProxyObjectFactory.getProxyObject(serviceType, handler);
   }
  
   public OsgiServices getServices() {
   returnservices;
   }
  
   publicvoid setServices(OsgiServices services) {
   this.services = services;
   }
  
  }
  
  Step4.为了方便Web端得调用,我们创建了类OsgiServiceFacade
  package com.dinsotne.web.osgi;
  
  imp<wbr>ort</wbr> com.dinstone.osgi.OsgiServices;
  
  publicclassOsgiServiceFacade {
  
   publicstatic <T> T getOsgiService(String jndiName, Class<T> serviceType,
  String serviceName) {
   JndiOsgiServicesFactory factory = new JndiOsgiServicesFactory();
   factory.setJndiName(jndiName);
  
   OsgiServices services = factory.getOsgiServices();
   OsgiServiceFactory sf = new OsgiServiceFactory(services);
   return sf.getOsgiService(serviceType, serviceName);
   }
  }
  
  Step5.Web调用示例。
  publicstatic String getUserName(String id) {
   try {
  IUserService service = OsgiServiceFacade.getOsgiService(
  "osgi/services", IUserService.class, IUserService.class
  .getName());
  
  return service.getUserName(id);
   } catch (IllegalArgumentException e) {
  e.printStackTrace();
  e.printStackTrace();
   }
  
   returnnull;
   }
  
  说明:
  1.以上的代码应用了java代理和反射技术,其它的代码参见源码。
  2. OsgiServiceFactory在获取OSGi平台服务时,使用了java代理。读者可能会疑问,为什么Datasource资源服务的引用就不必使用反射,而我们的OSGi服务就需要使用反射啊?这个都是java的类加载机制惹得祸。对于Datasource资源,它的类型是javax.sql.DataSource,为系统类,且运行在Tomcat中的web应用都使用Tomcat容器的类加载器加载这个类,故web应用中的javax.sql.DataSourceTomcat加载的是同一类。但是,对于OSGi服务类,该类由OSGi容器的类加载器加载,而我们的web应用是不能使用该类加载器加载该类的,故只能通过反射来调用服务了。
  3.将项目工程com.dinsotne.web.osgi导出打包:com.dinsotne.web.osgi_1.12.0.jar

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-334231-1-1.html 上篇帖子: Tomcat启动时classloader加载顺序 下篇帖子: tomcat内存溢出 网上拷贝的
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表