SpringBoot integration (4) Integrate Ehcache, Redis, Memcached, jetcache, j2cache cache

​ The main function of enterprise-level applications is information processing. When data needs to be read, the overall system performance is low due to the limited access efficiency of the database.

​ In order to improve the above phenomenon, developers usually establish a temporary data storage mechanism between the application program and the database. The data in this area is stored in the memory, and the reading and writing speed is fast, which can effectively solve the problem of low database access efficiency. question. This area for temporarily storing data is the cache.

1. SpringBoot built-in caching solution

​ springboot technology provides a built-in caching solution that can help developers quickly enable caching technology and use caching technology for fast data operations, such as reading cached data and writing data to the cache.

Step ① : Import the starter corresponding to the caching technology provided by springboot

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

Step ② : Enable caching, annotate @EnableCaching above the boot class to configure the springboot program to use the cache

@SpringBootApplication
//开启缓存功能
@EnableCaching
public class SpringbootCacheApplication {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(SpringbootCacheApplication.class, args);
    }
}

Step ③ : Set whether to use cache for the data of the operation

@Service
public class BookServiceImpl implements BookService {
    
    
    @Autowired
    private BookDao bookDao;

    @Cacheable(value="cacheSpace",key="#id")
    public Book getById(Integer id) {
    
    
        return bookDao.selectById(id);
    }
}

​ Use the annotation @Cacheable on the business method to declare that the return value of the current method is placed in the cache, where the storage location of the cache is specified, and the name corresponding to the return value of the current method is saved in the cache. In the above example, the value attribute describes the storage location of the cache, which can be understood as a storage space name, and the key attribute describes the name of the data stored in the cache. Use #id to read the id value in the formal parameter as the cache name.

​ After using the @Cacheable annotation, execute the current operation. If you find that the corresponding name has no data in the cache, read the data normally and put it into the cache; if the corresponding name has data in the cache, terminate the execution of the current business method and return directly data in the cache.

2. Mobile phone verification code case

Create a mobile phone verification code case environment to simulate the process of using the cache to save the mobile phone verification code.

​ The mobile phone verification code case requirements are as follows:

  • Enter the mobile phone number to obtain the verification code, and organize the document to be sent to the user in the form of a text message
  • Enter the mobile phone number and verification code to verify the result

​ In order to describe the above operations, we make two presentation layer interfaces, one is used to simulate the process of sending SMS, in fact, a verification code is generated according to the mobile phone number provided by the user, and then put into the cache, and the other is used to simulate verification code verification The process is actually to use the incoming mobile phone number and verification code to match, and return the final matching result. The simulation code of this case is directly produced below, and the built-in caching technology provided by springboot in the above example is used to complete the production of the current case.

Step ① : Import the starter corresponding to the caching technology provided by springboot

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

Step ② : Enable caching, annotate @EnableCaching above the boot class to configure the springboot program to use the cache

@SpringBootApplication
//开启缓存功能
@EnableCaching
public class SpringbootCacheApplication {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(SpringbootCacheApplication.class, args);
    }
}

Step ③ : Define the entity class corresponding to the verification code, and encapsulate the two attributes of the mobile phone number and the verification code

@Data
public class SMSCode {
    
    
    private String tele;
    private String code;
}

Step ④ : Define the business layer interface and implementation class of the verification code function

public interface SMSCodeService {
    
    
    public String sendCodeToSMS(String tele);
    public boolean checkCode(SMSCode smsCode);
}

@Service
public class SMSCodeServiceImpl implements SMSCodeService {
    
    
    @Autowired
    private CodeUtils codeUtils;

    @CachePut(value = "smsCode", key = "#tele")
    public String sendCodeToSMS(String tele) {
    
    
        String code = codeUtils.generator(tele);
        return code;
    }

    public boolean checkCode(SMSCode smsCode) {
    
    
        //取出内存中的验证码与传递过来的验证码比对,如果相同,返回true
        String code = smsCode.getCode();
        String cacheCode = codeUtils.get(smsCode.getTele());
        return code.equals(cacheCode);
    }
}

​ After obtaining the verification code, the verification code must be obtained again when the verification code becomes invalid. Therefore, the @Cacheable annotation cannot be used in the function of obtaining the verification code. The @Cacheable annotation means that if there is no value in the cache, the value is put in, and if there is a value in the cache, the value is taken. value. The function here is only to generate the verification code and put it into the cache, and does not have the function of getting values ​​from the cache, so the @Cacheable annotation cannot be used, and it should only have the function of saving data in the cache, using the @CachePut annotation .

