動態代理模式_應用(Redis工具類)

来源:https://www.cnblogs.com/zaizouggg/archive/2019/11/25/11930723.html
-Advertisement-
Play Games

本次使用動態代理的初衷是學習Redis,使用Java操作Redis時用到Jedis的JedisPool,而後對Jedis的方法進一步封裝完善成為一個工具類。因為直接使用Jedis對象時,為了保證性能,總會需要手動的獲取到連接池中的連接,使用完成後還需要手動的釋放連接,都是完全重覆的操作。所以想要使用 ...


本次使用動態代理的初衷是學習Redis,使用Java操作Redis時用到Jedis的JedisPool,而後對Jedis的方法進一步封裝完善成為一個工具類。
因為直接使用Jedis對象時,為了保證性能,總會需要手動的獲取到連接池中的連接,使用完成後還需要手動的釋放連接,都是完全重覆的操作。
所以想要使用一些方法來抽取出這些重覆操作,初時想到的是使用模板方法或是動態代理,但考慮到到模板方法會使用到大量的類,似乎與主旨不符,遂使用動態代理進行加強。

實現動態代理可使用JDK對應的方法,或是CGlib。由於工具類本身不會去定義介面,所以選擇CGlib。本身是在SpringBoot項目中進行,所以沒有額外導入CGlib的包(spring的面向切麵就使用到了CGlib與JDK自帶的動態 代理)。

具體的思路就是使用動態代理來增強工具類對象,使得工具類在調用方法前後對應的進行獲取連接及釋放連接操作。在獲得到增強工具類後只需要進行相關操作即可。

使用了Maven來管理項目,代碼所需的依賴如下

1 <!-- Jedis -->
2 <dependency>
3     <groupId>com.redislabs</groupId>
4     <artifactId>jredisearch-jedis</artifactId>
5     <version>3.0.0-20180508</version>
6 </dependency>

此外還需要自己電腦安裝Redis,或有對應的伺服器

代碼如下

 

Redis連接池代碼

 1 package com;
 2 
 3 import org.apache.logging.log4j.Logger;
 4 
 5 import redis.clients.jedis.Jedis;
 6 import redis.clients.jedis.JedisPool;
 7 import redis.clients.jedis.JedisPoolConfig;
 8 /**
 9  * Jedis連接池
10  * 
11  * @author zaizouGGG
12  *
13  */
14 public class RedisPool {
15     
16     private Logger logger = LogUtil.get(JedisUtil.class);
17     private static SysConfigUtil sysConfigUtil = SysConfigUtil.getSysConfigUtil("redis.properties");
18     
19     //聲明成static的原因:保證jedis連接池在tomcat啟動時就載入出來
20     //jedis連接池
21     private static JedisPool pool;
22     //與redis連接池連接的最大連接數
23     private static Integer maxTotal = sysConfigUtil.getInt("redis.maxTotal");
24     //在jedis連接池中最大的idle狀態(空閑的)的jedis實例的個數
25     private static Integer maxIdle = sysConfigUtil.getInt("redis.maxIdle");
26     //在jedis連接池中最小的idle狀態(空閑的)的jedis實例的個數
27     private static Integer minIdle = sysConfigUtil.getInt("redis.minIdle");
28     //在borrow一個jedis實例的時候,是否要進行驗證操作,如果賦值為true,則得到的jedis實例肯定是可用的
29     private static Boolean testOnBorrow = sysConfigUtil.getBoolean("redis.testOnBorrow");
30     //在return一個jedis實例的時候,是否要進行驗證操作,如果賦值為true,則返回jedis連接池的jedis實例肯定是可用的
31     private static Boolean testOnReturn = sysConfigUtil.getBoolean("redis.testOnReturn");
32     private static String redisIp = sysConfigUtil.getString("redis.host");
33     private static Integer redisPort = sysConfigUtil.getInt("redis.port");
34     private static String password = sysConfigUtil.getString("redis.password");
35 
36     //初始化連接池,只會調用一次
37     private static void initPool() {
38         JedisPoolConfig config = new JedisPoolConfig();
39 
40         config.setMaxTotal(maxTotal);
41         config.setMaxIdle(maxIdle);
42         config.setMinIdle(minIdle);
43 
44         config.setTestOnBorrow(testOnBorrow);
45         config.setTestOnReturn(testOnReturn);
46 
47         //連接池耗盡的時候,是否阻塞,false會拋出異常,true阻塞直到超時,會拋出超時異常,預設為true
48         config.setBlockWhenExhausted(true);
49 
50         //這裡超時時間是2s
51         if (password != null && !"".equals(password)) {
52             // redis 設置了密碼
53             pool = new JedisPool(config, redisIp, redisPort, 1000*2, password);
54         } else {
55             // redis 未設置密碼
56             pool = new JedisPool(config, redisIp, redisPort, 1000*2);
57         };
58         
59 
60     }
61 
62     static {
63         initPool();
64     }
65 
66     //從連接池中拿取一個實例
67     public static Jedis getJedis() {        
68         return pool.getResource();
69     }
70 
71     //返還Jedis
72     public static void returnJedis(Jedis jedis) {
73         jedis.close();
74     }
75 
76     //被使用的連接數
77     public static int getNumActive() {
78         return pool.getNumActive();
79     }
80     
81     //被阻塞的連接數?
82     public static int getNumWaiters() {
83         return pool.getNumWaiters();
84     }
85     
86     //空閑的連接數
87     public static int getNumIdle() {
88         return pool.getNumIdle();
89     }
90 }

