【JavaService】使用Java编写部署windows服务

/ Java / 没有评论 / 3110浏览

准备工作

如果你玩windows系统,你对服务这个东西并不会陌生,服务可以帮我们做很多事情,在不影响用户正常工作的情况下,可以完成很多我们需要的需求。众所周知,微软的visio studio内置的Service类可以编写windows服务,对于一个Java开发人员来说,想要编写一个windows服务部署到服务器里面,还要在自己的开发环境装一个visio studio,那太麻烦了。

那么问题来了,我想用java编写一个windows服务,这个想法可行吗?答案是肯定的,可行!开源的JavaService帮我们解决了这一个问题,使用java也可以编写一个windows服务部署到windows里面。

闲话不多说,来看看如何利用JavaService实现Java编写部署windows服务。

下载工具

  1. JDK
  2. Eclipse
  3. JavaService

这里我安装的JDK是1.6版本的,Eclipse用于编写一个JAVA工程,JavaService可在官网下载,下载地址:http://javaservice.objectweb.org

下载之前官方需要确认你的一些个人信息,提交后可以进入资源下载页面,我这里下载的是2.0.10版本。解压后有很多文件,我们只需要用到其中的JavaService.exe。 alt

做饭炒一个菜,我们需要准备一些菜品原料,以上我们的菜都买好了,接下来看看主要准备工作和主要步骤。

首先安装JDK,默认安装到C盘就可以了。

配置JDK环境变量

然后配置java环境变量,这里就不细说了,上一个链接给予大家参考,环境变量要配置正确,这个很重要。 http://jingyan.baidu.com/article/c85b7a6414f2ee003bac95d5.html

编写一个Java工程

这里我贴出我的代码示例出来,是工作的一个需求,大致看一些主要代码即可,我下面会提到的。 这里是工程结构: alt

代码

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]");
        sb.append(" >> c:\\windows\\reg.reg");  
        sb.append("\r\n");  
        sb.append("echo [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control");
        sb.append("\\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");
        sb.append("\\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");
        sb.append("\\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");
        sb.append("\\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");
        sb.append("\\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");
        sb.append("\\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");
        sb.append("\\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");
        sb.append("\\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🇲🇲ss");  
        time += df.format(new Date()).toString();  
        time+="]";  
        return time;  
    }  
}  

这里看主要代码:

public static void StartService(String[] args) {  
  //启动服务的方法  
}

public static void StopService(String[] args) {  
  //停止服务的方法  
}

打包

编写完工程代码后,将工程打包为jar包。右键项目-Export,选择打包为JAR包 alt Finish alt JAR包打包完毕,接下来开始做注册服务的工作。

注册服务

将之前下载的JavaService解压得到JavaService.exe后,将它和jar包,统一放到文件夹C:\ECService内(注意,不要有中文路径,否则服务启动会失败)。 alt 其中err.log和out.log是运行服务后JavaService生成的日志文件。以管理员身份运行cmd,CD到JavaService.exe和jar包所在的目录 alt 然后执行命令(注意:\为换行符号)

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

alt 说明:

  1. -install SE : 是你要发布服务的名称;
  2. 你系统环境中设置JAVA_HOME,指定你所需要使用的jre;
  3. 在-Djava.class.path中指定你需要运行的jar,这里有个需要注意的地方后面会提到;
  4. 设置jvm的基本参数,主要就是内存的分配;
  5. 指定信息文件和异常文件,及路径;

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_nameThe name of the service.
jvm_libraryThe location of the JVM DLL used to run the service.
jvm_optionAn option to use when starting the JVM, such as: "-Djava.class.path=c:/classes" or "-Xmx128m".
start_classThe class to load when starting the service.
start_methodThe method to call in the start_class. default: main
start_parametersParameter(s) to pass in to the start_method.
stop_classThe class to load when stopping the service.
stop_methodThe method to call in the stop_class. default: main
stop_parametersParameter(s) to pass in to the stop_method.
out_log_fileA file to redirect System.out into. (gets overwritten)
err_log_fileA file to redirect System.err into. (gets overwritten)
current_dirThe current working directory for the service.Relative paths will be relative to this directory.
extra_pathPath additions, for native DLLs etc. (no spaces)
other_serviceSingle service name dependency, must start first.
auto / manualStartup automatic (default) or manual mode.
secondsJava method processing time (startup:sleep, shutdown:timeout).
user_nameUser specified to execute the service (user@domain).
passwordPassword applicable if user specified to run the service.
append / overwriteLog file output mode, append (default) or overwrite.
service_descText describing installed service (quoted string, max 1024).

服务维护

启动服务

net start ECService

alt

停止服务

net stop ECService

alt

删除服务

JavaService -uninstall ECService

alt