扩展Tomcat支持OSGi应用服务

转自 扩展Tomcat支持OSGi应用服务(1)

扩展Tomcat支持OSGi应用服务(2)

扩展Tomcat支持OSGi应用服务(3)

1.摘要

OSGi的动态服务,包版本管理,安全设施,热插拔等特性吸引了越来越多开发人员的关注,由于OSGi不同于以往的设计理念,在企业级应用中一直没有很大的发挥。不过通过大家的不断努力,OSGi已在企业级服务平台中有所集成。本文站在另一个角度尝试Tomcat服务器下的OSGi服务集成,为web应用提供动态服务,为企业级开发提供参考。

本文需要读者了解以下内容:

l         Java编程及一些简单的设计模式

l         OSGi的相关知识

l         Tomcat服务器的相关知识

2.集成思路

我们知道OSGi R4.0平台中发布的服务为java对象服务,只能在其内部使用,而不能够为外部环境所使用的主要原因是类加载问题。要想为外部环境引用OSGi平台中的服务,我们需要使用java的反射机制来达到目的。

鉴于OSGi平台服务的各种新的让人向往的优势,我们当然希望将其应用于开发和生产环境中。那么如何将OSGi平台服务集成到Tomcat中,并被web应用所使用呢?首先我们需要了解一些基本知识。

2.1 J2EE基础知识

我们知道,J2EE平台的JNDI规范,规定了服务器如何提供JNDI服务,同时也规定了web应用如何使用JNDI服务。举个例子,我们经常在服务器中配置数据库连接池,然后在web应用中使用(不明白的可以参考《Tomcat中数据源的配置及原理》)DataSource对象,而这个DataSource对象就是通过JNDI发布给web应用的。

当然,JNDI不仅仅能够发布DataSource服务对象,它还可以发布其它java服务对象。基于这个原理,我们很自然地会想,能否将OSGi平台的服务对象发布到JNDI呢?答案是肯定的。把OSGi平台的服务对象发布到JNDI的方式有很多种,这里介绍通过扩展Tomcat服务器来集成OSGi平台来实现以上的想法。

2.2 扩展Tomcat,支持OSGi平台

这里我们选择支持以下OSGi平台和Tomcat服务器:

1. Eclipse的OSGi平台实现equinox,版本equinox3.3.2。

2. Apache的OSGi平台实现felix,版本felix1.6.0。

3.Apache的Web应用服务器Tomcat,版本tomcat6.0.18(6.0以上目录结构一致)。

我们选择扩展Tomcat服务器的目的是,希望保持OSGi环境对Tomcat的透明,即OSGi平台的集成不会影响Tomcat服务器的功能。我们需要在Tomcat启动时启动OSGi平台,在Tomcat停止时停止OSGi平台。所以我们将服务器的启动作为扩展点,具体来说,就是在Tomcat的server组件启动时,添加一个关于OSGi平台生命周期的监听器(OsgiLifecycleListener),OsgiLifecycleListener必须实现LifecycleListener接口,这样就可以接受到server组件的事件通知了,根据不同事件,就可以在Tomcat的server组件启动时,启动OSGi平台,在server组件停止时,停止OSGi平台了。

2.3 Tomcat中发布JNDI服务

集成了OSGi平台后,我们希望将OSGi平台中服务发布到JNDI中,而OSGi平台中的服务对象各不相同,且是动态的,如果直接将这些服务发布给JNDI,web的使用将是痛苦的,也将不能获得OSGi动态服务的特性。所以,我们需要抽象一个共同的服务接口(OsgiServices),将该接口发布到JNDI中,而当web应用使用OSGi服务时,通过该接口来查找相应的服务。

为了在Tomcat中发布JNDI资源(OsgiServices),我们创建自己的资源工厂OsgiServicesFactory,OsgiServicesFactory实现了对象工厂(ObjectFactory)。

2.4 集成模型

到目前为止,我们的集成模型可以用图表示如下:

3.实现步骤

有了以上的分析和设计思路,我们接下来详细描述实现过程及需要注意的地方。

3.1扩展Tomcat,集成OSGi平台

