新增两个接口:jmap
和 jstack
,用于获取 Java 应用程序的内存堆转储(heap dump)和线程转储(thread dump)。
添加依赖:
implementation("commons-io:commons-io:2.11.0")
添加controller的API代码:
import org.apache.commons.io.FileUtils
import org.springframework.boot.actuate.management.HeapDumpWebEndpoint
import org.springframework.boot.actuate.management.ThreadDumpEndpoint
import org.springframework.core.io.Resource
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.ResponseBody
import org.springframework.web.bind.annotation.RestController
import java.io.IOException
import java.nio.charset.StandardCharsets
import javax.servlet.http.HttpServletResponse
@RestController
@RequestMapping
class MonitorController(
private val threadDumpEndpoint: ThreadDumpEndpoint?,
private val heapDumpWebEndpoint: HeapDumpWebEndpoint?
) {
@RequestMapping("jmap")
@ResponseBody
@Throws(IOException::class)
fun jmap(response: HttpServletResponse?): String? {
if (this.heapDumpWebEndpoint == null) {
return "not existed"
}
val resource: Resource = this.heapDumpWebEndpoint.heapDump(true).getBody()
val bytes: ByteArray = FileUtils.readFileToByteArray(resource.getFile())
val delete: Boolean = resource.getFile().delete()
return download(response!!, resource.getFilename()!!, bytes, delete.toString())
}
@GetMapping("jstack")
@ResponseBody
fun jstack(response: HttpServletResponse): String? {
if (threadDumpEndpoint == null) {
return "not existed"
}
val threads = threadDumpEndpoint.textThreadDump()
return download(response, "thread-dump.txt", threads.toByteArray(StandardCharsets.UTF_8), "")
}
private fun download(response: HttpServletResponse, fileName: String, bytes: ByteArray, value: String): String? {
response.characterEncoding = "utf-8"
response.contentType = "application/octet-stream"
response.addHeader("Content-Length", bytes.size.toString())
response.setHeader("Content-Disposition", "attachment; filename=$fileName")
try {
response.outputStream.use { outputStream ->
outputStream.write(bytes)
outputStream.flush()
return value
}
} catch (exception: Exception) {
return exception.message
}
}
}