java | Spring Boot 與 Redis 實現 Cache 以及 Session 共享

完成狀態

  • [ ] 編寫中
  • [ ] 已完成
  • [x] 維護中

原文html

Redis

Redis是一個使用ANSI C編寫的開源、支持網絡、基於內存、可選持久性的鍵值對存儲數據庫 ------ 維基百科

Redis 是目前業界使用普遍的基於內存的 Key-Value數據庫。 其提供了豐富的數據結構,不只限於字符串類型,例如hash, lists ,sets等複雜數據結構,同時提供了數據持久化功能。其基於內存的特性以及豐富的數據結構使起很是使用用於緩存系統而且其也提供了通常關係型數據庫所局域的事務,主從數據庫等功能。而且能夠方便的實現集羣擴展。本文將針對 Redis 以及Spring Boot結合進行簡單介紹html5

Redis 安裝
redis 安裝能夠參照其餘關於Docker 部份內容,實現基於Docker 的redis 服務。這裏將再也不單獨介紹Redis 安裝。若是想要單獨安裝Redis 服務,請自行查找

本文將包含如下內容:java

Redis 與spring boot 整合

1.引入Redis 支持的包redis

<dependency>  
    <groupId>org.springframework.boot</groupId>  
    <artifactId>spring-boot-starter-redis</artifactId>  
</dependency>

2.配置spring boot Redis支持 spring

如下是基於Spring Boot 自動化的屬性配置,其能夠參照Spring Boot 配置篇進行單獨配置數據庫

# Redis數據庫索引(默認爲0)
spring.redis.database=0  
# Redis服務器地址
spring.redis.host=192.168.99.100
# Redis服務器鏈接端口
spring.redis.port=32769  
# Redis服務器鏈接密碼(默認爲空)
spring.redis.password=  
# 鏈接池最大鏈接數(使用負值表示沒有限制)
spring.redis.pool.max-active=8  
# 鏈接池最大阻塞等待時間(使用負值表示沒有限制)
spring.redis.pool.max-wait=-1  
# 鏈接池中的最大空閒鏈接
spring.redis.pool.max-idle=8  
# 鏈接池中的最小空閒鏈接
spring.redis.pool.min-idle=0  
# 鏈接超時時間(毫秒)
spring.redis.timeout=0

3.測試 apache

經過以上方式已經完成了Redis 的配置,接下來經過實現測試用例的方式針對Redis進行測試,查看配置是否成功緩存

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Test
    public void contextLoads() {
    }
    @Test
    public void test(){
        stringRedisTemplate.opsForValue().set("test","redis");
        Assert.assertEquals("redis", stringRedisTemplate.opsForValue().get("test"));
    }
}

注意: 經過以上方式測試,Spring Boot 的版本必須是1.5.x。 能夠經過查看pom.xml文件中的內容肯定版本

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.8.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

Spring Boot 2.0 Redis 集成

Spring Boot 1.5.8.RELEASE 版本的默認的Redis 客戶端操做採用的是Jedis 實現的,不過最新版本的Spring Boot 添加了lettuce 的實現方式,默認配置中心的Redis 配置進行了區別實現,而且默認採用lettuce 實現的。下面將針對最新版本的Spring Boot 進行兩種不一樣方式配置測試

  • Spring Boot 1.5.x 版本Starter Redis pom.xml 內容
<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>
    </dependencies>
  • Spring Boot 2.x Redis pom.xml 內容
<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>jcl-over-slf4j</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>io.lettuce</groupId>
            <artifactId>lettuce-core</artifactId>
        </dependency>
    </dependencies>

能夠在Spring Boot 下查看具體的Starter引用

Spring Boot 2.0 經過 Jedis 集成 Redis 服務

經過以上不一樣版本的Redis 集成引用能夠發現,默認的2.x版本中,默認只引入了 Lettuce包,並無引入Redis包支持,因此若是要實現此功能,必須手動引入具體的包

1.引入須要的jar包

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <exclusions>
            <exclusion>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            </exclusion>
            </exclusions>
        </dependency>
        <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        </dependency>

經過以上方式引入jedis,而且將spring-boot-starter-data-redis中自帶的替換爲 jedis

2.修改配置

前面提到了,默認最新版本的將配置進行了分離,因此以上的部分配置已通過期,下面將採用最新的配置