Step1.创建java项目com.dinstone.tomcat.osgi,创建OsgiLifecycleListener类:

 1 package com.dinstone.tomcat.osgi;
 2
 3 import java.util.logging.Logger;
 4
 5 import org.apache.catalina.Lifecycle;
 6 import org.apache.catalina.LifecycleEvent;
 7 import org.apache.catalina.LifecycleListener;
 8
 9 import com.dinstone.osgi.OsgiServices;
10
11 public class OsgiLifecycleListener implements LifecycleListener
12 {
13     private static Logger log = Logger.getLogger(OsgiLifecycleListener.class.getName());
14     private static OsgiLifecycleListener listener = null;
15
16     /** the osgiType default value is ‘Equixox‘. */
17     private String osgiType = "Equinox";
18     private OsgiContent osgiContent = null;
19
20     public OsgiLifecycleListener()
21     {
22
23     }
24
25     public static OsgiLifecycleListener getInstance()
26     {
27        return listener;
28     }
29
30     @Override
31     public void lifecycleEvent(LifecycleEvent event)
32     {
33        if (Lifecycle.INIT_EVENT.equals(event.getType()))
34        {
35            log.info("The osgi content is initialized. Using osgi content:" + osgiType);
36            try
37            {
38               initContent();
39            }
40            catch (Exception e)
41            {
42               e.printStackTrace();
43            }
44        }
45        else if (Lifecycle.START_EVENT.equals(event.getType()))
46        {
47            try
48            {
49               log.info("Starting osgi service.");
50               osgiContent.start();
51            }
52            catch (Exception e)
53            {
54               e.printStackTrace();
55               log.info("Starting the osgi content occured error. " + e.getMessage());
56            }
57        }
58        else if (Lifecycle.STOP_EVENT.equals(event.getType()))
59        {
60            try
61            {
62               log.info("Stopping osgi service.");
63               osgiContent.stop();
64            }
65            catch (Exception e)
66            {
67               e.printStackTrace();
68               log.info("Stopping the osgi content occured error. " + e.getMessage());
69            }
70        }
71     }
72
73     private void initContent() throws Exception
74     {
75        listener = this;
76        osgiContent = OsgiContentFactory.getInstance().getOsgiContent(osgiType);
77     }
78
79     public String getOsgiType()
80     {
81        return osgiType;
82     }
83
84     public void setOsgiType(String osgiType)
85     {
86        this.osgiType = osgiType;
87     }
88
89     public OsgiServices getOsgiServices()
90     {
91        return osgiContent;
92     }
93
94     public void setOsgiContent(OsgiContent osgiContent)
95     {
96        this.osgiContent = osgiContent;
97     }
98 }

Step2.打开${Tomcat_Home}/conf/server.xml.。${Tomcat_Home}为Tomcat安装目录,下同。

添加红色部分:

 1 <Server port="8005" shutdown="SHUTDOWN">
 2
 3   <!--APR library loader. Documentation at /docs/apr.html -->
 4   <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
 5
 6   <!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html -->
 7   <Listener className="org.apache.catalina.core.JasperListener" />
 8
 9   <!-- JMX Support for the Tomcat server. Documentation at /docs/non-existent.html -->
10   <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
11   <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
12
13   <!-- OSGi support for the Tomcat server -->
14   <Listener className="com.dinstone.tomcat.osgi.OsgiLifecycleListener" osgiType="felix"/>

Step3. 打开${Tomcat_Home}/conf/catalina.properties。修改红色部分:

 1 #
 2
 3 #
 4
 5 # List of comma-separated paths defining the contents of the "common"
 6
 7 # classloader. Prefixes should be used to define what is the repository type.
 8
 9 # Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute.
10
11 # If left as blank,the JVM system loader will be used as Catalina‘s "common"
12
13 # loader.
14
15 # Examples:
16
17 #     "foo": Add this folder as a class repository
18
19 #     "foo/*.jar": Add all the JARs of the specified folder as class
20
21 #                  repositories
22
23 #     "foo/bar.jar": Add bar.jar as a class repository
24
25 # ${catalina.home}/osgi/equinox/plugins,${catalina.home}/osgi/equinox/plugins/*.jar,
26
27 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解压到该目录。最终的目录结构如图:

Step5.创建服务接口:

package com.dinstone.osgi;

