您的位置:首页 > 编程语言 > Java开发

SpringBoot特性之Actuator

2017-11-19 20:48 573 查看
SpringBoot自动配置的特性,很大程度上解放了我们繁琐的配置的工作,但是也向我们屏蔽了很多内部运行

的细节,好在SpringBoot为我们提供了Actuator,Actuator在应用程序里提供了众多的Web端点,通过它

们,我们可以了解应用程序运行时的内部状况。我们可以了解Bean的组装信息,获取环境配置信息,等等

Actuator为我们提供了如下的一些端口

HTTP方法路径描述Sensitive Default
GET/autoconfig自动配置报告,记录哪些自动配置条件通过了,哪些没通过true
GET/configprops自动配置的属性信息true
GET/beans应用程序上下文里全部的Bean,以及它们的关系true
GET/dump获取线程活动的快照true
GET/env获取全部环境属性,包含环境变量和配置属性信息true
GET/env/{name}根据名称获取特定的环境属性值true
GET/health报告应用程序的健康指标,这些值由HealthIndicator的实现类提供false
GET/info获取应用程序的定制信息,这些信息由info打头的属性提供false
GET/mappings全部的URI路径,以及它们和控制器(包含Actuator端点)的映射关系true
GET/metrics报告各种应用程序度量信息,比如内存用量和HTTP请求计数true
GET/metrics/{name}报告指定名称的应用程序度量值true
GET/shutdown优雅的关闭应用程序(endpoints.shutdown.enabled设置为true才会生效)true
GET/trace提供基本的HTTP请求跟踪信息(时间戳、HTTP头等)true
GET/loggers展示应用程序中的日志配置信息true
GET/heapdump当访问这个请求的时候,会下载一个压缩的hprof的堆栈信息文件true
我们如果要使用Actuator的话也很简单,我们首先在pom文件中引入Actuator的依赖就行了,如下:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>


然后再添加一个配置项即可:

management:
security:
enabled: false


下面我们访问几个来看一下功能(端口号换成自己应用的端口号):

请求:http://localhost:8003/beans

效果如下:



在上面的图片中,Actuator为我们展示了一个Bean的信息,Bean的名字(bean)、别名(aliases)、

scope(singleton or prototype)、类型(type)、位置(resource绝对路径)、依赖(dependencies)

请求:http://localhost:8003/autoconfig

效果如下:



SpringBoot的另一个重要的特性是自动配置,当我们访问/autoconfig的时候,Actuator为我们输出了

autoconfig的一些信息,自动配置这个bean需要什么样的条件。

其他的一些Actuator端点也很有意思,例如:/configprops、/mappings、/heapdump等。当然我们也可以自定义Actuator来满足自己的功能需要,demo如下所示:

package com.zkn.springboot.exercise.endpoint;

import org.springframework.boot.actuate.endpoint.AbstractEndpoint;
import org.springframework.stereotype.Component;

import java.lang.management.*;
import java.util.HashMap;
import java.util.Map;

/**
* @author zkn
* @date 2017/11/15 22:50
*/
@Component
public class ThreadInfoEndpoint extends AbstractEndpoint<Map<String, String>> {

public ThreadInfoEndpoint() {
//id
super("threadInfo");
}

/**
* Called to invoke the endpoint.
*
* @return the results of the invocation
*/
@Override
public Map<String, String> invoke() {
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
//获取所有的线程信息
ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(true, true);
if (threadInfos != null && threadInfos.length > 0) {
Map<String, String> map = new HashMap<>(threadInfos.length);
for (ThreadInfo threadInfo : threadInfos) {
map.put(threadInfo.getThreadName(), getThreadDumpString(threadInfo));
}
return map;
}
return null;
}

/**
* 组装线程信息
*
* @param threadInfo
*/
private String getThreadDumpString(ThreadInfo threadInfo) {

StringBuilder sb = new StringBuilder("threadName:" + threadInfo.getThreadName() + ",threadId:" + threadInfo.getThreadId() + ",threadStatus:" + threadInfo.getThreadState());
//锁的名字
if (threadInfo.getLockName() != null) {
sb.append(",lockName:" + threadInfo.getLockName());
}
//锁的持有者
if (threadInfo.getLockOwnerName() != null) {
sb.append(",lockOwnerName:" + threadInfo.getLockOwnerName());
}
//线程中断
if (threadInfo.isSuspended()) {
sb.append(",suspended:" + threadInfo.isSuspended());
}
if (threadInfo.isInNative()) {
sb.append(",inNative:" + threadInfo.isInNative());
}
sb.append("\n");

StackTraceElement[] stackTraceElementst = threadInfo.getStackTrace();
MonitorInfo[] monitorInfos = threadInfo.getLockedMonitors();
StackTraceElement stackTraceElement;
if (stackTraceElementst != null) {
int i;
for (i = 0; i < stackTraceElementst.length; i++) {
stackTraceElement = stackTraceElementst[i];
sb.append(",stackTraceElement:" + i + ";" + stackTraceElement.toString());
if (i == 0 && threadInfo.getLockInfo() != null) {
Thread.State ts = threadInfo.getThreadState();
switch (ts) {
case BLOCKED:
sb.append("\t-  blocked on " + threadInfo.getLockInfo());
sb.append('\n');
break;
case WAITING:
sb.append("\t-  waiting on " + threadInfo.getLockInfo());
sb.append('\n');
break;
case TIMED_WAITING:
sb.append("\t-  waiting on " + threadInfo.getLockInfo());
sb.append('\n');
break;
default:
}
}
for (MonitorInfo mi : monitorInfos) {
if (mi.getLockedStackDepth() == i) {
sb.append("\t-  locked " + mi);
sb.append('\n');
}
}
}
if (i < stackTraceElementst.length) {
sb.append("\t...");
sb.append('\n');
}

LockInfo[] locks = threadInfo.getLockedSynchronizers();
if (locks.length > 0) {
sb.append("\n\tNumber of locked synchronizers = " + locks.length);
sb.append('\n');
for (LockInfo li : locks) {
sb.append("\t- " + li);
sb.append('\n');
}
}
sb.append('\n');
}
return sb.toString();
}
}


关键点是:一:继承AbstractEndpoint这个类(注意泛型类型),二:写一个无参的构造函数,调用父类的一

个有参构造函数,传入一个id描述(id描述会映射为响应的请求),三:重写invoke方法。在

AbstractEndpoint中注入Environment,所以你可以通过Environment获取系统环境变量中的值。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息