{"id":23206953,"url":"https://github.com/lianglliu/cache-sharing","last_synced_at":"2025-07-24T19:05:03.799Z","repository":{"id":47057898,"uuid":"404683994","full_name":"LiangLliu/cache-sharing","owner":"LiangLliu","description":"Redis缓存共享探究","archived":false,"fork":false,"pushed_at":"2021-09-16T08:27:35.000Z","size":115,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-05T11:16:44.307Z","etag":null,"topics":["cache","cacheable","java","redis-cache"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LiangLliu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-09-09T10:47:29.000Z","updated_at":"2021-09-15T12:08:02.000Z","dependencies_parsed_at":"2022-09-03T02:42:07.246Z","dependency_job_id":null,"html_url":"https://github.com/LiangLliu/cache-sharing","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/LiangLliu/cache-sharing","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiangLliu%2Fcache-sharing","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiangLliu%2Fcache-sharing/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiangLliu%2Fcache-sharing/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiangLliu%2Fcache-sharing/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LiangLliu","download_url":"https://codeload.github.com/LiangLliu/cache-sharing/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LiangLliu%2Fcache-sharing/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266890310,"owners_count":24001526,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-24T02:00:09.469Z","response_time":99,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cache","cacheable","java","redis-cache"],"created_at":"2024-12-18T17:16:12.446Z","updated_at":"2025-07-24T19:05:03.317Z","avatar_url":"https://github.com/LiangLliu.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# cachedemo\n\n* 探究 Redis + Cacheable 的使用\n* 不同微服务共享缓存问题\n* 探究由于微服务架构划分错误，两个微服务使用了相同的domain时，配置相同的key，redis读取缓存时存在缓存冲突的问题\n\n### 场景\n\n* 两个微服务，对象结构一致，但是包路径不同\n* 两个User对象，结构完全一致，包路径不同\n    * com.edwin.cache.account.User\n  ```java\n  package com.edwin.cache.account;\n  \n  import lombok.*;\n  \n  import java.io.Serializable;\n  \n  @Setter\n  @Getter\n  @AllArgsConstructor\n  @NoArgsConstructor\n  @Builder\n  @ToString\n  public class User implements Serializable {\n    private Long id;\n    private String username;\n    private String password;\n  }\n\n  ``` \n\n    * com.edwin.cache.user.User\n  ```java\n  package com.edwin.cache.user;\n  \n  import lombok.*;\n  \n  import javax.persistence.*;\n  import java.io.Serializable;\n  \n  @Setter\n  @Getter\n  @AllArgsConstructor\n  @NoArgsConstructor\n  @Entity\n  @Builder\n  @Table(name = \"user\")\n  @ToString\n  public class User implements Serializable {\n      @Id\n      @GeneratedValue(strategy = GenerationType.IDENTITY)\n      private Long id;\n      private String username;\n      private String password;\n  }\n  ```\n* 缓存方案\n    * com.edwin.cache.account.User\n  ```java\n  @CacheConfig(cacheNames = \"user\")\n  @Repository\n  @RequiredArgsConstructor\n  public class AccountRepository {\n  private final AccountJpaRepository accountJpaRepository;\n  \n      public static final String USER_PEX = \"USER_\";\n  \n      @Cacheable(cacheNames = USER_PEX, key = \"'user.id:'+#id\")\n      public User findUserById(Long id) {\n          Optional\u003cAccount\u003e optionalAccount = accountJpaRepository.findById(id);\n          if (optionalAccount.isEmpty()) {\n              return new User();\n          }\n          Account account = optionalAccount.get();\n          return User.builder()\n                  .id(account.getId())\n                  .username(account.getUsername())\n                  .password(account.getPassword())\n                  .build();\n      }\n  }\n  ```\n    * com.edwin.cache.user.UserRepository\n  ```java\n  @CacheConfig(cacheNames = \"user\")\n  @Repository\n  @RequiredArgsConstructor\n  public class UserRepository {\n  private final UserJpaRepository userJpaRepository;\n  \n      public static final String USER_PEX = \"USER_\";\n  \n      @Cacheable(cacheNames = USER_PEX, key = \"'user.id:'+#id\")\n      public User findUserById(Long id) {\n          return userJpaRepository.findById(id).orElse(new User());\n      }\n  }\n  ```\n* 希望存到Redis后可以做缓存共享\n\n### 方案1\n\n* 配置一个 Map\u003cString, String\u003e 关系\n\n```java \nMap\u003cString, String\u003e map = new HashMap\u003c\u003e();\nmap.put(\"com.edwin.cache.user.User\",\"com.edwin.cache.account.User\")\nmap.put(\"com.edwin.cache.account.User\",\"com.edwin.cache.user.User\")\n```\n\n* 当反序列化时，在读取二进制（Json）数据时，进行转换\n* 问题：\n    * 如果redis存入的对象为 com.edwin.cache.user.User，当反序列化为 com.edwin.cache.account.User时，由于反序列化时需要把数据\n      放进实例化对象中，这时候涉及到类加载，在account上下文中并没有com.edwin.cache.user.User的对象，因此会挂掉。\n    * 转换时并不知道是哪个对象在获取缓存\n\n### 方案2\n* 如同方案1也配置一个map关系\n* 对redis存储的数据反序列化时，尝试类加载，如果不能加载该类，那么通过加载 map.get(key)的值，尝试类加载，如果失败，走原来的，如果成功，\n  替换原来的序列化类加载路径\n* RedisSerializer 默认使用 JdkSerializationRedisSerializer\n  * JdkSerializationRedisSerializer 默认会使用 org.springframework.core.serializer.support.SerializingConverter 和\n    org.springframework.core.serializer.support.DeserializingConverter, 我们只需要关注反序列化器\n  * DeserializingConverter 中 会使用 org.springframework.core.ConfigurableObjectInputStream\n  * ConfigurableObjectInputStream 中有一个 resolveClass方法，我们只需要继承这个类并且把整个方法重写, 就可以按照需求加载对应的类\n  ```java\n  public class DemoObjectInputStream extends ConfigurableObjectInputStream {\n      @Override\n      protected Class\u003c?\u003e resolveClass(ObjectStreamClass classDesc) throws IOException, ClassNotFoundException {\n  \n          String name = classDesc.getName();\n          System.out.println(name);\n  \n          Map\u003cString, String\u003e map = new HashMap\u003c\u003e();\n          map.put(\"com.edwin.cache.account.User\", \"com.edwin.cache.user.User\");\n          map.put(\"com.edwin.cache.user.User\", \"com.edwin.cache.account.User\");\n  \n          if (!ClassUtils.isPresent(name, classLoader)) {\n              String className = map.get(name);\n              if (!ObjectUtils.isEmpty(className) \u0026\u0026 ClassUtils.isPresent(className, classLoader)) {\n                  return ClassUtils.forName(className, this.classLoader);\n              }\n          }\n  \n          return super.resolveClass(classDesc);\n      }\n  }\n\n  ```\n### 测试\n分别启动服务 cache-service 和 cache-account\n* 通过测试可以拿到相同的结果\n* 访问 http://localhost:8080/user\n```shell\ncurl http://localhost:8080/user | python -m json.too\n```\n```json\n[\n    {\n        \"id\": 1,\n        \"password\": \"111111\",\n        \"username\": \"\\u5f20\\u4e09\"\n    },\n    {\n        \"id\": 2,\n        \"password\": \"222222\",\n        \"username\": \"\\u674e\\u56db\"\n    },\n    {\n        \"id\": 3,\n        \"password\": \"333333\",\n        \"username\": \"\\u738b\\u4e94\"\n    },\n    {\n        \"id\": 4,\n        \"password\": \"444444\",\n        \"username\": \"\\u7530\\u516d\"\n    }\n]\n```\n\n* 访问 http://localhost:8090/account\n```shell\ncurl http://localhost:8090/account | python -m json.tool\n```\n```json\n[\n    {\n        \"id\": 1,\n        \"password\": \"111111\",\n        \"username\": \"\\u5f20\\u4e09\"\n    },\n    {\n        \"id\": 2,\n        \"password\": \"222222\",\n        \"username\": \"\\u674e\\u56db\"\n    },\n    {\n        \"id\": 3,\n        \"password\": \"333333\",\n        \"username\": \"\\u738b\\u4e94\"\n    },\n    {\n        \"id\": 4,\n        \"password\": \"444444\",\n        \"username\": \"\\u7530\\u516d\"\n    }\n]\n``` ","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flianglliu%2Fcache-sharing","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flianglliu%2Fcache-sharing","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flianglliu%2Fcache-sharing/lists"}