Detailed explanation of the services in the cache architecture! Implementation of the second-level cache service in SpringBoot

Detailed explanation of the services in the cache architecture! Implementation of the second-level cache service in SpringBoot

Create a cache service

Create a cache service interface project

  • Create the myshop-service-redis-api project, which is only responsible for defining the interface
  • Create the pom.xml of the project :
<?xml version="1.0" encoding="UTF-8"?> < project xmlns = "http://maven.apache.org/POM/4.0.0" xmlns:xsi = "http://www.w3 .org/2001/XMLSchema-instance" xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" > < modelVersion > 4.0.0 </modelVersion > < parent > < groupId > com.oxford </groupId > < artifactId > myshop-dependencies </artifactId > <version > 1.0.0-SNAPSHOT </version > < relativePath > ../myshop-dependencies/pom.xml </relativePath > </parent > < The artifactId > MyShop-Redis-API-Service- </the artifactId > < Packaging > JAR </Packaging > </Project > copy the code
  • Define the data Redis interface RedisService:
package com.oxford.myshop.service.redis.api public interface RedisService { void set (String key,Object value) ; void set (String key,Object value, int seconds) ; void del (String key) ; Object get (String key) ; } Copy code

Create a cache service provider project

  • Create the myshop-service-redis-provider project, which is used as a cache service provider
  • Create the pom.xml of the project :
<?xml version="1.0" encoding="UTF-8"?> < project xmlns = "http://maven.apache.org/POM/4.0.0" xmlns:xsi = "http://www.w3 .org/2001/XMLSchema-instance" xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" > < modelVersion > 4.0.0 </modelVersion > < parent > < groupId > com.oxford </groupId > < artifactId > myshop-dependencies </artifactId > <version > 1.0.0-SNAPSHOT </version > < relativePath > ../myshop-dependencies/pom.xml </relativePath > </parent > < artifactId > myshop-service-redis-api </artifactId > < packaging > jar </packaging > < dependencies > <!-- Spring Boot Starter Settings--> < dependency > < groupId > org.springframework.boot </groupId > < artifactId > spring-boot-starter-data-redis </artifactId > </dependency > < dependency > < groupId > org.springframework.boot </groupId > < artifactId > spring-boot-starter-test </artifactId > < scope > test </scope > </dependency > <!--Common Setting--> < dependency > < groupId > org.apache.commons </groupId > < artifactId > commons-pool2 </artifactId > </dependency > < dependency > < groupId > de.javakaffee </groupId > < artifactId > kryo-serializers </artifactId > </dependency > <!--Project Settings--> < dependency > < groupId > com.oxford </groupId > < artifactId > my-shop-commons-dubbo </artifactId > < version > ${Project.parent.version} </version > </dependency > < dependency > < groupId > com.oxford </groupId > < artifactId > my-shop-service-redis-api </artifactId > <version > ${Project.parent.version} </version > </dependency > </dependencies > < build > < plugins > < plugin > < groupId > org.springframework.boot </groupId > < artifactId > spring-boot-maven-plugin </artifactId > < configuration > < mainClass > com.oxford.myshop.service.redis .provider.MyshopServiceRedisProviderApplication </mainClass > </Configuration > </plugin > </plugins > </build > </project > copy code

Java lettuce client implemented at the bottom of Redis

  • Create a cache service interface implementation class RedisServiceImpl
package com.oxford.myshop.service.redis.provider.api.impl; @Service(version="${service.versions.redis.v1}") public class RedisServiceImpl implements RedisService { @Override public void set (String key,Object value) { redisTemplate.opsForValue().set(key,value); } @Override public void set (String key,Object value, int seconds) { redisTemplate.opsForValue().set(key,value,seconds,TimeUnit.SECONDS); } @Override public void del(String key){ redisTemplate.delete(key); } @Override public Object get(String key){ return redisTemplate.opsForValue().get(key); } }
  • SpringBootApplication
