对于发布后的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控制台中修改文本的显示颜色。在Java中,我们通常不能直接设置控制台的前景(字体)颜色和背景颜色,因为Java的标准`System.out.println()`方法不...
Java模拟Console程序开发框架是一种用于创建命令行界面应用的工具,它可以帮助开发者高效地构建具有交互功能的控制台应用程序。这种框架通常包含一系列类和方法,使得开发者可以专注于业务逻辑,而无需过于关注用户...
JDK 6中新增的Java Console类功能及常见问题
2. **Java Console**:Java Console通常指的是Java应用程序的控制台界面,用于输入和输出数据,调试程序或展示程序运行状态。在这个项目中,"Java Console"可能指的是系统提供的一种命令行界面,允许用户通过文本...
框架 eclipse + java + console + 无数据库 Console图书管理系统 框架 eclipse + java + console + 无数据库 Console图书管理系统 框架 eclipse + java + console + 无数据库 Console图书管理系统 框架 eclipse + ...
《银行管理系统的VC++实现与Console界面详解》 在信息技术高速发展的今天,银行业务的数字化已成为必然趋势。本文将深入探讨一个基于VC++语言开发的银行管理系统,该系统采用Console界面,为用户提供基础的银行服务...
Jboss控制台jmx-console的安全设置
如果你的程序是使用的MFC的界面,但是又需要用console界面进行调试,这个时候就需要像这个程序这样设置和写!
框架 eclipse + java + console + 无数据库 ConsoleTicket投票Socket版 框架 eclipse + java + console + 无数据库 ConsoleTicket投票Socket版 框架 eclipse + java + console + 无数据库 ConsoleTicket投票Socket版...
本工具提取自 oracle 10gR2 Java 版的 OEM Console 解压后,看使用说明,很简单!
它是Java平台标准版(Java SE)的一部分,提供了一个图形用户界面(GUI),使得开发者和系统管理员能够深入洞察应用程序的运行状态,包括内存使用、线程活动、类加载、JVM(Java虚拟机)性能指标等。 开源软件是指...
在Unity中,"Unity界面显示Console工具"是开发者调试和追踪代码的重要辅助工具,尤其对于游戏逻辑、性能优化以及错误排查至关重要。 Unity的Console工具是一个内置的日志查看器,它能够实时显示在运行时引擎生成的...
Java的异常处理机制(try...catch...finally)可以帮助我们优雅地处理这些问题,避免程序因异常而中断。 8. **面向对象设计**:Java鼓励使用面向对象的编程思想,将数据和操作封装在类中。在ATM模拟程序中,可能有...
Java Console Progress Indicator是一款开源的Java库,专门设计用于在控制台上显示进度指示器。这个库为开发者提供了一种简单的方法,以便在执行长时间运行的任务时向用户反馈操作进度,尤其适用于那些没有图形用户...
Java console application that interacts with a REST API for a SQL Database
该API的某些部分也具有可比性,但Console UI不是Inquirer.js的Java克隆。 特征 控制台用户界面当前支持: 具有完成功能和GNU ReadLine兼容编辑的文本输入 选框 清单 扩展选择(帮助和可选列表导航的基于多个键的...
在开发过程中,频繁地操作文件和目录是常见的任务,Java Console通过提供简洁的命令行界面,使得这些操作变得简单易行。用户可以创建、删除、重命名文件,以及浏览和移动目录。此外,它可能还支持批量处理,例如批量...
RocketMQ Console提供了一个友好的图形用户界面,用户可以通过它来查看和管理RocketMQ的主题、队列、消费者和生产者等。主要功能包括发布和订阅主题、查看消息轨迹、监控消费者状态以及进行性能调优等。 2. **应用...
Java中Console对象实例代码 Java中Console对象实例代码是Java 6中引入的新功能,位于java.io包下,提供了访问控制台的功能。Console对象实例代码主要用于控制台输入输出操作,例如读取用户输入、读取密码输入等。 ...
标题中的“在GUI界面上运行Console程序”意味着我们要探讨如何将传统的控制台应用程序(Console Application)集成到图形用户界面(GUI)中,以便用户可以在友好的图形环境下与之交互。这种做法常见于需要提供可视化...