Моя цель состояла в том, чтобы создать Java-сервис в Windows, который будет работать локально и взаимодействовать с локальными программами с использованием JSON. Услуга должна быть надежной и надежной.
Служба запускает ServerSocket и получает и отвечает на сообщения JSON. Ниже приведен скелет, в котором соответствующие «команды» будут добавлены в класс SigningController. Сервис, скорее всего, останется небольшим и будет содержать ~ 10 различных команд.
Вопросы
Является ли сервер надежным (т. Е. Нет потенциальных зависаний, исключений и т. Д.)?
Я заметил, что после интенсивного использования (отправка большого количества команд "echo" с большими строками) использование памяти увеличивается до ~ 530 МБ, а затем медленно уменьшается. У меня есть утечка ресурсов или памяти, или это стандартное поведение JVM?
Может быть, не по теме, но есть ли способ изменить имя и значок задачи, которые отображаются в диспетчере задач? В настоящее время этот процесс отображается как «двоичный файл Java (TM) Platform SE».
Служба установлена с nssm и файлами bat
install.bat (от имени администратора)
@echo off
pushd %~dp0
nssm.exe stop JavaSigningService
nssm.exe remove JavaSigningService confirm
nssm.exe install JavaSigningService %~dp0start.bat
nssm.exe start JavaSigningService
popd
pause
start.bat
java -Xmx512m -jar signingservice.jar
Файл POM и классы ниже.
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>Server.Main</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<finalName>signingservice</finalName>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<modelVersion>4.0.0</modelVersion>
<groupId>...</groupId>
<artifactId>signingservice</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
</dependencies>
</project>
Main
package Server;
import java.net.ServerSocket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
int port = Integer.parseInt(args[0]);
try (ServerSocket listener = new ServerSocket(port)) {
System.out.println("Server is running...");
ExecutorService pool = Executors.newFixedThreadPool(10);
while (true) {
try {
pool.execute(new Signer(listener.accept()));
} catch (Exception e){
// Log
}
}
} catch (Exception e) {
// Log
} finally {
System.exit(0);
}
}
}
Utils
package Server;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.io.PrintWriter;
import java.io.StringWriter;
public class Utils {
private static JsonParser parser = new JsonParser();
public static JsonObject getJsonFromString(String str) throws Exception{
JsonObject jsonObject = parser.parse(str).getAsJsonObject();
return jsonObject;
}
public static String getJsonProperty(JsonObject json, String property){
String value = null;
try {
value = json.get(property).getAsString();
} catch (Exception e) {}
return value;
}
public static JsonObject errorMessageTemplate(Exception e){
JsonObject result = new JsonObject();
result.addProperty("result", "ERROR");
result.addProperty("errormessage", e.getMessage());
result.addProperty("stacktrace", stackTraceAsString(e));
return result;
}
public static String stackTraceAsString(Exception e){
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
return sw.toString();
}
}
SigningController
package Server;
import com.google.gson.JsonObject;
public class SigningController {
public static JsonObject handle(JsonObject received) throws Exception{
String command = Utils.getJsonProperty(received, "command");
if("echo".equals(command)){
return simpleEcho(received);
}
return Utils.errorMessageTemplate(new Exception("Command not specified or unknown."));
}
public static JsonObject simpleEcho(JsonObject received) throws Exception{
String data = "" + Utils.getJsonProperty(received, "data");
JsonObject result = new JsonObject();
result.addProperty("result", "OK");
result.addProperty("data", data);
return result;
}
}
подписывающего
package Server;
import com.google.gson.JsonObject;
import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class Signer implements Runnable{
private Socket socket;
private BufferedReader socketIn;
private PrintWriter socketOut;
Signer(Socket socket) throws IOException {
this.socket = socket;
this.socket.setSoTimeout(60*1000); // read timeout in milliseconds
socketIn = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
socketOut = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8), true);
}
@Override
public void run() {
System.out.println("Connected: " + socket);
try {
socketOut.println("hello");
String line = socketIn.readLine();
JsonObject json = Utils.getJsonFromString(line);
JsonObject result = SigningController.handle(json);
socketOut.println(result);
} catch (Exception e){
// Log
System.out.println("Error: " + socket);
e.printStackTrace();
try {
socketOut.println(Utils.errorMessageTemplate(e));
} catch (Exception e1) {}
} finally{
// Cleanup
try{
socketIn.close();
} catch (IOException e){
e.printStackTrace();
}
try{
socketOut.close();
} catch (Exception e){
e.printStackTrace();
}
try{
socket.close();
System.out.println("Closed: " + socket);
} catch (IOException e){
e.printStackTrace();
}
}
}
}