package com.oxford.myshop.service.redis.provider; import com.alibaba.dubbo.container.Main; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.hystrix.EnableHystrix; import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; @EnableHystrix @EnableHystrixDashboard public class MyShopServiceRedisrProviderApplication { public static void main(String[]args) { SpringApplication.run(MyShopServiceRedisProviderApplication.class,args); Main.main(args); } }
  • application.yml
spring: application: name: myshop-service-redis-provider redis: lettuce: pool: max-active: 8 max-idle: 8 max-wait: -1ms min-idle: 0 sentinel: master: mymaster nodes: 192.168.32.255:26379,192.168.32.255:26380,192.168.32.255:26381 server: port: 8503 services: version: redis: v1: 1.0.0 user: v1: 1.0.0 dubbo: scan: basePackages: com.oxford.myshop.service.redis.provider.api.impl application: id: com.oxford.myshop.service.redis.provider.api name: com.oxford.myshop.service.redis.provider.api qos-port: 22224 qos-enable: true protocal: id: dubbo name: dubbo port: 20883 status: server serialization: kryo regitry: id: zookeeper address: zookeeper://localhost:2181?backup=192.168.32.255:2182,192.168.32.255:2183 management: endpoint: dubbo: enabled: true dubbo-shutdown: enabled: true dubbo-configs: enabled: true dubbo-sevicies: enabled: true dubbo-reference: enabled: true dubbo-properties: enabled: true health: dubbo: status: defaults: memory extras: load,threadpool

  • pom redis
  • ServiceImpl RedisService
@Reference(version="services.versions.redis.v1") private RedisService redisService;

MyBatis Redis

MyBatis

  • :
    • MyBatis SqlSession : , , , , ,
    • SqlSession :
      • SqlSession
      • ( ) (HashMap)
      • SqlSession (HashMap) ,
      • SqlSession
      • SqlSession SQL : ( ), , ,
      • SqlSession SqlSession
      • MyBatis
  • :
    • Mapper : SqlSession Mapper SQL , SqlSession , SqlSession , SqlSession
    • mapper namespace
    • SqlSession namespace SQL SQL SQL : ( ), ,
    • MyBatis , setting

MyBatis

SpringBoot MyBatis
  • myshop-service-user-provider MyBatis
spring: application: name: myshop-service-user-provider datasource: druid: url: jdbc:mysql://localhost:3306/myshop?useUnicode=true&characterEncoding=utf-8&useSSL=false username: root password: 123456 initial-size: 1 min-idle: 1 main-active: 20 test-on-borrow: true driver-class-name: com.mysql.cj.jdbc.Driver redis: lettuce: pool: max-active: 8 max-idle: 8 max-wait: -1ms min-idle: 0 sentinel: master: mymaster nodes: 192.168.32.255:26379,192.168.32.255:26380,192.168.32.255:26381 server: port: 8501 # MyBatis Config properties mybatis: configuration: cache-enabled: true type-aliases-package: com.oxford.myshop.commons.domain mapper-location: classpath:mapper/*.xml services: version: redis: v1: 1.0.0 user: v1: 1.0.0 dubbo: scan: basePackages: com.oxford.myshop.service.user.provider.api.impl application: id: com.oxford.myshop.service.user.provider.api name: com.oxford.myshop.service.user.provider.api qos-port: 22222 qos-enable: true protocal: id: dubbo name: dubbo port: 20001 status: server serialization: kryo regitry: id: zookeeper address: zookeeper://localhost:2181?backup=192.168.32.255:2182,192.168.32.255:2183 management: endpoint: dubbo: enabled: true dubbo-shutdown: enabled: true dubbo-configs: enabled: true dubbo-sevicies: enabled: true dubbo-reference: enabled: true dubbo-properties: enabled: true health: dubbo: status: defaults: memory extras: load,threadpool
  • myshop-commons-mapper pom.xml redis :
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifacted> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifacted> </dependency>
private static final long serialVersionUID = 82897704415244673535L
IDEA : - GenerateSerialVersionUID , - Alt+Insert ,
Mybatis Cache , Redis
  • myshop-commons ApplicationContextHolder