public interface OsgiServices
{
    public Object getOSGiService(String serviceName);
    public Class<?> getBundleClass(String bundleName, String className)throws ClassNotFoundException;
}

3.2 发布OSGi服务到JNDI

Step6.创建资源工厂类:

 1 package com.dinstone.tomcat.osgi;
 2
 3 import java.util.Enumeration;
 4 import java.util.Hashtable;
 5 import java.util.logging.Logger;
 6
 7 import javax.naming.Context;
 8 import javax.naming.Name;
 9 import javax.naming.RefAddr;
10 import javax.naming.Reference;
11 import javax.naming.spi.ObjectFactory;
12
13 import com.dinstone.osgi.OsgiServices;
14
15 public class OsgiServicesFactory implements ObjectFactory
16 {
17     private static Logger log = Logger.getLogger(OsgiServicesFactory.class.getName());
18     private OsgiServices osgiServices;
19
20     @Override
21     public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception
22     {
23         // Customize the bean properties from our attributes
24         Reference ref = (Reference) obj;
25
26         Enumeration<RefAddr> addrs = ref.getAll();
27
28         while (addrs.hasMoreElements())
29         {
30             RefAddr addr = addrs.nextElement();
31
32             String attrName = addr.getType();
33
34             String value = (String) addr.getContent();
35
36             log.info("the attribute is (" + attrName + " == " + value);
37         }
38
39         initContext();
40
41         return osgiServices;
42     }
43
44     private void initContext()
45     {
46         if (osgiServices == null)
47         {
48             OsgiLifecycleListener osgilcl = OsgiLifecycleListener.getInstance();
49             osgiServices = osgilcl.getOsgiServices();
50         }
51     }
52 }

Step7.打开${Tomcat_Home}/conf/context.xml。添加以下内容:

<Resource name="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服务。

 1 package com.dinsotne.web.osgi;
 2
 3 import javax.naming.Context;
 4
 5 import javax.naming.InitialContext;
 6 import javax.naming.NamingException;
 7
 8 import com.dinstone.osgi.OsgiServices;
 9
10 public class JndiOsgiServicesFactory implements OsgiServicesFactory
11 {
12     /** JNDI prefix used in a J2EE container */
13     private static final String CONTAINER_PREFIX = "java:comp/env/";
14     private String jndiName;
15
16     public String getJndiName()
17     {
18         return jndiName;
19     }
20
21     public void setJndiName(String jndiName)
22     {
23         this.jndiName = jndiName;
24     }
25
26     public OsgiServices getOsgiServices()
27     {
28         return (OsgiServices) lookup(getJndiName());
29     }
30
31     private Object lookup(String jndiName)
32     {
33         String convertedName = convertJndiName(jndiName);
34         Object jndiObject = null;
35
36         try
37         {
38             Context context = new InitialContext();
39             jndiObject = context.lookup(convertedName);
40         }
41         catch (NamingException e)
42         {
43             throw new IllegalServiceException("The JNDI OSGi services name is error.", e);
44         }
45         catch (Exception e)
46         {
47             throw new IllegalServiceException("The JNDI OSGi services can not be initialed.", e);
48         }
49         return jndiObject;
50     }
51
52     private String convertJndiName(String jndiName)
53     {
54         if (!jndiName.startsWith(CONTAINER_PREFIX) && jndiName.indexOf(‘:‘) == -1)
55         {
56             jndiName = CONTAINER_PREFIX + jndiName;
57         }
58         return jndiName;
59     }
60 }

Step2.在web应用的web.xml中添加如下内容:

1 <resource-env-ref>
2        <description>osgi services</description>
3        <resource-env-ref-name>osgi/services</resource-env-ref-name>
4        <resource-env-ref-type>
5            com.dinstone.osgi.OsgiServices
6        </resource-env-ref-type>
7 </resource-env-ref>

3.4 Web应用调用OSGi服务

