使用restlet暴露activeMQ5的队列信息对外发布resource

第一次写blog把自己的经验写到网上分享,有点小兴奋呢。

restful一直很火热,而且由restful提供出的resource非常轻便快捷。

我是在研究spring mvc和activiti5的过程中逐渐接触到restful的,尤其在修改activiti5源码的时候觉得activiti5使用的restlet非常轻便,配置文件也很简洁。

所以当我们项目组在监控activeMQ的queue时我就想能不能把activeMQ的队列信息暴露出来,供我们的监控接口实时进行监控呢。后来下了activeMQ-5.2.0的源码之后发现activeMQ所有的资源信息都已经加载到spring环境中了,有了spring这么熟悉的框架的帮助下要做的事情就变得非常清晰了。

把重点放在activeMQ项目下的activemq-web-console这个子项目上。(访问http://localhost:8161/admin其实就是访问的这个web应用)首先在classpath下加入以下几个restlet的jar包:org.restlet.ext.fileupload-2.0.8.jar,org.restlet.ext.jackson-2.0.8.jar,org.restlet.ext.servlet-2.0.8.jar,org.restlet-2.0.8.jar。
restlet的环境就已经准备好了,然后在web.xml中加入restlet的servlet配置(所有*/service/*的请求就都会由这个servlet进行分发了):

  <!-- restlet -->
  <servlet> 
    <servlet-name>RestletServlet</servlet-name> 
    <servlet-class>org.restlet.ext.servlet.ServerServlet</servlet-class>
    <init-param>
      <!-- Application class name -->
      <param-name>org.restlet.application</param-name>
      <param-value>org.apache.activemq.web.restful.ActiveMqRestApplication</param-value>
    </init-param>
  </servlet>
 
  <!-- Catch all requests --> 
  <servlet-mapping> 
    <servlet-name>RestletServlet</servlet-name> 
    <url-pattern>/service/*</url-pattern> 
  </servlet-mapping>

当然'org.apache.activemq.web.restful'这个目录是我新建的,所以接下来我们要在这个新建的目录下编写ActiveMqRestApplication。

import org.restlet.Application;
import org.restlet.Restlet;
import org.restlet.data.ChallengeScheme;
import org.restlet.routing.Router;
import org.restlet.security.ChallengeAuthenticator;
import org.restlet.security.SecretVerifier;
import org.restlet.security.Verifier;

public class ActiveMqRestApplication extends Application {

private ChallengeAuthenticator authenticator;

@Override
public synchronized Restlet createInboundRoot() {
Verifier verifier = new SecretVerifier() {

@Override
public boolean verify(String username, char[] password){
return true;
}
};
authenticator = new ChallengeAuthenticator(null, true,ChallengeScheme.HTTP_BASIC,
          "ActiveMQ Realm",verifier);

Router router = new Router(getContext());

router.attach("/comsumers/{queueName}", ConsumersResource.class);

authenticator.setNext(router);

return authenticator;
}
}

所有想要暴露的资源都按照以上形式attach到router中即可。我现在暴露了一个查看某队列所有consumers数量的资源。

接下来就要编写ConsumersResource类了:

import org.apache.activemq.broker.jmx.QueueViewMBean;
import org.apache.activemq.web.LocalBrokerFacade;
import org.restlet.representation.Representation;
import org.restlet.resource.Get;
import org.restlet.resource.ServerResource;
import org.springframework.context.ApplicationContext;

public class ConsumersResource extends ServerResource {

@Get
public String getConsumerCount(Representation entity) {
try {
String queueName = (String) getRequest().getAttributes().get("queueName");
ApplicationContext context = RestfulApplicationContextUtil.getContext();
LocalBrokerFacade brokerQuery = (LocalBrokerFacade)context.getBean("brokerQuery");
QueueViewMBean queue = brokerQuery.getQueue(queueName);
if (queue != null){
return queue.getConsumerCount() + "";
}else {
return "-1";
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("检测队列消费者时出错");
}
}
}

这个类就是通过get请求根据queueName查找这个queue的consumers的数量,然后返回字符串

这里的RestfulApplicationContextUtil是自己写的一个工具类,用于能把spring环境中管理的bean拿出来在非spring环境中使用,其实就是一个静态方法调出web工程中的spring环境。

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class RestfulApplicationContextUtil implements ApplicationContextAware {

private static ApplicationContext applicationContext;// 声明一个静态变量保存

public static ApplicationContext getContext() {
return applicationContext;
}

public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
}

然后把这个工具类放到spring环境里,我图省事就但写了一个spring的配置文件springUtil.xml

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
                           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
  <bean id ="restfulApplicationContextUtil" class="org.apache.activemq.web.restful.RestfulApplicationContextUtil"></bean>
</beans>

最后一步就是找到这个web工程加载默认环境的初始化类中的初始化方法(用的默认的数据源配置,并没有把消息信息进行持久化)
WebConsoleStarter类的createWebapplicationContext()方法,在加载configuration时捎带手的把新建的springUtil.xml也加载进去:

private WebApplicationContext createWebapplicationContext(ServletContext servletContext) {
        String webconsoleType = System.getProperty("webconsole.type", "embedded");
        String configuration = "/WEB-INF/webconsole-" + webconsoleType + ".xml";

        XmlWebApplicationContext context = new XmlWebApplicationContext();
        context.setServletContext(servletContext);
        context.setConfigLocations(new String[] {
            configuration, "/WEB-INF/springUtil.xml"
        });
        context.refresh();
        context.start();

        servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, context);

        return context;
    }

由于activemq用的web容器是jetty,我对jetty一点也不熟,所以就没有在eclipse里进行部署和测试,不过把那4个restlet的jar包扔到apache-activemq-5.2.0\lib目录下,编译过后的.class文件按相应目录结构扔到apache-activemq-5.2.0\webapps\admin之后启动访问
http://localhost:8161/admin/service/comsumers/MyQueue这个地址就能获得MyQueue这个队列的consumers的数量了。

用restlet客户端调用也非常简单,首先把restlet环境加进去(那4个jar包),具体代码就两行:

import org.restlet.resource.ClientResource;

ClientResource cr = new ClientResource("http://localhost:8161/admin/service/comsumers/MyQueue");
String resultStr = cr.get().getText();

返回的resultStr如果是"1"的话就说明MyQueue这个队列只有一个消费者。

然后,就没然后了。

猜你喜欢

转载自bigbullyrn.iteye.com/blog/1405703