- Создание Windows службы на Java
- Введение
- Создание минимизированной версии JRE
- Создание Windows службы из любого приложения
- WinSW
- Взаимодействие Java и Windows API
- Работа с процессами
- Взаимодействие с другими компонентами системы
- WebSocket
- HTTP-клиент
- Заключение
- How to find the process id of a running Java process on Windows? And how to kill the process alone?
- 8 Answers 8
- How to get a list of current open windows/process with Java?
- 14 Answers 14
Создание Windows службы на Java
February 22, 2019 Jazz Team Технические статьи
Введение
В рамках одного из проектов требовалось разработать Windows службу, которая могла бы выполнять ряд действий с помощью Windows API, Websocket и стандартных средств Java. Далее в статье будут описаны шаги, которые были сделаны для создания такой службы.
Потребность в Windows службе возникла из-за необходимости иметь программу со следующими возможностями:
- она должна быть постоянно запущена,
- выполнялась от системного пользователя,
- автоматически запускалась при старте системы,
- чтобы её сложно было остановить обычному пользователю.
Создание минимизированной версии JRE
Так как GraalVM всё ещё не поддерживает создание исполняемых файлов под Windows, было решено воспользоваться другими возможностями, которые предоставляет экосистема Java, а именно создание минимизированной версии JRE.
Для того, чтобы создать минимизированную версию JRE, для начала необходимо узнать зависимости на определенные пакеты, которые будут включены в JRE.
В первую очередь необходимо собрать jar-файл “fat jar” со всеми зависимостями.
Затем выполнить команду jdeps -s , чтобы получить список всех зависимостей. Например:
Далее создаём нашу версию JRE с данными зависимостями:
jlink –module-path –add-modules
java.base,java.datatransfer,java.desktop,java.logging,java.net.http,java.sql,java.xml,jdk.unsupported –strip-debug –compress 2 –no-header-files –no-man-pages –output
Обратите внимание, что перечисление пакетов для опции –add-modules необходимо разделять запятой и не ставить между ними пробелов. Остальные опции отвечают за сжатие и убирание файлов и другой информации, которая не пригодится для выполнения программы.
После выполнения этих действий JRE будет занимать порядка 30 mb, вместо сотен.
Создание Windows службы из любого приложения
Java не имеет стандартных средств по созданию служб, поэтому были изучены сторонние инструменты и был выбран WinSW в силу его бесплатности и простоты использования.
WinSW
WinSW – это утилита, которая позволяет запустить и обернуть любой процесс как Windows службу. Для того, чтобы начать с ней работать, необходимо скачать исполняемый и конфигурационный файлы по этой ссылке https://github.com/kohsuke/winsw/releases.
Необходимо поместить эти два файла в директорию. Переименовать исполняемый файл на своё усмотрение и дать такое же название файлу конфигурации, затем поместить в эту директорию jar-файл приложения и созданную JRE.
В конфигурационном файле необходимо прописать минимальную конфигурацию:
jre\bin\java.exe – относительный путь внутри нашей папки к исполняемому файлу нашей JRE.
После этих действий можно установить службу, для этого необходимо выполнить команду от имени администратора:
Список команд можно посмотреть здесь .
Взаимодействие Java и Windows API
Для использования функций Windows (таких как создание нового процесса или добавление ключей реестра) в нашем приложении был использован JNA.
JNA (Java Native Access) предоставляет Java-программам легкий доступ к библиотекам, написанным на другом языке, без написания чего-либо, кроме кода Java. JNA позволяет напрямую вызывать нативные функции, используя обычный вызов метода Java. Большинство методов не требуют специальной обработки или конфигурации; не требуется шаблон или сгенерированный код.
Подключить и работать с JNA очень просто, для этого необходимо скачать jar-файл или подключить зависимость в сборщик проекта – в нашем случает Maven:
В нашем проекте мы использовали JNA для достижения следующих целей: заблокировать и сделать вновь доступным диспетчер задач 1) по комбинации Ctrl+Shift+Esc и 2) в меню, доступном по комбинации Ctrl+Alt+Del.
Для достижения этого были использованы класс Advapi32Util (удобная обёртка над библиотекой advapi32.dll) и интерфейс WinReg с полезными константами , которые предоставляют функциональность для внесения изменений в реестр Windows (Рисунок 1. Класс TaskManager с методами enable() и disable() для изменения ключей реестра диспетчера задач).
Рисунок 1. Класс TaskManager с методами enable() и disable() для изменения ключей реестра диспетчера задач.
- Создать новый процесс от имени определённого пользователя Windows. Для этого мы использовали метод CreateProcessAsUser()интерфейса Advapi32. В метод необходимо передать следующие параметры:
- hToken – дескриптор токена пользователя, для которого мы запускаем процесс.
- lpApplicationName – имя модуля, который должен быть выполнен.
- lpCommandLine – командная строка для выполнения.
- lpProcessAttributes – указатель на структуру SECURITY_ATTRIBUTES, которая определяет дескриптор безопасности для нового объекта процесса и определяет, могут ли дочерние процессы наследовать возвращенный дескриптор процесса.
- lpThreadAttributes – указатель на структуру SECURITY_ATTRIBUTES, который определяет дескриптор безопасности для нового объекта потока и определяет, могут ли дочерние процессы наследовать возвращенный дескриптор потока.Создать новый процесс от имени определённого пользователя Windows. Для этого мы использовали метод CreateProcessAsUser() интерфейса Advapi32. В метод необходимо передать следующие параметры:
- bInheritHandles – если этот параметр TRUE, каждый наследуемый дескриптор вызывающего процесса наследуется новым процессом. Если параметр FALSE, процессы не наследуются.
- dwCreationFlags – флаги, которые контролируют класс приоритета и создают процесс.
- lpEnvironment – указатель на блок среды для нового процесса. Если этот параметр равен NULL, новый процесс использует среду вызывающего процесса. Блок среды состоит из блока с нулевым завершением строк с нулевым завершением. Каждая строка имеет следующий вид: name = value \ 0.
- lpCurrentDirectory – полный путь к текущему каталогу для процесса. Строка также может указывать путь UNC (universal naming convention).
- lpStartupInfo – указатель на структуру STARTUPINFO или STARTUPINFOEX.lpProcessInformation – указатель на структуру PROCESS_INFORMATION, которая получает идентификационную информацию о новом процессе.
Рисунок 2. Метод для создания нового процесса для определённого пользователя Windows.
- Получить токен активного пользователя, т.к. он необходим для создания процесса от определённого пользователя.
Работа с процессами
Для работы и слежения за процессами в Windows был использован, добавленный в Java 9, класс ProcessHandle. ProcessHandle позволяет получать и производить различные манипуляции с процессами. В частности, при решении задачи, требовалось собирать PID процессов, фильтровать процессы на основе имени и принудительно завершать необходимые процессы.
Рисунок 3. Класс ProcessHandler с методами takeSnapshot() для создания снимка текущих процессов и closeNewProcesses() для завершения процессов, отличных от снимка.
Взаимодействие с другими компонентами системы
WebSocket
Для Java существует стандартизированный API для работы с WebSocket.
Но одного API недостаточно, поэтому для запуска кода была выбрана одна из его реализаций – Tyrus.
Далее можно создать минималистичный сервер и указать обработчики (EndPoints).
Заготовка обработчика выглядит следующим образом:
HTTP-клиент
С выпуском 11-ой версии Java в ней появился удобный HTTP-клиент, поэтому потребность в сторонних клиентах исчезла.
Для создания экземпляра клиента необходимо воспользоваться билдером. В простейшем случае:
Далее необходимо создать запрос(request), например:
Затем этот запрос можно использовать для отправки на сервер:
Заключение
Благодаря модульной организации версий Java 9 и выше, утилите WinSW, обновлённому Process API для взаимодействия с процессами операционной системы и библиотеки JNA (Java Native Access), которая предоставляет программам Java простой доступ к нативным библиотекам, мы смогли создать Windows службу с использованием языка Java, на котором была реализована и серверная часть. Что в итоге позволило не вводить в процесс разработки новый язык.
How to find the process id of a running Java process on Windows? And how to kill the process alone?
I want to kill the particular Java process in Windows, like in Linux ( ps -aux to get processid and then kill processid to kill the process).
8 Answers 8
You can use the jps utility that is included in the JDK to find the process id of a Java process. The output will show you the name of the executable JAR file or the name of the main class.
Then use the Windows task manager to terminate the process. If you want to do it on the command line, use
You can also find the PID of a java program with the task manager. You enable the PID and Command Line columns View -> Select Columns and are then able to find the right process.
Your result will be something like this :
After setting the path of your jdk use JPS .Then You can eaisly kill it by Task Manager
JPS will give you all java processes
This will work even when there are multiple instance of jar is running
The solution I found is very simple. Use Window’s WMIC & Java’s Runtime to locate & kill the process.
Part 1: You need to put some sort of identifier into your app’s startup command line. E.g. something like:
Part 2: When you run your app, make sure to include the string. Let’s say you start it from within Java, do the following:
Part 3: To kill the process, use Window’s WMIC. Just make sure you app was started containing your id from above:
In windows XP and later, there’s a command: tasklist that lists all process id’s.
For killing a process in Windows, see:
You can execute OS-commands in Java by:
If you need to handle the output of a command, see example: using Runtime.exec() in Java
This is specific to Windows. I was facing the same issue where I have to kill one specific java program using taskkill. When I run the java program, tasklist was showing the same program with Image name set as java.exe. But killing it using taskkill /F java.exe will stop all other java applications other than intended one which is not required.
So I run the same java program using:
Here start command will open a new window and run the java program with window’s title set to MyProgramName.
Now to kill this java-program use the following taskkill command:
Your Java program will be killed only. Rest will be unaffected.
How to get a list of current open windows/process with Java?
Does any one know how do I get the current open windows or process of a local machine using Java?
What I’m trying to do is: list the current open task, windows or process open, like in Windows Taskmanager, but using a multi-platform approach — using only Java if it’s possible.
14 Answers 14
This is another approach to parse the the process list from the command «ps -e«:
If you are using Windows, then you should change the line: «Process p = Runtime.getRun. » etc. (3rd line), for one that looks like this:
Hope the info helps!
Finally, with Java 9+ it is possible with ProcessHandle :
On Windows there is an alternative using JNA:
The only way I can think of doing it is by invoking a command line application that does the job for you and then screenscraping the output (like Linux’s ps and Window’s tasklist).
Unfortunately, that’ll mean you’ll have to write some parsing routines to read the data from both.
YAJSW (Yet Another Java Service Wrapper) looks like it has JNA-based implementations of its org.rzo.yajsw.os.TaskList interface for win32, linux, bsd and solaris and is under an LGPL license. I haven’t tried calling this code directly, but YAJSW works really well when I’ve used it in the past, so you shouldn’t have too many worries.
You can easily retrieve the list of running processes using jProcesses
There is no platform-neutral way of doing this. In the 1.6 release of Java, a «Desktop» class was added the allows portable ways of browsing, editing, mailing, opening, and printing URI’s. It is possible this class may someday be extended to support processes, but I doubt it.
If you are only curious in Java processes, you can use the java.lang.management api for getting thread/memory information on the JVM.
For windows I use following:
This might be useful for apps with a bundled JRE: I scan for the folder name that i’m running the application from: so if you’re application is executing from:
then you can find if it’s already running in J9, by:
Using code to parse ps aux for linux and tasklist for windows are your best options, until something more general comes along.
Linux can pipe the results of ps aux through grep too, which would make processing/searching quick and easy. I’m sure you can find something similar for windows too.
The below program will be compatible with Java 9+ version only.
To get the CurrentProcess information,
For all running processes,
We have to use process.getOutputStream.close() otherwise it will get locked in while loop.
TASKLIST /v /FI «STATUS eq running» /FO «CSV» /FI «Username eq LHPL002\soft» /FI «MEMUSAGE gt 10000» /FI «Windowtitle ne N/A» /NH