osgi加载模式引发的错误

来源:互联网 发布:ubuntu下安装win10 编辑:程序博客网 时间:2024/06/04 04:45


今天,一个osgi项目运行出现了ClassCastException异常,具体情况下面介绍一下:


1、项目

一个运行在servicemix上的OSGi项目,使用activemq进行异步通信,接收方运行在服务器上,主要代码如下:

/** * JMS消息监听器 */public class Test implements MessageListener {       //监听的队列名     private final String queueName = "zhs/test";        //连接工厂,通过服务注入    private ConnectionFactory connectionFactory;    private Session session;    private Connection connection;           //开始监听队列    public void start() {        try {                    connection = connectionFactory.createConnection();                    connection.start();                      session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);                                       MessageConsumer consumer = session.createConsumer(session.createQueue(queueName));               //当监听到信息,调用onMessage方法            consumer.setMessageListener(this);        } catch (Exception e) {           //...        }    }        @Override    public void onMessage(Message message) {             try {            String data = null;            //转换message类型                       ActiveMQBytesMessage bytesMessage = (ActiveMQBytesMessage) message;            data = new String(bytesMessage.getContent().getData());                              LOGGER.info("收到信息:" + data);                      session.commit();        } catch (Exception e) {            LOGGER.error("接收信息时发生异常", e);        }    }    public void setConnectionFactory(ConnectionFactory connectionFactory) {        this.connectionFactory = connectionFactory;    }  }

上面的代码功能很简单,直接简单的将受到的信息记录到日志上


这个bundle启动正常,但是在接受信息时出现ClassCastException异常:message明明是ActiveMQbytesMessage类型,但为什么无法转换?


首先应该想到的是类加载器的不同引起的问题,我们把这两个类的类加载器打印出来看一下:


在接受到信息时添加记录:


        ClassLoader cl1 = message.getClass().getClassLoader();        LOGGER.warn("接受到的信息类加载器:"+cl1);                ClassLoader cl2 = ActiveMQBytesMessage.class.getClassLoader();        LOGGER.warn("ActiveMQBytesMessage的类加载路径:"+cl2);

结果出来了:


cl1显示:org.apache.activemq.activemq-osgi [89]

cl2显示:com.test [282]


解释一下:onMessage ( Message message ) 这个方法中,参数message来自org.apache.activemq.activemq-osgi,id为89的bundle

而我们希望转换的ActiveMQbytesMessage类型来自com.test,即本项目


OSGi的核心在于其复杂的类加载机制,一不小心就会发生类加载的错误,下面找一下错误发生的地方:


    首先看onMessage ( Message message )这个方法中message的来源:是从信息队列中得到的信息,而信息队列是由activemq连接工厂来监听的(参考上面的代码),那么我们就找连接工厂是怎样注入的


    高度模块化的OSGi项目中,这些公共依赖一般都是通过注入来实现了,这里,activemq的连接工厂通过监听osgi服务来注入,看blueprint的配置:

    <!-- 引用 activemq jms connection factory 服务 -->    <reference id="connectionFactory"               timeout="0"               interface="javax.jms.ConnectionFactory"               filter="(osgi.jndi.service.name=jms/activemq-connection-fctory/zhs-dev-amq)" />      <!-- 信息监听器 -->    <bean class="com.Test" init-method="start" destroy-method="stop">        <property name="connectionFactory" ref="connectionFactory" />    </bean>

看到了吗?连接工厂是通过监听一个名称为“jms/activemq-connection-fctory/zhs-dev-amq”的服务来注入的,下面追踪这个服务发现是由org.apache.activemq.activemq-osgi [89]提供的,也就是上面的cd1


    下面看希望转换的ActiveMQbytesMessage类型为何来自我们本身的项目:


    这个项目有一个外部jar包懒得转换为bundle,就直接集成在bundle里面,pom中有一个地方:

                        <Embed-Dependency>*</Embed-Dependency><Embed-Directory>lib/</Embed-Directory><Embed-StripGroup>true</Embed-StripGroup> 

这个是把lib包中的所有jar包含到bundle的ClassPath下面,这样ActiveMQbytesMessage就来自bundle本身的ClassPath了


解决办法:知道了原理,解决就很容易了,修改任意一方的加载路径即可


0 0
原创粉丝点击