​ For the function of verifying the verification code, it is recommended to put it into the tool class.

Step ⑤ : Define the verification code generation strategy and the function of reading the verification code according to the mobile phone number

@Component
public class CodeUtils {
    
    
    private String [] patch = {
    
    "000000","00000","0000","000","00","0",""};

    public String generator(String tele){
    
    
        int hash = tele.hashCode();
        int encryption = 20206666;
        long result = hash ^ encryption;
        long nowTime = System.currentTimeMillis();
        result = result ^ nowTime;
        long code = result % 1000000;
        code = code < 0 ? -code : code;
        String codeStr = code + "";
        int len = codeStr.length();
        return patch[len] + codeStr;
    }

    @Cacheable(value = "smsCode",key="#tele")
    public String get(String tele){
    
    
        return null;
    }
}

Step ⑥ : Define the web layer interface of the verification code function, one method is used to provide the mobile phone number to obtain the verification code, and the other method is used to provide the mobile phone number and verification code for verification

@RestController
@RequestMapping("/sms")
public class SMSCodeController {
    
    
    @Autowired
    private SMSCodeService smsCodeService;
    
    @GetMapping
    public String getCode(String tele){
    
    
        String code = smsCodeService.sendCodeToSMS(tele);
        return code;
    }
    
    @PostMapping
    public boolean checkCode(SMSCode smsCode){
    
    
        return smsCodeService.checkCode(smsCode);
    }
}

3. SpringBoot integrates Ehcache cache

​ The mobile phone verification code case has been completed, and springboot will start to integrate various caching technologies, the first to integrate Ehcache technology. Ehcache is a caching technology. Using springboot to integrate Ehcache is actually changing the implementation of caching technology.

Step ① : Import the coordinates of Ehcache

<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
</dependency>

​ Why is it not importing the Ehcache starter here, but importing the technical coordinates? In fact, springboot's integrated caching technology is in a general format. No matter which caching technology you integrate, it just changes the implementation, and the operation method is the same. This also reflects the advantages of springboot technology and unifies the integration method of similar technologies.

Step ② : Configure caching technology to use Ehcache

# 整合ehcache缓存
spring:
  cache:
    type: ehcache
    ehcache:
      config: classpath:ehcache.xml

配置缓存的类型type为ehcache,此处需要说明一下,当前springboot可以整合的缓存技术中包含有ehcach,所以可以这样书写。其实这个type不可以随便写的,不是随便写一个名称就可以整合的。

​ Since the configuration of ehcache has an independent configuration file format, it is also necessary to specify the configuration file of ehcache in order to read the corresponding configuration

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">
    <diskStore path="D:\ehcache" />

    <!--默认缓存策略 -->
    <!-- external:是否永久存在,设置为true则不会被清除,此时与timeout冲突,通常设置为false-->
    <!-- diskPersistent:是否启用磁盘持久化-->
    <!-- maxElementsInMemory:最大缓存数量-->
    <!-- overflowToDisk:超过最大缓存数量是否持久化到磁盘-->
    <!-- timeToIdleSeconds:最大不活动间隔,设置过长缓存容易溢出,设置过短无效果,可用于记录时效性数据,例如验证码-->
    <!-- timeToLiveSeconds:最大存活时间-->
    <!-- memoryStoreEvictionPolicy:缓存清除策略-->
    <defaultCache
        eternal="false"
        diskPersistent="false"
        maxElementsInMemory="1000"
        overflowToDisk="false"
        timeToIdleSeconds="60"
        timeToLiveSeconds="60"
        memoryStoreEvictionPolicy="LRU" />

    <cache
        name="smsCode"
        eternal="false"
        diskPersistent="false"
        maxElementsInMemory="1000"
        overflowToDisk="false"
        timeToIdleSeconds="10"
        timeToLiveSeconds="10"
        memoryStoreEvictionPolicy="LRU" />
</ehcache>

​ Note that in the previous case, the location where the data is saved is set to smsCode

@CachePut(value = "smsCode", key = "#tele")
public String sendCodeToSMS(String tele) {
    
    
    String code = codeUtils.generator(tele);
    return code;
}	

​ This setting needs to ensure that there is a cache space name called smsCode configuration in ehcache, which must be unified before and after. In the enterprise development process, different caching strategies are set by setting caches with different names, which are applied to different cached data.

​ At this point, the springboot integration of Ehcache is finished. It can be found that the original code has not been modified. Just adding a set of configurations can change the cache provider. This is also the advantage of springboot providing a unified cache operation interface. Change implementation Does not affect the writing of the original code.

