Introduction to commons-net package
commons-net is Apache commons tool kit for network. It implements some common network tools, such as smtp, pop3, telnet, ftp, udp and so on. This paper mainly uses its FTP tool.
Problems with FTP Tools
When using the ftp tool provided by commons-net, it is found that the complete connection and login process must be made once at a time. Every time a connection is created, it will soon run out of connections. If you use singletons, it will be inefficient, because there is only one connection, so consider using object pooling.
I've done this before, but there are a lot of things to consider when defining object pools myself. Like thread pools, you need to consider the number of core objects, the maximum number of objects, when to create objects, and queues, so you can use apache's commons-pool2 to make an object pool.
How to use commons-pool2
It can be said that if I want to make an object pool tool for others to use, the first thing to consider is what is in the pool, how users create objects in the pool, and then provide methods to borrow and recycle objects. I can abstract objects in the pool, which are managed by a factory, and users'objects are from me. Common objects inherit or implement, or aggregate.
In fact, spring-data-redis has given us a complete example of using commons-pool2, which is commons-pool2. Its pool object is redis connection, which you can see if you are interested.
Define Extended Objects for Objects FTPClient in the Pool
Because FTPClient's function is too simple to create a multi-tier directory by itself, it's necessary to wrap it up. Here you can expand the commonly used methods.
import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPFile; @Slf4j public class FtpClientExtend { private FTPClient ftpClient ; public FtpClientExtend(FTPClient ftpClient) { this.ftpClient = ftpClient; } /** * List files * @param filePath * @return * @throws IOException */ public FTPFile[] listFiles(String filePath) throws IOException { return ftpClient.listFiles(filePath); } /** * Download File * @param filePath * @return */ public InputStream downloadFile(String filePath) throws IOException { return ftpClient.retrieveFileStream(filePath); } /** * Storage file * @param s * @param inputStream */ public void uploadFile(String filePath, InputStream inputStream) throws IOException { File targetFilePath = new File(filePath); Path path = targetFilePath.getParentFile().toPath(); Iterator<Path> iterator = path.iterator(); StringBuffer root = new StringBuffer(""); while (iterator.hasNext()){ Path next = iterator.next(); root.append("/").append(next); //Try to cut into the catalog boolean success = ftpClient.changeWorkingDirectory(root.toString()); if(!success){ int mkd = ftpClient.mkd(next.toString()); ftpClient.changeWorkingDirectory(root.toString()); } } ftpClient.enterLocalPassiveMode(); ftpClient.setControlEncoding("UTF-8"); ftpClient.setFileType(FTP.BINARY_FILE_TYPE); boolean storeFileResult = ftpClient.storeFile(targetFilePath.getName(), inputStream); if (storeFileResult) { log.debug("Upload files:" + filePath + ",To directory:" + ftpClient.printWorkingDirectory() + " Success"); }else{ log.debug("Upload files:" + filePath + ",To directory:" + ftpClient.printWorkingDirectory() + " fail"); } } }
Using objects in aggregated package pools
The class of the wrapped object is the class that the factory actually generates in the pool. The diagram is given at the end of the article.
import org.apache.commons.pool2.PooledObjectFactory; import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; public class FtpClientPool extends GenericObjectPool<FtpClientExtend> { public FtpClientPool(PooledObjectFactory<FtpClientExtend> factory) { super(factory); } public FtpClientPool(PooledObjectFactory<FtpClientExtend> factory, GenericObjectPoolConfig config) { super(factory, config); } }
Establishing a factory for creating objects
import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.pool2.BasePooledObjectFactory; import org.apache.commons.pool2.PooledObject; import org.apache.commons.pool2.impl.DefaultPooledObject; public class FtpClientFactory extends BasePooledObjectFactory<FtpClientExtend> { @Value("${ftp.host:localhost}") private String host; @Value("${ftp.port:21}") private int port; @Value("${ftp.username:ftpadmin}") private String username; @Value("${ftp.password:salt202}") private String password; @Override public FtpClientExtend create() throws Exception { FTPClient ftpClient = new FTPClient(); ftpClient.connect(host,port); boolean login = ftpClient.login(username, password); if(!login){ throw new RuntimeException("ftp Login failed,Check that the username password is correct["+host+":"+port+"]["+username+"]["+password+"]"); } return new FtpClientExtend(ftpClient); } @Override public PooledObject<FtpClientExtend> wrap(FtpClientExtend ftpClientExtend) { return new DefaultPooledObject(ftpClientExtend); } }
Usage method
@Autowired private FtpClientPool ftpClientPool; public void method(){ FtpClientExtend ftpClientExtend = null; try{ ftpClientExtend = ftpClientPool.borrowObject(); }finally{ if(ftpClientExtend != null) { ftpClientPool.returnObject(ftpClientExtend); } } }