前些天,写一个监控程序,为了可扩展监控的类型,用反射和模板做了一个插件形式的代码。
1、通过dubbo做远程调用,接口参数CollectCommandBean如下:
package com.cloudeye.common.bean.collect;
import java.util.List;
import com.cloudeye.common.bean.BaseBean;
import com.cloudeye.common.bean.metric.MetricBean;
import com.cloudeye.common.bean.plugin.PluginBean;
import com.cloudeye.common.bean.resource.ConnectionBean;
import com.cloudeye.common.bean.resource.ResourceBean;
public class CollectCommandBean extends BaseBean {
private static final long serialVersionUID = 1L;
String commandId;
ResourceBean resource;
ConnectionBean connection;
PluginBean plugin;//这是是存插件类的类名
List<MetricBean> metricList;
public CollectCommandBean() {}
public CollectCommandBean(String commandId) {
this.commandId = commandId;
}
public String getCommandId() {
return commandId;
}
public void setCommandId(String commandId) {
this.commandId = commandId;
}
public ResourceBean getResource() {
return resource;
}
public void setResource(ResourceBean resource) {
this.resource = resource;
}
public ConnectionBean getConnection() {
return connection;
}
public void setConnection(ConnectionBean connection) {
this.connection = connection;
}
public PluginBean getPlugin() {
return plugin;
}
public void setPlugin(PluginBean plugin) {
this.plugin = plugin;
}
public List<MetricBean> getMetricList() {
return metricList;
}
public void setMetricList(List<MetricBean> metricList) {
this.metricList = metricList;
}
}
2、创建一个模板接口
public interface AgentBasePlugin<T> {
//获取连接
T getConnection(ConnectionBean connection);
//返回连接
void returnConnection(ConnectionBean connection);
//探测指标
public List<MetricIndividualBean> detect(String commandId, ResourceBean resource,
ConnectionBean connection, List<MetricProbeBean> metricProbeList);
//采集指标
public List<MetricMonitorDataBean> collect(String commandId, ConnectionBean connection,
List<MetricBean> metricList);
}
3、创建一个处理类,来实例化AgentBasePlugin接口
public class AgentProxyHandler extends AbstractInvocationHandler {
private Object proxied;
public AgentProxyHandler(Object proxied) {
this.proxied = proxied;
}
@Override
protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(proxied, args);
}
}
4、创建一个service,传入CollectCommandBean ,通过plugin中的类名实例化出的类(这个类必须实现AgentBasePlugin借口),调用模板方法,返回给dubbo接口
package com.cloudeye.agent.core.service.impl;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.cloudeye.agent.core.handler.AgentProxyHandler;
import com.cloudeye.agent.core.plugin.base.AgentBasePlugin;
import com.cloudeye.agent.core.service.AgentCallPluginService;
import com.cloudeye.common.bean.collect.CollectCommandBean;
import com.cloudeye.common.bean.collect.CollectResultBean;
import com.cloudeye.common.bean.detect.DetectCommandBean;
import com.cloudeye.common.bean.detect.DetectResultBean;
import com.cloudeye.common.bean.metric.MetricBean;
import com.cloudeye.common.bean.metric.MetricIndividualBean;
import com.cloudeye.common.bean.metric.MetricProbeBean;
import com.cloudeye.common.bean.monitor.MetricMonitorDataBean;
import com.cloudeye.common.bean.resource.ConnectionBean;
import com.cloudeye.common.bean.resource.ResourceBean;
import com.google.common.reflect.AbstractInvocationHandler;
import com.google.common.reflect.Reflection;
@Service
public class AgentCallPluginServiceImpl implements AgentCallPluginService {
private static final Logger logger = LoggerFactory.getLogger(AgentCallPluginServiceImpl.class);
public CollectResultBean callCollect(CollectCommandBean collectCommand) {
logger.debug("Collect:[{}]", collectCommand.toString());
CollectResultBean result = new CollectResultBean(collectCommand.getCommandId());
String pluginClass = collectCommand.getPlugin().getPluginClass();
ConnectionBean connect = collectCommand.getConnection();
List<MetricBean> metricList = collectCommand.getMetricList();
ResourceBean resource = collectCommand.getResource();
result.setResource(resource);
Class<?> clazz;
try {
clazz = Class.forName(pluginClass);
AbstractInvocationHandler handler = new AgentProxyHandler(clazz.newInstance());
AgentBasePlugin<?> plugin = Reflection.newProxy(AgentBasePlugin.class, handler);
List<MetricMonitorDataBean> metricMonitorDataList =
plugin.collect(collectCommand.getCommandId(), connect, metricList);
result.setMetricMonitorDataList(metricMonitorDataList);
} catch (Exception e) {
logger.error("Plugin error: [{}]", pluginClass, e);
}
return result;
}
@Override
public DetectResultBean callDetect(DetectCommandBean detectCommand) {
logger.debug("Detect:[{}]", detectCommand.toString());
DetectResultBean result = new DetectResultBean(detectCommand.getCommandId());
String pluginClass = detectCommand.getPlugin().getPluginClass();
ConnectionBean connect = detectCommand.getConnection();
List<MetricProbeBean> metricProbeList = detectCommand.getMetricProbeList();
ResourceBean resource = detectCommand.getResource();
result.setResource(resource);
Class<?> clazz;
try {
clazz = Class.forName(pluginClass);
AbstractInvocationHandler handler = new AgentProxyHandler(clazz.newInstance());
AgentBasePlugin<?> plugin = Reflection.newProxy(AgentBasePlugin.class, handler);
List<MetricIndividualBean> metricIndividualList =
plugin.detect(detectCommand.getCommandId(), resource, connect, metricProbeList);
result.setMetricIndividualList(metricIndividualList);
} catch (Exception e) {
logger.error("Plugin error: [{}]", pluginClass, e);
}
return result;
}
}
5、demo插件
package com.cloudeye.agent.plugin.demo;
import java.util.List;
import com.cloudeye.agent.core.plugin.AgentAbstractPlugin;
import com.cloudeye.common.bean.metric.MetricBean;
import com.cloudeye.common.bean.monitor.MetricMonitorDataBean;
import com.cloudeye.common.bean.resource.ConnectionBean;
import com.google.common.collect.Lists;
public class PLUGDemoPlugin implements AgentBasePlugin<String> {
@Override
public List<MetricMonitorDataBean> collect(String commandId,ConnectionBean connection,
List<MetricBean> metricList) {
List<MetricMonitorDataBean> list = Lists.newArrayList();
MetricMonitorDataBean bean = new MetricMonitorDataBean();
bean.setMetId(1l);
bean.setMetKey("test");
bean.setMetValue(100.0);
list.add(bean);
return list;
}
@Override
public String getConnection(ConnectionBean connection) {
return null;
}
}