4. SpringBoot integrates Redis cache

​ Compare the process of using Ehcache, add coordinates, change the cache implementation type to ehcache, and configure Ehcache. What if it is also used as redis for caching? It is exactly the same, add coordinates, change the cache implementation type to redis, and configure redis.差别之处只有一点,redis的配置可以在yml文件中直接进行配置,无需制作独立的配置文件。

Step ① : Import the coordinates of redis

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

Step ② : Configure caching technology to use redis

spring:
  redis:
    host: localhost
    port: 6379
  cache:
    type: redis

​ If you need to configure redis as a cache, be careful not to configure the original redis, but to configure redis as a cache to use related configurations, which belong to the spring.cache.redis node, and be careful not to write the wrong location.

spring:
  redis:
    host: localhost
    port: 6379
  cache:
    type: redis
    redis:
      use-key-prefix: false
      key-prefix: sms_
      cache-null-values: false
      time-to-live: 10s
   // Spring的Redis注解添加 unless="#result == null",这样当结果为空时则不存入Redis
    @Cacheable(value = "smsCode",key="#tele",unless="#result == null")
    public String get(String tele){
    
    
        return null;
    }

5. SpringBoot integrates Memcached cache

​ A more popular caching memcached in China.

According to the previous routine, changing the cache is actually not cumbersome, but springboot does not support the use of memcached as its cache solution, that is to say, there is no memcached configuration option in the type attribute, and the processing method needs to be changed here. Install memcached first before integrating.

5.1 Installation

​ Windows version installation package download address:https://www.runoob.com/memcached/window-install-memcached.html

​ The downloaded installation package is a zip file that can be used after decompression

​ The executable file has only one memcached.exe, which can be used to start memcached as a system service. Execute this to switch administrator account permissions to start the command line

​As follows:

memcached.exe -d install

After the service is installed, you can use the command to start and stop the service, as follows:

memcached.exe -d start		# 启动服务
memcached.exe -d stop		# 停止服务

5.2 Change cache to Memcached

​ Since memcached is not included as a caching solution by springboot, using memcached needs to be used by manual hardcoding, so the previous routines are not applicable, and you need to write it yourself.

​ memcached currently provides three client technologies, namely Memcached Client for Java, SpyMemcached, and Xmemcached. Among them, Xmemcached is the client with the best performance indicators. This integration will use this as the client implementation technology. Let's start using Xmemcached

Step ① : Import the coordinates of xmemcached

<dependency>
    <groupId>com.googlecode.xmemcached</groupId>
    <artifactId>xmemcached</artifactId>
    <version>2.4.7</version>
</dependency>

Step ② : configure memcached, make memcached configuration class

@Configuration
public class XMemcachedConfig {
    
    
    @Bean
    public MemcachedClient getMemcachedClient() throws IOException {
    
    
        MemcachedClientBuilder memcachedClientBuilder = new XMemcachedClientBuilder("localhost:11211");
        MemcachedClient memcachedClient = memcachedClientBuilder.build();
        return memcachedClient;
    }
}

​ The default external service port of memcached is 11211.

Step ③ : Use the xmemcached client to operate the cache and inject the MemcachedClient object

@Service
public class SMSCodeServiceImpl implements SMSCodeService {
    
    
    @Autowired
    private CodeUtils codeUtils;
    @Autowired
    private MemcachedClient memcachedClient;