Step3.有了OsgiServices服务后,我们创建OsgiServiceFactory类,负责获取OSGi平台的动态服务。

 1 package com.dinsotne.web.osgi;
 2
 3 import com.dinstone.osgi.OsgiServices;
 4
 5 public class OsgiServiceFactory
 6 {
 7     private OsgiServices services;
 8
 9     public OsgiServiceFactory(OsgiServices services)
10     {
11         this.services = services;
12     }
13
14     public OsgiServiceFactory()
15     {
16     }
17
18     public <T> T getOsgiService(Class<T> serviceType, String serviceName)
19     {
20         OsgiServiceInvocationHandler handler = new OsgiServiceInvocationHandler(services, serviceName);
21         return JavaProxyObjectFactory.getProxyObject(serviceType, handler);
22     }
23
24     public OsgiServices getServices()
25     {
26         return services;
27     }
28
29     public void setServices(OsgiServices services)
30     {
31         this.services = services;
32     }
33 }

Step4.为了方便Web端得调用,我们创建了类OsgiServiceFacade。

 1 package com.dinsotne.web.osgi;
 2
 3 import com.dinstone.osgi.OsgiServices;
 4
 5 public class OsgiServiceFacade
 6 {
 7     public static <T> T getOsgiService(String jndiName, Class<T> serviceType, String serviceName)
 8     {
 9         JndiOsgiServicesFactory factory = new JndiOsgiServicesFactory();
10         factory.setJndiName(jndiName);
11
12         OsgiServices services = factory.getOsgiServices();
13         OsgiServiceFactory sf = new OsgiServiceFactory(services);
14
15         return sf.getOsgiService(serviceType, serviceName);
16     }
17 }

Step5.Web调用示例。

 1 public static String getUserName(String id)
 2 {
 3     try
 4     {
 5         IUserService service = OsgiServiceFacade.getOsgiService("osgi/services",                                                                    IUserService.class,                                                                    IUserService.class.getName());
 6         return service.getUserName(id);
 7     }
 8     catch (IllegalArgumentException e)
 9     {
10         e.printStackTrace();
11     }
12    return null;
13 }

说明:

1.以上的代码应用了java代理和反射技术,其它的代码参见源码。

2. OsgiServiceFactory在获取OSGi平台服务时,使用了java代理。读者可能会疑问,为什么Datasource资源服务的引用就不必使用反射,而我们的OSGi服务就需要使用反射啊?这个都是java的类加载机制惹得祸。对于Datasource资源,它的类型是javax.sql.DataSource,为系统类,且运行在Tomcat中的web应用都使用Tomcat容器的类加载器加载这个类,故web应用中的javax.sql.DataSource跟Tomcat加载的是同一类。但是,对于OSGi服务类,该类由OSGi容器的类加载器加载,而我们的web应用是不能使用该类加载器加载该类的,故只能通过反射来调用服务了。

3.将项目工程com.dinsotne.web.osgi导出打包:com.dinsotne.web.osgi_1.12.0.jar。

4.测试

通过以上的实现,我们将OSGi平台集成到了Tomcat中,并且明确了web应用如何使用OSGi服务。下面就来创建一个测试的例子,看看OSGi编程模式对web应用开发的影响,同时也测试一下集成的效果。

4.1 创建并发布OSGi服务

Step1.创建插件工程com.dinstone.demo.user,选择standard OSGi framework。创建接口:

1 package com.dinstone.demo.user;
2
3 public interface IUserService
4 {
5     public String getUserName(String id);
6 }

Step2.创建插件工程com.dinstone.demo.user.db,创建类UserServiceImpl实现IUserService接口。

package com.dinstone.demo.user.db;

import java.util.logging.Logger;

import com.dinstone.demo.user.IUserService;

public class UserServiceImpl implements IUserService
{
     private static Logger log = Logger.getLogger(UserServiceImpl.class .getName());

    @Override
    public String getUserName(String id)
    {
         log.info("get user name from db");
         return "db" + id;
     }
}

Step3.向OSGi平台发布IUserService服务。创建Activator注册服务对象。

package com.dinstone.demo.user.db;

import java.util.Properties;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;

import com.dinstone.demo.user.IUserService;

public class Activator implements BundleActivator
{
    private ServiceRegistration serviceReg;

    /*
     * (non-Javadoc)
     *
     * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
     */
    public void start(BundleContext context) throws Exception
    {
        Properties p = new Properties();
        serviceReg = context.registerService(IUserService.class.getName(),
                                             new UserServiceImpl(), p);
    }

    /*
     * (non-Javadoc)
     *
     * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
     */
    public void stop(BundleContext context) throws Exception
    {
         serviceReg.unregister();
    }
}

