在内存有限的Linux环境中使用Java来监听远程服务器上的多个目录文件,并在生成文件后将其复制到另一个目录,可以采用以下几种方式来实现:
-
使用JSch库连接远程服务器并监控文件变化: JSch(Java Secure Channel)是一个纯Java实现的SSH2客户端库,可以用来连接远程服务器,执行命令,以及进行文件传输。通过定期轮询的方式检查远程目录的文件变化,可以在发现新文件后进行复制操作。
-
使用Apache Commons VFS(Virtual File System): Apache Commons VFS是一个文件系统抽象层库,支持包括SFTP在内的多种文件系统协议。通过VFS可以方便地访问远程服务器的文件系统,并对其进行操作。
-
使用WatchService API本地监听文件系统变化: Java 7引入了WatchService API,可以监听本地文件系统的变化。如果远程目录可以通过NFS、CIFS等方式挂载到本地文件系统,可以利用WatchService API进行监听。
以下是使用JSch库的示例代码:
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import java.io.InputStream;
import java.util.Properties;
import java.util.Vector;
public class RemoteFileMonitor {
private static final String USER = "username";
private static final String HOST = "remote-host";
private static final int PORT = 22;
private static final String PASSWORD = "password";
private static final String REMOTE_DIR = "/remote/directory";
private static final String LOCAL_DIR = "/local/directory";
public static void main(String[] args) {
try {
JSch jsch = new JSch();
Session session = jsch.getSession(USER, HOST, PORT);
session.setPassword(PASSWORD);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect();
while (true) {
Vector<ChannelSftp.LsEntry> list = channelSftp.ls(REMOTE_DIR);
for (ChannelSftp.LsEntry entry : list) {
if (!entry.getAttrs().isDir()) {
String remoteFilePath = REMOTE_DIR + "/" + entry.getFilename();
String localFilePath = LOCAL_DIR + "/" + entry.getFilename();
try (InputStream inputStream = channelSftp.get(remoteFilePath)) {
java.nio.file.Files.copy(inputStream, java.nio.file.Paths.get(localFilePath));
System.out.println("Copied: " + entry.getFilename());
}
}
}
Thread.sleep(5000); // 每隔5秒检查一次
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
以上代码每隔5秒检查一次远程目录中的文件,并将新文件复制到本地目录。你可以根据需要调整轮询间隔时间和其他参数。
注意事项:
确保远程服务器的SSH配置允许连接和文件传输。
- 根据实际需求调整轮询间隔,避免过于频繁的检查导致资源浪费。
- 如果目录中文件数量较多,可以优化代码,避免重复复制已经存在的文件。
如果对文件变化的响应时间要求较高,可以考虑使用更加复杂的事件驱动方式或其他优化手段来降低轮询的频率和延迟。java1.8在3.43这台机器上同时监听20.12和20.16两台虚拟机的多个目录下的不通文件,为了避免频繁的连接可不可以保持连接状态下一直监听多个目录的不同文件,如果监听到了一个目录下的文件,就把文件复制到/data/file里然后结束这个目录文件的监听,继续监听其他目录文件,通过接口调用开启监听,通过接口控制停止监听
要在Java 1.8中实现同时监听多个远程目录,并在检测到文件生成后将其复制到本地目录,可以保持连接状态进行持续监听,并通过接口进行控制。以下是实现这个功能的详细步骤和示例代码:
- 保持SSH连接状态:使用JSch库创建到两台虚拟机(20.12和20.16)的持久连接。
- 多线程监听多个目录:使用多线程来监听多个目录的文件变化,每个线程负责一个目录。
- 接口控制监听:通过HTTP接口来启动和停止监听。
首先,引入必要的依赖项:
<!-- Add this to your pom.xml if you are using Maven -->
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>2.34</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-http</artifactId>
<version>2.34</version>
</dependency>
核心代码实现:
- 定义文件监听任务:
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import java.io.InputStream;
import java.util.Properties;
import java.util.Vector;
public class RemoteFileMonitor implements Runnable {
private String user;
private String host;
private int port;
private String password;
private String remoteDir;
private String localDir;
private volatile boolean running = true;
public RemoteFileMonitor(String user, String host, int port, String password, String remoteDir, String localDir) {
this.user = user;
this.host = host;
this.port = port;
this.password = password;
this.remoteDir = remoteDir;
this.localDir = localDir;
}
@Override
public void run() {
try {
JSch jsch = new JSch();
Session session = jsch.getSession(user, host, port);
session.setPassword(password);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect();
while (running) {
Vector<ChannelSftp.LsEntry> list = channelSftp.ls(remoteDir);
for (ChannelSftp.LsEntry entry : list) {
if (!entry.getAttrs().isDir()) {
String remoteFilePath = remoteDir + "/" + entry.getFilename();
String localFilePath = localDir + "/" + entry.getFilename();
try (InputStream inputStream = channelSftp.get(remoteFilePath)) {
java.nio.file.Files.copy(inputStream, java.nio.file.Paths.get(localFilePath));
System.out.println("Copied: " + entry.getFilename());
running = false; // Stop monitoring this directory
break;
}
}
}
Thread.sleep(5000); // Check every 5 seconds
}
channelSftp.disconnect();
session.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
public void stop() {
this.running = false;
}
}
- 管理和控制监听任务:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ConcurrentHashMap;
public class MonitorManager {
private ExecutorService executorService;
private ConcurrentHashMap<String, Future<?>> monitors;
public MonitorManager() {
this.executorService = Executors.newCachedThreadPool();
this.monitors = new ConcurrentHashMap<>();
}
public void startMonitor(String id, RemoteFileMonitor monitor) {
Future<?> future = executorService.submit(monitor);
monitors.put(id, future);
}
public void stopMonitor(String id) {
Future<?> future = monitors.get(id);
if (future != null) {
monitor.stop();
future.cancel(true);
monitors.remove(id);
}
}
public void shutdown() {
executorService.shutdown();
}
}
- 通过HTTP接口启动和停止监听:
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;
import java.net.URI;
@Path("/monitor")
public class MonitorController {
private static MonitorManager manager = new MonitorManager();
@GET
@Path("/start")
public Response startMonitor(@QueryParam("id") String id, @QueryParam("user") String user,
@QueryParam("host") String host, @QueryParam("port") int port,
@QueryParam("password") String password, @QueryParam("remoteDir") String remoteDir,
@QueryParam("localDir") String localDir) {
RemoteFileMonitor monitor = new RemoteFileMonitor(user, host, port, password, remoteDir, localDir);
manager.startMonitor(id, monitor);
return Response.ok("Monitor started for " + id).build();
}
@GET
@Path("/stop")
public Response stopMonitor(@QueryParam("id") String id) {
manager.stopMonitor(id);
return Response.ok("Monitor stopped for " + id).build();
}
public static void main(String[] args) {
ResourceConfig config = new ResourceConfig(MonitorController.class);
URI uri = URI.create("http://localhost:8080/");
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(uri, config);
System.out.println("Server started at " + uri);
}
}
使用方法:
- 启动主程序,HTTP服务器将开始监听请求。
- 通过访问
http://localhost:8080/monitor/start
,并附加必要的参数来启动监控任务,例如:http://localhost:8080/monitor/start?id=1&user=username&host=20.12&port=22&password=password&remoteDir=/path/to/remote/dir&localDir=/path/to/local/dir
- 通过访问
http://localhost:8080/monitor/stop
停止特定的监控任务,例如:http://localhost:8080/monitor/stop?id=1
此方案保证了连接的持久性和任务的可控性,同时避免了频繁的连接开销。
Java1.8在4.28这台机器上启动有springboot服务同时监听20.12和20.16两台虚拟机的多个目录下的不同文件,为了避免频繁的连接可不可以保持连接状态下一直监听多个目录的不同文件,如果监听到了一个目录下的文件, 就把文件复制到/data/file里然后结束这个目录文件的监听,继续监听其他目录文件,通过接口调用开启监听,通过接口控制停止监听
在Java 1.8环境中使用Spring Boot来实现持续监听远程服务器多个目录的文件变化,并在检测到文件生成后将其复制到本地目录,然后停止监听该目录并继续监听其他目录,可以按照以下步骤进行实现:
- 创建SSH连接池:保持与远程服务器的持久连接。
- 使用多线程处理每个监听任务:每个监听任务由一个线程处理,监听到文件后进行复制,并停止监听。
- 使用Spring Boot提供REST接口进行控制:通过REST接口启动和停止监听任务。
以下是详细的实现步骤和代码示例:
1. 创建SSH连接池
使用JSch库创建SSH连接池,以便重用连接,避免频繁连接。
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
public class SSHConnectionPool {
private static Map<String, Session> sessionMap = new HashMap<>();
public static Session getSession(String user, String host, int port, String password) throws Exception {
String key = user + "@" + host + ":" + port;
if (!sessionMap.containsKey(key) || !sessionMap.get(key).isConnected()) {
JSch jsch = new JSch();
Session session = jsch.getSession(user, host, port);
session.setPassword(password);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
sessionMap.put(key, session);
}
return sessionMap.get(key);
}
public static void closeSession(String key) {
if (sessionMap.containsKey(key) && sessionMap.get(key).isConnected()) {
sessionMap.get(key).disconnect();
sessionMap.remove(key);
}
}
public static void closeAllSessions() {
for (String key : sessionMap.keySet()) {
closeSession(key);
}
}
}
2. 创建文件监听任务
定义一个Runnable任务来监听远程目录中的文件变化。
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.Session;
import java.io.InputStream;
import java.util.Vector;
public class RemoteFileMonitorTask implements Runnable {
private String user;
private String host;
private int port;
private String password;
private String remoteDir;
private String localDir;
private volatile boolean running = true;
public RemoteFileMonitorTask(String user, String host, int port, String password, String remoteDir, String localDir) {
this.user = user;
this.host = host;
this.port = port;
this.password = password;
this.remoteDir = remoteDir;
this.localDir = localDir;
}
@Override
public void run() {
try {
Session session = SSHConnectionPool.getSession(user, host, port, password);
ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect();
while (running) {
Vector<ChannelSftp.LsEntry> list = channelSftp.ls(remoteDir);
for (ChannelSftp.LsEntry entry : list) {
if (!entry.getAttrs().isDir()) {
String remoteFilePath = remoteDir + "/" + entry.getFilename();
String localFilePath = localDir + "/" + entry.getFilename();
try (InputStream inputStream = channelSftp.get(remoteFilePath)) {
java.nio.file.Files.copy(inputStream, java.nio.file.Paths.get(localFilePath));
System.out.println("Copied: " + entry.getFilename());
running = false; // Stop monitoring this directory
break;
}
}
}
Thread.sleep(5000); // Check every 5 seconds
}
channelSftp.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
public void stop() {
this.running = false;
}
}
3. 使用Spring Boot提供REST接口
使用Spring Boot提供REST接口来启动和停止监听任务。
配置Spring Boot项目:
在pom.xml
中添加依赖项:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>
定义Spring Boot控制器:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.*;
import java.util.concurrent.*;
@SpringBootApplication
@RestController
@RequestMapping("/monitor")
public class MonitorController {
private static MonitorManager monitorManager = new MonitorManager();
public static void main(String[] args) {
SpringApplication.run(MonitorController.class, args);
}
@PostMapping("/start")
public String startMonitor(@RequestParam String id, @RequestParam String user,
@RequestParam String host, @RequestParam int port,
@RequestParam String password, @RequestParam String remoteDir,
@RequestParam String localDir) {
RemoteFileMonitorTask monitorTask = new RemoteFileMonitorTask(user, host, port, password, remoteDir, localDir);
monitorManager.startMonitor(id, monitorTask);
return "Monitor started for " + id;
}
@PostMapping("/stop")
public String stopMonitor(@RequestParam String id) {
monitorManager.stopMonitor(id);
return "Monitor stopped for " + id;
}
}
定义监控管理器:
使用和测试
- 启动Spring Boot应用程序。
- 通过POST请求启动和停止监听任务。
启动监听任务的请求示例:yaml
POST http://localhost:8080/monitor/start
Params:
- id: unique-task-id
- user: username
- host: 20.12
- port: 22
- password: password
- remoteDir: /path/to/remote/dir
- localDir: /path/to/local/dir
停止监听任务的请求示例:
POST http://localhost:8080/monitor/stop
Params:
- id: unique-task-id
通过这种方式,可以在同一台机器上启动Spring Boot服务,并持续监听远程服务器多个目录的文件变化,监听到文件后进行复制并停止监听。可以通过HTTP接口动态启动和停止监听任务。
上面代码在哪里看是同时连接多台虚拟机监听多个目录的
要在代码中同时连接多台虚拟机并监听多个目录,可以在Spring Boot应用中维护一个任务管理器,任务管理器可以启动多个任务,每个任务负责一个远程目录的监听。这样,每个任务都可以独立地处理不同的虚拟机和目录。
下面是改进后的完整代码,展示如何实现同时连接多台虚拟机并监听多个目录。我们将添加对多个虚拟机的支持,并确保每个目录都有一个独立的监听任务。
1. SSH连接池
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
public class SSHConnectionPool {
private static Map<String, Session> sessionMap = new HashMap<>();
public static Session getSession(String user, String host, int port, String password) throws Exception {
String key = user + "@" + host + ":" + port;
if (!sessionMap.containsKey(key) || !sessionMap.get(key).isConnected()) {
JSch jsch = new JSch();
Session session = jsch.getSession(user, host, port);
session.setPassword(password);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
sessionMap.put(key, session);
}
return sessionMap.get(key);
}
public static void closeSession(String key) {
if (sessionMap.containsKey(key) && sessionMap.get(key).isConnected()) {
sessionMap.get(key).disconnect();
sessionMap.remove(key);
}
}
public static void closeAllSessions() {
for (String key : sessionMap.keySet()) {
closeSession(key);
}
}
}
2. 文件监听任务
定义一个Runnable任务来监听远程目录中的文件变化。
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.Session;
import java.io.InputStream;
import java.util.Vector;
public class RemoteFileMonitorTask implements Runnable {
private String user;
private String host;
private int port;
private String password;
private String remoteDir;
private String localDir;
private volatile boolean running = true;
public RemoteFileMonitorTask(String user, String host, int port, String password, String remoteDir, String localDir) {
this.user = user;
this.host = host;
this.port = port;
this.password = password;
this.remoteDir = remoteDir;
this.localDir = localDir;
}
@Override
public void run() {
try {
Session session = SSHConnectionPool.getSession(user, host, port, password);
ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect();
while (running) {
Vector<ChannelSftp.LsEntry> list = channelSftp.ls(remoteDir);
for (ChannelSftp.LsEntry entry : list) {
if (!entry.getAttrs().isDir()) {
String remoteFilePath = remoteDir + "/" + entry.getFilename();
String localFilePath = localDir + "/" + entry.getFilename();
try (InputStream inputStream = channelSftp.get(remoteFilePath)) {
java.nio.file.Files.copy(inputStream, java.nio.file.Paths.get(localFilePath));
System.out.println("Copied: " + entry.getFilename());
running = false; // Stop monitoring this directory
break;
}
}
}
Thread.sleep(5000); // Check every 5 seconds
}
channelSftp.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
public void stop() {
this.running = false;
}
}
3. 监控管理器
管理多个监控任务。
import java.util.concurrent.*;
public class MonitorManager {
private ExecutorService executorService;
private ConcurrentHashMap<String, Future<?>> monitors;
private ConcurrentHashMap<String, RemoteFileMonitorTask> tasks;
public MonitorManager() {
this.executorService = Executors.newCachedThreadPool();
this.monitors = new ConcurrentHashMap<>();
this.tasks = new ConcurrentHashMap<>();
}
public void startMonitor(String id, RemoteFileMonitorTask monitorTask) {
Future<?> future = executorService.submit(monitorTask);
monitors.put(id, future);
tasks.put(id, monitorTask);
}
public void stopMonitor(String id) {
Future<?> future = monitors.get(id);
RemoteFileMonitorTask task = tasks.get(id);
if (future != null && task != null) {
task.stop();
future.cancel(true);
monitors.remove(id);
tasks.remove(id);
}
}
public void shutdown() {
for (RemoteFileMonitorTask task : tasks.values()) {
task.stop();
}
executorService.shutdown();
}
}
4. Spring Boot控制器
通过Spring Boot提供REST接口来启动和停止监听任务。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.*;
import java.util.concurrent.*;
@SpringBootApplication
@RestController
@RequestMapping("/monitor")
public class MonitorController {
private static MonitorManager monitorManager = new MonitorManager();
public static void main(String[] args) {
SpringApplication.run(MonitorController.class, args);
}
@PostMapping("/start")
public String startMonitor(@RequestParam String id, @RequestParam String user,
@RequestParam String host, @RequestParam int port,
@RequestParam String password, @RequestParam String remoteDir,
@RequestParam String localDir) {
RemoteFileMonitorTask monitorTask = new RemoteFileMonitorTask(user, host, port, password, remoteDir, localDir);
monitorManager.startMonitor(id, monitorTask);
return "Monitor started for " + id;
}
@PostMapping("/stop")
public String stopMonitor(@RequestParam String id) {
monitorManager.stopMonitor(id);
return "Monitor stopped for " + id;
}
}
使用方法
-
启动Spring Boot应用程序。
-
通过POST请求启动和停止监听任务。
启动监听任务的请求示例:yaml
POST http://localhost:8080/monitor/start
Params:
- id: unique-task-id-1
- user: username
- host: 20.12
- port: 22
- password: password
- remoteDir: /path/to/remote/dir1
- localDir: /path/to/local/dir
启动另一个监听任务的请求示例:
yaml
POST http://localhost:8080/monitor/start
Params:
- id: unique-task-id-2
- user: username
- host: 20.16
- port: 22
- password: password
- remoteDir: /path/to/remote/dir2
- localDir: /path/to/local/dir
停止监听任务的请求示例:
POST http://localhost:8080/monitor/stop
Params:
- id: unique-task-id-1
通过这种方式,可以在同一台机器上启动Spring Boot服务,同时连接多台虚拟机,并监听它们的多个目录。每个任务都是独立的,可以通过接口动态启动和停止。
用java1.8的maven的springboot项目在4.58这台机器上部署启动同时监听20.12和20.16两台虚拟机的多个目录下的不同文件,为了避免频繁的连接可不可以保持连接状态下每秒监听多个目录的不同文件,如果监听到了一个目录下的文件,就把文件复制到/data/file里然后结束这个目录文件的监听,继续监听其他目录文件,通过接口调用开启监听返回监听状态,通过接口控制停止监听返回监听状态
要在Java 1.8的Spring Boot项目中实现并部署到4.58机器上,监听20.12和20.16两台虚拟机的多个目录,保持连接状态每秒监听多个目录的不同文件,并通过接口控制开启和停止监听并返回监听状态,可以按以下步骤进行:
项目结构和依赖
在Maven项目的pom.xml
文件中,添加Spring Boot、JSch和必要的依赖项:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
SSH连接池
用于保持连接状态:
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
public class SSHConnectionPool {
private static Map<String, Session> sessionMap = new HashMap<>();
public static Session getSession(String user, String host, int port, String password) throws Exception {
String key = user + "@" + host + ":" + port;
if (!sessionMap.containsKey(key) || !sessionMap.get(key).isConnected()) {
JSch jsch = new JSch();
Session session = jsch.getSession(user, host, port);
session.setPassword(password);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
sessionMap.put(key, session);
}
return sessionMap.get(key);
}
public static void closeSession(String key) {
if (sessionMap.containsKey(key) && sessionMap.get(key).isConnected()) {
sessionMap.get(key).disconnect();
sessionMap.remove(key);
}
}
public static void closeAllSessions() {
for (String key : sessionMap.keySet()) {
closeSession(key);
}
}
}
文件监听任务
定义一个监听远程目录的任务:
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.Session;
import java.io.InputStream;
import java.util.Vector;
public class RemoteFileMonitorTask implements Runnable {
private String user;
private String host;
private int port;
private String password;
private String remoteDir;
private String localDir;
private volatile boolean running = true;
public RemoteFileMonitorTask(String user, String host, int port, String password, String remoteDir, String localDir) {
this.user = user;
this.host = host;
this.port = port;
this.password = password;
this.remoteDir = remoteDir;
this.localDir = localDir;
}
@Override
public void run() {
try {
Session session = SSHConnectionPool.getSession(user, host, port, password);
ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect();
while (running) {
Vector<ChannelSftp.LsEntry> list = channelSftp.ls(remoteDir);
for (ChannelSftp.LsEntry entry : list) {
if (!entry.getAttrs().isDir()) {
String remoteFilePath = remoteDir + "/" + entry.getFilename();
String localFilePath = localDir + "/" + entry.getFilename();
try (InputStream inputStream = channelSftp.get(remoteFilePath)) {
java.nio.file.Files.copy(inputStream, java.nio.file.Paths.get(localFilePath));
System.out.println("Copied: " + entry.getFilename());
running = false; // Stop monitoring this directory
break;
}
}
}
Thread.sleep(1000); // Check every second
}
channelSftp.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
public void stop() {
this.running = false;
}
}
监控管理器
管理多个监控任务:
import java.util.concurrent.*;
public class MonitorManager {
private ExecutorService executorService;
private ConcurrentHashMap<String, Future<?>> monitors;
private ConcurrentHashMap<String, RemoteFileMonitorTask> tasks;
public MonitorManager() {
this.executorService = Executors.newCachedThreadPool();
this.monitors = new ConcurrentHashMap<>();
this.tasks = new ConcurrentHashMap<>();
}
public String startMonitor(String id, RemoteFileMonitorTask monitorTask) {
if (monitors.containsKey(id)) {
return "Monitor with ID " + id + " is already running.";
}
Future<?> future = executorService.submit(monitorTask);
monitors.put(id, future);
tasks.put(id, monitorTask);
return "Monitor started for " + id;
}
public String stopMonitor(String id) {
Future<?> future = monitors.get(id);
RemoteFileMonitorTask task = tasks.get(id);
if (future != null && task != null) {
task.stop();
future.cancel(true);
monitors.remove(id);
tasks.remove(id);
return "Monitor stopped for " + id;
} else {
return "Monitor with ID " + id + " is not running.";
}
}
public void shutdown() {
for (RemoteFileMonitorTask task : tasks.values()) {
task.stop();
}
executorService.shutdown();
}
public boolean isRunning(String id) {
Future<?> future = monitors.get(id);
return future != null && !future.isCancelled();
}
}
Spring Boot控制器
通过Spring Boot提供REST接口来启动和停止监听任务,并返回状态。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.*;
import java.util.concurrent.*;
@SpringBootApplication
@RestController
@RequestMapping("/monitor")
public class MonitorController {
private static MonitorManager monitorManager = new MonitorManager();
public static void main(String[] args) {
SpringApplication.run(MonitorController.class, args);
}
@PostMapping("/start")
public String startMonitor(@RequestParam String id, @RequestParam String user,
@RequestParam String host, @RequestParam int port,
@RequestParam String password, @RequestParam String remoteDir,
@RequestParam String localDir) {
RemoteFileMonitorTask monitorTask = new RemoteFileMonitorTask(user, host, port, password, remoteDir, localDir);
return monitorManager.startMonitor(id, monitorTask);
}
@PostMapping("/stop")
public String stopMonitor(@RequestParam String id) {
return monitorManager.stopMonitor(id);
}
@GetMapping("/status")
public String monitorStatus(@RequestParam String id) {
boolean isRunning = monitorManager.isRunning(id);
return "Monitor with ID " + id + " is " + (isRunning ? "running" : "stopped") + ".";
}
}
部署和使用
-
将项目部署到4.58机器上,可以使用
mvn spring-boot:run
命令启动Spring Boot应用。 -
通过POST请求启动和停止监听任务,并通过GET请求获取任务状态。
启动监听任务的请求示例:
yaml
POST http://localhost:8080/monitor/start
Params:
- id: unique-task-id-1
- user: username
- host: 20.12
- port: 22
- password: password
- remoteDir: /path/to/remote/dir1
- localDir: /data/file
启动另一个监听任务的请求示例:
yaml
POST http://localhost:8080/monitor/start
Params:
- id: unique-task-id-2
- user: username
- host: 20.16
- port: 22
- password: password
- remoteDir: /path/to/remote/dir2
- localDir: /data/file
停止监听任务的请求示例:
POST http://localhost:8080/monitor/stop
Params:
- id: unique-task-id-1
获取任务状态的请求示例:
GET http://localhost:8080/monitor/status
Params:
- id: unique-task-id-1
通过这种方式,可以在同一台机器上启动Spring Boot服务,同时连接多台虚拟机,并监听它们的多个目录。每个任务都是独立的,可以通过接口动态启动和停止,并且保持连接状态以避免频繁连接。
用java1.8的maven的springboot项目在20.12和20.16两台虚拟机分别启动服务同时监听多个目录下的不同文件,如果监听到了一个目录下的文件,就把文件复制到/data/file里然后结束这个目录文件的监听,继续监听其他目录文件,通过接口调用开启监听同时返回监听状态,通过接口控制停止监听同时返回监听状态
要在两台虚拟机(20.12和20.16)上分别启动Spring Boot服务来监听多个目录,并在检测到文件后将其复制到本地目录并停止监听该目录,可以按照以下步骤进行:
- 创建Maven Spring Boot项目,在每个虚拟机上部署相同的服务。
- 定义一个文件监听任务,每个任务监听一个特定的目录。
- 创建一个监控管理器,管理多个任务的启动和停止。
- 通过Spring Boot REST接口,提供启动和停止监听任务的功能,同时返回任务的状态。
项目结构和依赖
在Maven项目的pom.xml
文件中,添加Spring Boot和JSch依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
文件监听任务
定义一个监听远程目录的任务:
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import java.io.InputStream;
import java.util.Vector;
public class RemoteFileMonitorTask implements Runnable {
private String remoteDir;
private String localDir;
private String user;
private String host;
private int port;
private String password;
private volatile boolean running = true;
public RemoteFileMonitorTask(String user, String host, int port, String password, String remoteDir, String localDir) {
this.user = user;
this.host = host;
this.port = port;
this.password = password;
this.remoteDir = remoteDir;
this.localDir = localDir;
}
@Override
public void run() {
try {
JSch jsch = new JSch();
Session session = jsch.getSession(user, host, port);
session.setPassword(password);
session.setConfig("StrictHostKeyChecking", "