前言
最近项目中经常用的jsch来进行文件上传下载,在业务量大的时候,每次都去获取sftp连接很消耗资源,后面就想着使用连接池来解决。
简述
1)jsch是ssh2的一个纯Java实现。它允许你连接到一个sshd服务器,使用端口转发、X11转发、文件传输等。
2)SSH 是较可靠,专为远程登录会话和其他网络服务提供安全性的协议。
3)ftp协议通常是用来在两个服务器之间传输文件的,但是它本质上是不安全的。
4)SFTP可以理解为SSH + FTP,也就是安全的网络文件传输协议。
Maven依赖
<!-- sftp -->
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>
<!-- 连接池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
application.yml配置文件
sftp:
#服务器ip
host: 192.168.xx.xx
#ssh端口
port: 22
#用户名
username: USER001
#密码
password: 123456
#连接池参数
pool:
#对象池中管理的最多对象个数。默认值是8
max-total: 10
#对象池中最大的空闲对象个数。默认值是8
max-idle: 10
#对象池中最小的空闲对象个数。默认值是0
min-idle: 5
连接池实现
public class SftpGenericObjectPool{
private final GenericObjectPool<ChannelSftp> genericObjectPool;
public SftpGenericObjectPool(SftpFactory sftpFactory, GenericObjectPoolConfig<ChannelSftp> sftpPoolConfig) {
this.genericObjectPool = new GenericObjectPool<>(sftpFactory, sftpPoolConfig);
}
public ChannelSftp borrowObject() throws Exception {
return genericObjectPool.borrowObject();
}
public void returnObject(ChannelSftp obj) {
genericObjectPool.returnObject(obj);
}
}
public class SftpFactory extends BasePooledObjectFactory<ChannelSftp> {
@Value("${sftp.host}")
private String host;
@Value("${sftp.port}")
private int port;
@Value("${sftp.username}")
private String username;
@Value("${sftp.password}")
private String password;
@Override
public ChannelSftp create() throws JSchException {
JSch jsch = new JSch();
Session sshSession = jsch.getSession(username, host, port);
sshSession.setPassword(password);
Properties sshConfig = new Properties();
sshConfig.put("StrictHostKeyChecking", "no");
sshSession.setConfig(sshConfig);
sshSession.connect();
ChannelSftp channel = (ChannelSftp) sshSession.openChannel("sftp");
channel.connect();
return channel;
}
@Override
public PooledObject<ChannelSftp> wrap(ChannelSftp channelSftp) {
return new DefaultPooledObject<>(channelSftp);
}
/**
* 销毁对象
*
* @param p
* @return
* @author fengfan
* @date 2022/1/14 15:26
*/
@Override
public void destroyObject(PooledObject<ChannelSftp> p) {
ChannelSftp channelSftp = p.getObject();
channelSftp.disconnect();
}
/**
* 激活连接池里面的sftp连接
*
* @param p
* @throws Exception
*/
@Override
public void activateObject(PooledObject<ChannelSftp> p) throws Exception {
ChannelSftp channelSftp = p.getObject();
if(!channelSftp.isConnected()){
channelSftp.connect();
}
}
}
Sftp工具类
public class SftpUtil {
//连接池
private SftpGenericObjectPool pool;
public SftpUtil(SftpGenericObjectPool pool) {
this.pool = pool;
}
/**
* 下载文件
*
* @param dir 远程目录
* @param name 远程文件名
* @return 文件字节数组
*/
public InputStream download(String dir, String name) throws Exception {
ChannelSftp sftp = pool.borrowObject();
try {
sftp.cd(dir);
return sftp.get(name);
} finally {
pool.returnObject(sftp);
}
}
/**
* 上传文件
*
* @param dir 远程目录
* @param name 远程文件名
* @param in 输入流
*/
public void upload(String dir, String name, InputStream in) throws Exception {
ChannelSftp sftp = pool.borrowObject();
try {
mkdirs(sftp, dir);
sftp.cd(dir);
sftp.put(in, name);
} finally {
pool.returnObject(sftp);
}
}
/**
* 删除文件
*
* @param dir 远程目录
* @param name 远程文件名
*/
public void delete(String dir, String name) throws Exception {
ChannelSftp sftp = pool.borrowObject();
try {
sftp.cd(dir);
sftp.rm(name);
} finally {
pool.returnObject(sftp);
}
}
/**
* 递归创建多级目录
*
* @param dir 多级目录
*/
private void mkdirs(ChannelSftp sftp, String dir) throws SftpException {
String[] folders = dir.split("/");
sftp.cd("/");
for (String folder : folders) {
if (folder.length() > 0) {
try {
sftp.cd(folder);
} catch (Exception e) {
sftp.mkdir(folder);
sftp.cd(folder);
}
}
}
}
public SftpGenericObjectPool getPool() {
return pool;
}
public void setPool(SftpGenericObjectPool pool) {
this.pool = pool;
}
}
配置成Bean
@Configuration
public class SftpConfig {
/**
* 工厂
*
* @author fengfan
* @date 2022/1/14 14:37
* @return
*/
@Bean
public SftpFactory sftpFactory() {
return new SftpFactory();
}
@Bean
@ConfigurationProperties(prefix = "sftp.pool")
public GenericObjectPoolConfig<ChannelSftp> sftpPoolConfig(){
return new GenericObjectPoolConfig<>();
}
@Bean
public SftpGenericObjectPool sftpPool(SftpFactory sftpFactory, GenericObjectPoolConfig<ChannelSftp> sftpPoolConfig){
return new SftpGenericObjectPool(sftpFactory, sftpPoolConfig);
}
@Bean
public SftpUtil sftpUtil(SftpGenericObjectPool sftpPool){
return new SftpUtil(sftpPool);
}
}