Jarboot
is a platform for Java process startup, shutdown, management and diagnosis. It can manage, guard, monitor and diagnose local and remote Java processes.
In the test environment and daily built integrated environment, a series of jar files such as compilation output can be put into the agreed directory. Jarboot
provides a friendly browser UI interface and HTTP interface to manage its start, stop and status monitoring, and execute commands to debug the target process.
📚 Document: https://www.yuque.com/jarboot
🍏 Best practices 🔥 : Jarboot with Spring Cloud Alibaba Example ⭐️
🐳 Extensible: Support both JDK SPI
and Spring SPI
, support plugins develop.
Jarboot
uses Java agent and ASM
technology to inject code into the target java process,
which is non-invasive. The injected code is only used for command interaction with jarboot's service. Some commands
modify the bytecode of the class for class enhancement. A command system similar to Arthas
is added, such
as acquiring JVM information, monitoring thread status, acquiring thread stack information, etc.
- 🌈 Browser interface management, one click start, stop, do not have to manually execute one by one.
- 🔥 Support start and stop priority configuration[1], and default parallel start.
- ⭐ Process daemon. If the service exits abnormally after opening, it will be automatically started and notified.
- ☀️ Support file update monitoring, and restart automatically if jar file is updated after opening.[2]
- 🚀 Debug command execution, remote debugging multiple Java processes at the same time, the interface is more friendly.
- 💎 Support user-define command by
SPI
, support develop plugins.
Detailed architecture design view
Front-end interface adopts React
technology, scaffold uses UmiJs
, component library uses
UmiJs
built-in antd
. The back-end service is mainly implemented by SpringBoot
, which provides HTTP interface and static resource broker. The process information is pushed through websocket
to the front-end interface in real time, and a long connection is maintained with the started java process to monitor its status.
Use docker
sudo docker run -itd --name jarboot -p 9899:9899 mazheng0908/jarboot
Ignore this when using zip package or docker
.
Build the jarboot code.
#At first build ui
$ cd jarboot-ui
#First time, execute yarn or npm install
$ yarn
#execute compile, yarn build or npm run build, execute yarn start or npm run start at development mode.
$ yarn build
#Switch to the code root directory and compile the Java code
$ cd ../
$ mvn clean install
Ignore this when using docker
.
#Execute startup.sh to start, use startup.cmd when in windows OS.
$ sh startup.sh
Browser access http://127.0.0.1:9899
Enter the login page. Initial username: jarboot
, default password: jarboot
Use SPI extension can implement your own command, define a command how to execute. And,also can notify stated event to Jarboot server , don't need to wait no console time.
- Import
spring-boot-starter-jarboot
dependency
<dependency>
<groupId>io.github.majianzheng</groupId>
<artifactId>spring-boot-starter-jarboot</artifactId>
<version>${jarboot.version}</version>
</dependency>
- Implement
CommandProcessor
SPI interface
Also, you can use @Bean
in the method.
It will use bean name as the command name if not annotated by @Name
.
@Name("spring.command.name")
@Summary("The command summary")
@Description("The command usage detail")
@Component
public class DemoServiceImpl implements DemoService, CommandProcessor {
@Override
public String process(CommandSession session, String[] args) {
return "Spring boot Demo user-defined command using Spring SPI";
}
//implement other method...
}
It will add two new spring debug command spring.bean
and spring.env
after imported
spring-boot-starter-jarboot
dependence.
#spring.bean usage:
$ spring.bean [-b <name>] [-d]
#Examples:
# Get all bean names
$ spring.bean
# Get bean info
$ spring.bean -b beanName
# Get bean detail definition
$ spring.bean -b beanName -d
#sping.env usage:
$ spring.env <name>
#Examples:
$ spring.env spring.application.name
Demonstrate how to use ordinary non springboot applications.
- Import jarboot api dependency
<dependency>
<groupId>io.github.majianzheng</groupId>
<artifactId>jarboot-api</artifactId>
<scope>provided</scope>
<version>${jarboot.version}</version>
</dependency>
- Implement spi interface
/**
* Use Name to define the command name
*/
@Name("demo")
@Summary("The command summary")
@Description("The command usage detail")
public class DemoCommandProcessor implements CommandProcessor {
@Override
public String process(CommandSession session, String[] args) {
return "demo SPI command result.";
}
}
- Create spi define file
Then create a file in resources
/META-INF
/services
named
com.mz.jarboot.api.cmd.spi.CommandProcessor
the content is class full name.
public class DemoApplication {
public static void main(String[] args) {
// do something
try {
//Notify completion
JarbootFactory.createAgentService().setStarted();
} catch (Exception e) {
log(e.getMessage());
}
}
}
View the class bytes,Usage:
jarboot$ bytes com.mz.jarboot.demo.DemoServerApplication
ClassLoader: org.springframework.boot.loader.LaunchedURLClassLoader@31221be2
------
getUser
L0
LINENUMBER 27 L0
...
ILOAD 1
ILOAD 2
IADD
IRETURN
L8
Turn on or off real-time display of standard output stream (initially on), it will be displayed on the front-end UI of
the web in real time. The output stream includes System.out.println
, System.err.println
and
log printing information such as logger.info("hello")
in the code.
Note: The implementation mechanism of this function has been carefully designed. It is recommended to be turned on all the time, which has no impact on performance and can be accelerated when starting.
#Turn on real time display of standard output stream
jarboot$ stdout on
#Turn off real time display of standard output stream
jarboot$ stdout off
#Get current status on or off
jarboot$ stdout
This is the real time statistics dashboard for the current system,click x cancel.
Decompile the specified classes.
jarboot$ jad [-c] java.lang.String
Check the current JVM’s info
jarboot$ jvm
Search any loaded class with detailed information.
$ sc -d org.springframework.web.context.support.XmlWebApplicationContext
class-info org.springframework.web.context.support.XmlWebApplicationContext
code-source /Users/xxx/work/test/WEB-INF/lib/spring-web-3.2.11.RELEASE.jar
name org.springframework.web.context.support.XmlWebApplicationContext
isInterface false
isAnnotation false
isEnum false
isAnonymousClass false
isArray false
isLocalClass false
isMemberClass false
isPrimitive false
isSynthetic false
simple-name XmlWebApplicationContext
modifier public
annotation
interfaces
super-class +-org.springframework.web.context.support.AbstractRefreshableWebApplicationContext
+-org.springframework.context.support.AbstractRefreshableConfigApplicationContext
+-org.springframework.context.support.AbstractRefreshableApplicationContext
+-org.springframework.context.support.AbstractApplicationContext
+-org.springframework.core.io.DefaultResourceLoader
+-java.lang.Object
class-loader +-org.apache.catalina.loader.ParallelWebappClassLoader
+-java.net.URLClassLoader@6108b2d7
+-sun.misc.Launcher$AppClassLoader@18b4aac2
+-sun.misc.Launcher$ExtClassLoader@1ddf84b8
classLoaderHash 25131501
method calling path, and output the time cost for each node in the path.
jarboot$ trace com.mz.jarboot.demo.DemoServerApplication add
Affect(class count: 2 , method count: 1) cost in 63 ms, listenerId: 2
`---ts=2021-06-15 23:34:20;thread_name=http-nio-9900-exec-3;id=13;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@4690b489
`---[0.053485ms] com.mz.jarboot.demo.DemoServerApplication:add()
methods in data aspect including return values, exceptions and parameters
Watch the first parameter and thrown exception of com.mz.jarboot.demo.DemoServerApplicatio#add
only if it throws exception.
jarboot$ watch com.mz.jarboot.demo.DemoServerApplicatio add {params[0], throwExp} -e
Press x to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 65 ms.
ts=2018-09-18 10:26:28;result=@ArrayList[
@RequestFacade[org.apache.catalina.connector.RequestFacade@79f922b2],
@NullPointerException[java.lang.NullPointerException],
]
Check the basic info and stack trace of the target thread.
jarboot$ thread -n 3
"nioEventLoopGroup-2-1" Id=31 cpuUsage=0.37% deltaTime=0ms time=880ms RUNNABLE
at sun.management.ThreadImpl.dumpThreads0(Native Method)
at sun.management.ThreadImpl.getThreadInfo(ThreadImpl.java:448)
at com.mz.jarboot.core.cmd.impl.ThreadCommand.processTopBusyThreads(ThreadCommand.java:209)
at com.mz.jarboot.core.cmd.impl.ThreadCommand.run(ThreadCommand.java:120)
at com.mz.jarboot.core.basic.EnvironmentContext.runCommand(EnvironmentContext.java:162)
at com.mz.jarboot.core.cmd.CommandRequestSubscriber.execute(CommandDispatcher.java:35)
at com.mz.jarboot.core.server.JarbootBootstrap$1.onText(JarbootBootstrap.java:94)
at com.mz.jarboot.core.ws.WebSocketClientHandler.channelRead0(WebSocketClientHandler.java:83)
at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99)
"C2 CompilerThread1" [Internal] cpuUsage=3.14% deltaTime=6ms time=4599ms
"C2 CompilerThread0" [Internal] cpuUsage=2.28% deltaTime=4ms time=4692ms
View the class loader extends tree, url and class loader info.
jarboot$ classloader
name numberOfInstances loadedCountTotal
org.springframework.boot.loader.LaunchedURLClassLoader 1 3929
BootstrapClassLoader 1 2623
com.mz.jarboot.agent.JarbootClassLoader 1 1780
sun.misc.Launcher$AppClassLoader 1 59
sun.reflect.DelegatingClassLoader 58 58
sun.misc.Launcher$ExtClassLoader 1 18
Affect(row-cnt:6) cost in 35 ms.
dump java heap in hprof binary format, like jmap.
jarboot$ heapdump
Examine the system properties from the target JVM
#Get all.
jarboot$ sysprop
#Get one property.
jarboot$ sysprop user.home
- Mail: [email protected]
- QQ group: 663881845
1: You can configure the priority level, starting from the integer value of 1. The more you start first, the reverse is the order of stop.
2: In development, it can be built automatically by tools such as gitlab runner, Jenkins, etc. and copied to the directory specified by Jarboot through script. Updates monitored by Jarboot will restart the service automatically. Directory monitoring implements anti-shake design (multiple updates within a certain period of time will trigger only one restart).