讀取.properties配置文件的工具類

用於讀取配置在.properties中的參數

 1 package com;
 2 
 3 import java.io.BufferedInputStream;
 4 import java.io.FileInputStream;
 5 import java.io.IOException;
 6 import java.io.InputStream;
 7 import java.util.Properties;
 8 
 9 import org.apache.logging.log4j.Logger;
10 
11 /**
12  * 獲取自定義配置文件參數的共用方法
13  * 
14  * @author zaizouGGG
15 * 16 */ 17 public class SysConfigUtil { 18 19 private static Logger logger = LogUtil.get(SysConfigUtil.class); 20 private Properties properties = null; 21 22 public SysConfigUtil() { 23 24 } 25 26 public SysConfigUtil(Properties p) { 27 properties = p; 28 } 29 30 31 public static SysConfigUtil getSysConfigUtil(String url) { 32 try(InputStream in = new BufferedInputStream(new FileInputStream(url));) { 33 Properties p = new Properties(); 34 p.load(in); 35 //return p.getProperty("jdbc.type"); 36 return new SysConfigUtil(p); 37 } catch (IOException e) { 38 // TODO Auto-generated catch block 39 logger.error("Jedis工具類初始化失敗,讀取配置文件 "+url+" 出錯"); 40 e.printStackTrace(); 41 return null; 42 } 43 44 } 45 46 public String getString(String key) { 47 return properties.getProperty(key); 48 } 49 50 public int getInt(String key) { 51 int result = Integer.parseInt(properties.getProperty(key)); 52 return result; 53 } 54 55 public boolean getBoolean(String key) { 56 boolean result = Boolean.parseBoolean(properties.getProperty(key)); 57 return result; 58 } 59 60 public long getLong(String key) { 61 long result = Long.parseLong(properties.getProperty(key)); 62 return result; 63 } 64 }

Redis配置文件

此處的配置是我從網上找的,普通的使用沒有問題,要應用請慎重

redis.host=localhost
redis.port=6379
redis.password=root
#在指定時刻通過pool能夠獲取到的最大的連接的jedis個數
redis.maxTotal=8
#最大能夠保持idle的數量,控制一個pool最多有多少個狀態為idle的jedis實例
redis.maxIdle=8
#最小能夠保持idle的數量,控制一個pool最多有多少個狀態為idle的jedis實例
redis.minIdle=2
#在borrow一個jedis實例的時候,是否要進行驗證操作,如果賦值為true,則得到的jedis實例肯定是可用的
redis.testOnBorrow=true
#在return一個jedis實例的時候,是否要進行驗證操作,如果賦值為true,則返回jedis連接池的jedis實例肯定是可用的
redis.testOnReturn=false
#當連接池內的連接耗盡時,getBlockWhenExhausted為true時,連接會阻塞,超過了阻塞的時間(設定的maxWaitMillis,單位毫秒)時會報錯
redis.maxWaitMillis=3000
#在borrow一個jedis實例時,是否提前進行validate操作;如果為true,則得到的jedis實例均是可用的;預設是false
redis.testOnBorrow=false

Jedis的工具類

 

  1 package com;
  2 
  3 import java.io.IOException;
  4 import java.util.List;
  5 import java.util.Map;
  6 import java.util.Set;
  7 
  8 import org.apache.logging.log4j.Logger;
  9 
 10 import redis.clients.jedis.Jedis;
 11 import redis.clients.jedis.JedisPool;
 12 import redis.clients.jedis.JedisPoolConfig;
 13 import redis.clients.jedis.ListPosition;
 14 
 15 /**
 16  * Jedis 通用工具類
 17  * @author zaizouGGG
 18  *
 19  */
 20 public class JedisUtil {
 21     
 22     private Logger logger = LogUtil.get(JedisUtil.class);
 23     private Jedis jedis = null;
 24     
 25     public Jedis getJedis() {
 26         return jedis;
 27     }
 28 
 29     public void setJedis(Jedis jedis) {
 30         this.jedis = jedis;
 31     }
 32 
 33     /**
 34      * 獲取指定key的值,如果key不存在返回null,如果該Key存儲的不是字元串,會拋出一個錯誤
 35      *
 36      * @param key
 37      * @return
 38      */
 39     public String get(String key) {
 40         String value = jedis.get(key);
 41         return value;
 42     }
 43 
 44     /**
 45      * 設置key的值為value
 46      *
 47      * @param key
 48      * @param value
 49      * @return
 50      */
 51     public String set(String key, String value) {
 52         String result = jedis.set(key, value);
 53         return result;
 54     }
 55     
 56     /**
 57      * 刪除指定的key,也可以傳入一個包含key的數組
 58      *
 59      * @param keys
 60      * @return
 61      */
 62     public Long del(String... keys) {
 63         
 64         return jedis.del(keys);
 65     }
 66 
 67     /**
 68      * 通過key向指定的value值追加值
 69      *
 70      * @param key
 71      * @param str
 72      * @return
 73      */
 74     public Long append(String key, String str) {
 75         
 76         return jedis.append(key, str);
 77     }
 78 
 79     /**
 80      * 判斷key是否存在
 81      *
 82      * @param key
 83      * @return
 84      */
 85     public Boolean exists(String key) {
 86         
 87         return jedis.exists(key);
 88     }
 89 
 90     /**
 91      * 設置key value,如果key已經存在則返回0
 92      *
 93      * @param key
 94      * @param value
 95      * @return
 96      */
 97     public Long setnx(String key, String value) {
 98         
 99         return jedis.setnx(key, value);
100     }
101 
102     /**
103      * 設置key value並指定這個鍵值的有效期
104      *
105      * @param key
106      * @param seconds
107      * @param value
108      * @return
109      */
110     public String setex(String key, String value, int seconds) {
111         String result = jedis.setex(key, seconds, value);
112         return result;
113     }
114 
115     /**
116      * 通過key 和offset 從指定的位置開始將原先value替換
117      *
118      * @param key
119      * @param offset
120      * @param str
121      * @return
122      */
123     public Long setrange(String key, int offset, String str) {
124         
125         return jedis.setrange(key, offset, str);
126     }
127 
128     /**
129      * 通過批量的key獲取批量的value
130      *
131      * @param keys
132      * @return
133      */
134     public List<String> mget(String... keys) {
135         
136         return jedis.mget(keys);
137     }
138 
139     /**
140      * 批量的設置key:value,也可以一個
141      *
142      * @param keysValues
143      * @return
144      */
145     public String mset(String... keysValues) {
146         
147         return jedis.mset(keysValues);
148     }
149 
150     /**
151      * 批量的設置key:value,可以一個,如果key已經存在則會失敗,操作會回滾
152      *
153      * @param keysValues
154      * @return
155      */
156     public Long msetnx(String... keysValues) {
157         
158         return jedis.msetnx(keysValues);
159     }
160 
161     /**
162      * 設置key的值,並返回一個舊值
163      *
164      * @param key
165      * @param value
166      * @return
167      */
168     public String getSet(String key, String value) {
169         
170         return jedis.getSet(key, value);
171     }
172 
173     /**
174      * 通過下標 和key 獲取指定下標位置的 value
175      *
176      * @param key
177      * @param startOffset
178      * @param endOffset
179      * @return
180      */
181     public String getrange(String key, int startOffset, int endOffset) {
182         
183         return jedis.getrange(key, startOffset, endOffset);
184     }
185 
186     /**
187      * 通過key 對value進行加值+1操作,當value不是int類型時會返回錯誤,當key不存在是則value為1
188      *
189      * @param key
190      * @return
191      */
192     public Long incr(String key) {
193         
194         return jedis.incr(key);
195     }
196 
197     /**
198      * 通過key給指定的value加值,如果key不存在,則這是value為該值
199      *
200      * @param key
201      * @param integer
202      * @return
203      */
204     public Long incrBy(String key, long integer) {
205         
206         return jedis.incrBy(key, integer);
207     }
208 
209     /**
210      * 對key的值做減減操作,如果key不存在,則設置key為-1
211      *
212      * @param key
213      * @return
214      */
215     public Long decr(String key) {
216         
217         return jedis.decr(key);
218     }
219 
220     /**
221      * 減去指定的值
222      *
223      * @param key
224      * @param integer
225      * @return
226      */
227     public Long decrBy(String key, long integer) {
228         
229         return jedis.decrBy(key, integer);
230     }
231 
232     /**
233      * 通過key獲取value值的長度
234      *
235      * @param key
236      * @return
237      */
238     public Long strLen(String key) {
239         
240         return jedis.strlen(key);
241     }
242 
243     /**
244      * 通過key給field設置指定的值,如果key不存在則先創建,如果field已經存在,返回0
245      *
246      * @param key
247      * @param field
248      * @param value
249      * @return
250      */
251     public Long hsetnx(String key, String field, String value) {
252         
253         return jedis.hsetnx(key, field, value);
254     }
255 
256     /**
257      * 通過key給field設置指定的值,如果key不存在,則先創建
258      *
259      * @param key
260      * @param field
261      * @param value
262      * @return
263      */
264     public Long hset(String key, String field, String value) {
265         
266         return jedis.hset(key, field, value);
267     }
268 
269     /**
270      * 通過key同時設置 hash的多個field
271      *
272      * @param key
273      * @param hash
274      * @return
275      */
276     public String hmset(String key, Map<String, String> hash) {
277         
278         return jedis.hmset(key, hash);
279     }
280 
281     /**
282      * 通過key 和 field 獲取指定的 value
283      *
284      * @param key
285      * @param failed
286      * @return
287      */
288     public String hget(String key, String failed) {
289         
290         return jedis.hget(key, failed);
291     }
292 
293     /**
294      * 設置key的超時時間為seconds
295      *
296      * @param key
297      * @param seconds
298      * @return
299      */
300     public Long expire(String key, int seconds) {
301         
302         return jedis.expire(key, seconds);
303     }
304 
305     /**
306      * 通過key 和 fields 獲取指定的value 如果沒有對應的value則返回null
307      *
308      * @param key
309      * @param fields 可以是 一個String 也可以是 String數組
310      * @return
311      */
312     public List<String> hmget(String key, String... fields) {
313         
314         return jedis.hmget(key, fields);
315     }
316 
317     /**
318      * 通過key給指定的field的value加上給定的值
319      *
320      * @param key
321      * @param field
322      * @param value
323      * @return
324      */
325     public Long hincrby(String key, String field, Long value) {
326         
327         return jedis.hincrBy(key, field, value);
328     }
329 
330     /**
331      * 通過key和field判斷是否有指定的value存在
332      *
333      * @param key
334      * @param field
335      * @return
336      */
337     public Boolean hexists(String key, String field) {
338         
339         return jedis.hexists(key, field);
340     }
341 
342     /**
	   

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 小圖展示大圖 1 <style> 2 *{margin:0;padding:0;} 3 ul,ol{list-style:none;} 4 #box { 5 position:relative; 6 margin:100px auto; 7 border:1px solid #ccc; 8 widt ...
  • 自引jquery 1 <style> 2 * { margin: 0; padding: 0; } 3 ul { list-style: none; margin: 100px; } 4 .comment { 5 color: red; 6 } 7 8 .comment li { 9 float: ...
  • 螢火蟲 <style type="text/css"> *{ padding: 0; margin: 0; } #bg{ background: url(img/bg.jpg) no-repeat; background-size: cover; width: 100%; height: 100%; ...
  • 下雪效果 1 <style> 2 * { 3 margin: 0; 4 padding: 0; 5 } 6 #box { 7 width: 1000px; 8 height: 600px; 9 background: #000000; 10 border: 5px solid red; 11 mar ...
  • 選項卡(tab欄切換) 1 <style type="text/css"> 2 *{margin: 0; padding: 0; font-family: "微軟雅黑";font-size: 14px;} 3 #container{ 4 width: 398px; 5 margin: 100px a ...
  • 前端開發工作中經常會碰到奇形怪狀的圖形,當然也少不了UI設計童鞋的腦洞和創意啦,初級的開發人員可能會選擇使用圖片做背景加上位置屬性實現,不過很多時候,CSS能實現的就不要再動用PS等工具了,時間寶貴,經驗更寶貴,畢竟簡單的搬磚很容易就會,不動“聲色“的實現才是來之不易的經(踩)驗(坑) 完事開通難, ...
  • 在看設計模式這本書,遇到一個令人疑惑的for迴圈語句 比較疑惑,因為從平時接觸的來看基本上都是 現在的疑惑如下 實際上上面的語句等同於,這是為什麼 原來這裡等同於把迴圈終止條件和迴圈被執行後執行的語句相結合了即把判斷和賦值放到一起了,一邊迴圈一邊賦值,i--是什麼判斷條件,當i--為fasle即,循 ...
  • 基於offsetHeight和clientHeight判斷是否出現滾動條 by:授客 QQ:1033553122 HTMLEelement.offsetHeight簡介 HTMLElement.offsetHeight 是一個只讀屬性,它返回該元素的像素高度,高度包含該元素的垂直內邊距和邊框,且是一 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...