Step4. 创建插件工程com.dinstone.demo.user.file,创建类UserServiceImpl实现IUserService接口。

package com.dinstone.demo.user.file;

import java.util.logging.Logger;

import com.dinstone.demo.user.IUserService;

public class UserServiceImpl implements IUserService
{
    private static Logger log = Logger.getLogger(UserServiceImpl.class.getName());

    @Override
    public String getUserName(String id)
    {
        log.info("get user name from file");
        return "file" + id;
    }
}

Step5.向OSGi平台发布IUserService服务。创建Activator注册服务对象。

package com.dinstone.demo.user.file;

import java.util.Properties;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;

import com.dinstone.demo.user.IUserService;

public class Activator implements BundleActivator
{
    private ServiceRegistration serviceReg;

    /*
     * (non-Javadoc)
     *
     * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
     */
    public void start(BundleContext context) throws Exception
    {
        Properties p = new Properties();
        serviceReg = context.registerService(IUserService.class.getName(), new UserServiceImpl(), p);
    }

    /*
     * (non-Javadoc)
     *
     * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
     */
    public void stop(BundleContext context) throws Exception
    {
        serviceReg.unregister();
    }
}

4.2 创建Web应用

Step1.创建动态web工程webDemo,并新建类:UserServiceFacade。

package com.dinsotne.web.demo;

import com.dinsotne.web.osgi.OsgiServiceFacade;

import com.dinstone.demo.user.IUserService;

public class UserServiceFacade
{
    public static 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();
        }
        return null;
    }
}

Step2.创建index.jsp页面。

<%@ page language="java" contentType="text/html; charset=utf-8"  pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@page import="com.dinsotne.web.demo.UserServiceFacade"%>

<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <title>Insert title here</title>
</head>
<body>
  User Name is
  <%=UserServiceFacade.getUserName("001") %>
</body>
</html>

Step3.修改web.xml文件,添加红色部分。

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    id="WebApp_ID" version="2.5">

    <display-name>webDemo</display-name>

    <welcome-file-list>
       <welcome-file>index.html</welcome-file>
       <welcome-file>index.htm</welcome-file>
       <welcome-file>index.jsp</welcome-file>
       <welcome-file>default.html</welcome-file>
       <welcome-file>default.htm</welcome-file>
       <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>

    <resource-env-ref>
       <description>osgi service</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>
</web-app>

说明:

1. 由于UserServiceFacade依赖IUserService类,故需要将com.dinstone.demo.user_1.0.0.jar(参见4.3)添加到lib中。

2. 由于UserServiceFacade依赖OsgiServiceFacade类,故将com.dinsotne.web.osgi_1.12.0.jar(参见3.4说明)添加到lib中。

4.3 发布OSGi Bundle

Step1.依次从插件工程导出插件包:com.dinstone.demo.user_1.0.0.jar,com.dinstone.demo.user.file_1.0.0.jar,com.dinstone.demo.user.db_1.0.0.jar。

Step2.将以上的插件放于${Tomcat_Home}\osgi\felix\bundle目录下。

4.4 发布web应用

Step1.导出web应用webDemo.war。

Step2.将webDemo.war放于${Tomcat_Home}\webapps目录下。

4.5 启动Tomcat并安装OSGi Bundle

Step1.在命令行下启动Tomcat。E:\Cluster\apache-tomcat-6.0.18为我的${Tomcat_Home}。

