当前位置: 首页 > news >正文

石家庄建立网站的公司阿里网站制作需要多少钱

石家庄建立网站的公司,阿里网站制作需要多少钱,请人做网站注意事项,怎么免费申请个人网站目录 1、Caffeine 简介 1.1、Caffeine 简介1.2、对比 Guava cache 的性能主要优化项1.3、常见的缓存淘汰算法1.4、SpringBoot 集成 Caffeine 两种方式 2、SpringBoot 集成 Caffeine 方式一 2.1、缓存加载策略 2.1.1、手动加载2.1.2、自动加载【Loading Cache】2.1.3、异步加载…目录 1、Caffeine 简介 1.1、Caffeine 简介1.2、对比 Guava cache 的性能主要优化项1.3、常见的缓存淘汰算法1.4、SpringBoot 集成 Caffeine 两种方式 2、SpringBoot 集成 Caffeine 方式一 2.1、缓存加载策略 2.1.1、手动加载2.1.2、自动加载【Loading Cache】2.1.3、异步加载【AsyncLoadingCache】 2.2、回收策略 2.2.1、基于大小的过期方式2.2.2、基于时间的过期方式2.2.3、基于引用的过期方式 2.3、写入外部存储2.4、统计2.5、刷新机制2.6、快速入门 2.6.1、引入依赖2.6.2、创建 Caffeine 缓存配置类2.6.3、定义实体对象2.6.4、定义服务实现类2.6.5、定义控制器调用测试 2.7、总结 3、SpringBoot 集成 Caffeine 方式二 3.1、常用的注解 3.1.1、Cacheable 注解3.1.2、CachePut 注解3.1.3、CacheEvict 注解3.1.4、Caching 注解3.1.5、CacheConfig 注解 3.2、快速入门 3.2.1、引入依赖3.2.2、开启缓存功能3.2.3、配置缓存类3.2.4、使用缓存3.2.5、添加 Controller 3.3、配置数据源 3.3.1、不配置(默认)3.3.2、配置 Caffeine 缓存 3.3.2.1、CaffeineCacheManager 3.3.2.1.1、使用 Java 配置类3.3.2.1.2、使用配置文件 3.3.2.2、SimpleCacheManager 3.3.3、配置 Redis 缓存3.3.4、配置多缓存源 3.4、keyGenerator3.5、CacheResolver 5、SPEL6、Caffeine 的优劣势和适用场景 1、Caffeine 简介 1.1、Caffeine 简介 Caffeine 官网 Caffeine 是基于Java 1.8 的高性能本地缓存库同样是 Google 开发的由 Guava 改进而来底层设计思路、功能和使用方式与 Guava 非常类似但是各方面的性能都要远远超过前者可以看做是 Guava cache 的升级版。而且在 Spring5 开始的默认缓存实现就将 Caffeine 代替原来的 Google Guava官方说明指出其缓存命中率已经接近最优值 可以通过下图观测到在下面缓存组件中 Caffeine 性能是其中最好的 1.2、对比 Guava cache 的性能主要优化项 Caffeine 底层又做了哪些优化才能让其性能高于 Guava cache 呢主要包含以下三点 异步策略Guava cache 在读操作中可能会触发淘汰数据的清理操作虽然自身也做了一些优化来减少读的时候的清理操作但是一旦触发就会降低查询效率对缓存性能产生影响。而Caffeine 支持异步操作采用异步处理的策略查询请求在触发淘汰数据的清理操作后会将清理数据的任务添加到独立的线程池中进行异步操作不会阻塞查询请求提高了查询性能ConcurrentHashMap 优化Caffeine 底层都是通过 ConcurrentHashMap 来进行数据的存储因此随着 Java8 中对 ConcurrentHashMap 的调整数组 链表的结构升级为数组 链表 红黑树的结构以及分段锁升级为 syschronized CAS降低了锁的粒度减少了锁的竞争这两个优化显著提高了 Caffeine 在读多写少场景下的查询性能新型淘汰算法 W-TinyLFU传统的淘汰算法如 LRU、LFU、FIFO在实际的缓存场景中都存在一些弊端。因此Caffeine 引入了 W-TinyLFU 算法由窗口缓存、过滤器、主缓存组成。缓存数据刚进入时会停留在窗口缓存中这个部分只占总缓存的 1%当被挤出窗口缓存时会在过滤器汇总和主缓存中淘汰的数据进行比较如果频率更高则进入主缓存否则就被淘汰主缓存被分为淘汰段和保护段两段都是 LRU 算法第一次被访问的元素会进入淘汰段第二次被访问会进入保护段保护段中被淘汰的元素会进入淘汰段这种算法实现了高命中率和低内存占用 1.3、常见的缓存淘汰算法 常见的缓存淘汰算法 FIFO先进先出在这种淘汰算法中先进入缓存的会先被淘汰会导致命中率很低 局限性如果缓存使用的频率较高那么缓存数据会一直处在进进出出的状态间接影响到缓存命中率 LRU最近最少使用算法每次访问数据都会将其放在我们的队首如果需要淘汰数据就只需要淘汰队尾即可。仍然有个问题如果有个数据在 1 分钟访问了 1000次再后 1 分钟没有访问这个数据但是有其它的数据访问就导致了我们这个热点数据被淘汰 局限性LRU 可以很好的应对突发流量的情况因为它不需要累计数据频率。但 LRU 通过历史数据来预测未来是局限的它会认为最后到来的数据是最可能被再次访问的从而给与它最高的优先级。 LFU最近最少频率使用利用额外的空间记录每个数据的使用频率然后选出频率最低进行淘汰 局限性在 LFU 中只要数据访问模式的概率分布随时间保持不变时其命中率就能变得非常高。比如有部新剧出来了我们使用 LFU 给它缓存下来这部新剧在这几天大概访问了几亿次这个访问频率也在我们的 LFU 中记录了几亿次。但是新剧总会过气的比如一个月之后这个新剧的前几集其实已经过气了但是它的访问量的确是太高了其它的电视剧根本无法淘汰这个新剧所以在这种模式下是有局限性。 上面三种策略各有利弊实现的成本也是一个比一个高同时命中率也是一个比一个好。Guava Cache 虽然有这么多的功能但是本质上还是对 LRU 的封装如果有更优良的算法并且也能提供这么多功能相比之下就相形见绌了。 在现有算法的局限性下会导致缓存数据的命中率或多或少的受损而命中略又是缓存的重要指标。HighScalability 网站刊登了一篇文章由前 Google 工程师发明的 W-TinyLFU ——一种现代的缓存 。Caffine Cache 就是基于此算法而研发。Caffeine 因使用 Window TinyLfu 回收策略提供了一个近乎最佳的命中率 当数据的访问模式不随时间变化的时候LFU 的策略能够带来最佳的缓存命中率。然而 LFU 有两个缺点 它需要给每个记录项维护频率信息每次访问都需要更新这是个巨大的开销如果数据访问模式随时间有变LFU 的频率信息无法随之变化。因此早先频繁访问的记录可能会占据缓存而后期访问较多的记录则无法被命中。 因此大多数的缓存设计都是基于LRU或者其变种来进行的。相比之下LRU 并不需要维护昂贵的缓存记录元信息同时也能够反应随时间变化的数据访问模式。然而在许多负载之下LRU 依然需要更多的空间才能做到跟 LFU一致的缓存命中率。因此一个“现代”的缓存应当能够综合两者的长处。 TinyLFU 维护了近期访问记录的频率信息作为一个过滤器当新记录来时只有满足 TinyLFU 要求的记录才可以被插入缓存。如前所述作为现代的缓存它需要解决两个挑战 如何避免维护频率信息的高开销如何反应随时间变化的访问模式 更详细的解释可以参考论文https://arxiv.org/pdf/1512.00727.pdf 1.4、SpringBoot 集成 Caffeine 两种方式 Caffeine Cache 的 github 地址 在 SpringBoot 中有两种使用 Caffeine 作为缓存的方式 直接引入 Caffeine 依赖然后使用 Caffeine 方法实现缓存引入 Caffeine 和 Spring Cache 依赖使用 SpringCache 注解方法实现缓存 2、SpringBoot 集成 Caffeine 方式一 引入依赖 dependencygroupIdcom.github.ben-manes.caffeine/groupIdartifactIdcaffeine/artifactIdversion3.0.5/version /dependencyCaffeine Cache 提供了三种缓存填充策略手动、同步加载和异步加载。 2.1、缓存加载策略 2.1.1、手动加载 最普通的一种缓存无需指定加载方式需要手动调用 put() 进行加载通过 get 获取缓存值。如果想要的缓存值不存在并且原子地将值写入缓存则可以调用 get(key, k - value) 方法该方法将避免写入竞争。 在多线程情况下当使用 get(key, k - value) 时如果有另一个线程同时调用本方法进行竞争则后一线程会被阻塞直到前一线程更新缓存完成而若另一线程调用 getIfPresent() 方法则会立即返回 null不会被阻塞 CacheString, Object cache Caffeine.newBuilder()// 初始容量.initialCapacity(100)// 最大缓存数量.maximumSize(500)// 缓存过期时间写入缓存后经过某个时间缓存失效.expireAfterWrite(3, TimeUnit.SECONDS)// 缓存失效监听器.removalListener((key, value, cause) - System.out.println(key: key value: value cause: cause))// 开启统计功能.recordStats().build();cache.put(name, zzc);// 如果一个 key 不存在那么会进入指定的函数生成 value cache.get(age, key - 18);// 判断是否存在如果不存在则返回 null Object ageValue cache.getIfPresent(age);// 移除一个key cache.invalidate(name); return cache;2.1.2、自动加载【Loading Cache】 LoadingCache 是一种自动加载的缓存。其和普通缓存不同的地方在于当缓存不存在/缓存已过期时若调用 get() 方法则会自动调用 CacheLoader.load() 方法加载最新值调用 getAll() 方法将遍历所有的 key 调用 get()除非实现了 CacheLoader.loadAll() 方法。 使用 LoadingCache 时需要指定 CacheLoader并实现其中的 load() 方法供缓存缺失时自动加载。 在多线程情况下当两个线程同时调用get()则后一线程将被阻塞直至前一线程更新缓存完成 LoadingCacheString, Object cache Caffeine.newBuilder()// 初始容量.initialCapacity(100)// 最大缓存数量.maximumSize(500)// 缓存过期时间写入缓存后经过某个时间缓存失效【仅支持 LoadingCache】.refreshAfterWrite(3, TimeUnit.SECONDS)// 缓存失效监听器.removalListener((key, value, cause) - System.out.println(key: key value: value cause: cause))// 开启统计功能.recordStats().build(key - zzc); return cache;2.1.3、异步加载【AsyncLoadingCache】 AsyncLoadingCache 是 Cache 的一个变体其响应结果均为 CompletableFuture通过这种方式AsyncLoadingCache 对异步编程模式进行了适配。默认情况下缓存计算使用ForkJoinPool.commonPool() 作为线程池如果想要指定线程池则可以覆盖并实现Caffeine.executor(Executor) 方法。 synchronous() 提供了阻塞直到异步缓存生成完毕的能力它将以 Cache 进行返回。 在多线程情况下当两个线程同时调用 get(key, k - value)则会返回同一个 CompletableFuture 对象。由于返回结果本身不进行阻塞可以根据业务设计自行选择阻塞等待或者非阻塞 如果要以同步方式调用时应提供 CacheLoader要以异步表示时应该提供一个AsyncCacheLoader并返回一个 CompletableFuture AsyncLoadingCacheString, Object cache Caffeine.newBuilder()// 初始容量.initialCapacity(100)// 最大缓存数量.maximumSize(500)// 缓存过期时间写入缓存后经过某个时间缓存失效.expireAfterWrite(3, TimeUnit.SECONDS)// 缓存失效监听器.removalListener((key, value, cause) - System.out.println(key: key value: value cause: cause))// 开启统计功能.recordStats().buildAsync(key - zzc);//异步缓存返回的是 CompletableFuture CompletableFutureObject future cache.get(1); future.thenAccept(System.out::println);2.2、回收策略 Caffeine提供了 3 种回收策略基于大小回收基于时间回收基于引用回收。 2.2.1、基于大小的过期方式 基于大小的回收策略有两种方式 基于缓存大小maximumSize()基于权重maximumWeight()、weigher() maximumWeight 与 maximumSize 不可以同时使用 2.2.2、基于时间的过期方式 基于固定的到期策略 expireAfterAccess()expireAfterWrite() 基于不同的到期策略expireAfter(Expiry expiry) expireAfterCreate()expireAfterUpdate()expireAfterRead() 2.2.3、基于引用的过期方式 Java 中四种引用类型 引用类型 被垃圾回收时间 用途 生存时间 强引用 Strong Reference 从来不会 对象的一般状态 JVM停止运行时终止 软引用 Soft Reference 在内存不足时 对象缓存 内存不足时终止 弱引用 Weak Reference 在垃圾回收时 对象缓存 gc运行后终止 虚引用 Phantom Reference 从来不会 可以用虚引用来跟踪对象被垃圾回收器回收的活动当一个虚引用关联的对象被垃圾收集器回收之前会收到一条系统通知 JVM停止运行时终止 // 当key和value都没有引用时驱逐缓存 LoadingCacheString, Object cache Caffeine.newBuilder().weakKeys().weakValues().build(key - function(key));// 当垃圾收集器需要释放内存时驱逐 LoadingCacheString, Object cache1 Caffeine.newBuilder().softValues().build(key - function(key))【注意】AsyncLoadingCache 不支持弱引用和软引用 weakKeys()使用弱引用存储 key。如果没有其它地方对该 key 有强引用那么该缓存就会被垃圾回收器回收。由于垃圾回收器只依赖于身份(identity)相等因此这会导致整个缓存使用身份 () 相等来比较 key而不是使用 equals()weakValues()使用弱引用存储value。如果没有其它地方对该 value 有强引用那么该缓存就会被垃圾回收器回收。由于垃圾回收器只依赖于身份(identity)相等因此这会导致整个缓存使用身份 () 相等来比较 key而不是使用 equals()softValues() 使用软引用存储 value。当内存满了过后软引用的对象以将使用最近最少使用(least-recently-used ) 的方式进行垃圾回收。由于使用软引用是需要等到内存满了才进行回收所以我们通常建议给缓存配置一个使用内存的最大值。softValues() 将使用身份相等(identity) () 而不是equals() 来比较值 【注意】weakValues() 和 softValues() 不可以一起使用 2.3、写入外部存储 CacheWriter 方法可以将缓存中所有的数据写入到第三方 LoadingCacheString, Object cache2 Caffeine.newBuilder().writer(new CacheWriterString, Object() {Override public void write(String key, Object value) {// 写入到外部存储}Override public void delete(String key, Object value, RemovalCause cause) {// 删除外部存储}}).build(key - function(key));如果你有多级缓存的情况下这个方法还是很实用 【注意】CacheWriter 不能与弱键或 AsyncLoadingCache 一起使用 2.4、统计 CacheString, Object cache Caffeine.newBuilder().maximumSize(10_000).recordStats().build();通过使用 Caffeine.recordStats(), 可以转化成一个统计的集合. 通过 Cache.stats() 返回一个 CacheStats。 CacheStats提供以下统计方法 // 返回缓存命中率 hitRate() // 缓存回收数量 evictionCount() // 加载新值的平均时间 averageLoadPenalty()2.5、刷新机制 refreshAfterWrite() 表示 x 秒后自动刷新缓存的策略可以配合淘汰策略使用 private static int NUM 0;LoadingCacheInteger, Integer cache Caffeine.newBuilder().refreshAfterWrite(1, TimeUnit.SECONDS)//模拟获取数据每次获取就自增1.build(integer - NUM);//获取ID1的值由于缓存里还没有所以会自动放入缓存System.out.println(cache.get(1));// 1// 延迟2秒后理论上自动刷新缓存后取到的值是2// 但其实不是值还是1因为refreshAfterWrite并不是设置了n秒后重新获取就会自动刷新// 而是x秒后第二次调用getIfPresent的时候才会被动刷新Thread.sleep(2000);System.out.println(cache.getIfPresent(1));// 1//此时才会刷新缓存而第一次拿到的还是旧值 System.out.println(cache.getIfPresent(1));// 2【注意】刷新机制只支持 LoadingCache 和 AsyncLoadingCache 2.6、快速入门 2.6.1、引入依赖 2.6.2、创建 Caffeine 缓存配置类 Configuration public class CacheConfig {Beanpublic CacheString, Object caffeineCache() {CacheString, Object cache Caffeine.newBuilder()// 初始容量.initialCapacity(100)// 最大缓存数量.maximumSize(500)// 缓存过期时间写入缓存后经过某个时间缓存失效.expireAfterWrite(3, TimeUnit.SECONDS)// 缓存失效监听器.removalListener((key, value, cause) - System.out.println(key: key value: value cause: cause))// 开启统计功能.recordStats().build();cache.put(name, zzc);// 如果一个 key 不存在那么会进入指定的函数生成 valuecache.get(age, key - 18);// 判断是否存在如果不存在则返回 nullObject ageValue cache.getIfPresent(age);// 移除一个keycache.invalidate(name);return cache;} }2.6.3、定义实体对象 Data public class User {private Integer id;private String name; }2.6.4、定义服务实现类 Service public class UserServiceImpl {Autowiredprivate CacheString, Object caffeineCache;// 模拟数据库数据private MapInteger, User userMap new HashMap();public void add(User user) {userMap.put(user.getId(), user);// 添加缓存caffeineCache.put(String.valueOf(user.getId()), user);}public User get(Integer id) {// 从缓存中获取User user (User)caffeineCache.asMap().get(String.valueOf(id));if (Objects.nonNull(user)) {return user;}// 缓存没有从数据库获取user userMap.get(id);if (Objects.nonNull(user)) {// 添加缓存caffeineCache.put(String.valueOf(id), user);}return user;}public void update(User user) {// 更新数据库userMap.put(user.getId(), user);// 更新缓存caffeineCache.put(String.valueOf(user.getId()), user);}public void delete(Integer id) {// 删除数据库userMap.remove(id);// 删除缓存caffeineCache.asMap().remove(String.valueOf(id));} }2.6.5、定义控制器调用测试 2.7、总结 上述一些策略在创建时都可以进行自由组合一般情况下有两种方法 设置 maxSize、refreshAfterWrite不设置 expireAfterWrite/expireAfterAccess设置 expireAfterWrite当缓存过期时会同步加锁获取缓存所以设置 expireAfterWrite 时性能较好但是某些时候会取旧数据,适合允许取到旧数据的场景设置 maxSize、expireAfterWrite/expireAfterAccess不设置 refreshAfterWrite数据一致性好不会获取到旧数据但是性能没那么好适合获取数据时不耗时的场景 3、SpringBoot 集成 Caffeine 方式二 3.1、常用的注解 Spring缓存注解Cacheable、CachePut、CacheEvict 【日积月累】SpringBoot 通过注解CacheConfig Cacheable CacheEvict CachePut Caching使用缓存 cache 方面的注解主要有以下 5 个 Cacheable【创建、查询缓存】触发缓存入口一般放在创建和获取的方法上Cacheable 注解会先查询是否已经有缓存。如果有则直接从缓存中返回如果没有则会执行方法并返回结果缓存【返回方法返回 NULL则不进行缓存】CachePut【更新缓存】更新缓存且不影响方法执行用于修改的方法上该注解下的方法始终会被执行CacheEvict【删除缓存】触发缓存的 eviction用于删除的方法上Caching【组合缓存配置】将多个缓存组合在一个方法上该注解可以允许一个方法同时设置多个注解CacheConfig【类级别共享配置】在类级别设置一些缓存相关的共同配置与其它缓存配合使用避免在每个缓存方法上重复配置相同的缓存属性 Cacheable 和 CachePut 的区别 Cacheable它的注解的方法是否被执行取决于 Cacheable 中的条件方法很多时候都可能不被执行CachePut这个注解不会影响方法的执行也就是说无论它配置的条件是什么方法都会被执行更多的时候是被用到修改上 如果不想使用注解的方式去操作缓存也可以直接使用 SimpleCacheManager 获取缓存的 key 进而进行操作 3.1.1、Cacheable 注解 Cacheable 注解使方法返回结果被缓存【返回结果为 NULL则不进行缓存】再次通过相同参数调用时会直接从缓存获取而不再执行该方法逻辑。 Cacheable 注解参数如下 value()/cacheNames()指定缓存/缓存管理器名称用来划分不同的缓存区避免相同 key 值互相影响key()指定缓存的键值 key。默认情况下Spring 会根据方法的参数生成缓存键也可以使用 Spring EL 表达式来自定义缓存键的生成方式如#id,#user.id 等keyGenerator()指定使用的缓存键生成器的名称可以自定义 key 生成类通过反射方式自己构建 key跟 key() 参数不能同时赋值 在 Spring 框架中缓存键生成器KeyGenerator负责为缓存中的每个数据项生成唯一的键用于在检索时查找数据项。默认情况下Spring 使用 SimpleKeyGenerator 作为缓存键生成器它使用方法的参数作为键 key cacheManager()指定使用的缓存管理器的名称。不赋值时为默认管理器常用于多缓存源场景cacheResolver()指定使用的缓存解析器的名称跟 keyGenerator() 类似condition()设置匹配条件【针对请求参数】用于判断是否执行缓存操作只有当表达式的结果为 true 时才会执行缓存操作。格式为 spring EL 表达式unless()设置排除条件【针对返回值】用于判断是否不执行缓存操作只有当表达式的结果为 false 时才会执行缓存操作。格式为 spring EL 表达式sync()指定是否使用同步模式进行缓存操作。若使用同步模式在多个线程同时对一个 key 进行 load 时其它线程将被阻塞默认值为false表示使用异步模式。在异步模式下如果多个线程同时访问同一个缓存项可能会导致缓存穿透的问题。可以将 sync 设置为 true 来避免这个问题 如 Cacheable(cacheNamesusers, key#user.id) public User get(User user) {return new User(user.getId()); } Cacheable(cacheNamesusers, key#user.id, condition#user.id 300, unless#result.id 500) public User get(User user) {return new User(user.getId()); }3.1.2、CachePut 注解 CachePut 注解在功能上跟 Cacheable 基本相同不同之处就是每次都会执行方法逻辑更新缓存 参数除不包含 sync 参数外其它跟 Cacheable 一致 如 CachePut(cacheNamesusers, key#id) public User put(int id) {return new User(id); }3.1.3、CacheEvict 注解 CacheEvict 注解对符合参数条件的缓存做删除处理 参数除跟 Cacheable 类似的参数外还包含另外 allEntries删除指定 cacheNames 区域内所有的缓存beforeInvocation如果为 true 在执行方法之前做删除缓存处理为 false 时在执行方法之后做删除处理默认为 false 如 CacheEvict(cacheNamesusers, key#id) public void delete(int id) {System.out.println(do delete: id); }CacheEvict(cacheNamesusers, allEntriestrue) public void clear() {System.out.println(do clear); }3.1.4、Caching 注解 Caching 注解可同时组合、配置多个 Cacheable、CachePut、CacheEvict 注解 Caching(cacheable {Cacheable(value userCache, key #id)},put {CachePut(value userCache, key #result.id)},evict {CacheEvict(value userListCache, allEntries true)} ) public User getUserById(Long id) {// 从数据库中获取用户信息的逻辑return user; }当调用 getUserById 方法时会先从名为 userCache 的缓存中查找对应的用户信息如果缓存中不存在则执行方法的逻辑并将返回的用户信息存储到 userCache 缓存中并且将 userListCache 缓存中的所有数据移除 3.1.5、CacheConfig 注解 CacheConfig 注解类级别的注解类下所有被缓存注解的方法都会继承所配置的参数避免方法上相同参数重复配置 如 Service CacheConfig(cacheNamesusers, cacheManagermyCacheManager) public class UserService2 {Cacheable(key#id)public User get(int id) {return new User(id);} CachePut(key#id)public User put(int id) {return new User(id);} }3.2、快速入门 3.2.1、引入依赖 dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-cache/artifactId /dependency dependencygroupIdcom.github.ben-manes.caffeine/groupIdartifactIdcaffeine/artifactIdversion2.6.2/version /dependency3.2.2、开启缓存功能 开启缓存功能需要先添加使能注解 EnableCaching通常习惯在启动类配置否则缓存注解Cacheable 等不起作用 EnableCaching SpringBootApplication public class TestApplication {public static void main(String[] args) {SpringApplication.run(TestApplication.class, args);} }3.2.3、配置缓存类 Configuration public class CacheConfig {Bean(caffeineCacheManager)public CacheManager cacheManager() {CaffeineCacheManager cacheManager new CaffeineCacheManager();cacheManager.setCaffeine(Caffeine.newBuilder().initialCapacity(100).maximumSize(500).expireAfterWrite(3, TimeUnit.SECONDS));return cacheManager;} }3.2.4、使用缓存 修改 UserServiceImpl Slf4j Service CacheConfig(cacheNames caffeineCacheManager) public class UserServiceImpl3 {// 模拟数据库数据private MapInteger, User userMap new HashMap();CachePut(key #user.id)public User add(User user) {log.info(add);userMap.put(user.getId(), user);return user;}Cacheable(key #id)public User get(Integer id) {log.info(get);return userMap.get(id);}CachePut(key #user.id)public User update(User user) {log.info(update);userMap.put(user.getId(), user);return user;}CacheEvict(key #id)public void delete(Integer id) {log.info(delete);userMap.remove(id);} }3.2.5、添加 Controller RestController public class TestController {Autowiredprivate UserServiceImpl3 userServiceImpl3;PostMappingpublic String add(RequestBody User user) {userServiceImpl3.add(user);return add;}GetMapping(/{id})public String get(PathVariable Integer id) {User user userServiceImpl3.get(id);return get;}PutMappingpublic String update(RequestBody User user) {userServiceImpl3.update(user);return update;}DeleteMapping(/{id})public String delete(PathVariable Integer id) {userServiceImpl3.delete(id);return delete;} }3.3、配置数据源 既然是对数据进行缓存就会涉及数据缓存到哪里问题是进程本地内存还是进程外远程存储就需要配置缓存源Spring 提供了丰富的缓存源种类。不同的种类引入的依赖不同 !-- Cache公共依赖 -- dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-cache/artifactId /dependency !-- 配置redis缓存时 -- dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId /dependency!-- 配置本地caffeine缓存时 -- dependencygroupIdcom.github.ben-manes.caffeine/groupIdartifactIdcaffeine/artifactId /dependency3.3.1、不配置(默认) 如果项目没有第三方缓存源依赖时SpringBoot 会默认配置 ConcurrentMapCacheManager 缓存管理器其内部由 ConcurrentHashMap存储缓存数据如果有第三方缓存依赖例如caffeine、redis 时就会相应的配置 CaffeineCacheManager 或 RedisCacheManager做默认缓存管理器 3.3.2、配置 Caffeine 缓存 缓存配置有两种 CaffeineCacheManager使用一个全局的 Caffeine 配置来创建所有的缓存。不能为每个方法单独配置缓存过期时间但可以在程序启动时全局的配置缓存方便设置所有方法的缓存过期时间SimpleCacheManager当应用程序启动时通过配置多个 CaffeineCache 来创建多个缓存。可以为每个方法单独配置缓存过期时间 3.3.2.1、CaffeineCacheManager 3.3.2.1.1、使用 Java 配置类 Java 配置方式 Configuration public class CacheConfig {Bean(caffeineCacheManager)public CacheManager cacheManager() {CaffeineCacheManager cacheManager new CaffeineCacheManager();cacheManager.setCaffeine(Caffeine.newBuilder().initialCapacity(100).maximumSize(500).expireAfterWrite(3, TimeUnit.SECONDS));return cacheManager;} }当然也可以使用配置文件进行配置缓存项信息但是灵活性不够高。 3.3.2.1.2、使用配置文件 配置文件方式可参考通用配置类 CacheProperties 定义 使用配置文件进行配置缓存项信息 spring:cache:type: caffeinecache-names:- userCachecaffeine:spec: maximumSize1024,refreshAfterWrite60s如果使用 refreshAfterWrite 配置必须指定一个 CacheLoader不用该配置则无需这个 bean。如上所述该 CacheLoader 将关联被该缓存管理器管理的所有缓存所以必须定义为CacheLoaderObject, Object自动配置将忽略所有泛型类型 Configuration public class CacheConfig {/*** 相当于在构建LoadingCache对象的时候 build()方法中指定过期之后的加载策略方法* 必须要指定这个BeanrefreshAfterWrite60s属性才生效* return*/Beanpublic CacheLoaderString, Object cacheLoader() {CacheLoaderString, Object cacheLoader new CacheLoaderString, Object() {Overridepublic Object load(String key) throws Exception {return null;}// 重写这个方法将oldValue值返回回去进而刷新缓存Overridepublic Object reload(String key, Object oldValue) throws Exception {return oldValue;}};return cacheLoader;} }3.3.2.2、SimpleCacheManager 配置多个 CaffeineCache 来创建多个缓存 Bean(name simpleCacheManager) public SimpleCacheManager simpleCacheManager() {SimpleCacheManager result new SimpleCacheManager();CaffeineCache users new CaffeineCache(users,Caffeine.newBuilder().expireAfterWrite(600, TimeUnit.SECONDS).maximumSize(10000L).build());CaffeineCache roles new CaffeineCache(roles,Caffeine.newBuilder().expireAfterWrite(600, TimeUnit.SECONDS).maximumSize(10000L).build()); result.setCaches(Arrays.asList(users, roles)); return result ; }3.3.3、配置 Redis 缓存 Bean(name redisCacheManager) public RedisCacheManager cacheManager(RedisConnectionFactory factory) {RedisCacheConfiguration config RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(600)).serializeKeysWith(SerializationPair.fromSerializer(new StringRedisSerializer())).serializeValuesWith(SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())).disableCachingNullValues().prefixCacheNameWith(mtr);RedisCacheManager redisCacheManager RedisCacheManager.builder(factory).cacheDefaults(config).transactionAware().build();return redisCacheManager; }3.3.4、配置多缓存源 Configuration public class CacheConfig { Bean(name simpleCacheManager)public SimpleCacheManager simpleCacheManager() {SimpleCacheManager result new SimpleCacheManager();CaffeineCache users new CaffeineCache(users,Caffeine.newBuilder().expireAfterWrite(600, TimeUnit.SECONDS).maximumSize(10000L).build());CaffeineCache roles new CaffeineCache(roles,Caffeine.newBuilder().expireAfterWrite(600, TimeUnit.SECONDS).maximumSize(10000L).build()); result.setCaches(Arrays.asList(users, roles)); return result ;}Bean(name redisCacheManager)Primarypublic RedisCacheManager cacheManager(RedisConnectionFactory factory) {RedisCacheConfiguration config RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(600)).serializeKeysWith(SerializationPair.fromSerializer(new StringRedisSerializer())).serializeValuesWith(SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())).disableCachingNullValues().prefixCacheNameWith(mtr);RedisCacheManager redisCacheManager RedisCacheManager.builder(factory).cacheDefaults(config).transactionAware().build();return redisCacheManager;} }【注意】如果使用了多个 cahce比如redis、caffeine 等必须指定某一个 CacheManage 为 primary在Cacheable 注解中没指定 cacheManager 则使用标记为 primary的那个。 3.4、keyGenerator Component(keyGenerator) public class CacheKeyGenerator implements KeyGenerator {public static final int NO_PARAM_KEY 0;public static final int NULL_PARAM_KEY 53;Overridepublic Object generate(Object target, Method method, Object... params) {StringBuilder key new StringBuilder();key.append(target.getClass().getSimpleName()).append(.).append(method.getName()).append(:);if (params.length 0) {key.append(NO_PARAM_KEY);} else {int count 0;for (Object param : params) {if (0 ! count) {key.append(,);}if (param null) {key.append(NULL_PARAM_KEY);} else if (ClassUtils.isPrimitiveArray(param.getClass())) {int length Array.getLength(param);for (int i 0; i length; i) {key.append(Array.get(param, i));key.append(,);}} else if (ClassUtils.isPrimitiveOrWrapper(param.getClass()) || param instanceof String) {key.append(param);} else {//Java一定要重写hashCode和eqaulskey.append(param.hashCode());}count;}}String finalKey key.toString();System.out.println(using cache key finalKey);return finalKey;} }3.5、CacheResolver SimpleCacheResolverNamedCacheResolver 是 Spring 内部的 CacheResolver接口实现类可根据实际情况参考实现 5、SPEL Spring Cache 提供了一些供我们使用的 SpEL 上下文数据下表 名称 位置 描述 示例 methodName root 对象 当前被调用的方法名 #root.methodname method root 对象 当前被调用的方法 #root.method.name target root 对象 当前被调用的目标对象实例 #root.target targetClass root 对象 当前被调用的目标对象的类 #root.targetClass args root 对象 当前被调用的方法的参数列表 #root.args[0] caches root 对象 当前方法调用使用的缓存列表 #root.caches[0].name Argument Name 执行上下文 当前被调用的方法的参数如findArtisan(Artisan artisan),可以通过#artsian.id获得参数 #artsian.id result 执行上下文 方法执行后的返回值仅当方法执行后的判断有效如 unless cacheEvict的beforeInvocationfalse #result 当我们要使用root对象的属性作为key时我们也可以将“#root”省略因为Spring默认使用的就是root对象的属性。如Cacheable(key targetClass methodName #p0)使用方法参数时我们可以直接使用“#参数名”或者“#p参数index”。如Cacheable(valueuserCache, key#id)、Cacheable(valueuserCache, key#p0) SpEL 提供了多种运算符 类型 运算符 关系 !ltgtlegeeqne 算术 - * /%^ 逻辑 条件 (ternary): (elvis) 正则表达式 matches 其他类型 .[…]![…]1$[…] 6、Caffeine 的优劣势和适用场景 优势对比 Guava cache 有更高的缓存性能劣势仍然存在缓存漂移的问题JDK 版本过低无法使用适用场景读多写少对数据一致性要求不高的场景纯内存缓存JDK8 及更高版本中追求比 Guava cache 更高的性能 … ??
http://www.hkea.cn/news/14426839/

