最近做的电商项目中,使用了fastDFS文件系统来作为图片和文件的存储,然后官方提供的API中并没有提供连接池的实现,必然导致每次建立连接的开销较大,为了节约系统资源和提高效率,便自己动手写一个。原理是数据库连接池类似。如有不足,和问题往指出,我加以修改
首先来看连接池的接口,我这里做的很简单
class="java" name="code">
/**
*
* @ClassName: ITrackerServerPool
* @Description: TODO(连接池的基本接口)
* @author LiuYi
* @date 2014年5月19日 下午2:07:05
*
*/
public interface ITrackerServerPool {
public TrackerServer geTrackerServer() throws Exception;
public TrackerServer geTrackerServer(long timeout) throws Exception;
public boolean close(TrackerServer server) throws Exception;
public void reset() throws Exception;
}
连接池的实现
/**
*
* @ClassName: LinkedQueueTrackerPool
* @Description: TODO(使用jdk1.5新增的并发库LinkedBlockingQueue实现连接池)
* @author LiuYi
*
*/
public class LinkedQueueTrackerPool implements
ITrackerServerPool{
private LinkedBlockingQueue<TrackerServer> tspool = null;
private int poolSize;
public LinkedQueueTrackerPool(String clientConfigPath, int poolSize)
throws FileNotFoundException, IOException, MyException, InterruptedException {
super();
this.poolSize = poolSize;
ClientGlobal.init(clientConfigPath);
init();
}
/**
* @Description: TODO(使用远DFSAPI来保持长连接,轮询,开销小于创建一个新连接)
* @author LiuYi
*/
private void keepingPool() {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
for(TrackerServer ts : tspool){
try {
ProtoCommon.activeTest(ts.getSocket());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}, 30*1000, 30*1000);
}
/**
*
* @Description: TODO(初始化方法)
* @author LiuYi
* @throws IOException
* @throws InterruptedException void
*/
private void init() throws IOException, InterruptedException{
this.tspool = new LinkedBlockingQueue<>(this.poolSize);
for(int i=0;i<this.poolSize;i++){
TrackerClient tc = new TrackerClient();
TrackerServer ts = tc.getConnection();
ProtoCommon.activeTest(ts.getSocket());
this.tspool.put(ts);
}
keepingPool();
}
@Override
public TrackerServer geTrackerServer() throws Exception {
return this.tspool.poll();
}
@Override
public TrackerServer geTrackerServer(long timeout) throws Exception {
TrackerServer ts = this.geTrackerServer();
if(ts == null){
return this.tspool.poll(timeout, TimeUnit.SECONDS);
}
return ts;
}
@Override
public boolean close(TrackerServer server) throws Exception {
if(server != null){
this.tspool.put(server);
return true;
}
return false;
}
@Override
public void reset() throws Exception {
this.init();
}
}
下面是对客户端操作的一个封装
客户端操作的接口,很简单
public interface IDFSClient {
public String upload(File file) throws Exception;
public String upload(File file,NameValuePair... metaList) throws Exception;
public File download(String fileName,String localPath) throws Exception;
public boolean remove(String fileName) throws Exception;
public NameValuePair[] getFileMate(String fileName) throws Exception;
}
接下来是一个抽象的实现
/**
*
* @ClassName: AbstractClientImpl
* @Description: TODO(Client的抽象实现,主要是保存一些公用方法)
* @author LiuYi
*
*/
public abstract class AbstractClientImpl implements IDFSClient {
protected String getFileTypeName(String fileName) {
if (fileName != null && fileName.contains(".")) {
fileName = fileName.substring(fileName.lastIndexOf(".") + 1);
}
return fileName;
}
/**
*
* @Description: TODO(文件转换为字节数组)
* @author LiuYi
* @param file
* @return byte[]
*/
protected byte[] file2Byte(File file) {
FileInputStream fis = null;
ByteArrayOutputStream ops = null;
BufferedInputStream bis = null;
try {
byte[] temp = new byte[2048];
fis = new FileInputStream(file);
bis = new BufferedInputStream(fis);
ops = new ByteArrayOutputStream(2048);
int n;
while ((n = bis.read(temp)) != -1) {
ops.write(temp, 0, n);
}
return ops.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (ops != null) {
ops.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (bis != null) {
bis.close();
}
} catch (IOException e1) {
e1.printStackTrace();
}
try {
if (fis != null) {
fis.close();
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
return null;
}
/**
*
* @Description: TODO(这里用一句话描述这个方法的作用)
* @author LiuYi
* @param buf
* @param filePath
* @param fileName void
*/
public File byte2File(byte[] buf, String filePath, String fileName) {
BufferedOutputStream bos = null;
FileOutputStream fos = null;
File file = null;
try {
File dir = new File(filePath);
if (!dir.exists() && dir.isDirectory()) {
dir.mkdirs();
}
file = new File(filePath + File.separator + fileName);
fos = new FileOutputStream(file);
bos = new BufferedOutputStream(fos);
bos.write(buf);
return file;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return file;
}
}
具体的实现
/**
*
* @ClassName: SimpleClientImpl
* @Description: TODO(对DFSjavaAPI的一个封装,加入连接池技术,提高效率)
* @author LiuYi
*
*/
public class SimpleClientImpl extends AbstractClientImpl {
private ITrackerServerPool pool = null;
private int waitTime = 3;
public SimpleClientImpl(String clientConfigPath,int poolSize) throws FileNotFoundException, IOException, MyException, InterruptedException{
this.pool = new LinkedQueueTrackerPool(clientConfigPath, poolSize);
}
public SimpleClientImpl(String clientConfigPath,int poolSize,int waitTime) throws FileNotFoundException, IOException, MyException, InterruptedException{
this.pool = new LinkedQueueTrackerPool(clientConfigPath, poolSize);
this.waitTime=waitTime;
}
public SimpleClientImpl(ITrackerServerPool pool){
this.pool = pool;
}
@Override
public String upload(File file) throws Exception {
TrackerServer ts = null;
try {
ts = pool.geTrackerServer(waitTime);
System.out.println(ts);
StorageClient1 client1 = new StorageClient1(ts, null);
return client1.upload_file1(file2Byte(file), getFileTypeName(file.getName()), null);
} catch (Exception e) {
e.printStackTrace();
}finally{
this.pool.close(ts);
}
return null;
}
@Override
public String upload(File file, NameValuePair... metaList) throws Exception {
TrackerServer ts = null;
try {
ts = pool.geTrackerServer(waitTime);
StorageClient1 client1 = new StorageClient1(ts, null);
System.out.println(ts);
return client1.upload_file1(file2Byte(file), getFileTypeName(file.getName()), metaList);
} catch (Exception e) {
e.printStackTrace();
}finally{
this.pool.close(ts);
}
return null;
}
/**
* 文件名为默认的
*/
@Override
public File download(String fileName,String localPath) throws Exception {
TrackerServer ts = null;
try {
ts = pool.geTrackerServer(waitTime);
StorageClient1 client1 = new StorageClient1(ts, null);
return this.byte2File( client1.download_file1(fileName),localPath,UUID.randomUUID().toString()+"."+getFileTypeName(fileName));
} catch (Exception e) {
e.printStackTrace();
throw e;
}finally{
this.pool.close(ts);
}
}
@Override
public boolean remove(String fileName) throws Exception {
boolean result = false;
TrackerServer ts = null;
try {
ts = this.pool.geTrackerServer(waitTime);
StorageClient1 client1 = new StorageClient1(ts, null);
result = client1.delete_file1(fileName) == 0 ? true : false;
} catch (Exception e) {
e.printStackTrace();
throw e;
}finally{
this.pool.close(ts);
}
return result;
}
@Override
public NameValuePair[] getFileMate(String fileName) throws Exception {
TrackerServer ts = null;
try {
ts = pool.geTrackerServer(waitTime);
StorageClient1 client1 = new StorageClient1(ts, null);
return client1.get_metadata1(fileName);
} catch (Exception e) {
e.printStackTrace();
throw e;
}finally{
this.pool.close(ts);
}
}
}
测试代码
public class Test {
public String local_filename = "D:\\seafood_project\\fast_DFS\\src\\client.conf";
public static String conf_filename = "D:\\seafood_project\\fast_DFS\\src\\client.conf";
public static String jpg = "D:/seafood_project/seafood-front/src/main/webapp/common/productImg/11.png";
@org.junit.Test
public void test() throws FileNotFoundException, IOException, MyException, InterruptedException{
}
public static void main(String[] args) throws FileNotFoundException, IOException, MyException, InterruptedException {
final IDFSClient client = new SimpleClientImpl(conf_filename, 2);
//使用定时任务模拟并发
for(int i=0;i<10;i++){
new Timer()
.schedule(new TimerTask() {
@Override
public void run() {
try {
//测试上传
// System.out.println(client.upload(new File(jpg)));
//测试下载
// System.out.println(client.download("g1/M00/00/07/wKjriVN6C9iAPX3HAACsXXNt0Y8813.png","D:\\image"));
} catch (Exception e) {
e.printStackTrace();
}
}
}, 1, 1000);
}
}
}
在simplClient中添加一句System.out.println(ts);把TraeckServer打印出来,运行测试上传,控制台输出
org.csource.fastdfs.TrackerServer@933bcb
org.csource.fastdfs.TrackerServer@3ac93e
org.csource.fastdfs.TrackerServer@15718f2
g1/M00/00/08/wKjriVN6HFOAN7-VAACsXXNt0Y8407.png
org.csource.fastdfs.TrackerServer
@933bcb
g1/M00/00/08/wKjriVN6HFOAYseLAACsXXNt0Y8802.png
org.csource.fastdfs.TrackerServer
@3ac93e
g1/M00/00/08/wKjriVN6HFOAIj-dAACsXXNt0Y8445.png
org.csource.fastdfs.TrackerServer
@15718f2
g1/M00/00/08/wKjriVN6HFOAf7l2AACsXXNt0Y8484.png
org.csource.fastdfs.TrackerServer
@3ac93e
g1/M00/00/08/wKjriVN6HFOAN2ToAACsXXNt0Y8894.png
org.csource.fastdfs.TrackerServer@15718f2
g1/M00/00/08/wKjriVN6HFOAAvNuAACsXXNt0Y8064.png
org.csource.fastdfs.TrackerServer@933bcb
g1/M00/00/08/wKjriVN6HFOAMs7BAACsXXNt0Y8246.png
org.csource.fastdfs.TrackerServer@3ac93e
g1/M00/00/08/wKjriVN6HFOAJmNSAACsXXNt0Y8331.png
g1/M00/00/08/wKjriVN6HFOAH0VDAACsXXNt0Y8359.png
g1/M00/00/08/wKjriVN6HFOAEG62AACsXXNt0Y8530.png