简介
jsvc可以理解为类unix系统下的启动并守护java进程的可执行程序,属于Apache Commons Daemon项目。
使用方法
编译jsvc可执行程序
前提是gcc环境和下载了jdk。先下载jsvc的c语言源码commons-daemon-1.2.3-native-src.tar.gz。解压,命令行进入到unix目录下,执行
./configure --with-java=/usr/java path to java jsvc中引用了jni.h头文件,依赖jdk。
然后执行make编译,最后生成一个jsvc的二进制可执行程序。
java类实现org.apache.commons.daemon.Daemon接口
包括一下方法:
void init(String[] arguments): Here open configuration files, create a trace file, create ServerSockets, Threads
void start(): Start the Thread, accept incoming connections
void stop(): Inform the Thread to terminate the run(), close the ServerSockets
void destroy(): Destroy any object created in init()
调用jscv 执行命令./jsvc -cp commons-daemon.jar:my.jar MyClass
cp指class路径 MyClass是实现了Daemon接口的启动类
加上参数-stop则可以调用destroy()方法,停止java虚拟机进程
使用jsvc启动SpringBoot项目,启动配置类如下:
import org.apache.commons.daemon.Daemon;
import org.apache.commons.daemon.DaemonContext;
import org.apache.commons.daemon.support.DaemonLoader;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableAutoConfiguration
@ComponentScan
@EnableConfigurationProperties
public class Application implements Daemon {
private ConfigurableApplicationContext ctx;
private String[] args;
@Override
public void init(DaemonContext context) throws Exception {
args = context.getArguments();
}
@Override
public void start() throws Exception {
ctx = SpringApplication.run(Application.class, args);
}
@Override
public void stop() throws Exception {
ctx.stop();
}
@Override
public void destroy() {
ctx.close();
}
// Main - mostly for development.
public static void main(String[] args) throws Exception {
System.err.println("WARNING - running as current user");
DaemonLoader.Context ctx = new DaemonLoader.Context();
Application app = new Application();
ctx.setArguments(args);
app.init(ctx);
app.start();
}
}
在执行命令./jsvc -cp springboot-jar-path : MyApplication-0.1.jar Application时候注意springboot依赖的jar包路径。可以将项目依赖的jar包拷贝出来,使用maven插件
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>
${directory}/lib/
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
jsvc原理
jsvc会启动3个进程:启动进程、控制进程、java服务进程。
启动进程,fork子进程:
main()
{
fork()
parent: wait_child(), wait until JAVA service started when the child says "I am ready".
child: controller process.
}
控制进程:和java进程通信,控制java进程的启动停止等。
while (fork()) {
parent: wait_for_child.
if exited and restart needed continue
else exit.
child: exit(child()). controlled process.
}
java服务进程:
In child(): controlled process.
init_JVM().
load_service().
start_service().
say "I am ready"
wait for signal or poll for stop
stop_service().
destroy_service().
destroy_JVM().
exit (with different codes so that parent knows if it has to restart us).
启动虚拟机,调用实现Daemon接口的启动类的int(),start()等方法。
在头文件java.h中定义了如下方法:
char *java_library(arg_data *args, home_data *data);
bool java_init(arg_data *args, home_data *data);
bool java_destroy(void);
bool java_load(arg_data *args);
bool java_signal(void);
bool java_start(void);
bool java_stop(void);
bool java_version(void);
bool java_check(arg_data *args);
bool JVM_destroy(int exit);
在java.c中引用头文件<jni.h>,通过虚拟暴露的jni接口与虚拟机通信,启动虚拟机,调用java方法。
为什么使用jsvc
- 一个JAVA应用可能包括多个虚拟机进程,通过jsvc可以方便管理应用中的不同java进程。
- java进程启动、停止或者退出时,执行init stop destroy等方法,java应用能通过这些方法。执行一下必要的操作。例如:Servlet容器在java进程退出时,需要将session序列化到硬盘。