    public String sendCodeToSMS(String tele) {
    
    
        String code = codeUtils.generator(tele);
        try {
    
    
            memcachedClient.set(tele,10,code);
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
        return code;
    }

    public boolean checkCode(SMSCode smsCode) {
    
    
        String code = null;
        try {
    
    
            code = memcachedClient.get(smsCode.getTele()).toString();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
        return smsCode.getCode().equals(code);
    }
}

​ Use the set operation to set the value to the cache, and use the get operation to get the value, which is actually more in line with the habits of our developers.

​ In the above code, the configuration of the server is hard-coded into the code, and the data is extracted and made into an independent configuration attribute.

5.3 Define configuration properties

  • Define the configuration class, load the necessary configuration attributes, and read the memcached node information in the configuration file

    @Component
    @ConfigurationProperties(prefix = "memcached")
    @Data
    public class XMemcachedProperties {
          
          
        private String servers;
        private int poolSize;
        private long opTimeout;
    }
    
  • Define memcached node information

    memcached:
      servers: localhost:11211
      poolSize: 10
      opTimeout: 3000
    
  • Load information in the memcached configuration class

@Configuration
public class XMemcachedConfig {
    
    
    @Autowired
    private XMemcachedProperties props;
    @Bean
    public MemcachedClient getMemcachedClient() throws IOException {
    
    
        MemcachedClientBuilder memcachedClientBuilder = new XMemcachedClientBuilder(props.getServers());
        memcachedClientBuilder.setConnectionPoolSize(props.getPoolSize());
        memcachedClientBuilder.setOpTimeout(props.getOpTimeout());
        MemcachedClient memcachedClient = memcachedClientBuilder.build();
        return memcachedClient;
    }
}

6. SpringBoot integrates jetcache cache

​ At present, the caches we use are either A or B. Can AB be used together? This section addresses this issue. The integration of springboot for the cache only stays on the cache. If the cache itself does not support the use of AB at the same time, springboot can’t do anything about it. Therefore, if you want to solve the problem of using AB cache together, you must find a cache that can support both AB and AB. Used together with cache. Strictly speaking, jetcache is not a caching solution. It can only be said that it is a caching framework, and then put other caches into jetcache for management, so that it can support the use of AB cache. And jetcache refers to the idea of ​​springboot integrated cache, the overall technology usage is very similar to springboot's cache solution idea.

​ Jetcache can't just take two caches and put them together. Currently, jetcache supports two types of caching schemes: local caching and remote caching, which are as follows:

  • Local cache (Local)
    • LinkedHashMap
    • Caffeine
  • Remote cache (Remote)
    • Redis
    • Three

6.1 Pure remote solution

Step ① : Import springboot to integrate the coordinate starter corresponding to jetcache. The default remote solution for current coordinates is redis

<dependency>
    <groupId>com.alicp.jetcache</groupId>
    <artifactId>jetcache-starter-redis</artifactId>
    <version>2.6.2</version>
</dependency>

Step ② : Basic configuration of the remote solution

jetcache:
  remote:
    default:
      type: redis
      host: localhost
      port: 6379
      poolConfig:
        maxTotal: 50

​ Among them, poolConfig is a mandatory item, otherwise an error will be reported

Step 3 : Enable the cache, and mark the annotation @EnableCreateCacheAnnotation above the boot class to configure the springboot program to create a cache in the form of annotations

@SpringBootApplication
//jetcache启用缓存的主开关
@EnableCreateCacheAnnotation
public class SpringbootJetCacheApplication {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(SpringbootJetCacheApplication.class, args);
    }
}

Step ④ : Create a cache object Cache, and use the annotation @CreateCache to mark the current cache information, and then use the API of the Cache object to operate the cache, put write cache, and get read cache.

@Service
public class SMSCodeServiceImpl implements SMSCodeService {
    
    
    @Autowired
    private CodeUtils codeUtils;
    
    @CreateCache(name="jetCache_",expire = 10,timeUnit = TimeUnit.SECONDS)
    private Cache<String ,String> jetCache;

    public String sendCodeToSMS(String tele) {
    
    
        String code = codeUtils.generator(tele);
        jetCache.put(tele,code);
        return code;
    }

    public boolean checkCode(SMSCode smsCode) {
    
    
        String code = jetCache.get(smsCode.getTele());
        return smsCode.getCode().equals(code);
    }
}

​ Through the above-mentioned jetcache using the remote solution to connect to redis, it can be seen that the interface operation of jetcache when operating the cache is more in line with the developer's habits. When using the cache, first obtain the cache object Cache, put the data into it, and get the data out, which is simpler and easier Understand. And when jetcache operates the cache, you can set an expiration time for a certain cache object, and put the same type of data into the cache to facilitate the management of the effective period.

​ The above scheme uses the default cache defined in the configuration. In fact, this default is a name, which can be written or added at will. For example, to add another caching solution, refer to the following configuration:

jetcache:
  remote:
    default:
      type: redis
      host: localhost
      port: 6379
      poolConfig:
        maxTotal: 50
    sms:
      type: redis
      host: localhost
      port: 6379
      poolConfig:
        maxTotal: 50

​ If you want to use a cache whose name is sms, you need to specify the parameter area when creating the cache, and declare to use the corresponding cache

@Service
public class SMSCodeServiceImpl implements SMSCodeService {
    
    
    @Autowired
    private CodeUtils codeUtils;
    
    @CreateCache(area="sms",name="jetCache_",expire = 10,timeUnit = TimeUnit.SECONDS)
    private Cache<String ,String> jetCache;