E:\Cluster\apache-tomcat-6.0.18>bin\startup.bat
Using CATALINA_BASE:   E:\Cluster\apache-tomcat-6.0.18
Using CATALINA_HOME:   E:\Cluster\apache-tomcat-6.0.18
Using CATALINA_TMPDIR: E:\Cluster\apache-tomcat-6.0.18\temp
Using JRE_HOME:        C:\Program Files\Java\jdk1.6.0_10
2009-8-12 13:21:39 com.dinstone.tomcat.osgi.OsgiLifecycleListener lifecycleEvent
信息: The osgi content is initialized. Using osgi content:felix
2009-8-12 13:21:39 org.apache.coyote.http11.Http11Protocol init
信息: Initializing Coyote HTTP/1.1 on http-8080
2009-8-12 13:21:40 org.apache.coyote.http11.Http11Protocol init
信息: Initializing Coyote HTTP/1.1 on http-8443
2009-8-12 13:21:40 org.apache.catalina.startup.Catalina load
信息: Initialization processed in 1748 ms
2009-8-12 13:21:41 com.dinstone.tomcat.osgi.OsgiLifecycleListener lifecycleEvent
信息: Starting osgi service.
2009-8-12 13:21:41 com.dinstone.tomcat.osgi.felix.FelixContent start
信息: *********************************
2009-8-12 13:21:41 com.dinstone.tomcat.osgi.felix.FelixContent start
信息: catalina home is E:\Cluster\apache-tomcat-6.0.18
2009-8-12 13:21:41 com.dinstone.tomcat.osgi.felix.FelixContent start
信息: osgi home is E:\Cluster\apache-tomcat-6.0.18\osgi\felix
2009-8-12 13:21:41 com.dinstone.tomcat.osgi.felix.FelixContent start
信息: ******user.dir is E:\Cluster\apache-tomcat-6.0.18

Welcome to Felix.
=================
-> 2009-8-12 13:21:42 org.apache.catalina.core.StandardService start
信息: Starting service Catalina
2009-8-12 13:21:42 org.apache.catalina.core.StandardEngine start
信息: Starting Servlet Engine: Apache Tomcat/6.0.18
2009-8-12 13:21:42 org.apache.catalina.loader.WebappLoader start
信息: Dual registration of jndi stream handler: factory already defined
2009-8-12 13:21:44 org.apache.coyote.http11.Http11Protocol start
信息: Starting Coyote HTTP/1.1 on http-8080
2009-8-12 13:21:44 org.apache.coyote.http11.Http11Protocol start
信息: Starting Coyote HTTP/1.1 on http-8443
2009-8-12 13:21:44 org.apache.jk.common.ChannelSocket init
信息: JK: ajp13 listening on /0.0.0.0:8009
2009-8-12 13:21:44 org.apache.jk.server.JkMain start
信息: Jk running ID=0 time=0/47  config=null
2009-8-12 13:21:44 org.apache.catalina.startup.Catalina start
信息: Server startup in 3882 ms
-> ps
START LEVEL 1
   ID   State         Level  Name
[   0] [Active     ] [    0] System Bundle (1.6.0)
[  25] [Active     ] [    1] Apache Felix Shell Service (1.2.0)
[  26] [Active     ] [    1] Apache Felix Shell TUI (1.2.0)
[  27] [Active     ] [    1] Apache Felix Bundle Repository (1.4.0)
->

Step3.访问web应用,http://localhost:8080/webDemo/。由于没有启动OSGi服务,故出现500异常页面,错误原因是没有找到服务。

root cause

com.dinsotne.web.osgi.IllegalServiceException: Cann‘t find out osgi service:com.dinstone.demo.user.IUserService
        com.dinsotne.web.osgi.OsgiServiceInvocationHandler.invoke(OsgiServiceInvocationHandler.java:30)
        $Proxy0.getUserName(Unknown Source)
        com.dinsotne.web.demo.UserServiceFacade.getUserName(UserServiceFacade.java:14)
        org.apache.jsp.index_jsp._jspService(index_jsp.java:64)
        org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:374)
        org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
        org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:717)

Step4.启动User DB Implement Plug-in服务,激活User模块的DB实现。

->ps
START LEVEL 1
   ID   State         Level  Name
[   0] [Active     ] [    0] System Bundle (1.6.0)
[  25] [Active     ] [    1] Apache Felix Shell Service (1.2.0)
[  26] [Active     ] [    1] Apache Felix Shell TUI (1.2.0)
[  27] [Active     ] [    1] Apache Felix Bundle Repository (1.4.0)
[  39] [Installed  ] [    1] User Model Interface Plug-in (1.0.0)
[  40] [Installed  ] [    1] User DB Implement Plug-in (1.0.0)
[  41] [Installed  ] [    1] User File Implement Plug-in (1.0.0)
-> start 40

-> ps -s
START LEVEL 1
   ID   State         Level  Symbolic name