package com.oxford.myshop.commons.context; @Component public class ApplicationContextHolder implements ApplicationContextAware,DisposableBean{ private static final Logger logger=LoggerFactory.getLogger(ApplicationContext.class); private static ApplicationContext applicationContext; /** * ApplicationContext */ public static ApplicationContext getApplicationContext(){ assertContextInjected(); return applicationContext; } /** * applicationContext Bean, */ public static <T> T getBean(String name){ assertContextInjected(); return (T) applicationContext.getBean(name); } /** * applicationContext Bean, */ public static <T> T getBean(Class<T> clazz){ assertContextInjected(); return (T) applicationContext.getBean(clazz); } /** * DisposableBean , Context */ public void destroy() throws Exception{ logger.debug(" SpringContext ApplicationContext: {}",applicationContext); applicationContext=null; } /** * ApplicationContextAware , Context */ public void setApplicationContext(ApplicationContext applicationContext) throws BeanException{ ApplicationContext.applicationContext=applicationContext; } /** * Context */ private static void assertContextInjected(){ Validate.validState(applicationContext !=null,"applicationContext , ApplicationContextContext"); } }
  • myshop-commons-mapper RedisCache
package com.oxford.myshop.commons.utils; public class RedisCache implements Cache{ private static final Logger logger=LoggerFactory.getLogger(RedisCache.class); private final ReadWriteLock readWriteLock=new ReentranReadWriteLock(); private final String id; private RedisTemplate redisTemplate; private static final long EXPIRE_TIME_IN_MINUTES=30 //redis public RedisCache(String id){ if(id==null){ throw new IllegalArgumentException("Cache instances require an ID"); } this.id=id; } @Override public String getId(){ return id; } /** * Put query result to redis */ @Override public void putObject(Object key,Object value){ try{ RedisTemplate redisTemplate=getRedisTemplate(); ValueOperations opsForValue=redisTemplate.opsForValue(); opsForValue.set(key, value, EXPIRE_TIME_IN_MINUTES, TimeUnit.MINUTES); logger.debug("Put query result to redis"); }catch(Throwable t){ logger.error("Redis put failed",t); } } /** * Get cached query result from redis */ @Override public Object getObject(Object key){ try{ RedisTemplate redisTemplate=getRedisTemplate(); ValueOperations opsForValue=redisTemplate.opsForValue(); opsForValue.set(key, value, EXPIRE_TIME_IN_MINUTES, TimeUnit.MINUTES); logger.debug("Get cache query result from redis"); return opsForValue.get(key); }catch(Throwable t){ logger.error("Redis get failed, fail over to db"); return null; } } /** * Get cached query result from redis */ @Override public Object getObject(Object key){ try{ RedisTemplate redisTemplate=getRedisTemplate(); ValueOperations opsForValue=redisTemplate.opsForValue(); opsForValue.set(key, value, EXPIRE_TIME_IN_MINUTES, TimeUnit.MINUTES); logger.debug("Get cache query result from redis"); return opsForValue.get(key); }catch(Throwable t){ logger.error("Redis get failed, fail over to db"); return null; } } /** * Remove cached query result from redis */ @Override @SuppressWarnings("unchecked") public Object removeObject(Object key){ try{ RedisTemplate redisTemplate=getRedisTemplate(); redisTemplate.delete(key); logger.debug("Remove cached query result from redis"); }catch(Throwable t){ logger.error("Redis remove failed"); } return null; } /** * Clear this cache instance */ @Override public void clear(){ RedisTemplate redisTemplate=getRedisTemplate(); redisTemplate.execute((RedisCallback)->{ connection.flushDb(); return null; }); logger.debug("Clear all the cached query result from redis"); } @Override public int getSize(){ return 0; } @Override public ReadWriteLock getReadWriteLock(){ return readWriteLock; } private RedisTemplate getRedisTemplate(){ if(redisTemplate==null){ redisTemplate=ApplicationContextHolder.getBean("redisTemplate"); } return redisTemplate; } }
Mapper
  • Mapper ,
@CacheNamespace(implementation=RedisCache.class)