# Redis數據庫索引(默認爲0)
spring.redis.database=0
# Redis服務器地址
spring.redis.host=192.168.99.100
# Redis服務器鏈接端口
spring.redis.port=32770
# Redis服務器鏈接密碼(默認爲空)
spring.redis.password=
spring.redis.jedis.pool.max-active=8
spring.redis.jedis.pool.max-wait=-1
spring.redis.jedis.pool.min-idle=0
spring.redis.jedis.pool.max-idle=8

3.jedis 配置

經過以上配置實現的,在新的版本下是沒法正常工做的,由於默認採用的Lettuce實現的,因此沒法初始化出Jedis 的鏈接對象JedisConnectionFactory,須要本身建立並自行注入

public class JedisRedisConfig {
    @Bean
    JedisConnectionFactory jedisConnectionFactory() {
        JedisConnectionFactory factory = new JedisConnectionFactory();
        return factory;
    }

經過以上方式,你會發現,仍是沒法測試經過,默承認能會報一下兩個錯誤
錯誤1
錯誤緣由:commons-pool2庫缺失

<dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
        <version>2.4.2</version>
    </dependency>

錯誤2
錯誤緣由 : jedis 版本低或者maven導入失敗

錯誤3

錯誤緣由: redis 鏈接失敗, 不止爲什麼,spring boot 2.x 經過以上方式集成jedis,可是其不會讀取配置文件中的spring.redis.host等這樣的配置,須要本身手動設置

若是有人知道爲何,還請告知,感激涕零,或者我後續研究會補上具體的緣由內容

雖然系統沒有提供正確的支持,不過咱們能夠經過本身的配置實現具體的功能支持,經過添加如下配置內容

@Configuration
@PropertySource(value = "classpath:/application.properties")
public class JedisRedisConfig {

    @Value("${spring.redis.host}")
    private  String host;
    @Value("${spring.redis.password}")
    private  String password;
    @Value("${spring.redis.port}")
    private  int port;
    @Value("${spring.redis.timeout}")
    private  int timeout;

    @Bean
    JedisConnectionFactory jedisConnectionFactory() {
        JedisConnectionFactory factory = new JedisConnectionFactory();
        factory.setHostName(host);
        factory.setPort(port);
        factory.setTimeout(timeout); //設置鏈接超時時間
        return factory;
    }
}

將系統配置設置爲以上形式,就能夠鏈接正確的redis 服務了,若是不設置,將採用默認配置鏈接的是localhost 的redis服務

4.測試

ok, 經過以上配置,運行測試用例, jedis 測試是能夠連通的

Spring Boot 2.0 經過 Lettuce 集成 Redis 服務

1.導入包

默認的 Spring Boot 2.x 已經採用Lettuce爲默認實現,因此只須要導入默認的 Redis支持包就好

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

2.配置

spring.redis.database=0
# Redis服務器地址
spring.redis.host=192.168.99.100
# Redis服務器鏈接端口
spring.redis.port=32770
# Redis服務器鏈接密碼(默認爲空)
spring.redis.password=
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=-1
spring.redis.lettuce.shutdown-timeout=100
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0

3.測試鏈接

經過單元測試,測試是否鏈接經過

Redis應用場景一 ------ 基於Redis 緩存實現

因爲Redis獨特的基於內存設計,優越性能以及豐富的數據結構,很是適合用於做爲緩存系統實現,下面將實現基於Spring Boot與Redis 的緩存系統實現

緩存

磁盤緩存(Disk Buffer)或磁盤快取(Disk Cache)其實是將下載到的數據先保存於系統爲軟件分配的內存空間中(這個內存空間被稱之爲「內存池」),當保存到內存池中的數據達到一個程度時,便會將數據保存到硬盤中。這樣能夠減小實際的磁盤操做,有效的保護磁盤免於重複的讀寫操做而致使的損壞。
磁盤緩存是爲了減小CPU透過I/O讀取磁盤機的次數,提高磁盤I/O的效率,用一塊內存來儲存存取較頻繁的磁盤內容;由於內存的存取是電子動做,而磁盤的存取是機械動做,感受上磁盤I/O變得較爲快速。
相同的技巧可用在寫入動做,咱們先將欲寫入的內容放入內存中,等到系統有其它空閒的時間,再將這塊內存的資料寫入磁盤中。 ------ 維基百科

以上內容是維基百科中關於磁盤緩存的介紹,在大型網絡應用程序中,緩存的應用和磁盤緩存同樣,都是爲了提升讀寫性能,網絡應用中減小對數據庫的訪問就能夠必定程度上很好的提升性能(數據庫訪問仍是對磁盤I/O 訪問,到最後仍是磁盤讀取的問題)

緩存實現

