概述:
在之前的博客中,有提到過Redis 在服務端的一些相關知識,今天主要講一下Java 整合Redis的相關內容。
下面是Jedis 的相關依賴:
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.5.1</version> </dependency> <!-- redis --> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.0.2.RELEASE</version> </dependency>
1、Jedis 單機客戶端
首先我們了解一下,使用Jedis 連接我們的Redis 服務器:
public static void main(String[] args) {
String host = "127.0.0.1"; int port = 6379; Jedis jedis = new Jedis(host,port,50000); jedis.set("name","jayce"); String name = jedis.get("name"); System.out.println(name); jedis.close(); }
我們先來看直觀的運行結果:
1.1 Jedis 構造函數:
我們先從Jedis 的構造函數開始說起,在Jedis的源碼中,我們可以看到Jedis 提供以下幾種構造函數:
從上圖中我們可以看到一個很重要的信息,Jedis 繼承BinaryJedis,並且它的所有構造函數都采用了父類的構造函數:
//根據host 默認端口6379獲取連接
public Jedis(final String host) {
super(host); } //根據host 與特定端口獲取連接 public Jedis(final String host, final int port) { super(host, port); } //根據host 與特定端口獲取連接,並且設定key的生命周期 public Jedis(final String host, final int port, final int timeout) { super(host, port, timeout); } //根據JedisShardInfo 配置信息,獲取連接 public Jedis(JedisShardInfo shardInfo) { super(shardInfo); } //根據特定URI 獲取連接 public Jedis(URI uri) { super(uri); }
我們可以觀察到父類BinaryJedis 的構造函數中,最終的目的是為了創建一個client,而這個client實質上是一個connection:
因此,我們在創建一個Jedis 對象的過程中,創建了一個對服務器進行連接的Client,而接下來的相關操作,也是由這個client 進行操作。
1.2 Jedis 的Get和Set:
在調用Get和Set方法之前,我們需要創建一個連接,然后進行相應的操作,下述代碼提供了設置字符串,和設置對象到Redis 中,需要注意的是,我們在將對象放到Redis 之前,需要將對象進行序列化,因此對象需要實現Serializable接口:
public static void main(String[] args) {
String host = "127.0.0.1"; int port = 6381; Jedis jedis = new Jedis(host, port); setString(jedis); setObject(jedis); jedis.close(); } private static void setString(Jedis jedis) { jedis.set("name", "jayce"); String name = jedis.get("name"); System.out.println(name); } private static void setObject(Jedis jedis) { User user = new User(); user.setId(1); user.setName("jayce"); user.setPassword("kong"); byte[] values = SerializeUtil.serialize(user); byte[] names = "user".getBytes(); jedis.set(names, values); byte[] bytes = jedis.get("user".getBytes()); User userCache = (User) SerializeUtil.unserialize(bytes); System.out.println(userCache); }
我們在服務器中的Redis 中可以看到:
數據已經緩存到了Redis 中。
然后,我們再跟蹤一下,Jedis 是如何將一個對象存到了服務器中的:
第一步:Jedis 調用 set 方法,然后調用內部的client進行操作:
public String set(final String key, String value) {
checkIsInMulti();
client.set(key, value);
return client.getStatusCodeReply(); }
第二步:client 調用 SafeEncoder.encode(key) 方法,將字符串轉換成二進制數組,再調用client 中的 set(byte[],byte[])方法:
public void set(final String key, final String value) {
set(SafeEncoder.encode(key), SafeEncoder.encode(value));
}
public void set(final byte[] key, final byte[] value) { sendCommand(Command.SET, key, value); }
第三步:在調用父類Connection中的 sendCommand() 方法,最終將內容傳到服務器中:
protected Connection sendCommand(final Command cmd, final byte[]... args) {
try { connect(); Protocol.sendCommand(outputStream, cmd, args); pipelinedCommands++; return this; } catch (JedisConnectionException ex) { // Any other exceptions related to connection? broken = true; throw ex; } }
2、Jedis 單機版整合Spring
在Spring官網中,給出了這樣得一個Demo:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:host-name="server" p:port="6379" /> </beans>
這個配置文件比較直接的幫我們配置了 jedisConectionFactory ,我們需要做的是注入這個Bean 之后,在工廠里面獲取到Connection,然后進行相應的操作。
根據常用的場景,我們用到的比較多的是 Pool<Jedis>,因此,這里為大家分享的是JedisPool 的相關配置:
<bean id="redisClient" class="redis.clients.jedis.JedisPool"> <constructor-arg name="host" value="${redis.host}"/> <constructor-arg name="port" value="${redis.port}"/> <!--<constructor-arg name="poolConfig" ref="jedisPoolConfig"/>--> </bean>
接下來我們研究一下,JedisPool 的源碼,方便我們對配置文件的理解:
public JedisPool(GenericObjectPoolConfig poolConfig, String host) {
this(poolConfig, host, 6379, 2000, (String)null, 0, (String)null); } public JedisPool(String host, int port) { this(new GenericObjectPoolConfig(), host, port, 2000, (String)null, 0, (String)null); } public JedisPool(String host) { URI uri = URI.create(host); if(uri.getScheme() != null && uri.getScheme().equals("redis")) { String h = uri.getHost(); int port = uri.getPort(); String password = uri.getUserInfo().split(":", 2)[1]; int database = Integer.parseInt(uri.getPath().split("/", 2)[1]); this.internalPool = new GenericObjectPool(new JedisFactory(h, port, 2000, password, database, (String)null), new GenericObjectPoolConfig()); } else { this.internalPool = new GenericObjectPool(new JedisFactory(host, 6379, 2000, (String)null, 0, (String)null), new GenericObjectPoolConfig()); } } public JedisPool(URI uri) { String h = uri.getHost(); int port = uri.getPort(); String password = uri.getUserInfo().split(":", 2)[1]; int database = Integer.parseInt(uri.getPath().split("/", 2)[1]); this.internalPool = new GenericObjectPool(new JedisFactory(h, port, 2000, password, database, (String)null), new GenericObjectPoolConfig()); } public JedisPool(GenericObjectPoolConfig poolConfig, String host, int port, int timeout, String password) { this(poolConfig, host, port, timeout, password, 0, (String)null); } public JedisPool(GenericObjectPoolConfig poolConfig, String host, int port) { this(poolConfig, host, port, 2000, (String)null, 0, (String)null); } public JedisPool(GenericObjectPoolConfig poolConfig, String host, int port, int timeout) { this(poolConfig, host, port, timeout, (String)null, 0, (String)null); } public JedisPool(GenericObjectPoolConfig poolConfig, String host, int port, int timeout, String password, int database) { this(poolConfig, host, port, timeout, password, database, (String)null); } public JedisPool(GenericObjectPoolConfig poolConfig, String host, int port, int timeout, String password, int database, String clientName) { super(poolConfig, new JedisFactory(host, port, timeout, password, database, clientName)); }
JedisPool 的構造函數與上述的Jedis 的構造函數很相似,這里比較特別的是 GenericObjectPoolConfig 這個配置類,這個類 是org.apache.commons.pool2 包下面的一個用來設置池的大小的類
我們在配置application.xml文件的時候,可以自己配置對應的池大小,但是如果沒有相應的配置文件的同學,推薦還是使用默認配置。
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext-Redis.xml"); Pool<Jedis> jedisPool = (Pool)applicationContext.getBean("redisClient"); Jedis jedis = jedisPool.getResource(); setString(jedis); setObject(jedis); jedisPool.returnResource(jedis); } private static void setString(Jedis jedis) { jedis.set("name", "jayce"); String name = jedis.get("name"); System.out.println(name); } private static void setObject(Jedis jedis) { User user = new User(); user.setId(1); user.setName("jayce"); user.setPassword("kong"); byte[] values = SerializeUtil.serialize(user); byte[] names = "user".getBytes(); jedis.set(names, values); byte[] bytes = jedis.get("user".getBytes()); User userCache = (User) SerializeUtil.unserialize(bytes); System.out.println(userCache); }
運行結果:
jayce
User{id=1, name='jayce', password='kong'}
3、總結
項目源碼:https://github.com/jaycekon/Crawl-Page
后面會繼續總結,Spring 整合 Redis 集群~