    public String sendCodeToSMS(String tele) {
    
    
        String code = codeUtils.generator(tele);
        jetCache.put(tele,code);
        return code;
    }

    public boolean checkCode(SMSCode smsCode) {
    
    
        String code = jetCache.get(smsCode.getTele());
        return smsCode.getCode().equals(code);
    }
}

6.2 Pure local solution

​ In the remote solution, remote is used in the configuration to indicate remote, and local is local, but the type is different.

Step ① : import springboot to integrate the coordinates corresponding to jetcache starter

<dependency>
    <groupId>com.alicp.jetcache</groupId>
    <artifactId>jetcache-starter-redis</artifactId>
    <version>2.6.2</version>
</dependency>

Step ② : Local cache basic configuration

jetcache:
  local:
    default:
      type: linkedhashmap
      keyConvertor: fastjson

​ In order to speed up the key matching speed during data acquisition, jetcache requires the specified key type converter. To put it simply, if you give an Object as a key, I will use the key type converter to convert it into a string first, and then save it. When the data is obtained, it is still converted into a string using the given Object first, and then matched according to the string. Since jetcache is Ali's technology, it is recommended to use Ali's fastjson for the key type converter.

Step ③ : Enable caching

@SpringBootApplication
//jetcache启用缓存的主开关
@EnableCreateCacheAnnotation
public class SpringbootJetCacheApplication {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(SpringbootJetCacheApplication.class, args);
    }
}

Step ④ : When creating the cache object Cache, mark the current use of the local cache

@Service
public class SMSCodeServiceImpl implements SMSCodeService {
    
    
    @CreateCache(name="jetCache_",expire = 1000,timeUnit = TimeUnit.SECONDS,cacheType = CacheType.LOCAL)
    private Cache<String ,String> jetCache;

    public String sendCodeToSMS(String tele) {
    
    
        String code = codeUtils.generator(tele);
        jetCache.put(tele,code);
        return code;
    }

    public boolean checkCode(SMSCode smsCode) {
    
    
        String code = jetCache.get(smsCode.getTele());
        return smsCode.getCode().equals(code);
    }
}

​ cacheType controls whether the current cache uses a local cache or a remote cache. Configuring cacheType=CacheType.LOCAL means using a local cache.

6.3 Local + remote solution

​ There are both local and remote methods, how to configure the two solutions together? In fact, it is enough to combine the two configurations together.

jetcache:
  local:
    default:
      type: linkedhashmap
      keyConvertor: fastjson
  remote:
    default:
      type: redis
      host: localhost
      port: 6379
      poolConfig:
        maxTotal: 50
    sms:
      type: redis
      host: localhost
      port: 6379
      poolConfig:
        maxTotal: 50

​ When creating a cache, configure the cacheType to BOTH, that is, the local cache and the remote cache will be used at the same time.

@Service
public class SMSCodeServiceImpl implements SMSCodeService {
    
    
    @CreateCache(name="jetCache_",expire = 1000,timeUnit = TimeUnit.SECONDS,cacheType = CacheType.BOTH)
    private Cache<String ,String> jetCache;
}

If cacheType is not configured, the default value is REMOTE, that is, only the remote cache solution is used. For the configuration of jetcache, refer to the following information

Attributes Defaults illustrate
jetcache.statIntervalMinutes 0 Statistics interval, 0 means no statistics
jetcache.hiddenPackages none When automatically generating name, hide the specified package name prefix
jetcache.[local|remote].${area}.type none Cache type, local support linkedhashmap, caffeine, remote support redis, tair
jetcache.[local|remote].${area}.keyConvertor none key converter, currently only supports fastjson
jetcache.[local|remote].${area}.valueEncoder java Only the remote type cache needs to be specified, java and kryo are optional
jetcache.[local|remote].${area}.valueDecoder java Only the remote type cache needs to be specified, java and kryo are optional
jetcache.[local|remote].${area}.limit 100 Only the cache of the local type needs to be specified, and the maximum number of elements of the cache instance
jetcache.[local|remote].${area}.expireAfterWriteInMillis Unprecedented Default expiration time, in milliseconds
jetcache.local.${area}.expireAfterAccessInMillis 0 Only local caches are valid, in milliseconds, the maximum inactivity interval

The above scheme only supports manual control of caching, but the method caching in the springcache scheme is particularly useful. Add an annotation to a method, and the method will automatically use the cache. jetcache also provides the corresponding function, that is, method caching.

6.4 Method caching

​ jetcache provides a method caching solution, but the name has changed. Just use the annotation @Cached above the corresponding operation interface

