分布式環境下用redis類比session

來源:互聯網
上載者:User

首先為什麼使用redis。

因為分布式有不同伺服器的緣故,如果你安照一般方式儲存session,那麼你的session會儲存在某一台伺服器上,如果你的下一個請求並不是訪問這台伺服器,那麼會發生讀取不到session的情況

redis儲存的實現方案:

第一種 是使用容器拓展來實現,一般都是通過容器外掛程式來實現,例如基於Tomcat的tomcat-redis-session-manager,基於Jetty的jetty-session-redis等等。好處是對項目來說是透明的,無需更改代碼,但是目前還不支援Tomcat8。個人覺得由於過於依賴容器,,一旦更換容器或者容器升級,那又得重新來過。而且代碼並不在項目中,對於開發人員的維護也是個麻煩。

第二種 是自訂會話管理的工具類,這樣的話靈活性很大,可以根據自身需求來實現,但是需要額外的開發時間

第三種是使用架構的會話管理工具,例如spring-session,shiro等,可以理解是替換了servlet那一套會話管理,不依賴容器,不用改動代碼。如果採用spring-session的話,使用的是spring-data-redis那一套串連池,prefect,不過前提是你得用spring架構。至於shiro,那是一個十分成熟,強大易用的安全架構,學習成本比spring-session來的要多一些。

下面我們介紹一下第二種方式的實現

要注意的是為什麼前端用ajax的方式登入,因為把類比的session資訊用存到redis後,需要在本地存入userId和token來作為使用者的標識,通過這個標識去redis裡驗證該使用者是否登入,從而擷取redis中的使用者登入資訊,但是分布式中多個系統對應多個domain,所以login模組產生的userId和token要想每個系統都用,必須每個系統都產生自己的cookie資訊,java端無法為每個系統產生一份cookie所以只能在前端用iframe的方式為每個系統產生一份cookie

下面是詳細代碼

redis的配置:

<?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:context="http://www.springframework.org/schema/context"    xmlns:mongo="http://www.springframework.org/schema/data/mongo" xmlns:p="http://www.springframework.org/schema/p"    xsi:schemaLocation="http://www.springframework.org/schema/context             http://www.springframework.org/schema/context/spring-context.xsd             http://www.springframework.org/schema/data/mongo             http://www.springframework.org/schema/data/mongo/spring-mongo-1.7.xsd             http://www.springframework.org/schema/beans             http://www.springframework.org/schema/beans/spring-beans.xsd">    <!-- redis緩衝部分 -->    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">        <property name="maxIdle" value="${redis.maxIdle}" />        <property name="maxTotal" value="${redis.maxTotal}" />        <property name="maxWaitMillis" value="${redis.maxWaitMillis}" />        <property name="testOnBorrow" value="${redis.testOnBorrow}" />    </bean>    <bean id="redisConnectionFactory"        class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"        p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.pass}"        p:pool-config-ref="poolConfig" />    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">        <property name="connectionFactory" ref="redisConnectionFactory" />    </bean>    <!--載入redis -->    <bean id="redisService" class="com.maigangle.b2b.common.redis.RedisSpringServiceImpl">        <!-- 控制redis開關 -->        <property name="isUse" value="true"></property>    </bean></beans>

RedisSpringServiceImpl.java

