文档章节

多个平台的 Java Launcher 脚本

Force武装卫队
 Force武装卫队
发布于 2015/06/09 16:17
字数 1361
阅读 3322
收藏 101

通常对于服务来说,过长的命令往往让人感到厌烦,人们需要的只是简单的操作,并且能够支持复杂的功能,对于 Java 开发的服务来说更是如此。
一个比较复杂的 Jar 服务使用Java启动,命令如下

java -Xms512m -Xmx512m -jar fuck.jar --config config.server -port 10086

实际上许多虚拟机的语言的 Host 命令格式也是类似的。
我们分析可以知道对于基于虚拟机的语言,命令行基本上是 host+vm 运行参数+执行文件路径+输入参数。 当然如果参数较少,我们完全不用写一个 Launcher 脚本来管理服务。

Launcher 脚本需要提供的命令至少有:

  1. start
  2. stop
  3. restart
  4. status
  5. help

##实现 在 Linux 系统上,启动脚本应该是简单的,不许要过多依赖的,一般而言推荐使用 shell 脚本,实际上很多软件在 Linux 上的 Launcher 都是使用 Shell 语言。android studio,brackets Codebox ,甚至 Chrome,Firefox 都有 shell 脚本的启动器。
在 Windows 上早期,部分软件使用 cmd 来写启动器,然而 cmd 的功能孱弱,微软适时的推出了 PowerShell,PowerShell 在功能上非常强大,甚至要优于Shell,所以采用 PowerShell 来写启动器,并且写一个 cmd 辅助脚本启动PowerShell。

@echo off

if not exist "%~dp0launcher.ps1" goto NotFound
PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0launcher.ps1' %*"
goto :EOF
:NotFound
echo Not Found launcher.ps1 in %~dp0,Please reset your launcher
PAUSE

###配置文件的读取 选择合适的配置文件能够简化操作,对于简单的 Shell 脚本而言,复杂的配置文件是难以实现的。我将 Launcher 的配置文件分为两类,一个是 JVM 的参数,也就是上面的 "-Xms512m -Xmx512m" 这种文件的格式就是按行读取,行首存在‘#’字符就抛弃。 另一类是基于 INI-Style 的配置文件,主要是 JDK 的路径,需要运行的 jar 包的路径,以及重定向的设置,由于 Windows 和 Linux 的文件系统存在差异,所以在涉及到文件系统的设置迁移到了 Windows 和 Posix 节

Bash 解析 Ini 文件:


