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;
public class OsgiLifecycleListener implements LifecycleListener {
private static Logger log = Logger.getLogger (OsgiLifecycleListener. class
.getName());
private static OsgiLifecycleListener listener = null ;
/** the osgiType default value is 'Equixox'. */
private String osgiType = "Equinox" ;
private OsgiContent osgiContent = null ;
public OsgiLifecycleListener() {
}
public static OsgiLifecycleListener getInstance() {
return listener ;
}
@Override
public void 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();
}
} else if (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());
}
} else if (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());
}
}
}
private void initContent() throws Exception {
listener = this ;
osgiContent = OsgiContentFactory.getInstance ().getOsgiContent( osgiType );
}
public String getOsgiType() {
return osgiType ;
}
public void setOsgiType(String osgiType) {
this . osgiType = osgiType;
}
public OsgiServices getOsgiServices() {
return osgiContent ;
}
public void 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 解压到该目录。最终的目录结构如图:
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. 创建资源工厂类:
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 。添加以下内容:
< 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 服务。
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;
public class OsgiServiceFactory {
private OsgiServices services ;
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() {
return services ;
}
public void setServices(OsgiServices services) {
this . services = services;
}
}
Step4. 为了方便Web 端得调用,我们创建了类OsgiServiceFacade 。
package com.dinsotne.web.osgi;
imp<wbr>ort</wbr> com.dinstone.osgi.OsgiServices;
public class OsgiServiceFacade {
public static <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 调用示例。
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();
e.printStackTrace();
}
return null ;
}
说明:
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 。
运维网声明
1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网 享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com