package com.maigangle.b2b.common.redis;import java.io.UnsupportedEncodingException;import java.util.ArrayList;import java.util.HashMap;import java.util.LinkedHashMap;import java.util.List;import java.util.Map;import org.apache.commons.lang.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.dao.DataAccessException;import org.springframework.data.redis.RedisConnectionFailureException;import org.springframework.data.redis.connection.RedisConnection;import org.springframework.data.redis.core.RedisCallback;import org.springframework.data.redis.core.RedisTemplate;import com.alibaba.fastjson.JSON;import com.maigangle.b2b.common.exception.CommonException;/** * redis介面實現 *  * @author  * @since  * @version 1.0 * */public class RedisSpringServiceImpl implements RedisSpringService {    private static String redisCode = "utf-8";    private boolean isUse; // redis開關    private byte[] getBytes(String str) {        try {            return str.getBytes(redisCode);        } catch (UnsupportedEncodingException e) {            return str.getBytes();        }    }    public boolean isUse() {        return isUse;    }    public void setIsUse(boolean isUse) {        this.isUse = isUse;    }    @Autowired    private RedisTemplate<String, String> redisTemplate;    public void pub(String channel, String param) {        if (!isUse)            return;        redisTemplate.convertAndSend(channel, param);    }    /**     * @param key     */    public Long del(final String... keys) {        if (!isUse)            return null;        try {            long re = redisTemplate.execute(new RedisCallback<Long>() {                public Long doInRedis(RedisConnection connection) throws DataAccessException {                    long result = 0;                    for (int i = 0; i < keys.length; i++) {                        result = connection.del(keys[i].getBytes());                        result++;                    }                    return result;                }            });            return re;        } catch (Exception e) {            return null;        }    }    /**     * @param key     * @param value     * @param liveTime     */    public void set(final byte[] key, final byte[] value, final long liveTime) {        if (!isUse)            return;        try {            redisTemplate.execute(new RedisCallback<Long>() {                public Long doInRedis(RedisConnection connection) throws DataAccessException {                    connection.set(key, value);                    if (liveTime > 0) {                        connection.expire(key, liveTime);                    }                    return 1L;                }            });        } catch (Exception e) {            closeSwitch(e);            e.printStackTrace();        }    }    /**     * @param key     * @param value     * @param liveTime     */    public void set(String key, String value, long liveTime) {        this.set(getBytes(key), getBytes(value), liveTime);    }    /**     * @param key     * @param liveTime     */    public boolean expire(String key, long liveTime) {        if (!isUse)            return false;        try {            return redisTemplate.execute(new RedisCallback<Boolean>() {                public Boolean doInRedis(RedisConnection connection) throws DataAccessException {                    return connection.expire(key.getBytes(), liveTime);                }            });        } catch (Exception e) {            closeSwitch(e);            e.printStackTrace();            return false;        }    }    /**     * @param key     * @param value     */    public void set(String key, String value) {        this.set(key, value, 0L);    }    /**     * @param key     * @param value     */    public void set(byte[] key, byte[] value) {        this.set(key, value, 0L);    }    /**     * @param key     * @param value     */    public void set(String key, byte[] value) {        this.set(getBytes(key), value, 0L);    }    /**     *      */    @Override    public void setOjb(String key, Object value, long time) {        this.set(getBytes(key), getBytes(JSON.toJSONString(value)), time);    }    /**     * @param key     * @return     */    public String get(final String key) {        if (!isUse)            return null;        try {            return redisTemplate.execute(new RedisCallback<String>() {                public String doInRedis(RedisConnection connection) throws DataAccessException {                    try {                        byte[] bytes = connection.get(getBytes(key));                        if (bytes == null || bytes.length == 0) {                            return null;                        }                        return new String(bytes, redisCode);                    } catch (UnsupportedEncodingException e) {                        e.printStackTrace();                    } catch (Exception e1) {                        e1.printStackTrace();                        return null;                    }                    return "";                }            });        } catch (Exception e) {            closeSwitch(e);            e.printStackTrace();            return null;        }    }    public byte[] get4byte(final String key) {        if (!isUse)            return null;        try {            return redisTemplate.execute(new RedisCallback<byte[]>() {                public byte[] doInRedis(RedisConnection connection) throws DataAccessException {                    try {                        return connection.get(getBytes(key));                    } catch (Exception e1) {                        e1.printStackTrace();                        return null;                    }                }            });        } catch (Exception e) {            closeSwitch(e);            e.printStackTrace();            return null;        }    }    @Override    public <T> T getObj(String key, Class<T> elementType) {        String jsonString = this.get(key);        T obj;        obj = JSON.parseObject(jsonString, elementType);        if (obj == null) {            try {                obj = elementType.newInstance();// 防止null 指標異常            } catch (InstantiationException | IllegalAccessException e) {                throw new CommonException("get redis error:", e);            }        }        return obj;    }    /**     * @param pattern     * @return     */    public void Setkeys(String pattern) {        if (!isUse)            return;        try {            redisTemplate.keys(pattern);        } catch (Exception e) {            closeSwitch(e);            e.printStackTrace();        }    }    /**     * @param key     * @return     */    public boolean exists(final String key) {        if (!isUse)            return false;        try {            return redisTemplate.execute(new RedisCallback<Boolean>() {                public Boolean doInRedis(RedisConnection connection) throws DataAccessException {                    return connection.exists(getBytes(key));                }            });        } catch (Exception e) {            closeSwitch(e);            e.printStackTrace();            return false;        }    }    /**     * @return     */    // public String flushDB() {    // if(!isUse) return null;    // return redisTemplate.execute(new RedisCallback<String>() {    // public String doInRedis(RedisConnection connection) throws    // DataAccessException {    // connection.flushDb();    // return "ok";    // }    // });    // }    public boolean flushDB() {        if (!isUse)            return false;        try {            return redisTemplate.execute(new RedisCallback<Boolean>() {                public Boolean doInRedis(RedisConnection connection) throws DataAccessException {                    connection.flushDb();                    return true;                }            });        } catch (Exception e) {            closeSwitch(e);            e.printStackTrace();            return false;        }    }    /**     * @return     */    public long dbSize() {        if (!isUse)            return 0;        try {            return redisTemplate.execute(new RedisCallback<Long>() {                public Long doInRedis(RedisConnection connection) throws DataAccessException {                    return connection.dbSize();                }            });        } catch (Exception e) {            closeSwitch(e);            e.printStackTrace();            return 0;        }    }    /**     * @return     */    public String ping() {        if (!isUse)            return null;        try {            return redisTemplate.execute(new RedisCallback<String>() {                public String doInRedis(RedisConnection connection) throws DataAccessException {                    return connection.ping();                }            });        } catch (Exception e) {            closeSwitch(e);            e.printStackTrace();            return null;        }    }    private void closeSwitch(Exception e) {        if (e instanceof RedisConnectionFailureException) {            this.isUse = false;        }    }    /**     * submit check token     *      * @param token     * @return     */    public boolean checkToken(String token) {        if (StringUtils.isBlank(token)) {            return false;        }        Object tk = this.get(token);        if (tk != null) {            this.del(token);            return true;        }        return false;    }    @Override    public void setHm(String key, Map<String, String> map, long liveTime) {        if (!isUse)            return;        final Map<byte[], byte[]> hashes = new LinkedHashMap<byte[], byte[]>(map.size());        for (Map.Entry<String, String> entry : map.entrySet()) {            hashes.put(getBytes(entry.getKey()), getBytes(entry.getValue()));        }        redisTemplate.execute(new RedisCallback<Object>() {            public Object doInRedis(RedisConnection connection) {                connection.hMSet(getBytes(key), hashes);                if (liveTime > 0) {                    connection.expire(getBytes(key), liveTime);                }                return null;            }        }, true);    }    @Override    public Map<String, String> getHm(String key) {        final byte[] rawKey = getBytes(key);        Map<byte[], byte[]> entries = redisTemplate.execute(new RedisCallback<Map<byte[], byte[]>>() {            public Map<byte[], byte[]> doInRedis(RedisConnection connection) {                return connection.hGetAll(rawKey);            }        }, true);        Map<String, String> map = new LinkedHashMap<String, String>(entries.size());        for (Map.Entry<byte[], byte[]> entry : entries.entrySet()) {            try {                map.put(new String(entry.getKey(), redisCode), new String(entry.getValue(), redisCode));            } catch (UnsupportedEncodingException e) {                return new HashMap<String, String>();            }        }        return map;    }    @Override    public void setList(String key, List<String> list, long liveTime) {        if (!isUse)            return;        final List<byte[]> listes = new ArrayList<byte[]>(list.size());        for (String value : list) {            listes.add(getBytes(value));        }        redisTemplate.execute(new RedisCallback<Object>() {
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.