function GetPrivateProfileString()
{
	if [ ! -f $1 ] || [ $# -ne 3 ];then
		return 1
	fi
	blockname=$2
	fieldname=$3

	begin_block=0
	end_block=0

	cat $1 | while read line
	do

		if [ "X$line" = "X[$blockname]" ];then
			begin_block=1
			continue
		fi

		if [ $begin_block -eq 1 ];then
			end_block=$(echo $line | awk 'BEGIN{ret=0} /^\[.*\]$/{ret=1} END{print ret}')
			if [ $end_block -eq 1 ];then
				#echo "end block"
				break
			fi

			need_ignore=$(echo $line | awk 'BEGIN{ret=0} /^#/{ret=1} /^$/{ret=1} END{print ret}')
			if [ $need_ignore -eq 1 ];then
				#echo "ignored line:" $line
				continue
			fi
			field=$(echo $line | awk -F= '{gsub(" |\t","",$1); print $1}')
			#####Fix Me We Support Space Value
			value=$(echo $line | awk -F= '{gsub("","",$2); print $2}')
			#echo "'$field':'$value'"
			if [ "X$fieldname" = "X$field" ];then
				#echo "result value:'$result'"
				echo $value
				break
			fi

		fi
	done
	return 0
}

PowerShell 解析 Ini 文件:

Function Parser-IniFile
{
    param(
        [Parameter(Position=0,Mandatory=$True,HelpMessage="Enter Your Ini File Path")]
        [ValidateNotNullorEmpty()]
        [String]$File
        )
    $ini = @{}
    $section = "NO_SECTION"
    $ini[$section] = @{}
    switch -regex -file $File {
        "^\[(.+)\]$" {
            $section = $matches[1].Trim()
            $ini[$section] = @{}
        }
        "^\s*([^#].+?)\s*=\s*(.*)" {
            $name,$value = $matches[1..2]
            # skip comments that start with semicolon:
            if (!($name.StartsWith(";"))) {
                $ini[$section][$name] = $value.Trim()
            }
        }
    }
    $ini
}

###JDK 的检测 查看 Java 路径,通常来说,launcher 脚本会从 launcher.cfg 读取Posix(Windows) 节的 JAVA_HOME 键值,如果没有 JAVA_HOME 的变量就读取环境变量的 JAVA_HOME,如果存在 JAVA_HOME,但实际路径上并不存在,或者没有存在 JAVA_HOME,那么再从查找 java的路径。而 JAVA_HOME 的设置可以在有多个JDK的时候仍然正确的选择 JDK.而不用带来冲突。

	jdkenv=$(GetPrivateProfileString launcher.cfg Posix JAVA_HOME)
	javabin=`which java`
	if [ -f "$jdkenv/bin/java" ]; then
		javabin="$jdkenv/bin/java"
	fi

Get-JavaSE 函数是为了支持从注册表查询 JDK 安装。所以单独的写了一个函数。


Function Get-JavaSE
{
    $jdk=$env:JAVA_HOME
    #This is regedit search java
    return $jdk
}

$JdkRawEnv=$IniAttr["Windows"]["JAVA_HOME"]

$JavaEnv="$env:JAVA_HOME"
IF($JdkRawEnv -eq $null)
{
    $JavaEnv=Get-JavaSE
}else{
    $JavaEnv=$JdkRawEnv
}

###进程的管理 先说 PowerShell,PowerShell 是面向对象的,我们可以轻松的获得进城对象。
我们使用 Start-Process 启动一个进程。在这个 cmdlet 中 我们添加 -PassThru 就可以得到一个进程对象

$ProcessObj= Start-Process -FilePath "${JavaExe}" -PassThru -Argumentlist "${VMOptions} -jar ${PrefixDir}\${AppPackage} $Parameters"  -RedirectStandardOutput "${StdoutFile}" -RedirectStandardError "${StdErrorFile}" -WindowStyle Hidden

$ProcessObj 可以拿到进程的 Id,进程的镜像名,以及进程的资源占用情况。 当然进程对象在 Get-Process 也是可用的。 使用 Get-Process 获得一个进程,如果有进程 id 再好不过。如果不存在 id 对应的进程则会抛出异常

  $Obj=Get-Process -Id $javaid

结束一个进程需要 Stop-Process 只需要输入 -Id id 即可。 而对于 Linux,有文件系统 /proc,同样可以实现 PowerShell 的功能。判断进程是否存在可以检测 /proc/id 是否存在,可以检查 /proc/id/status 查看资源占用什么的。
我们在 launcher 脚本所在目录(通常也是 jar 包所在目录)当启动 java 进程成功后,我们将 pid 写入到 launcher.lock.pid 在需要停止和重启的时候使用launcher.lock.pid 存储的 id 来操作即可。 在 PowerShell 中可以用 Get-Content 读取 pid。在 Linux 中可以用 cat。

启动
Windows

launcher -start

Linux

./launcher -start

重启

launcher -restart

停止服务

launcher -restart

查看状态:

launcher -status

帮助:

launcher -help

###最终 上述代码已经托管到 GIT@OSC
项目:http://git.oschina.net/ipvb/ServiceLauncher 使用MIT协议,欢迎 Pull Request.

© 著作权归作者所有

Force武装卫队

Force武装卫队

粉丝 190
博文 40
码字总数 80436
作品 3
深圳
高级程序员
私信 提问
加载中

评论(8)

Force武装卫队
Force武装卫队 博主

引用来自“ddatsh”的评论

spring shell就有生成的
很多东西没有用到spring ,不需要再引入了。
ddatsh
ddatsh
spring shell就有生成的
云朵冰
33333
如梦技术
如梦技术
👍
Force武装卫队
Force武装卫队 博主

引用来自“翠翠”的评论

呃~~~试试 spring boot 或者 apache commons Launcher?
比如apache commons Launcher需要从环境变量读取Java而不能手动指定,这并不好。
Force武装卫队
Force武装卫队 博主

引用来自“翠翠”的评论

呃~~~试试 spring boot 或者 apache commons Launcher?

用那些不是本文的意义
翠翠
翠翠
呃~~~试试 spring boot 或者 apache commons Launcher?
Force武装卫队
Force武装卫队 博主
@叶秀兰 快来围观
Apache commons (Java常用工具包)简介

Apache Commons是一个非常有用的工具包,解决各种实际的通用问题,下面是一个简述表,详细信息访问http://jakarta.apache.org/commons/index.html BeanUtils Commons-BeanUtils 提供对 Java...

Coder小兵
2012/02/04
1K
1
java虚拟机的启动实例--eclipse的方式

查看eclipse的源代码,有以下一个zip压缩包: src/plugins/org.eclipse.platform/launchersrc.zip 这是eclipse的启动源码包,解压后有一个launchersrc/library目录,该目录中有一个文件eclip...

晨曦之光
2012/04/10
941
0
什么是编译性语言、解释性语言和脚本语言

什么是编译性语言、解释性语言和脚本语言   计算机不能直接理解高级语言,只能直接理解机器语言,所以必须要把高级语言翻译成机器语言,计算机才能值型高级语言编写的程序。  翻译的方式有...

AlphaJay
2010/08/18
545
0
sqoop1 导出与hue oozie踩坑

可能是不同版本不同吧,按网友的最终改为: export --connect jdbc:mysql://172.16.5.100:3306/dwtest --username testuser --password ** --table che100kv --export-dir /user/hive/wareho......

hblt-j
2018/09/18
68
1
关于 Java Scripting API 您不知道的 5 件事

现在,许多 Java 开发人员都喜欢在 Java 平台中使用脚本语言,但是使用编译到 Java 字节码中的动态语言有时是不可行的。在某些情况中,直接编写一个 Java 应用程序的脚本 部分 或者在一个脚本...

红薯
2010/09/12
525
2

没有更多内容

加载失败,请刷新页面

加载更多

一个activity中多个handler和消息的处理过程

Ø 能否有多个handler handler的构造方法 public Handler() { …. mLooper = Looper.myLooper(); mQueue = mLooper.mQueue; mCallback = null; … } 因为几乎主要的成员变量都是从Looper中拿......

shzwork
34分钟前
3
0
一起来学Java8(一)——函数式编程

在这篇文章中,我们将了解到在Java8下如何进行函数式编程。 函数式编程 所谓的函数式编程就是把函数名字当做值进行传递,然后接收方拿到这个函数名进行调用。 首先来看下JavaScript如何进行函...

猿敲月下码
54分钟前
4
0
vue 源码 断点调试

本文转载于:专业的前端网站➥vue 源码 断点调试 1、添加sourceMap sourceMap: true 2、npm run dev 会生成vue.js.map 3、断点调试 <!DOCTYPE html><html> <head> <meta cha......

前端老手
今天
4
0
流量运营系统demo1

TopkURLMapper public class TopkURLMapper extends Mapper<LongWritable, Text, Text, FlowBean> {private FlowBean bean = new FlowBean();private Text k = new Text();@Ove......

Garphy
今天
4
0
OSChina 周六乱弹 —— 如果是个帅小伙你愿意和他出去吗

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 小小编辑推荐:《Ghost 》游戏《死亡搁浅》原声 《Ghost 》游戏(《死亡搁浅》原声) - Au/Ra / Alan Walker 手机党少年们想听歌,请使劲儿戳...

小小编辑
今天
439
15

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部