`
yiqieanhao
  • 浏览: 67420 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

优雅地关闭java console界面

    博客分类:
  • JAVA
阅读更多
对于发布后的jar或class,我们经常会写一些bat脚本来方便地使之运行,比如:
java -jar XXX.jar
一旦双击这个bat脚本,会启动一个黑色的console界面,如果不需要这个,可以修改为:
@echo off
start javaw -jar xxx.jar 

某些时候,我们是需要这个console界面的,因为日志(system.out.print或logger.debug等)都可以很好地实时显示。但问题是:当需要关闭程序时,你指望别人会去按ctrl+C来终止,从而调用你的shutdownHook?呵呵,一般不会。那么,怎么实时看到日志,又可以优雅地关闭程序?我们有两个思路:

  • 双击bat后,执行自己的Java桌面应用,不显示console界面,把日志包括系统的system.out.print和log4j的日志都显示在自己的界面里。此时要关闭事件可以很容易捕捉。
  • 双击bat后,显示console界面,当用户关闭窗口时,捕获事件,回调java的善后处理方法。

第一个方法经过测试是可以实现的,但貌似很暴力,而且大多时候我只是想运行的时候看看日志,为什么还要拿个swing程序来封装?第二个办法还是更人性化一些。下面我们就看看如何实现。

实现依据:当用户关闭console窗口时,触发的是ctrl+close事件,详见这里。所以需要依靠JNI或是JNA来捕获底层事件。关于JNI的实现可以参考这里,下面我再整理一下:

JNI实现:
import java.io.File;
import java.io.IOException;

public class TestConsoleHandler {

	private static Thread hook;

	public static void main(String[] args) {
		System.out.println("Start");
		hook = new ShutdownHook();
		Runtime.getRuntime().addShutdownHook(hook);
		replaceConsoleHandler(); // actually not "replace" but "add"

		try {
			Thread.sleep(10000); // You have 10 seconds to close console
		} catch (InterruptedException e) {
		}
	}

	public static void shutdown() {
		hook.run();
	}

	private static native void replaceConsoleHandler();

	static {
		System.loadLibrary("TestConsoleHandler");
	}
}

class ShutdownHook extends Thread {
	public void run() {
		try {
			// do some visible work
			new File("d:/shutdown.mark").createNewFile();
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println("Shutdown");
	}
}


执行javah TestConsoleHandler来获取TestConsoleHandler.h。
在visual studio里新建c++项目  -> win32(dll)项目TestConsoleHandler,将TestConsoleHandler.h导入头文件,编写TestConsoleHandler.cpp如下:
#include "stdafx.h"
#include "TestConsoleHandler.h"

JavaVM *jvm;

BOOL WINAPI HandlerRoutine(__in DWORD dwCtrlType) {
    if (dwCtrlType == CTRL_CLOSE_EVENT) {
        JNIEnv *env;
        jint res =  jvm->AttachCurrentThread((void **)(&env), &env);
        jclass cls = env->FindClass("TestConsoleHandler");
        jmethodID mid = env->GetStaticMethodID(cls, "shutdown", "()V");
        env->CallStaticVoidMethod(cls, mid);
        jvm->DetachCurrentThread();
        return TRUE;
    }
    return FALSE;
}

JNIEXPORT void JNICALL Java_TestConsoleHandler_replaceConsoleHandler(JNIEnv *env, jclass clazz) {
 env->GetJavaVM(&jvm);
 SetConsoleCtrlHandler(&HandlerRoutine, TRUE);
}

编译成dll拷贝到java项目根目录即可。

JNA实现:
import java.io.File;
import java.io.IOException;

import com.sun.jna.Callback;
import com.sun.jna.Library;
import com.sun.jna.Native;


public class TestJnaConsoleHandler {
	private static Thread hook;
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		System.out.println("Start");
		hook = new ShutdownHook2();
		Runtime.getRuntime().addShutdownHook(hook);
        CLib lib = (CLib) Native.loadLibrary("TestJnaConsoleHandler", CLib.class);
        lib.init(new CLib.OpenFunc() {
            public void invoke(String name, int i) {                
            	hook.run();        		
            }
        });
        lib.replaceConsoleHandler();
        
    	try {
			Thread.sleep(10000); // You have 10 seconds to close console
		} catch (InterruptedException e) {
		}
	}
	public interface CLib extends Library{
	    public interface OpenFunc extends Callback {
	        void invoke(String name, int i);
	    }
	    void init(OpenFunc openfunc);
	    void replaceConsoleHandler();
	}
}

class ShutdownHook2 extends Thread {
	public void run() {
		try {
			// do some visible work
			new File("d:/shutdown.mark").createNewFile();
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println("Shutdown");
	}
}



c++实现:
#include "stdafx.h"
#include <iostream>

using namespace std;

#define MYLIBAPI  extern   "C"     __declspec( dllexport ) 


typedef void (*OpenFunc)(const char*,int);
OpenFunc openfunc = NULL;
MYLIBAPI void init(OpenFunc func) {
        cout << "init called" <<endl;
        openfunc = func;
}

BOOL WINAPI HandlerRoutine(__in DWORD dwCtrlType) {
    if (dwCtrlType == CTRL_CLOSE_EVENT) {

        (*openfunc)("test", 0);

        return TRUE;
    }
    return FALSE;
}

MYLIBAPI void replaceConsoleHandler() {
 SetConsoleCtrlHandler(&HandlerRoutine, TRUE);
}


至此,当用户关闭console窗口或是按下ctrl+C时,都会调用预定义的方法来优雅地处理。
分享到:
评论

相关推荐

    java console程序改变字的颜色和背景颜色

    标题"java console程序改变字的颜色和背景颜色"所指的就是如何在Java控制台中修改文本的显示颜色。在Java中,我们通常不能直接设置控制台的前景(字体)颜色和背景颜色,因为Java的标准`System.out.println()`方法不...

    java模拟Console程序开发框架

    Java模拟Console程序开发框架是一种用于创建命令行界面应用的工具,它可以帮助开发者高效地构建具有交互功能的控制台应用程序。这种框架通常包含一系列类和方法,使得开发者可以专注于业务逻辑,而无需过于关注用户...

    JDK 6中新增的Java Console类功能及常见问题

    JDK 6中新增的Java Console类功能及常见问题

    jbpm-console.rar_Java 企业OA_java console_jbpm_jbpm-side_工作流

    2. **Java Console**:Java Console通常指的是Java应用程序的控制台界面,用于输入和输出数据,调试程序或展示程序运行状态。在这个项目中,"Java Console"可能指的是系统提供的一种命令行界面,允许用户通过文本...

    Console图书管理系统,框架 eclipse + java + console + 无数据库

    框架 eclipse + java + console + 无数据库 Console图书管理系统 框架 eclipse + java + console + 无数据库 Console图书管理系统 框架 eclipse + java + console + 无数据库 Console图书管理系统 框架 eclipse + ...

    银行管理系统VC++版本,console界面

    《银行管理系统的VC++实现与Console界面详解》 在信息技术高速发展的今天,银行业务的数字化已成为必然趋势。本文将深入探讨一个基于VC++语言开发的银行管理系统,该系统采用Console界面,为用户提供基础的银行服务...

    Jboss控制台jmx-console的安全设置

    Jboss控制台jmx-console的安全设置

    windows的MFC程序添加console界面

    如果你的程序是使用的MFC的界面,但是又需要用console界面进行调试,这个时候就需要像这个程序这样设置和写!

    Ticket投票Socket版,框架 eclipse + java + console + 无数据库

    框架 eclipse + java + console + 无数据库 ConsoleTicket投票Socket版 框架 eclipse + java + console + 无数据库 ConsoleTicket投票Socket版 框架 eclipse + java + console + 无数据库 ConsoleTicket投票Socket版...

    Oracle 10gR2 OEM java console oem java客户端

    本工具提取自 oracle 10gR2 Java 版的 OEM Console 解压后,看使用说明,很简单!

    JavaConsole-开源

    它是Java平台标准版(Java SE)的一部分,提供了一个图形用户界面(GUI),使得开发者和系统管理员能够深入洞察应用程序的运行状态,包括内存使用、线程活动、类加载、JVM(Java虚拟机)性能指标等。 开源软件是指...

    Unity界面显示Console工具

    在Unity中,"Unity界面显示Console工具"是开发者调试和追踪代码的重要辅助工具,尤其对于游戏逻辑、性能优化以及错误排查至关重要。 Unity的Console工具是一个内置的日志查看器,它能够实时显示在运行时引擎生成的...

    ATM.rar_ATM Java console_atm java_atm 模拟程序_java ATM_java card

    Java的异常处理机制(try...catch...finally)可以帮助我们优雅地处理这些问题,避免程序因异常而中断。 8. **面向对象设计**:Java鼓励使用面向对象的编程思想,将数据和操作封装在类中。在ATM模拟程序中,可能有...

    解决html,servlet,sql,java console中文问题

    ### 解决 HTML、Servlet、SQL、Java Console 中的中文问题 #### 1....通过以上步骤,可以有效地解决 HTML、Servlet、SQL、Java Console 在处理中文时可能遇到的问题,确保中文字符的正确显示和传输。

    Java Console Progress Indicator-开源

    Java Console Progress Indicator是一款开源的Java库,专门设计用于在控制台上显示进度指示器。这个库为开发者提供了一种简单的方法,以便在执行长时间运行的任务时向用户反馈操作进度,尤其适用于那些没有图形用户...

    Java console application that interacts with a REST API for a SQ

    Java console application that interacts with a REST API for a SQL Database

    consoleui:微型Java库,可在基于ANSI控制台的终端上启用简单的UI元素

    该API的某些部分也具有可比性,但Console UI不是Inquirer.js的Java克隆。 特征 控制台用户界面当前支持: 具有完成功能和GNU ReadLine兼容编辑的文本输入 选框 清单 扩展选择(帮助和可选列表导航的基于多个键的...

    Java_console:Java 控制台用于管理文件、目录、URL、DBMS。-开源

    在开发过程中,频繁地操作文件和目录是常见的任务,Java Console通过提供简洁的命令行界面,使得这些操作变得简单易行。用户可以创建、删除、重命名文件,以及浏览和移动目录。此外,它可能还支持批量处理,例如批量...

    rocketmq-console后台管理jar包

    RocketMQ Console提供了一个友好的图形用户界面,用户可以通过它来查看和管理RocketMQ的主题、队列、消费者和生产者等。主要功能包括发布和订阅主题、查看消息轨迹、监控消费者状态以及进行性能调优等。 2. **应用...

    Java中Console对象实例代码

    Java中Console对象实例代码 Java中Console对象实例代码是Java 6中引入的新功能,位于java.io包下,提供了访问控制台的功能。Console对象实例代码主要用于控制台输入输出操作,例如读取用户输入、读取密码输入等。 ...

Global site tag (gtag.js) - Google Analytics