如果你玩windows系統,你對服務這個東西並不會陌生,服務可以幫我們做很多事情,在不影響用戶正常工作的情況下,可以完成很多我們需要的需求。
眾所周知,微軟的visio studio內置的Service類可以編寫windows服務,對於一個Java開發人員來說,想要編寫一個windows服務部署到服務器里面,
還要在自己的開發環境裝一個visio studio,那太麻煩了。
那么問題來了,我想用java編寫一個windows服務,這個想法可行嗎?答案是肯定的,可行!
開源的JavaService幫我們解決了這一個問題,使用java也可以編寫一個windows服務部署到windows里面。
閑話不多說,來看看如何利用JavaService實現Java編寫部署windows服務。
首先需要用到的一些開發工具:
JDK
Eclipse
JavaService
這里我安裝的JDK是1.6版本的,
Eclipse用於編寫一個JAVA工程,
JavaService可在官網下載,下載地址:http://javaservice.objectweb.org,下載之前官方需要確認你的一些個人信息,提交后可以進入資源下載頁面,我這里下載的是2.0.10版本。解壓后有很多文件,我們只需要用到其中的JavaService.exe。
做飯炒一個菜,我們需要准備一些菜品原料,以上我們的菜都買好了,接下來看看主要准備工作和主要步驟。
首先安裝JDK,默認安裝到C盤就可以了。
然后配置java環境變量,這里就不細說了,上一個鏈接給予大家參考,環境變量要配置正確,這個很重要。
配置JDK環境變量:http://jingyan.baidu.com/article/c85b7a6414f2ee003bac95d5.html
接着編寫一個Java工程
這里我貼出我的代碼示例出來,是工作的一個需求,大致看一些主要代碼即可,我下面會提到的。
這里是工程結構:
代碼:
- <span style="font-family:Microsoft YaHei;font-size:14px;">package com.ecservice;
- import java.io.BufferedReader;
- import java.io.File;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.net.InetAddress;
- import java.net.NetworkInterface;
- import java.net.SocketException;
- import java.net.UnknownHostException;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- public class ECService {
- private static Thread thread = null;
- private static Service service = null;
- /**
- * 退出服務方法(該方法必須有參數 String [] args)
- *
- * @param args
- */
- public static void StopService(String[] args) {
- System.out.println(service.getLocalTime()+"停止服務");
- service.setRunFlag(false);
- }
- /**
- * 啟動服務方法(該方法必須有參數 String [] args)
- *
- * @param args
- */
- public static void StartService(String[] args) {
- // 產生服務線程
- service = new Service();
- thread = new Thread(service);
- System.out.println("\r\n"+service.getLocalTime()+"-----------啟動服務-----------");
- try {
- // 將服務線程設定為用戶線程,以避免StartService方法結束后線程退出
- thread.setDaemon(false);
- if (!thread.isDaemon()) {
- System.out.println(service.getLocalTime()+"成功設定線程為用戶線程!");
- }
- // 啟動服務線程
- thread.start();
- } catch (SecurityException se) {
- System.out.println(service.getLocalTime()+"線程類型設定失敗!");
- }
- }
- public static void main(String[] args) {
- new Service().run();
- // ECService.StartService(null);
- }
- }
- class Service implements Runnable {
- private boolean runFlag = true;
- /**
- * 設定服務線程運行標志值
- *
- * @param runFlag
- */
- public synchronized void setRunFlag(boolean runFlag) {
- this.runFlag = runFlag;
- }
- /**
- * 取得服務線程運行標志值
- *
- * @param void
- */
- @SuppressWarnings("unused")
- private synchronized boolean getRunFlag() {
- return runFlag;
- }
- @Override
- public void run() {
- System.out.println(getLocalTime()+"服務線程開始運行");
- // while (getRunFlag()) {
- // 獲取當前計算機名和MAC
- String hostName = getHostName();
- if (hostName != null) {
- System.out.println(getLocalTime()+"計算機名獲取成功!");
- // 獲取本機mac地址
- String localMac = getMac();
- if (localMac != null) {
- System.out.println(getLocalTime()+"mac獲取成功!");
- String mac = subMac(localMac);
- // 匹配本機計算機名與mac地址
- if (!hostName.equals(mac)) {
- System.out.println(getLocalTime()+"開始執行修改計算機名稱。");
- // 執行修改計算機名
- // 生成一個bat批處理文件
- boolean isMakeBatSuccess = makeBat(mac);
- if(isMakeBatSuccess == true){
- System.out.println(getLocalTime()+"生成bat成功!");
- // 執行bat
- runCMD("C:\\ECService\\modify_hostname.bat");
- System.out.println(getLocalTime()+"執行bat完畢!");
- // 刪除bat
- removeBat("C:\\ECService\\modify_hostname.bat");
- System.out.println(getLocalTime()+"執行刪除bat完畢!");
- // 重啟機器
- runCMD("shutdown -r -t 0");
- System.out.println(getLocalTime()+"執行修改計算機名操作完畢,系統正在重啟。");
- }else{
- System.out.println(getLocalTime()+"生成bat失敗!");
- }
- } else {
- System.out.println(getLocalTime()+"本機計算機名與mac地址一致,不需要修改計算機名。");
- }
- } else {
- System.out.println(getLocalTime()+"獲取本機mac地址失敗!");
- }
- } else {
- System.out.println(getLocalTime()+"獲取本機計算機名失敗!");
- }
- // }
- System.out.println(getLocalTime()+"服務線程結束運行");
- }
- /**
- * 獲取計算機名稱
- *
- * @return
- */
- public String getHostName() {
- try {
- InetAddress inetAddress = InetAddress.getLocalHost();
- String hostName = "";
- hostName = inetAddress.getHostName();
- return hostName;
- } catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- System.out.println(getLocalTime()+"獲取計算機名稱失敗:" + e.getMessage());
- }
- return null;
- }
- /**
- * 獲取MAC地址
- *
- * @return
- */
- public String getMac() {
- NetworkInterface byInetAddress;
- try {
- InetAddress localHost = InetAddress.getLocalHost();
- byInetAddress = NetworkInterface.getByInetAddress(localHost);
- byte[] hardwareAddress = byInetAddress.getHardwareAddress();
- return getMacFromBytes(hardwareAddress);
- } catch (SocketException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- System.out.println(getLocalTime()+"獲取mac地址失敗:" + e.getMessage());
- } catch (UnknownHostException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- System.out.println(getLocalTime()+"獲取mac地址失敗:" + e.getMessage());
- } catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- System.out.println(getLocalTime()+"獲取mac地址失敗:" + e.getMessage());
- }
- return null;
- }
- public String subMac(String mac) {
- String r = mac.substring(9, mac.length());
- return r;
- }
- public String getMacFromBytes(byte[] bytes) {
- StringBuffer mac = new StringBuffer();
- byte currentByte;
- boolean first = false;
- for (byte b : bytes) {
- if (first) {
- mac.append("-");
- }
- currentByte = (byte) ((b & 240) >> 4);
- mac.append(Integer.toHexString(currentByte));
- currentByte = (byte) (b & 15);
- mac.append(Integer.toHexString(currentByte));
- first = true;
- }
- return mac.toString().toLowerCase();
- }
- public boolean makeBat(String hostname) {
- boolean isSuccess = false;
- File file = new File("C:\\ECService\\modify_hostname.bat");
- try {
- file.createNewFile();
- StringBuilder sb = appendBat(hostname);
- String str = sb.toString();
- byte bt[] = new byte[1024];
- bt = str.getBytes();
- FileOutputStream in;
- in = new FileOutputStream(file);
- in.write(bt, 0, bt.length);
- in.close();
- isSuccess = true;
- } catch (FileNotFoundException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (Exception e) {
- e.printStackTrace();
- }
- return isSuccess;
- }
- public StringBuilder appendBat(String hostname) {
- StringBuilder sb = new StringBuilder();
- sb.append("set cname=" + hostname);
- sb.append("\r\n");
- sb.append("echo REGEDIT4 >c:\\windows\\reg.reg");
- sb.append("\r\n");
- sb.append("echo [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\ComputerName] >> c:\\windows\\reg.reg");
- sb.append("\r\n");
- sb.append("echo [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\ComputerName\\ComputerName] >> c:\\windows\\reg.reg");
- sb.append("\r\n");
- sb.append("echo \"ComputerName\"=\"%cname%\" >> c:\\windows\\reg.reg");
- sb.append("\r\n");
- sb.append("echo [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\ComputerName\\ActiveComputerName] >> c:\\windows\\reg.reg");
- sb.append("\r\n");
- sb.append("echo \"ComputerName\"=\"%cname%\" >> c:\\windows\\reg.reg");
- sb.append("\r\n");
- sb.append("echo [HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet002\\Control\\ComputerName\\ComputerName] >> c:\\windows\\reg.reg ");
- sb.append("\r\n");
- sb.append("echo \"ComputerName\"=\"%cname%\" >> c:\\windows\\reg.reg");
- sb.append("\r\n");
- sb.append("echo [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters] >> c:\\windows\\reg.reg");
- sb.append("\r\n");
- sb.append("echo \"NV Hostname\"=\"%cname%\" >> c:\\windows\\reg.reg");
- sb.append("\r\n");
- sb.append("echo \"Hostname\"=\"%cname%\" >> c:\\windows\\reg.reg");
- sb.append("\r\n");
- sb.append("echo [HKEY_USERS\\S-1-5-18\\Software\\Microsoft\\Windows\\ShellNoRoam] >> c:\\windows\\reg.reg");
- sb.append("\r\n");
- sb.append("echo @=\"%cname%\" >> c:\\windows\\reg.reg");
- sb.append("\r\n");
- sb.append("echo [HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Control\\ComputerName\\ActiveComputerName] >> c:\\windows\\reg.reg");
- sb.append("\r\n");
- sb.append("echo \"ComputerName\"=\"%cname%\" >> c:\\windows\\reg.reg");
- sb.append("\r\n");
- sb.append("echo [HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters] >> c:\\windows\\reg.reg");
- sb.append("\r\n");
- sb.append("echo \"NV Hostname\"=\"%cname%\" >> c:\\windows\\reg.reg");
- sb.append("\r\n");
- sb.append("echo \"Hostname\"=\"%cname%\" >> c:\\windows\\reg.reg");
- sb.append("\r\n");
- sb.append("echo [HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon] >> c:\\windows\\reg.reg");
- sb.append("\r\n");
- sb.append("echo \"DefaultDomainName\"=\"%cname%\" >> c:\\windows\\reg.reg");
- sb.append("\r\n");
- sb.append("echo \"AltDefaultDomainName\"=\"%cname%\" >> c:\\windows\\reg.reg");
- sb.append("\r\n");
- sb.append("regedit /s c:\\windows\\reg.reg");
- sb.append("\r\n");
- sb.append("exit");
- return sb;
- }
- public String runCMD(String commands) {
- String result = "";
- try {
- Process process = Runtime.getRuntime().exec(commands);
- BufferedReader errorReader = new BufferedReader(
- new InputStreamReader(process.getInputStream()));
- String line = null;
- while ((line = errorReader.readLine()) != null) {
- result += line + "\n";
- }
- errorReader.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- return result;
- }
- public void removeBat(String path) {
- File file = new File(path);
- if (file.exists()) {
- boolean isflag = file.delete();
- if (isflag == true){
- System.out.println(getLocalTime()+"刪除bat成功!");
- }
- else {
- System.out.println(getLocalTime()+"刪除bat失敗!");
- }
- } else {
- System.out.println(getLocalTime()+"刪除bat失敗,批處理文件不存在!");
- }
- }
- public String getLocalTime(){
- String time ="[";
- SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- time += df.format(new Date()).toString();
- time+="]";
- return time;
- }
- }
- </span>
這里看主要代碼:
- public static void StartService(String[] args) {
- //啟動服務的方法
- }</span>
- public static void StopService(String[] args) {
- //停止服務的方法
- }</span>
編寫完工程代碼后,將工程打包為jar包。
右鍵項目-Export,選擇打包為JAR包
Finish
JAR包打包完畢,接下來開始做注冊服務的工作。
將之前下載的JavaService解壓得到JavaService.exe后,將它和jar包,統一放到文件夾C:\ECService內(注意,不要有中文路徑,否則服務啟動會失敗)。
其中err.log和out.log是運行服務后JavaService生成的日志文件。
以管理員身份運行cmd,CD到JavaService.exe和jar包所在的目錄
然后執行命令
JavaService.exe -install ECService "%JAVA_HOME%/jre/bin/server/jvm.dll" -Xmx128m -Djava.class.path="%JAVA_HOME%/lib/tools.jar;c:/ECService/ec.jar" -start com.ecservice.ECService -method StartService -stop com.ecservice.ECService -method StopService -out "%CD%/out.log" -err "%CD%/err.log" -current "%CD%" -auto
說明:
1. -install SE : 是你要發布服務的名稱;
2. 你系統環境中設置JAVA_HOME,指定你所需要使用的jre;
3. 在-Djava.class.path中指定你需要運行的jar,這里有個需要注意的地方后面會提到;
4. 設置jvm的基本參數,主要就是內存的分配;
5. 指定信息文件和異常文件,及路徑;
%JAVA_HOME%與環境變量一致,%CD%為當前的目錄路徑,參數-start 指定類ECService的路徑com.ecservice.ECService,-method指定類中要調用的方法名StartService,-auto代表服務開機自動啟動。
JavaService一共提供了8個參數可供選擇,其中我們只需要關心安裝NT服務的-install參數和卸載NT服務的-uninstall參數。
使用-install參數安裝NT服務時還需要提供與服務相關的其它一些參數,其命令格式如下:
JavaService -install service_name jvm_library [jvm_options]
-start start_class [-method start_method] [-params (start_parameters)]
[-stop start_class [-method stop_method] [-params (stop_parameters)]]
[-out out_log_file] [-err err_log_file]
[-current current_dir]
[-path extra_path]
[-depends other_service]
[-auto | -manual]
[-shutdown seconds]
[-user user_name -password password]
[-append | -overwrite]
[-startup seconds]
[-description service_desc]
相關參數的作用說明如下:
service_name: The name of the service.
jvm_library: The location of the JVM DLL used to run the service.
jvm_option: An option to use when starting the JVM, such as:
"-Djava.class.path=c:/classes" or "-Xmx128m".
start_class: The class to load when starting the service.
start_method: The method to call in the start_class. default: main
start_parameters:Parameter(s) to pass in to the start_method.
stop_class: The class to load when stopping the service.
stop_method: The method to call in the stop_class. default: main
stop_parameters: Parameter(s) to pass in to the stop_method.
out_log_file: A file to redirect System.out into. (gets overwritten)
err_log_file: A file to redirect System.err into. (gets overwritten)
current_dir: The current working directory for the service.
Relative paths will be relative to this directory.
extra_path: Path additions, for native DLLs etc. (no spaces)
other_service: Single service name dependency, must start first.
auto / manual: Startup automatic (default) or manual mode.
seconds: Java method processing time (startup:sleep, shutdown:timeout).
user_name: User specified to execute the service (user@domain).
password: Password applicable if user specified to run the service.
append / overwrite: Log file output mode, append (default) or overwrite.
service_desc: Text describing installed service (quoted string, max 1024).
注冊完畢后,執行啟動服務命令
net start ECService
停止服務
net stop ECService
運行命令JavaService -uninstall ECService 可以刪除掉服務。