本文是第二篇!
第一篇,《Java高級架構之FastDFS分佈式文件集羣》:http://www.javashuo.com/article/p-awevzoil-x.html
第三篇,《FastDFS的HA架構多Group多Storage多Tracker結合SpringBoot》http://www.javashuo.com/article/p-gotztyae-gc.html前端
SpringBoot是由Pivotal團隊提供的全新框架,其設計目的是用來簡化新Spring應用的初始搭建以及開發過程。該框架使用了特定的方式來進行配置,從而使開發人員再也不須要定義樣板化的配置。經過這種方式,Spring Boot致力於在蓬勃發展的快速應用開發領域(rapid application development)成爲領導者。java
建立獨立的Spring應用程序nginx
嵌入的Tomcat,無需部署WAR文件git
簡化Maven配置github
自動配置Spring正則表達式
提供生產就緒型功能,如指標,健康檢查和外部配置算法
概述spring
Nginx(engine x)是一個開源的,支持高併發的www服務和代理服務軟件。Nginx是俄羅斯人Igor Sysoev開發的,最初被應用到俄羅斯的大型網站(www.rambler.ru)上。後來做者將源代碼以類BSD許可證的形式開源出來供全球使用。在功能應用方面,Nginx不只是一個優秀的Web服務軟件,還具備反向代理負載均衡和緩存的功能。在反向代理負載均衡方面相似於LVS負載均衡及HAProxy等你專業代理軟件。Nginx部署起來更加方便簡單,在緩存服務功能方面,有相似於Squid等專業的緩存服務軟件。Nginx能夠運行在UNIX、Linux、MS Windows Server、Mac OS X Server、Solaris等操做系統中。數據庫
Nginx的重要特性apache
Nginx所具有的WWW服務特性
Nginx軟件主要企業應用
Web服務應用產品性能對比
爲何Nginx比Apache的性能高?
如何正確採用Web服務器?
關於部署,就不在重複了,若是須要請移步《Java高級架構之FastDFS分佈式文件集羣》:http://www.javashuo.com/article/p-awevzoil-x.html
<dependencies> <!-- SpringBoot的自動配置相關依賴 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> <version>1.5.20.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <version>1.5.20.RELEASE</version> </dependency> <!-- 日誌相關的依賴 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> <version>1.5.20.RELEASE</version> </dependency> <!-- 對象池相關的依賴 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.6.0</version> </dependency> </dependencies>
annotation
:存放相關的註解
autoconfiguation
: 存儲自動配置類
factory
: 存放工廠類
properties
: 存放配置參數類
service
: 存放服務類通常狀況下,SpringBoot都會提供相應的@EnableXxx
註解標註在應用的主啓動類上開啓某個功能:
// EnableFastdfsClient.java @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Import(FastdfsAutoConfiguration.class) @Documented public @interface EnableFastdfsClient { }
下面是相關的自動配置類:
// FastdfsAutoConfiguration.java @Configuration @EnableConfigurationProperties(FastdfsProperties.class) public class FastdfsAutoConfiguration { @Autowired private FastdfsProperties fastdfsProperties; @Bean @ConditionalOnMissingBean(FastdfsClientService.class) public FastdfsClientService fastdfsClientService() throws Exception { return new FastdfsClientService(fastdfsProperties); } }
建立相關的工廠類:
// StorageClientFactory.java // 用於建立鏈接對象的工廠類 public class StorageClientFactory implements PooledObjectFactory<StorageClient> { @Override public PooledObject<StorageClient> makeObject() throws Exception { TrackerClient client = new TrackerClient(); TrackerServer server = client.getConnection(); return new DefaultPooledObject<>(new StorageClient(server, null)); } @Override public void destroyObject(PooledObject<StorageClient> p) throws Exception { p.getObject().getTrackerServer().close(); } @Override public boolean validateObject(PooledObject<StorageClient> p) { return false; } @Override public void activateObject(PooledObject<StorageClient> p) throws Exception { } @Override public void passivateObject(PooledObject<StorageClient> p) throws Exception { } }
Properties類用來映射application.properties或者application.yml配置文件:
// FastdfsProperties.java @ConfigurationProperties(prefix = "fastdfs") public class FastdfsProperties { // 鏈接超時時間 // 網絡超時時間 // 字符集編碼 // 是否使用Token // Token加密密鑰 // 跟蹤器IP地址,多個使用分號隔開 // 鏈接池的鏈接對象最大個數 // 鏈接池的最大空閒對象個數 // 鏈接池的最小空閒對象個數 // Nginx服務器IP,多個使用分號分割 // 獲取鏈接對象時可忍受的等待時長(毫秒) private String connectTimeout = "5"; private String networkTimeout = "30"; private String charset = "UTF-8"; private String httpAntiStealToken = "false"; private String httpSecretKey = ""; private String httpTrackerHttpPort = ""; private String trackerServers = ""; private String connectionPoolMaxTotal = "18"; private String connectionPoolMaxIdle = "18"; private String connectionPoolMinIdle = "2"; private String nginxServers = ""; // 須要建立相關的Setter和Getter方法 }
在Service類中封裝方法, 下面僅展現3個經常使用的方法:
// FastdfsClientSerivce.java public class FastdfsClientService { // SpringBoot加載的配置文件 // 鏈接池配置項 // 轉換後的配置條目 // 鏈接池 // Nginx服務器地址 private FastdfsProperties fdfsProp; private GenericObjectPoolConfig config; private Properties prop; private GenericObjectPool<StorageClient> pool; private String[] nginxServers; private Logger logger; public FastdfsClientService(FastdfsProperties fdfsProp) throws Exception { this.fdfsProp = fdfsProp; this.logger = LoggerFactory.getLogger(getClass()); init(); create(); info(); } /** * 初始化全局客戶端 */ private void init() throws Exception { this.prop = new Properties(); this.logger.info("FastDFS: reading config file..."); this.logger.info("FastDFS: fastdfs.connect_timeout_in_seconds=" + this.fdfsProp.getConnectTimeout()); this.logger.info("FastDFS: fastdfs.network_timeout_in_seconds=" + this.fdfsProp.getNetworkTimeout()); this.logger.info("FastDFS: fastdfs.charset=" + this.fdfsProp.getCharset()); this.logger.info("FastDFS: fastdfs.http_anti_steal_token=" + this.fdfsProp.getHttpAntiStealToken()); this.logger.info("FastDFS: fastdfs.http_secret_key=" + this.fdfsProp.getHttpSecretKey()); this.logger.info("FastDFS: fastdfs.http_tracker_http_port=" + this.fdfsProp.getHttpTrackerHttpPort()); this.logger.info("FastDFS: fastdfs.tracker_servers=" + this.fdfsProp.getTrackerServers()); this.logger.info("FastDFS: fastdfs.connection_pool_max_total=" + this.fdfsProp.getConnectionPoolMaxTotal()); this.logger.info("FastDFS: fastdfs.connection_pool_max_idle=" + this.fdfsProp.getConnectionPoolMaxIdle()); this.logger.info("FastDFS: fastdfs.connection_pool_min_idle=" + this.fdfsProp.getConnectionPoolMinIdle()); this.logger.info("FastDFS: fastdfs.nginx_servers=" + this.fdfsProp.getNginxServers()); this.prop.put("fastdfs.connect_timeout_in_seconds", this.fdfsProp.getConnectTimeout()); this.prop.put("fastdfs.network_timeout_in_seconds", this.fdfsProp.getNetworkTimeout()); this.prop.put("fastdfs.charset", this.fdfsProp.getCharset()); this.prop.put("fastdfs.http_anti_steal_token", this.fdfsProp.getHttpAntiStealToken()); this.prop.put("fastdfs.http_secret_key", this.fdfsProp.getHttpSecretKey()); this.prop.put("fastdfs.http_tracker_http_port", this.fdfsProp.getHttpTrackerHttpPort()); this.prop.put("fastdfs.tracker_servers", this.fdfsProp.getTrackerServers()); ClientGlobal.initByProperties(this.prop); } /** * 顯示初始化信息 */ private void info() { this.logger.info("FastDFS parameter: ConnectionPoolMaxTotal ==> " + this.pool.getMaxTotal()); this.logger.info("FastDFS parameter: ConnectionPoolMaxIdle ==> " + this.pool.getMaxIdle()); this.logger.info("FastDFS parameter: ConnectionPoolMinIdle ==> " + this.pool.getMinIdle()); this.logger.info("FastDFS parameter: NginxServer ==> " + Arrays.toString(this.nginxServers)); this.logger.info(ClientGlobal.configInfo()); } /** * 建立鏈接池 */ private void create() { this.config = new GenericObjectPoolConfig(); this.logger.info("FastDFS Client: Creating connection pool..."); this.config.setMaxTotal(Integer.parseInt(this.fdfsProp.getConnectionPoolMaxTotal())); this.config.setMaxIdle(Integer.parseInt(this.fdfsProp.getConnectionPoolMaxIdle())); this.config.setMinIdle(Integer.parseInt(this.fdfsProp.getConnectionPoolMinIdle())); StorageClientFactory factory = new StorageClientFactory(); this.pool = new GenericObjectPool<StorageClient>(factory, this.config); this.nginxServers = this.fdfsProp.getNginxServers().split(","); } /** * Nginx服務器負載均衡算法 * * @param servers 服務器地址 * @param address 客戶端IP地址 * @return 可用的服務器地址 */ private String getNginxServer(String[] servers, String address) { int size = servers.length; int i = address.hashCode(); int index = abs(i % size); return servers[index]; } /** * 帶有防盜鏈的下載 * * @param fileGroup 文件組名 * @param remoteFileName 遠程文件名稱 * @param clientIpAddress 客戶端IP地址 * @return 完整的URL地址 */ public String autoDownloadWithToken(String fileGroup, String remoteFileName, String clientIpAddress) throws Exception { int ts = (int) (System.currentTimeMillis() / 1000); String token = ProtoCommon.getToken(remoteFileName, ts, ClientGlobal.getG_secret_key()); String nginx = this.getNginxServer(this.nginxServers, clientIpAddress); return "http://" + nginx + "/" + fileGroup + "/" + remoteFileName + "?token=" + token + "&ts=" + ts; } /** * 上傳文件,適合上傳圖片 * * @param buffer 字節數組 * @param ext 擴展名 * @return 文件組名和ID */ public String[] autoUpload(byte[] buffer, String ext) throws Exception { String[] upload = this.upload(buffer, ext, null); return upload; } /** * 不帶防盜鏈的下載,若是開啓防盜鏈會致使該方法拋出異常 * * @param fileGroup 文件組名 * @param remoteFileName 遠程文件ID * @param clientIpAddress 客戶端IP地址,根據客戶端IP來分配Nginx服務器 * @return 完整的URL地址 */ public String autoDownloadWithoutToken(String fileGroup, String remoteFileName, String clientIpAddress) throws Exception { if (ClientGlobal.getG_anti_steal_token()) { this.logger.error("FastDFS Client: You've turned on Token authentication."); throw new Exception("You've turned on Token authentication."); } String nginx = this.getNginxServer(this.nginxServers, clientIpAddress); return "http://" + nginx + fileGroup + "/" + remoteFileName; } // 後面還有好多方法,就不一一展現了 }
爲了在IDEA中使用便捷的配置提示功能,咱們須要建立元數據文件(resources/spring-configuration-metadata.json):
{ "groups": [ { "name": "fastdfs", "type": "com.bluemiaomiao.properties.FastdfsProperties", "sourceType": "com.bluemiaomiao.properties.FastdfsProperties" } ], "properties": [ { "name": "connectTimeout", "type": "java.lang.String", "sourceType": "com.bluemiaomiao.properties.FastdfsProperties", "defaultValue": "5" }, { "name": "networkTimeout", "type": "java.lang.String", "sourceType": "com.bluemiaomiao.properties.FastdfsProperties", "defaultValue": "30" }, { "name": "charset", "type": "java.lang.String", "defaultValue": "UTF-8" }, { "name": "httpAntiStealToken", "type": "java.lang.String", "sourceType": "com.bluemiaomiao.properties.FastdfsProperties", "defaultValue": "false" }, { "name": "httpSecretKey", "type": "java.lang.String", "sourceType": "com.bluemiaomiao.properties.FastdfsProperties" }, { "name": "httpTrackerHttpPort", "type": "java.lang.Integer", "sourceType": "com.bluemiaomiao.properties.FastdfsProperties" }, { "name": "trackerServers", "type": "java.lang.String", "sourceType": "com.bluemiaomiao.properties.FastdfsProperties" }, { "name": "connectionPoolMaxTotal", "type": "java.lang.Integer", "sourceType": "com.bluemiaomiao.properties.FastdfsProperties", "defaultValue": "18" }, { "name": "connectionPoolMaxIdle", "type": "java.lang.Integer", "sourceType": "com.bluemiaomiao.properties.FastdfsProperties", "defaultValue": "18" }, { "name": "connectionPoolMinIdle", "type": "java.lang.Integer", "sourceType": "com.bluemiaomiao.properties.FastdfsProperties", "defaultValue": "2" }, { "name": "nginxServers", "type": "java.lang.String", "sourceType": "com.bluemiaomiao.properties.FastdfsProperties" } ], "hints": [ { "name": "http_anti_steal_token", "values": [ { "value": "false" }, { "value": "true" } ] } ] }
建立SpringBoot項目,勾選Web選項,版本選擇1.5.20
進入場景啓動器的項目目錄執行mvn clean install
將其安裝到本地
<dependency> <groupId>com.bluemiaomiao</groupId> <artifactId>fastdfs-spring-boot-starter</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
記得開啓IDEA的自動導入功能
fastdfs.nginx-servers=192.168.80.2:8000,192.168.80.3:8000,192.168.80.4:8000 fastdfs.tracker-servers=192.168.80.2:22122,192.168.80.3:22122,192.168.80.4:22122 fastdfs.http-secret-key=2scPwMPctXhbLVOYB0jyuyQzytOofmFCBIYe65n56PPYVWrntxzLIDbPdvDDLJM8QHhKxSGWTcr+9VdG3yptkw fastdfs.http-anti-steal-token=true fastdfs.http-tracker-http-port=8080 fastdfs.network-timeout=30 fastdfs.connect-timeout=5 fastdfs.connection-pool-max-idle=18 fastdfs.connection-pool-min-idle=2 fastdfs.connection-pool-max-total=18 fastdfs.charset=UTF-8
或者使用application.yml
fastdfs: charset: UTF-8 connect-timeout: 5 http-secret-key: 2scPwMPctXhbLVOYB0jyuyQzytOofmFCBIYe65n56PPYVWrntxzLIDbPdvDDLJM8QHhKxSGWTcr+9VdG3yptkw network-timeout: 30 http-anti-steal-token: true http-tracker-http-port: 8080 connection-pool-max-idle: 20 connection-pool-max-total: 20 connection-pool-min-idle: 2 nginx-servers: 192.168.80.2:8000,192.168.80.3:8000,192.168.80.4:8000 tracker-servers: 192.168.80.2:22122,192.168.80.3:22122,192.168.80.4:22122
// controllers.DownloadController.java @Controller @RequestMapping(value = "/download") public class DownloadController { @Autowired private FastdfsClientService service; @ResponseBody @RequestMapping(value = "/image") public String image() throws Exception { // 以前上傳過的數據,實際應用場景應該使用SQL數據庫來存儲 return service.autoDownloadWithToken("group1", "M00/00/00/wKhQA1ysjSGAPjXbAAVFOL7FJU4.tar.gz", "192.168.80.1"); } }