[   0] [Active     ] [    0] org.apache.felix.framework (1.6.0)
[  25] [Active     ] [    1] org.apache.felix.shell (1.2.0)
[  26] [Active     ] [    1] org.apache.felix.shell.tui (1.2.0)
[  27] [Active     ] [    1] org.apache.felix.bundlerepository (1.4.0)
[  39] [Resolved   ] [    1] com.dinstone.demo.user (1.0.0)
[  40] [Active     ] [    1] com.dinstone.demo.user.db (1.0.0)
[  41] [Installed  ] [    1] com.dinstone.demo.user.file (1.0.0)
->

访问http://localhost:8080/webDemo/。页面显示:

Step5. 启动User File Implement Plug-in服务,激活User模块的File实现。

-> ps
START LEVEL 1
   ID   State         Level  Name
[   0] [Active     ] [    0] System Bundle (1.6.0)
[  25] [Active     ] [    1] Apache Felix Shell Service (1.2.0[  26] [Active     ] [    1] Apache Felix Shell TUI (1.2.0)
[  27] [Active     ] [    1] Apache Felix Bundle Repository (1.4.0)
[  39] [Resolved   ] [    1] User Model Interface Plug-in (1.0.0)
[  40] [Active     ] [    1] User DB Implement Plug-in (1.0.0)
[  41] [Installed  ] [    1] User File Implement Plug-in (1.0.0)
-> start 41

-> ps
START LEVEL 1
   ID   State         Level  Name
[   0] [Active     ] [    0] System Bundle (1.6.0)
[  25] [Active     ] [    1] Apache Felix Shell Service (1.2.0)
[  26] [Active     ] [    1] Apache Felix Shell TUI (1.2.0)
[  27] [Active     ] [    1] Apache Felix Bundle Repository (1.4.0)
[  39] [Resolved   ] [    1] User Model Interface Plug-in (1.0.0)
[  40] [Active     ] [    1] User DB Implement Plug-in (1.0.0)
[  41] [Active     ] [    1] User File Implement Plug-in (1.0.0)
->

访问http://localhost:8080/webDemo/。页面显示:

Step6.现在停止User DB Implement Plug-in服务。

-> ps
START LEVEL 1
   ID   State         Level  Name
[   0] [Active     ] [    0] System Bundle (1.6.0)
[  25] [Active     ] [    1] Apache Felix Shell Service (1.2.0)
[  26] [Active     ] [    1] Apache Felix Shell TUI (1.2.0)
[  27] [Active     ] [    1] Apache Felix Bundle Repository (1.4.0)
[  39] [Resolved   ] [    1] User Model Interface Plug-in (1.0.0)
[  40] [Active     ] [    1] User DB Implement Plug-in (1.0.0)
[  41] [Active     ] [    1] User File Implement Plug-in (1.0.0)
-> stop 40

-> ps
START LEVEL 1
   ID   State         Level  Name
[   0] [Active     ] [    0] System Bundle (1.6.0)
[  25] [Active     ] [    1] Apache Felix Shell Service (1.2.0)
[  26] [Active     ] [    1] Apache Felix Shell TUI (1.2.0)
[  27] [Active     ] [    1] Apache Felix Bundle Repository (1.4.0)
[  39] [Resolved   ] [    1] User Model Interface Plug-in (1.0.0)
[  40] [Resolved   ] [    1] User DB Implement Plug-in (1.0.0)
[  41] [Active     ] [    1] User File Implement Plug-in (1.0.0)
->

访问http://localhost:8080/webDemo/。页面显示:

4.6 停止Tomcat服务器

5结论

通过以上的测试,我们发现以上的实现基本符合最初的设想:

l         OSGi的集成对Tomcat几乎是透明的。

l         OSGi的所有优点。

l         Web表现和业务逻辑的完全分离。

l         基于模块化服务的编程模型。

同时,我们也发现了一些问题:

l         Web层没有支持模块化、可热插拔的编程模型。

l         OSGi层的服务日志跟web层的日志分离增加了维护的难度。

l         该集成方式没有经严格测试,虽然已经有产品应用了。

时间: 2024-10-05 10:43:24

扩展Tomcat支持OSGi应用服务的相关文章

让Tomcat支持引用软连接资源

默认情况下想通过在Tomcat下建立软连接来使tomcat上的应用引用该资源是不行的.会出现类似错误: java.lang.IllegalStateException: ContainerBase.addChild: start: LifecycleException: start: : java.io.IOException: Failed to access resource XXX 这时候需要打开支持引用软连接资源的开关:allowLinking="true", 比如在conte

让Tomcat支持中文文件名

--参考链接:http://blog.chinaunix.net/uid-26284395-id-3044132.html 解决问题的核心在于修改Tomcat的配置,在Server.xml文件中添加一个名为URIEncoding的属性,它用于对HTTP请求中的get方法传过来的URL进行编码.Tomcat内置的对于get协议中的URL编码是ISO-8859-1,这个字符集不能直接支持中文等双字节的信息,而中文文件的下载链接恰恰是通过get协议进行的. 打开$tomcat安装目录$/config/

tomcat支持多少并发

作者:孟男男 来源:https://zhidao.baidu.com/question/1445941399668603020.html Tomcat的最大并发数是可以配置的,实际运用中,最大并发数与硬件性能和CPU数量都有很大关系的. 更好的硬件,更多的处理器都会使Tomcat支持更多的并发. Tomcat默认的HTTP实现是采用阻塞式的Socket通信,每个请求都需要创建一个线程处理,当一个进程 有500个线程在跑的话,那性能已经是很低很低了. Tomcat 默认配置的最大请求数是150,也

Tomcat 支持的Java 版本和兼容性总结

最新最全的Tomcat 支持的Java版本对照,即兼容性一览表: Servlet Spec JSP Spec EL Spec WebSocket Spec Apache Tomcat version Actual release revision Support Java Versions 4.0 TBD (2.4?) TBD (3.1?) TBD (1.2?) 9.0.x None 8 and later 3.1 2.3 3.0 1.1 8.0.x 8.0.15 7 and later 3.0

使用HttpClient发送HTTPS请求以及配置Tomcat支持SSL

这里使用的是HttpComponents-Client-4.1.2 1 package com.jadyer.util; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.FileNotFoundException; 6 import java.io.IOException; 7 import java.security.KeyManagementException; 8 import java

tomcat支持中文文件名下载

Tomcat是Java开发者使用得较多的一个Web服务器,因为它占用资源小,运行速度快等特点,深受Java Web程序员的喜爱.不过,在使用中,由于Java中的中文问题的存在,如果不经过配置,在WEB程序中,不能直接支持具有中文文件名的文件的下载,这为Java Web程序的开发带来一定的不便.本文拟介绍一种手段,解决这个问题. 解决问题的核心在于修改Tomcat的配置,在Server.xml文件中添加一个名为URIEncoding的属性,它用于对HTTP请求中的get方法传过来的URL进行编码.

Servlet与JSP版本历史以及Tomcat支持的版本

查询这个的关键字:Java EE的版本历史. JavaServer Pages (JSP) Java Servlet 参考: https://en.wikipedia.org/wiki/Java_EE_version_history https://zh.wikipedia.org/wiki/Java_Servlet 从维基百科中可以快速的查看Java EE的版本,然后再从版本对Servlet与JSP的支持上可以分析出两者的关系,就Java EE 7来说: 以下为tomcat支持的版本: 参考:

远程调试部署在Tomcat中的应用服务(2种配置方式)

远程调试部署在Tomcat中的应用服务(tomcat 远程debug 配置文件) 方法一(编辑catalina.bat) 1. D:\iVMS_Platform\bin\apps\ivms6-liteTomcat\bin   编辑catalina.bat文件 set "JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG%" 替换成这样: set "JAVA_OPTS=%JAVA_OPTS% %LOGGING_CONFIG%  -Xdebug -Xrun

Tomcat 支持多少并发量

Tomcat的最大并发数是可以配置的,实际运用中,最大并发数与硬件性能和CPU数量都有很大关系的.更好的硬件,更多的处理器都会使Tomcat支持更多的并发. Tomcat默认的HTTP实现是采用阻塞式的Socket通信,每个请求都需要创建一个线程处理,当一个进程有500个线程在跑的话,那性能已经是很低很低了.Tomcat 默认配置的最大请求数是150,也就是说同时支持150个并发.具体能承载多少并发,需要看硬件的配置,CPU 越多性能越高,分配给JVM的内存越多性能也就越高,但也会加重GC的负担