Step ① : import springboot to integrate the coordinates corresponding to jetcache starter

<dependency>
    <groupId>com.alicp.jetcache</groupId>
    <artifactId>jetcache-starter-redis</artifactId>
    <version>2.6.2</version>
</dependency>

Step ② : Configure the cache

jetcache:
  local:
    default:
      type: linkedhashmap
      keyConvertor: fastjson
  remote:
    default:
      type: redis
      host: localhost
      port: 6379
      keyConvertor: fastjson
      valueEncode: java
      valueDecode: java
      poolConfig:
        maxTotal: 50
    sms:
      type: redis
      host: localhost
      port: 6379
      poolConfig:
        maxTotal: 50

​ Since redis cache does not support saving objects, it is necessary to set redis how to perform type conversion when Object type data enters redis. It is necessary to configure the keyConvertor to indicate the type conversion method of the key, and mark the conversion type of the value at the same time. When the value enters redis, it is java type, mark valueEncode as java, convert the value to java when reading from redis, and mark valueDecode as java.

​ Note that in order to realize the value of Object type entering and exiting redis, it is necessary to ensure that the object type data entering and exiting redis must implement the serialization interface.

@Data
public class Book implements Serializable {
    
    
    private Integer id;
    private String type;
    private String name;
    private String description;
}

Step ③ : Enable the method caching function when caching is enabled, and configure basePackages to indicate in which packages method caching is enabled

@SpringBootApplication
//jetcache启用缓存的主开关
@EnableCreateCacheAnnotation
//开启方法注解缓存
@EnableMethodCache(basePackages = "com.yyds")
public class SpringbootJetCacheApplication {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(SpringbootJetCacheApplication.class, args);
    }
}

Step ④ : Use the annotation @Cached to mark the current method using the cache

@Service
public class BookServiceImpl implements BookService {
    
    
    @Autowired
    private BookDao bookDao;
    
    @Override
    @Cached(name="book_",key="#id",expire = 3600,cacheType = CacheType.REMOTE)
    public Book getById(Integer id) {
    
    
        return bookDao.selectById(id);
    }
}

6.5 Data Synchronization of Remote Solutions

​ Since the data saved by redis in the remote solution can be shared by multiple clients, there is a problem of data synchronization. Jetcache provides 3 annotations to solve this problem, respectively synchronizing cache data during update and delete operations, and periodically refreshing data when reading cache

refresh cache

@CacheUpdate(name="book_",key="#book.id",value="#book")
public boolean update(Book book) {
    
    
    return bookDao.updateById(book) > 0;
}

delete cache

@CacheInvalidate(name="book_",key = "#id")
public boolean delete(Integer id) {
    
    
    return bookDao.deleteById(id) > 0;
}

Refresh the cache regularly

@Cached(name="book_",key="#id",expire = 3600,cacheType = CacheType.REMOTE)
@CacheRefresh(refresh = 5)
public Book getById(Integer id) {
    
    
    return bookDao.selectById(id);
}

6.6 Data report

​ jetcache also provides a simple data report function to help developers quickly view cache hit information, only need to add a configuration

jetcache:
  statIntervalMinutes: 1

​ After setting, cache data hit information will be output on the console every 1 minute

[DefaultExecutor] c.alicp.jetcache.support.StatInfoLogger  : jetcache stat from 2023-01-28 09:32:15,892 to 2022-02-28 09:33:00,003
cache    |    qps|   rate|   get|    hit|   fail|   expire|   avgLoadTime|   maxLoadTime
---------+-------+-------+------+-------+-------+---------+--------------+--------------
book_    |   0.66| 75.86%|    29|     22|      0|        0|          28.0|           188
---------+-------+-------+------+-------+-------+---------+--------------+--------------

7. SpringBoot integrates j2cache cache

​ jetcache can build a multi-level cache within a limited range, but it is not flexible enough to match the cache at will. We introduce a cache integration framework that can match the cache solution at will, j2cache. Let's explain how to use this caching framework, taking the integration of Ehcache and redis as an example:

Step ① : Import j2cache, redis, ehcache coordinates

<dependency>
    <groupId>net.oschina.j2cache</groupId>
    <artifactId>j2cache-core</artifactId>
    <version>2.8.4-release</version>
</dependency>
<dependency>
    <groupId>net.oschina.j2cache</groupId>
    <artifactId>j2cache-spring-boot2-starter</artifactId>
    <version>2.8.0-release</version>
</dependency>
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
</dependency>

​ j2cache's starter contains redis coordinates by default, and it is officially recommended to use redis as the second-level cache, so there is no need to import redis coordinates here