  1. 經過以上配置實現Redis 支持
    首先先經過以上內容實現Redis的正確支持
  2. 開啓緩存機制
    Spring Boot 針對緩存支持比較完備,不須要更多的配置,只須要一個註解就能夠開啓緩存,經過@EnableCaching
@SpringBootApplication
    @EnableCaching
    public class DemoApplication {

            public static void main(String[] args) {
                SpringApplication.run(DemoApplication.class, args);
            }
    }

經過以上方式雖然能夠開啓緩存功能,不過仍是推薦下面的方式,爲緩存操做單首創建配置類,方便管理而且方便自定義緩存功能

@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {
    // cache 功能
        @Override
    public CacheManager cacheManager() {
        return null;
    }

    @Override
    public KeyGenerator keyGenerator() {
        return null;
    }

    @Override
    public CacheResolver cacheResolver() {
        return null;
    }

    @Override
    public CacheErrorHandler errorHandler() {
        return null;
    }
}

CachingConfigurerSupport 類是 Spring Cache 模塊下的關於cache配置的支持類,其中默認定義了四個關於緩存配置的4個方法,默認都是返回 null 以使用系統默認的緩存設置
咱們能夠經過重寫此方法,進行自定義的操做,好比自定義緩存key的生成策略等。默認的生成策略是看不懂的(亂碼內容) 經過Spring 的依賴注入特性進行自定義的配置注入而且此類是一個配置類能夠更多程度的自定義配置

@Override
    @Bean
    public KeyGenerator keyGenerator() {
        return  new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
                StringBuilder stringBuilder = new StringBuilder();
                stringBuilder.append(target.getClass().getName());
                stringBuilder.append(method.getName());
                for (Object object : params){
                    stringBuilder.append(object.toString());
                }
                return  stringBuilder.toString();
            }
        };
    }

以上經過自定義key生成策略,經過自定義的策略規則,替換系統自動的策略規則(__Spring Cloud微服務部分會針對此處進行更加細緻的配置,來肯定來自哪一個服務,若是感興趣先看看如何實現__)

