Spring boot 调用 shell 命令
Spring boot 调用 shell 命令我们将“执行命令行”封装成一个Spring中的service,入参是命令,当执行顺利时返回标准输入流中的结果,当执行失败记录日志或抛出异常。并使用线程池来用线程读取流中的数据。/*** @author jiezhigang* @title:* @projectName assets* @description: 定义Command Service接口*
·
Spring boot 调用 shell 命令
我们将“执行命令行”封装成一个Spring中的service,入参是命令,当执行顺利时返回标准输入流中的结果,当执行失败记录日志或抛出异常。
并使用线程池来用线程读取流中的数据。
/**
* @author jiezhigang
* @title:
* @projectName assets
* @description: 定义Command Service接口
* @date 2021/1/18
*/
public interface CommandService {
String executeCmd(String cmd);
}
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
/**
* @author jiezhigang
* @title:
* @projectName assets
* @description:
* @date 2021/1/18
*/
@Slf4j
@Service
public class CommandServiceImpl implements CommandService, InitializingBean {
@Value("${cmd.threadname:cmd-executor}")
private String threadName;
@Value("${cmd.taskQueueMaxStorage:20}")
private Integer taskQueueMaxStorage;
@Value("${cmd.corePoolSize:4}")
private Integer corePoolSize;
@Value("${cmd.maximumPoolSize:8}")
private Integer maximumPoolSize;
@Value("${cmd.keepAliveSeconds:15}")
private Integer keepAliveSeconds;
private ThreadPoolExecutor executor;
private static final String BASH = "sh";
private static final String BASH_PARAM = "-c";
// use thread pool to read streams
@Override
public void afterPropertiesSet() {
executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveSeconds, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(taskQueueMaxStorage),
new ThreadFactory() {
public Thread newThread(Runnable r) {
return new Thread(r, threadName + r.hashCode());
}
},
new ThreadPoolExecutor.AbortPolicy());
}
@Override
public String executeCmd(String cmd) {
Process p = null;
String res;
log.debug("CommandService cmd info : {}", cmd);
try {
// need to pass command as bash's param,
// so that we can compatible with commands: "echo a >> b.txt" or "bash a && bash b"
List<String> cmds = new ArrayList<>();
cmds.add(BASH);
cmds.add(BASH_PARAM);
cmds.add(cmd);
ProcessBuilder pb = new ProcessBuilder(cmds);
p = pb.start();
Future<String> errorFuture = executor.submit(new ReadTask(p.getErrorStream()));
Future<String> resFuture = executor.submit(new ReadTask(p.getInputStream()));
int exitValue = p.waitFor();
if (exitValue > 0) {
log.info("exec cmd error: {} ", errorFuture.get());
res = errorFuture.get();
//throw new RuntimeException(errorFuture.get());
} else {
res = resFuture.get();
}
} catch (Exception e) {
log.info("exec cmd error: {} ", e.getMessage());
res = e.getMessage();
//throw new RuntimeException(e);
} finally {
if (p != null) {
p.destroy();
}
}
// remove System.lineSeparator() (actually it's '\n') in the end of res if exists
if (StringUtils.isNotBlank(res) && res.endsWith(System.lineSeparator())) {
res = res.substring(0, res.lastIndexOf(System.lineSeparator()));
}
return res;
}
class ReadTask implements Callable<String> {
InputStream is;
ReadTask(InputStream is) {
this.is = is;
}
@Override
public String call() throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
return sb.toString();
}
}
}
更多推荐
已为社区贡献2条内容
所有评论(0)