Step ② : Configure the first-level and second-level caches, and configure the data transfer method between the first and second level caches. The configuration is written in the file named j2cache.properties. If you use ehcache, you need to add the ehcache configuration file separately

# 1级缓存
j2cache.L1.provider_class = ehcache
ehcache.configXml = ehcache.xml

# 2级缓存
j2cache.L2.provider_class = net.oschina.j2cache.cache.support.redis.SpringRedisProvider
j2cache.L2.config_section = redis
redis.hosts = localhost:6379

# 1级缓存中的数据如何到达二级缓存
j2cache.broadcast = net.oschina.j2cache.cache.support.redis.SpringRedisPubSubPolicy

​ The configuration here cannot be configured indiscriminately, and you need to refer to the official configuration instructions. For example, the first-level supplier chooses ehcache, and the supplier name is just an ehcache, but when the second-level supplier chooses redis, it needs to write a dedicated Spring-integrated Redis supplier class name SpringRedisProvider, and this name is not available in all redis packages. It is not provided in the spring package. Therefore, to configure j2cache, you must refer to the official document configuration, and you must find a dedicated integration package and import the corresponding coordinates before it can be used.

​ One of the most important configurations of the first-level and second-level caches is the data communication method between the two. This type of configuration is not arbitrary, and the data communication methods provided by different cache solutions are very different. You need to check the official document to set it up.

Step ③ : Use cache

@Service
public class SMSCodeServiceImpl implements SMSCodeService {
    
    
    @Autowired
    private CodeUtils codeUtils;

    @Autowired
    private CacheChannel cacheChannel;

    public String sendCodeToSMS(String tele) {
    
    
        String code = codeUtils.generator(tele);
        cacheChannel.set("sms",tele,code);
        return code;
    }

    public boolean checkCode(SMSCode smsCode) {
    
    
        String code = cacheChannel.get("sms",smsCode.getTele()).asString();
        return smsCode.getCode().equals(code);
    }
}

​ The use of j2cache is similar to that of jetcache, but there is no need to turn on the switch for use, and it can be used by directly defining the cache object. The name of the cache object is CacheChannel.

​ The use of j2cache is not complicated, configuration is the core of j2cache, after all, it is an integrated caching framework. There are too many cache-related configurations, you can refer to the description in the j2cache.properties file in the j2cache-core core package. as follows:

#J2Cache configuration
#########################################
# Cache Broadcast Method
# values:
# jgroups -> use jgroups's multicast
# redis -> use redis publish/subscribe mechanism (using jedis)
# lettuce -> use redis publish/subscribe mechanism (using lettuce, Recommend)
# rabbitmq -> use RabbitMQ publisher/consumer mechanism
# rocketmq -> use RocketMQ publisher/consumer mechanism
# none -> don't notify the other nodes in cluster
# xx.xxxx.xxxx.Xxxxx your own cache broadcast policy classname that implement net.oschina.j2cache.cluster.ClusterPolicy
#########################################
j2cache.broadcast = redis

# jgroups properties
jgroups.channel.name = j2cache
jgroups.configXml = /network.xml

# RabbitMQ properties
rabbitmq.exchange = j2cache
rabbitmq.host = localhost
rabbitmq.port = 5672
rabbitmq.username = guest
rabbitmq.password = guest

# RocketMQ properties
rocketmq.name = j2cache
rocketmq.topic = j2cache
# use ; to split multi hosts
rocketmq.hosts = 127.0.0.1:9876

#########################################
# Level 1&2 provider
# values:
# none -> disable this level cache
# ehcache -> use ehcache2 as level 1 cache
# ehcache3 -> use ehcache3 as level 1 cache
# caffeine -> use caffeine as level 1 cache(only in memory)
# redis -> use redis as level 2 cache (using jedis)
# lettuce -> use redis as level 2 cache (using lettuce)
# readonly-redis -> use redis as level 2 cache ,but never write data to it. if use this provider, you must uncomment `j2cache.L2.config_section` to make the redis configurations available.
# memcached -> use memcached as level 2 cache (xmemcached),
# [classname] -> use custom provider
#########################################

j2cache.L1.provider_class = caffeine
j2cache.L2.provider_class = redis

# When L2 provider isn't `redis`, using `L2.config_section = redis` to read redis configurations
# j2cache.L2.config_section = redis

# Enable/Disable ttl in redis cache data (if disabled, the object in redis will never expire, default:true)
# NOTICE: redis hash mode (redis.storage = hash) do not support this feature)
j2cache.sync_ttl_to_redis = true