相关文章:

  • 安全的网站建设服务火车头采集器wordpress
  • 广州网站建设市场从零开始学手机网站开发教程
  • 左右翻网站模版wordpress 删除 下载文件
  • 福建建设执业资格注册管理中心网站保定公司网站建设
  • WordPress迁移网站打不开抖音代运营大概多少钱一个月
  • 自己做网站网站资源哪里来中学加强校园网站建设
  • vps搭建网站学校网站建设企业
  • 网站怎样建设才叫人性化免费做网站通栏广告
  • 自己怎么做淘宝网站中国建设官方网
  • 渭南企业网站建设wordpress more标签使用教程
  • 58同城网网站建设网站关键词排名消失
  • 2014最新网站模板-网页模板免费下载-风格吧珠海网站制作案例
  • 建筑设计人才招聘网站快速建站完整版
  • 网站建设昆明网络公司seo入门书籍推荐
  • 惠州做网站 百度优化网站优缺点分析
  • 天美影像传媒有限公司招聘广州seo外包公司
  • 制作一个网站数据库怎么做长沙网站建设与维护
  • 实名网站空间有经验的合肥网站建设
  • 网站记录ip 修改摄影作品网站app十大排名
  • 郑州路普科技惠州seo网站排名
  • 网站地图代码江苏网站建设方案
  • 单位内部网站建设调研模板 网站
  • 网站的动态是什么意思网站底部连接怎么做
  • 3营销型网站建设网上购物软件排行榜
  • 网站维护的基本内容有哪些华商网
  • 网站服务是什么腾讯qq
  • 教程网站搭建sem推广外包
  • 现在是用什么软件做网站网站没有做适配 怎么办
  • 网站建设ui设计公司wordpress文章编辑器连接七牛云
  • 网站建设套舟山建设信息港门户网站