3.Spring Boot 緩存支持
Spring Boot 是經過註解來進行緩存操做的,經過輸入 cache,能夠看到,Spring Boot默認支持一下幾個緩存相關注解
緩存註解
以上截圖中只有5個 仍是有一個沒有@Caching註解
下面將針對每一個註解進行詳細的介紹:

  • @EnableCaching
    此註解在上邊已經使用過了,其目的就是爲了開啓緩存
    次註解對應到XML配置中就是一下內容

    <beans xmlns="http://www.springframework.org/schema/beans"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:cache="http://www.springframework.org/schema/cache"
            xsi:schemaLocation="
                http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
                <!-- 關鍵在詞句,此註解就對應此句XML配置 -->
                <cache:annotation-driven />
        </beans>
  • @CacheConfig
    經過名稱就能夠看出,次註解是對cache配置註解(是類級別的)

    public @interface CacheConfig {
            String[] cacheNames() default {};
            String keyGenerator() default "";
            String cacheManager() default "";
            String cacheResolver() default "";
        }

    以上是此註解的內容,其中和CachingConfigurerSupport中部分相對應,設置關於註解的

    • cacheNames: 設置緩存存儲的名稱,容許提供多個
    • keyGenerator: 配置緩存key生成策略,默認採用的是系統自定義的(接下來對默認規則介紹),經過設置此屬性給定自定義的key生成規則,此處須要給出一個bean名稱實現(此處spring 默認生成bean名稱是類名首字母小寫,此處須要本身給出正確的bean名稱,能夠經過自定義實現key生成策略)
    • cacheManager: 給定義緩存管理器bean 名稱,默認會根據使用的緩存策略的不一樣生成不一樣的管理器,好比Redis 生成的就是 RedisCacheManager類的實例,默認系統實現的是一個 SimpleCacheManager, 使用的和keyGenerator規則相同
    • cacheResolver:
  • @Cacheable
    用於設置支持緩存,通常用於須要緩存的方法上進行數據緩存操做實現,訪問此方法時先查詢緩存是否存在對應的緩存值,沒有執行具體查詢操做,並將查詢結果寫入緩存中(方法級別)

    @AliasFor("cacheNames")
    String[] value() default {};
    @AliasFor("value")
    String[] cacheNames() default {};
    String key() default "";
    String keyGenerator() default "";
    String cacheManager() default "";
    String cacheResolver() default "";
    String condition() default "";
    String unless() default "";
    boolean sync() default false;

    以上是此註解的所有內容

    • value,cacheNames: 這兩個註解功能相同,就是設置緩存的名稱,容許設置多個,在方法執行以前,每一個緩存都將被檢測,只要一個檢測到有內容那麼就直接返回,不執行方法體。若是都沒有那麼執行事後每一個緩存都將設置內容(通常狀況下只用設置一個)
    • key: 設置緩存內容所對應的key

      //給出了經過 SpEL表達式生成key 的實例  
              @Cacheable(cacheNames="books", key="#isbn")
              public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
      
              @Cacheable(cacheNames="books", key="#isbn.rawNumber")
              public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
      
              @Cacheable(cacheNames="books", key="T(someType).hash(#isbn)")
              public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

      因爲SpEL表達式的支持,其key 存在的可能性就不少,能夠經過SpEL 表達式進行多種形式組合

    • keyGenerator:指定key 生成策略經過必定的操做自動生成惟一的key , 此參數和 key 參數是互斥的,因此不能同時使用
    • cacheManager: 用於指定使用哪一個緩存管理器
    • condition: 條件,緩存須要的條件,能夠經過設置此屬性,對內容進行條件性緩存,只有知足條件了才進行緩存
    • unless: 此屬性和condition同樣都是設置條件的,不過此屬性時針對執行後的判斷,能夠對執行結果進行判斷
  • @CachePut
    次註解用於對緩存的更新上, 使用此註解與@Cacheable不一樣之處在於方法會被執行,執行事後會更新緩存
  • @CacheEvict
    用於清除緩存

    boolean allEntries() default false;
        boolean beforeInvocation() default false;

    此註解相對以上註解添加了兩個屬性

    • allEntries: 刪除全部緩存,默認是false,不刪除的,只有設置Wie true後會在方法執行後刪除全部緩存
    • beforeInvocation: 是否在方法執行前就清空,默認是在方法執行後刪除緩存,若是方法執行拋出異常,那麼緩存不會被刪除

擴展

* Spring cache key 生成策略  
       * 默認系統給出的策略是根據方法參數來實現的,若是方法沒有參數則key就爲一個`SimpleKey.EMPTY`; 若是方法有一個參數,直接返回對象;若是有多個參數,那麼返回的是一個包含全部參數的鍵。  
       * key 生成還支持 `SpEL`表達式生成,經過指定`SpEL`表達式指定key的生成策略  
       * key 還支持經過指定特定的`keyGenerator`屬性,指定一個key 生成器來經過今生成器生成適合的key  
       * 因爲項目的需求,可能存在多個需求緩存相同,不過因爲參數的不一樣,能夠經過 `SpEL` 實現將對結果無關的參數忽略的形式組合成一組通用的key 實現多個需求可使用同一份緩存
  • @Caching
    此註解是一個輔助性註解,爲了解決在多個相同註解多個同時使用的狀況下。此註解容許@Cacheable,@CachePut,@CacheEvict三個註解的操做

    Cacheable[] cacheable() default {};
        CachePut[] put() default {};
        CacheEvict[] evict() default {};

    以上是註解的具體內容

    @Caching(evict = { @CacheEvict("primary"), @CacheEvict(cacheNames="secondary", key="#p0") })
        public Book importBooks(String deposit, Date date)

    具體的使用示例

若是須要了解詳細的內容,請查詢官方文檔Spring Cache

緩存功能測試

1.實現controller 以及service 代碼

@RestController
@RequestMapping("/cache")
public class CacheController {
    @Autowired
    private CacheService cacheService;
        @GetMapping("/get_user_by_name/{name}")
    public ResponseEntity findByName(@PathVariable String name)
    {
        return new ResponseEntity(cacheService.findByName(name), HttpStatus.OK);
    }

    @GetMapping("/get_user_by_age/{age}")
    public ResponseEntity findByAge(@PathVariable String age)
    {
        return new ResponseEntity(cacheService.findByAge(Integer.parseInt(age)), HttpStatus.OK);
    }
}

@Service
@CacheConfig(cacheNames = "cache")
public class CacheServiceImpl implements CacheService {

