之前在每個控制層OSSClient都是通過新new的方式創建OSSClientBuilder().build(endpoint,accessKeyId,accessKeySecret)進行創建
后期我想應該可以把這個進行單例化
改了一番,單例化是實現了,可以每次調用一個方法時,只有首次會獲取成功,第二次雖然連接會是true,但是會顯示ossClient實例為null,從而無法繼續調用
第一次執行獲取bucket的name集合
{ "success": true, "bucketsNames": [ "beijing-oss-1", "huhehaote-oss-1", "qingdao-oss-1", "sugar-oss1", "test-oss-create", "test-oss-create1", "ukyomooc123osstestdemo" ] }
第二次執行
{ "success": true, "bucketsNames": null }
錯誤信息
2019-12-23 10:03:46.053 WARN 1476 --- [nio-8011-exec-3] com.aliyun.oss : [Unknown]Unable to execute HTTP request: Connection pool shut down
com.aliyun.oss.ClientException: 網絡連接錯誤,詳細信息:Connection pool shut down
[ErrorCode]: Unknown
[RequestId]: Unknown
Caused by: java.lang.IllegalStateException: Connection pool shut down
這是因為在每個服務調用后都按照官方demo進行了shutdown
} finally { if(null != ossClient){ ossClient.shutdown(); } }
而我又查了下aliyun開發問題也有相同的問題https://developer.aliyun.com/ask
只不過都是挺久之前的了.
如果完成操作之后使用shutdown方法, 會拋出線程異常, 如果對OSSClient不做任何處理, 每隔60秒就有關閉空閑連接的日志輸出(new了2個OSSClient實例, 完成操作之后斷點停住):
從第二張圖,排行前35中,基本都是基礎類型和java、apache、sun的包,只有一個是aliyun的類,而且這個配置類,看第二列,實例數(instances),理論上不可能會達到1W8的客戶端同時在連接,再看那些HttpClientBuilder、SocksSocketImpl這些都是與網絡請求有關的,OSS的上傳也是需要這些,而且數量上,都是在1W8左右
后面去看過代碼,每次上傳文件到OSS,服務端都是采用先獲取授權令牌,然后new OSSClient()去開啟一個上傳客戶端連接,但是后面沒有關閉,初步斷定是這個地方的問題,隨即增加了 ossClient.shutdown();
問題已經解決了,內存也不需要那么大,最后要提醒下大家,用完一定要關閉,很重要!!! ossClient.shutdown();
https://developer.aliyun.com/ask/243394?spm=a2c6h.13524658 OSSClient 每次使用都new 還是 使用單例好,必須shutdown 嗎?
您的工程中可以有一個或多個OSSClient。OSSClient可以並發使用。
所以最終以取消掉shutdown()操作為最后操作
單例化ossclient工廠
package com.springboot.oss.entity; import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.PropertySource; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; /** * OSSClient單例化工廠 * 使用ossClient單例化后,不可以再進行shutdown操作 */ @PropertySource(value = "classpath:aliyunConfig.properties") @Component public class OssClientFactory { //volatile是Java提供的一種輕量級的同步機制,在並發編程中,也扮演着比較重要的角色. //同synchronized相比(synchronized通常稱為重量級鎖),volatile更輕量級,相比使用 //synchronized所帶來的龐大開銷,倘若能恰當的合理的使用volatile,則wonderful private volatile static OSS client; private OssClientFactory(){} private volatile static OSSClientBuilder ossClientBuilder; private static String endpoint; private static String accessKeyId; private static String accessKeySecret; @Value("${aliyun.endpoint}") public void setEndpoint(String endpoint) { this.endpoint = endpoint; } @Value("${aliyun.accessKey.Id}") public void setAccessKeyId(String accessKeyId) { this.accessKeyId = accessKeyId; } @Value("${aliyun.accessKey.Secret}") public void setAccessKeySecret(String accessKeySecret) { this.accessKeySecret = accessKeySecret; } @Bean @Scope("prototype") public static OSS getOSSClient(){ if(client == null){ synchronized(OssClientFactory.class){ if(client==null){ client = getOSSClientBuilder().build(endpoint,accessKeyId,accessKeySecret); } } } return client; // client = getOSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); // return client; } public static OSSClientBuilder getOSSClientBuilder(){ System.out.println("獲取OSSClientBuilder"); if(ossClientBuilder == null){ System.out.println("OSSClientBuilder為空,創建中"); synchronized(OssClientFactory.class){ if(ossClientBuilder==null){ System.out.println("進入同步實例化OSSClientBuilder"); ossClientBuilder = new OSSClientBuilder(); } } } return ossClientBuilder; } }
獲取OSSClientBuilder
OSSClientBuilder為空,創建中
進入同步實例化OSSClientBuilder
list buckets : [OSSBucket [name=beijing-oss-1, creationDate=Fri Dec 20 11:19:37 CST 2019, owner=Owner [name=1932998108284896,id=1932998108284896], location=oss-cn-beijing, ...
獲取OSSClientBuilder
list buckets : [OSSBucket [name=beijing-oss-1, creationDate=Fri Dec 20 11:19:37 CST 2019, owner=Owner [name=1932998108284896,id=1932998108284896], location=oss-cn-beijing, ...
您的工程中可以有一個或多個OSSClient。OSSClient可以並發使用。