使用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" + 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这个队列只有一个消费者。
然后,就没然后了。