# Whether to cache null objects by default (default false)
j2cache.default_cache_null_object = true

#########################################
# Cache Serialization Provider
# values:
# fst -> using fast-serialization (recommend)
# kryo -> using kryo serialization
# json -> using fst's json serialization (testing)
# fastjson -> using fastjson serialization (embed non-static class not support)
# java -> java standard
# fse -> using fse serialization
# [classname implements Serializer]
#########################################

j2cache.serialization = json
#json.map.person = net.oschina.j2cache.demo.Person

#########################################
# Ehcache configuration
#########################################

# ehcache.configXml = /ehcache.xml

# ehcache3.configXml = /ehcache3.xml
# ehcache3.defaultHeapSize = 1000

#########################################
# Caffeine configuration
# caffeine.region.[name] = size, xxxx[s|m|h|d]
#
#########################################
caffeine.properties = /caffeine.properties

#########################################
# Redis connection configuration
#########################################

#########################################
# Redis Cluster Mode
#
# single -> single redis server
# sentinel -> master-slaves servers
# cluster -> cluster servers (数据库配置无效,使用 database = 0)
# sharded -> sharded servers  (密码、数据库必须在 hosts 中指定,且连接池配置无效 ; redis://user:[email protected]:6379/0)
#
#########################################

redis.mode = single

#redis storage mode (generic|hash)
redis.storage = generic

## redis pub/sub channel name
redis.channel = j2cache
## redis pub/sub server (using redis.hosts when empty)
redis.channel.host =

#cluster name just for sharded
redis.cluster_name = j2cache

## redis cache namespace optional, default[empty]
redis.namespace =

## redis command scan parameter count, default[1000]
#redis.scanCount = 1000

## connection
# Separate multiple redis nodes with commas, such as 192.168.0.10:6379,192.168.0.11:6379,192.168.0.12:6379

redis.hosts = 127.0.0.1:6379
redis.timeout = 2000
redis.password =
redis.database = 0
redis.ssl = false

## redis pool properties
redis.maxTotal = 100
redis.maxIdle = 10
redis.maxWaitMillis = 5000
redis.minEvictableIdleTimeMillis = 60000
redis.minIdle = 1
redis.numTestsPerEvictionRun = 10
redis.lifo = false
redis.softMinEvictableIdleTimeMillis = 10
redis.testOnBorrow = true
redis.testOnReturn = false
redis.testWhileIdle = true
redis.timeBetweenEvictionRunsMillis = 300000
redis.blockWhenExhausted = false
redis.jmxEnabled = false

#########################################
# Lettuce scheme
#
# redis -> single redis server
# rediss -> single redis server with ssl
# redis-sentinel -> redis sentinel
# redis-cluster -> cluster servers
#
#########################################

#########################################
# Lettuce Mode
#
# single -> single redis server
# sentinel -> master-slaves servers
# cluster -> cluster servers (数据库配置无效,使用 database = 0)
# sharded -> sharded servers  (密码、数据库必须在 hosts 中指定,且连接池配置无效 ; redis://user:[email protected]:6379/0)
#
#########################################

## redis command scan parameter count, default[1000]
#lettuce.scanCount = 1000
lettuce.mode = single
lettuce.namespace =
lettuce.storage = hash
lettuce.channel = j2cache
lettuce.scheme = redis
lettuce.hosts = 127.0.0.1:6379
lettuce.password =
lettuce.database = 0
lettuce.sentinelMasterId =
lettuce.maxTotal = 100
lettuce.maxIdle = 10
lettuce.minIdle = 10
# timeout in milliseconds
lettuce.timeout = 10000
# redis cluster topology refresh interval in milliseconds
lettuce.clusterTopologyRefresh = 3000

#########################################
# memcached server configurations
# refer to https://gitee.com/mirrors/XMemcached
#########################################

memcached.servers = 127.0.0.1:11211
memcached.username =
memcached.password =
memcached.connectionPoolSize = 10
memcached.connectTimeout = 1000
memcached.failureMode = false
memcached.healSessionInterval = 1000
memcached.maxQueuedNoReplyOperations = 100
memcached.opTimeout = 100
memcached.sanitizeKeys = false
  • j2cache is a caching framework, it does not have a caching function itself, it provides a variety of caching integration solutions

  • j2cache needs to set up caches at all levels through complex configurations, as well as the way of data exchange between caches

  • The j2cache operation interface is implemented through CacheChannel

Guess you like

Origin blog.csdn.net/qq_44665283/article/details/129007813