|
| 1 | +--- |
| 2 | +title: Guava |
| 3 | +lock: need |
| 4 | +--- |
| 5 | + |
| 6 | +# Guava 使用 |
| 7 | + |
| 8 | +作者:小傅哥 |
| 9 | +<br/>博客:[https://bugstack.cn](https://bugstack.cn) |
| 10 | + |
| 11 | +> 沉淀、分享、成长,让自己和他人都能有所收获!😄 |
| 12 | +
|
| 13 | +本文的宗旨在于通过简单干净实践的方式教会读者,使用 Guava 的一些常用操作方法。这些方法也是日常使用 Guava 时最为常用的方法,如果你在使用中还有一些案例和特性,或者踩坑经验也可以在本文提交PR |
| 14 | + |
| 15 | +本文涉及的工程: |
| 16 | + |
| 17 | +- xfg-dev-tech-guava:[https://gitcode.net/KnowledgePlanet/road-map/xfg-dev-tech-fastjson](https://gitcode.net/KnowledgePlanet/road-map/xfg-dev-tech-guava) |
| 18 | +- Github:[https://github.com/google/guava/wiki](https://github.com/google/guava/wiki) |
| 19 | + |
| 20 | +## 一、组件介绍 |
| 21 | + |
| 22 | +Guava 是 Google 的一组核心 Java 库,其中包括新的集合类型(例如 multimap 和 multiset)、不可变集合、图形库以及用于并发、I/O、哈希、原语、字符串等的实用程序!它被广泛用于 Google 内部的大多数 Java 项目,也被许多其他公司广泛使用。—— 来自于 Guava 的介绍。 |
| 23 | + |
| 24 | +在小傅哥的小项目中使用 Guava,最常用也是非常喜欢用的就是它可以替代 Redis、MQ,在小项目中使用,这样我就不用一个项目引入过多的技术栈,包括; |
| 25 | +1. 它有一个有时效性的缓存,可以替代 Redis 使用。 |
| 26 | +2. 他有一个 EventBus 消息总线,可以替代 MQ 使用。 |
| 27 | + |
| 28 | +此外,他还有布隆过滤器、简化的Java反射,以及一些集合和并发的操作。也是可以使用的,非常方便。 |
| 29 | + |
| 30 | +## 二、常用功能 |
| 31 | + |
| 32 | +### 1. 本地缓存 |
| 33 | + |
| 34 | +```java |
| 35 | +@Test |
| 36 | +public void test_cache() { |
| 37 | + Cache<String, String> cache = CacheBuilder.newBuilder() |
| 38 | + // 最大存储条数,缓存将尝试逐出最近或不经常使用的条目 |
| 39 | + .maximumSize(10000) |
| 40 | + // 可以设定删除时候的权重判断 |
| 41 | + .weigher((Weigher<String, String>) (x, y) -> x.length() - y.length()) |
| 42 | + // 有效时间 |
| 43 | + .expireAfterWrite(3, TimeUnit.SECONDS) |
| 44 | + // 记录次数 |
| 45 | + .recordStats() |
| 46 | + .build(); |
| 47 | + cache.put("xfg", "bugstack.cn"); |
| 48 | + log.info("测试结果:{}", cache.getIfPresent("xfg")); |
| 49 | + cache.invalidate("xfg"); // cache.invalidateAll(); 也可以全部删除 |
| 50 | + log.info("测试结果:{}", cache.getIfPresent("xfg")); |
| 51 | + log.info("测试结果:{}", cache.stats()); |
| 52 | +} |
| 53 | +``` |
| 54 | + |
| 55 | +- 你可以自己设定有时效性的缓存对象,还可以记录次数、权重和最大条数。 |
| 56 | +- 如果你的项目不大,也不想自己实现有过期时间的缓存,那么 Guava 非常适合使用。 |
| 57 | + |
| 58 | +### 2. 事件总线 |
| 59 | + |
| 60 | +```java |
| 61 | +@Test |
| 62 | +public void test_eventbus() { |
| 63 | + EventBus eventBus = new EventBus(); |
| 64 | + eventBus.register(new Listener()); |
| 65 | + // 可以由其他服务推送消息,之后就可以在监听中收到了 |
| 66 | + eventBus.post("消息总线,订单号:100001"); |
| 67 | +} |
| 68 | +static class Listener { |
| 69 | + @Subscribe |
| 70 | + public void handleEvent(String orderId) { |
| 71 | + log.info("测试结果:{}", orderId); |
| 72 | + } |
| 73 | +} |
| 74 | +``` |
| 75 | + |
| 76 | +- 事件总线和MQ消息实现的效果是一致的,都是为了解耦功能流程。但 Guava 的这个组件,非常适合在自己的小项目中使用,接入成本非常低。 |
| 77 | + |
| 78 | +### 3. 并发回调 |
| 79 | + |
| 80 | +```java |
| 81 | +@Test |
| 82 | +public void test_ListenableFuture() throws InterruptedException { |
| 83 | + CountDownLatch countDownLatch = new CountDownLatch(1); |
| 84 | + ListeningExecutorService executorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10)); |
| 85 | + ListenableFuture<String> explosion = executorService.submit(() -> "finished"); |
| 86 | + ExecutorService callBackService = Executors.newFixedThreadPool(1); |
| 87 | + Futures.addCallback(explosion, new FutureCallback<String>() { |
| 88 | + public void onSuccess(String explosion) { |
| 89 | + System.out.println("onSuccess"); |
| 90 | + countDownLatch.countDown(); |
| 91 | + } |
| 92 | + public void onFailure(Throwable thrown) { |
| 93 | + System.out.println("onFailure"); |
| 94 | + countDownLatch.countDown(); |
| 95 | + } |
| 96 | + }, callBackService); |
| 97 | + countDownLatch.await(); |
| 98 | +} |
| 99 | +``` |
| 100 | + |
| 101 | +### 4. 布隆过滤器 |
| 102 | + |
| 103 | +```java |
| 104 | +@Test |
| 105 | +public void test_BloomFilter() { |
| 106 | + BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charset.defaultCharset()), |
| 107 | + 1000, |
| 108 | + 0.01); |
| 109 | + // 向布隆过滤器中添加元素 |
| 110 | + bloomFilter.put("apple"); |
| 111 | + bloomFilter.put("banana"); |
| 112 | + bloomFilter.put("orange"); |
| 113 | + // 检查元素是否存在于布隆过滤器中 |
| 114 | + System.out.println(bloomFilter.mightContain("apple")); // true |
| 115 | + System.out.println(bloomFilter.mightContain("banana")); // true |
| 116 | + System.out.println(bloomFilter.mightContain("orange")); // true |
| 117 | + System.out.println(bloomFilter.mightContain("grape")); // false |
| 118 | + // 输出布隆过滤器的统计信息 |
| 119 | + System.out.println("Expected FPP: " + bloomFilter.expectedFpp()); |
| 120 | + System.out.println("Number of Inserted Elements: " + bloomFilter.approximateElementCount()); |
| 121 | +} |
| 122 | +``` |
| 123 | + |
| 124 | +### 5. 反射工具包 |
| 125 | + |
| 126 | +```java |
| 127 | +@Test |
| 128 | +public void test_Invokable() throws NoSuchMethodException { |
| 129 | + Method method = UserEntity.class.getMethod("getUserName"); |
| 130 | + Invokable<?, ?> invokable = Invokable.from(method); |
| 131 | + log.info("测试结果 - 方法名称:{}", invokable.getName()); |
| 132 | + log.info("测试结果 - 参数类型:{}", JSON.toJSONString(invokable.getTypeParameters())); |
| 133 | + log.info("测试结果 - 静态判断:{}", invokable.isStatic()); |
| 134 | + // !(Modifier.isFinal(method.getModifiers()) || Modifiers.isPrivate(method.getModifiers()) || Modifiers.isStatic(method.getModifiers()) || Modifiers.isFinal(method.getDeclaringClass().getModifiers())) |
| 135 | + log.info("测试结果 - isOverridable:{}", invokable.isOverridable()); |
| 136 | +} |
| 137 | +``` |
| 138 | + |
| 139 | +- 如果你开发一些组件,有不少的操作都是需要判断方法的权限范围、包的权限范围等,使用 Guava 的插件也会非常方便。 |
| 140 | + |
| 141 | +--- |
| 142 | + |
| 143 | +其他更多的操作可以参考仓库代码和官网文档学习,基本都是非常完整的案例。 |
0 commit comments