一段时间以来,我一直在尝试创建一个本地进程,该进程将充当我的服务器的 CLI。这个想法类似于Drush所做的Drupal服务器所做的。
我还没有创建 CLI 界面(可能会使用第 3 方代码),但我想分享我的解决方案以解决我在这件事上遇到的最大障碍:在不使用 REST 服务的情况下将本地进程之间的消息传输到我正在运行的服务器和活动服务器,因为他们通过一些命令增加了安全风险。
注意:此代码是用Scala编写的,但可以转换为 Java
首先,我们需要创建一个扩展 HttpServlet 的 servlet 类。对于每个 GET 请求,servlet 类将检查我们的线程(稍后解释)是否打开,如果没有则尝试启动它。请注意,我们在 start 方法中使用了 try catch,因为如果线程的状态为TERMINATED isAlive 将返回 true(我不知道为什么)。
如果 servlet 死了,我还实现了 destroy 方法来杀死我们的线程。我不确定如果 servlet 死了,运行线程会发生什么,但以防万一......
Servlet.scala:
package com.example
import javax.servlet.http.HttpServlet
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
class Servlet extends HttpServlet {
override def doGet(req: HttpServletRequest, resp: HttpServletResponse) = {
if (!CLIThread.isAlive) {
try {
CLIThread.start
}
catch {
case _ => resp.getOutputStream().println("Error: thread state is, " + CLIThread.getState)
}
}
resp.getOutputStream().println(CLIThread.pool)
}
override def destroy(): Unit = {
super.destroy()
CLIThread.shutdown
}
}
我们的线程(CLIThread)是扩展Thread的scala 对象类
CLIThread 有 2 个方法,pool 和 shutdown,它们都传递给我们的Runnable实现。
CLIRunnable 是传递给 Thread 构造函数的 Runnable 实现对象。
CLIRunnable 有一个空的 ServerSocket (listener)、Socket (socket) 和 InputStream (in)、一个真正的 Boolean (keepAlive) 和一个空的 String (_pool) 作为变量。
运行方法:
池方法:
关机方法:
CLIThread.scala
package com.example
import java.io.InputStream
import java.net.ServerSocket
import java.net.Socket
object CLIThread extends Thread(CLIRunner) {
def pool: String = CLIRunner.pool
def shutdown() = CLIRunner.shutdown()
}
protected final object CLIRunner extends Runnable {
var listener: ServerSocket = null
var socket: Socket = null
var in: InputStream = null
private var keepAlive = true
private var _pool = ""
def run: Unit = {
var ok = false
while (!ok) {
try {
listener = new ServerSocket((math.random * 10000).toInt)
ok = true;
}
catch {
case _ => {}
}
}
socket = listener.accept()
in = socket.getInputStream
while (keepAlive) {
while (in.available() > 0) _pool += in.read().toChar
}
}
def pool: String = if (in != null) {
val temp = _pool
_pool = ""
return temp
}
else if (listener != null) (listener.getInetAddress, listener.getLocalPort).toString
else "listener == null..."
def shutdown() {
keepAlive = false
if (listener != null) {
if (socket == null)
(new Socket(listener.getInetAddress, listener.getLocalPort)).close()
if (socket != null)
socket.close()
listener.close()
}
}
}
CLI.scala
package com.example
import java.net.Socket
import java.net.URL
object CLI extends App {
val addr = args(0) // The server address (example.com:8080)
val addrUrl = new URL("http://" + addr + "/~cli/addr")
var con = addrUrl.openConnection()
var in = con.getInputStream()
var cliAddr = ""
while (in.available() > 0)
cliAddr += in.read.toChar
val portUrl = new URL("http://" + addr + "/~cli/port")
con = portUrl.openConnection()
in = con.getInputStream()
var cliPort = ""
while (in.available() > 0)
cliPort += in.read.toChar
val socket = new Socket(cliAddr, Integer.valueOf(cliPort))
implicit def stringToByteArray(s: String) = s.toCharArray.map(c => c.toByte)
socket.getOutputStream().write("Hellllo from CLI process")
}
CliAddr.scala
package org.sdms
import javax.servlet.http.HttpServlet
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
class CliAddr extends HttpServlet {
override def doGet(req: HttpServletRequest, resp: HttpServletResponse) {
resp.getWriter.print(CLIRunner.listener.getInetAddress.getHostAddress)
}
}
CliPort.scala
package com.example
import javax.servlet.http.HttpServlet
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
class CliPort extends HttpServlet {
override def doGet(req: HttpServletRequest, resp: HttpServletResponse) {
resp.getWriter.print(CLIRunner.listener.getLocalPort)
}
}