    @Cacheable(keyGenerator = "keyGenerator")
    @Override
    public User findByName(String name) {
        System.out.println("findByName沒有加載緩存");
        return  new User((new Long(1)),"張三", 18);
    }
    @Cacheable(keyGenerator = "keyGenerator")
    @Override
    public List findByAge(int age) {
        System.out.println("findByAge沒有加載緩存");
        return (List) new User(new Long(1),"李四", 18);
    }
}

以上是測試須要的代碼,代碼很簡單,不涉及到dao等數據庫操做,只是爲了測試緩存功能是否正常

2.測試
經過PostMan 等 REST Ful 等請求模擬測試軟件進行測試 第一次請求單個方法會進打印,不過第二次請求就不會進行打印。以上代碼只是測試了 @Cacheable 請求添加功能具體的其餘幾個功能請單獨測試
能夠經過debug跟蹤到 CacheAspectSupport 類中的execute方法查看緩存值

// CacheAspectSupport 跟蹤方法  
    private Object execute(final CacheOperationInvoker invoker, Method method, CacheOperationContexts contexts) {
        // Special handling of synchronized invocation
        if (contexts.isSynchronized()) {
            CacheOperationContext context = contexts.get(CacheableOperation.class).iterator().next();
            if (isConditionPassing(context, CacheOperationExpressionEvaluator.NO_RESULT)) {
                Object key = generateKey(context, CacheOperationExpressionEvaluator.NO_RESULT);
                Cache cache = context.getCaches().iterator().next();
                try {
                    return wrapCacheValue(method, cache.get(key, new Callable<Object>() {
                        @Override
                        public Object call() throws Exception {
                            return unwrapReturnValue(invokeOperation(invoker));
                        }
                    }));
                }
                catch (Cache.ValueRetrievalException ex) {
                    // The invoker wraps any Throwable in a ThrowableWrapper instance so we
                    // can just make sure that one bubbles up the stack.
                    throw (CacheOperationInvoker.ThrowableWrapper) ex.getCause();
                }
            }
            else {
                // No caching required, only call the underlying method
                return invokeOperation(invoker);
            }
        }
        // Process any early evictions
        processCacheEvicts(contexts.get(CacheEvictOperation.class), true,
                CacheOperationExpressionEvaluator.NO_RESULT);

        // Check if we have a cached item matching the conditions
        Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));

        // Collect puts from any @Cacheable miss, if no cached item is found
        List<CachePutRequest> cachePutRequests = new LinkedList<CachePutRequest>();
        if (cacheHit == null) {
            collectPutRequests(contexts.get(CacheableOperation.class),
                    CacheOperationExpressionEvaluator.NO_RESULT, cachePutRequests);
        }

        Object cacheValue;
        Object returnValue;

        if (cacheHit != null && cachePutRequests.isEmpty() && !hasCachePut(contexts)) {
            // If there are no put requests, just use the cache hit
            cacheValue = cacheHit.get();
            returnValue = wrapCacheValue(method, cacheValue);
        }
        else {
            // Invoke the method if we don't have a cache hit
            returnValue = invokeOperation(invoker);
            cacheValue = unwrapReturnValue(returnValue);
        }

        // Collect any explicit @CachePuts
        collectPutRequests(contexts.get(CachePutOperation.class), cacheValue, cachePutRequests);

        // Process any collected put requests, either from @CachePut or a @Cacheable miss
        for (CachePutRequest cachePutRequest : cachePutRequests) {
            cachePutRequest.apply(cacheValue);
        }

        // Process any late evictions
        processCacheEvicts(contexts.get(CacheEvictOperation.class), false, cacheValue);

        return returnValue;
    }

說明 : 此處測試比較簡單,只是測試cache功能是否正常,但更加詳細的沒有實現,須要本身實現,日後有時間我會補全更加詳細的測試實現

Redis應用場景二 ------ 基於Redis 的共享 Session 實現

在大型分佈式項目中,要保證項目的可伸縮型,帶狀態的 session 共享是越不過去的坎。針對Session 共享實現,業界有不一樣的實現方式,一種是將Session 直接持久化到數據庫中,不過這種方式針對數據庫的讀寫性能有很大要求,而且效率嚴重的受限於數據庫性能;另外一種方式就是直接將數據存儲到Cookie中,可是這種方式因爲Cookie的特性,存儲的數據大小受限;相比較下,將Session 存儲在 Redis 中是最好的選擇。其Redis 基於內存的實現知足了高效性,訪問速度快,而且 Redis 支持集羣化,因此不會受限數據庫的問題。下面將介紹基於Redis 實現的共享session

共享 Session 實現

1.引入 session支持包

<!-- redis 支持 -->
<dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>
        <!-- redis session支持 -->
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>
<!-- 爲了測試添加的jap 和內存數據庫 h2 -->
    <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.196</version>
            <scope>runtime</scope>
        </dependency>

Spring Boot 針對 Redis 實現 Session 共享操做進行了封裝實現,能夠很方便的將Session對象直接存儲在 Redis中

2.開啓 Session 支持
Spring Boot 中Session 支持多種形式存儲,包括Redis, Mongo,jdbc,hazelcast,hash_map等形式,此處須要指定爲Redis,經過修改 application.properties配置文件,添加一下配置

spring.session.store-type=redis

經過以上方式指定session管理方式爲redis,並經過一下方式開啓session redis 支持

@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 86400)
public class SessionConfig {
}

Spring Boot 經過註解開啓 Redis 針對 Session 的支持, 此註解針對session進行配置,其內部是自動建立了Spring Bean對象,是一個過濾器bean--- springSessionRepositoryFilter。 關於此部分詳細內容請查詢官方文檔HttpSession with Redis

public @interface EnableRedisHttpSession {
    int maxInactiveIntervalInSeconds() default 1800;

    String redisNamespace() default "";

    RedisFlushMode redisFlushMode() default RedisFlushMode.ON_SAVE;
}

以上內容是此註解的源碼,能夠發現,次註解主要設置了三個功能:

* `maxInactiveIntervalInSeconds`: 對應的是session的過時時間,默認是1800秒後過時,用戶能夠經過自定義時間,若是設置了此屬性,項目中的`server.session.timeout`屬性將失效, __此處須要注意__  
* `redisNamespace`: 設置redis 的命名空間,就是設置數據存儲到哪裏(至關於關係型數據庫中的庫)  
* `redisFlushMode`: redis 操做模式,是否當即刷新到redis數據庫中,默認的是不會的,系統並非在剛設置就刷新,而是選擇在某個時間點刷新到數據庫中

3.測試

@PostMapping("/register")
    public ResponseEntity register(@RequestBody User user, HttpServletRequest request)
    {
        request.getSession().setAttribute("user", user);
        return  new ResponseEntity(userRespository.save(user), HttpStatus.OK);
    }
   @GetMapping("/session")
    public ResponseEntity getSessionMessage(HttpServletRequest request)
    {
        Map<String, Object> map = new HashMap<>();
        map.put("sessionId", request.getSession().getId());
        map.put("message",request.getSession().getAttribute("user")) ;
        return  new ResponseEntity(map, HttpStatus.OK);
    }

以上代碼爲測試代碼

  • 測試過程:

    • 啓動項目,經過/register接口註冊用戶,系統會見用戶信息寫入session中
    • 訪問/session 查看session信息
    • 同時在另外一個端口上啓動本項目
    • 訪問 /session接口,查看session信息
  • 測試結果:
    經過以上方式測試會發現,本地訪問兩個不一樣的項目,拿到的session是相同的
    register
    查看session
    另外一個項目查看
    session 的內容以及 session ID 是相同的,達到了session共享的目的

總結

以上介紹了 Redis以及其在 Spring Boot 中的兩種應用方式,緩存和 Session共享。 針對其具體的實現細節以及功能作了簡單介紹,若是須要更加細緻的瞭解。能夠根據文中提到參考文章查找更加細緻了講解

因爲本人知識水平有限,文章可能會存在錯誤等,若是您有發現還請經過評論等方式聯繫我將積極完善和改正,在此不勝感激

擴展

IDEA Redis 支持

IDEA 對經過插件的方式對 Redis 有很好的集成,經過插件能夠實現Redis最基本的開發,下面將介紹如何實現

  • 安裝插件

插件安裝
按照以上步驟安裝插件,我這裏已經安裝,全部顯示的是update,根據提示安裝插件就好

  • 鏈接Redis
    安裝完成須要重啓IDEA


    經過以上方式,填寫對應的地址和端口以及密碼等內容,測試鏈接是否成功

    以上就是Redis支持的操做界面,能夠經過此界面操做Redis

參考

相關文章
相關標籤/搜索