|
| 1 | +package io.github.ms100.cacheasmulti.cache.annotation; |
| 2 | + |
| 3 | +import org.springframework.cache.annotation.CacheEvict; |
| 4 | +import org.springframework.cache.annotation.CachePut; |
| 5 | +import org.springframework.cache.annotation.Cacheable; |
| 6 | +import org.springframework.cache.interceptor.KeyGenerator; |
| 7 | + |
| 8 | +import javax.cache.annotation.CacheKey; |
| 9 | +import javax.cache.annotation.CacheKeyGenerator; |
| 10 | +import javax.cache.annotation.CacheRemove; |
| 11 | +import javax.cache.annotation.CacheResult; |
| 12 | +import javax.cache.annotation.CacheValue; |
| 13 | +import java.lang.annotation.ElementType; |
| 14 | +import java.lang.annotation.Retention; |
| 15 | +import java.lang.annotation.RetentionPolicy; |
| 16 | +import java.lang.annotation.Target; |
| 17 | +import java.lang.reflect.Method; |
| 18 | + |
| 19 | +/** |
| 20 | + * 本注解需要与下面两套注解搭配使用,以实现对被注解参数所在的方法进行批量的缓存操作。 |
| 21 | + * <ol> |
| 22 | + * <li>Spring的缓存注解{@link Cacheable @Cacheable}、{@link CachePut @CachePut}、{@link CacheEvict @CacheEvict} |
| 23 | + * <li>JSR-107的注解{@link CacheResult @CacheResult}、{@link javax.cache.annotation.CachePut JSR-107的@CachePut}、{@link CacheRemove @CacheRemove}、{@link CacheKey @CacheKey} |
| 24 | + * </ol> |
| 25 | + * <p><b>使用说明:</b></p> |
| 26 | + * <p> |
| 27 | + * 假设已有获取单个对象的方法,如下: |
| 28 | + * <pre><code> |
| 29 | + * public Foo getFoo(Integer fooId) { |
| 30 | + * ... |
| 31 | + * } |
| 32 | + * </code></pre> |
| 33 | + * 此时如果需要获取批量对象的方法,通常会是下面两种写法: |
| 34 | + * <pre><code> |
| 35 | + * public Map<Integer, Foo> getMultiFoo(Collection<Integer> fooIds) { |
| 36 | + * ... |
| 37 | + * } |
| 38 | + * |
| 39 | + * public List<Foo> getMultiFoo(List<Integer> fooIds) { |
| 40 | + * ... |
| 41 | + * } |
| 42 | + * </code></pre> |
| 43 | + * 获取批量对象的方法相对于获取单个对象的方法会有两点变化: |
| 44 | + * <ol> |
| 45 | + * <li>入参从单个对象(以下称【对象参数】)变为对象集合(以下称【对象集合参数】),例如 Integer 变为 Collection<Integer> 或 Set<Integer> 或 List<Integer>。</li> |
| 46 | + * <li>返回值从单个对象变为 Map<K,V> 或者 List<V> 。例如 Map<Integer,Foo> 或 List<Foo>,若返回的是 List,那应与【对象集合参数】大小相同并顺序一致。</li> |
| 47 | + * </ol></p> |
| 48 | + * <p> |
| 49 | + * 在上面例子中,如果需要对获取单个对象的方法做缓存,会使用 {@link Cacheable @Cacheable} 或 {@link CacheResult @CacheResult} 注解: |
| 50 | + * (PS: 这里将 @CacheResult 和 @Cacheable 放在一起举例子,实际使用时通常只用其中的一个) |
| 51 | + * <pre><code> |
| 52 | + * @Cacheable(cacheNames = "foo") |
| 53 | + * @CacheResult(cacheName = "foo") |
| 54 | + * public Foo getFoo(Integer fooId) { |
| 55 | + * // 用 fooId 生成缓存 key 和计算 condition、unless 条件,用 Foo 为缓存值 |
| 56 | + * } |
| 57 | + * </code></pre> |
| 58 | + * 如果对获取批量对象的方法直接加上 {@link Cacheable @Cacheable} 或 {@link CacheResult @CacheResult},则会使用【对象集合参数】整体生成一个缓存 key,将返回的 Map 或 List 整体作为一个缓存值。 |
| 59 | + * 但通常我们会希望它能变为多个 fooId => Foo 的缓存,即:使用【对象集合参数】中每个【元素】和它对应的值分别作缓存。此时只需要在【对象集合参数】上加上 {@link CacheAsMulti @CacheAsMulti} 注解即可实现我们想要的缓存方式。 |
| 60 | + * <pre><code> |
| 61 | + * @Cacheable(cacheNames = "foo") |
| 62 | + * @CacheResult(cacheName = "foo") |
| 63 | + * public Map<Integer, Foo> getMultiFoo(@CacheAsMulti Collection<Integer> fooIds) { |
| 64 | + * // 为 fooIds 集合中每个元素分别生成缓存 key 和计算 condition、unless 条件,用 Map 中对应的值作为缓存值 |
| 65 | + * } |
| 66 | + * |
| 67 | + * @Cacheable(cacheNames = "foo") |
| 68 | + * @CacheResult(cacheName = "foo") |
| 69 | + * public List<Foo> getMultiFoo(@CacheAsMulti List<Integer> fooIds) { |
| 70 | + * // 为 fooIds 集合中每个元素分别生成缓存 key 和计算 condition、unless 条件,用 List 中对应的值作为缓存值 |
| 71 | + * // 之后的例子中,返回 List 和 返回 Map 的处理方式都一样,就不再单独举例 |
| 72 | + * } |
| 73 | + * </code></pre> |
| 74 | + * 当方法有多个参数时,示例如下: |
| 75 | + * <ol><li> |
| 76 | + * 使用 {@link Cacheable} 时 {@link Cacheable#key()} 未配置、使用 {@link CacheResult} 时参数中没有 {@link CacheKey @CacheKey} |
| 77 | + * <pre><code> |
| 78 | + * @Cacheable(cacheNames = "foo", key="") |
| 79 | + * @CacheResult(cacheName = "foo") |
| 80 | + * public Foo getFoo(Integer fooId, String arg1) { |
| 81 | + * // 用 fooId 和 arg1 两个参数生成缓存的 key,用返回值作为缓存值 |
| 82 | + * } |
| 83 | + * |
| 84 | + * @Cacheable(cacheNames = "foo", key="") |
| 85 | + * @CacheResult(cacheName = "foo") |
| 86 | + * public Map<Integer, Foo> getMultiFoo(@CacheAsMulti Collection<Integer> fooIds, String arg1) { |
| 87 | + * // 用 fooIds 中的每个【元素】分别和 arg1 参数生成缓存的 key,用返回 Map 中【元素】对应的值作为缓存值 |
| 88 | + * } |
| 89 | + * </code></pre> |
| 90 | + * </li><li> |
| 91 | + * 使用 {@link Cacheable} 时 {@link Cacheable#key()} 只配置了【对象参数】的引用、使用 {@link CacheResult} 时只有【对象参数】上有 {@link CacheKey} |
| 92 | + * <pre><code> |
| 93 | + * @Cacheable(cacheNames = "foo", key="#fooId") |
| 94 | + * @CacheResult(cacheName = "foo") |
| 95 | + * public Foo getFoo(@CacheKey Integer fooId, String arg1) { |
| 96 | + * // 用 fooId 生成缓存的 key,用返回值作为缓存值 |
| 97 | + * } |
| 98 | + * |
| 99 | + * @Cacheable(cacheNames = "foo", key="#fooIds") |
| 100 | + * @CacheResult(cacheName = "foo") |
| 101 | + * public Map<Integer, Foo> getMultiFoo(@CacheAsMulti @CacheKey Collection<Integer> fooIds, String arg1) { |
| 102 | + * // 用 fooIds 中的每个【元素】分别生成缓存的 key,用返回 Map 中【元素】对应的值作为缓存值 |
| 103 | + * } |
| 104 | + * </code></pre> |
| 105 | + * </li><li> |
| 106 | + * 使用 {@link Cacheable} 时 {@link Cacheable#key()} 配置了若干参数的引用、使用 {@link CacheResult} 时参数中有若干 {@link CacheKey @CacheKey} |
| 107 | + * <pre><code> |
| 108 | + * @Cacheable(cacheNames = "foo", key="#fooId+#arg1") |
| 109 | + * @CacheResult(cacheName = "foo") |
| 110 | + * public Foo getFoo(@CacheKey Integer fooId, @CacheKey String arg1, Float arg2) { |
| 111 | + * // 用 fooId 和 arg1 两个参数生成缓存的 key,用返回值作为缓存值 |
| 112 | + * } |
| 113 | + * |
| 114 | + * @Cacheable(cacheNames = "foo", key="#fooIds+#arg1") |
| 115 | + * @CacheResult(cacheName = "foo") |
| 116 | + * public Map<Integer, Foo> getMultiFoo(@CacheAsMulti @CacheKey Collection<Integer> fooIds, @CacheKey String arg1, Float arg2) { |
| 117 | + * // 用 fooIds 中的每个【元素】分别和 arg1 参数生成缓存的 key,用返回 Map 中【元素】对应的值作为缓存值 |
| 118 | + * // 注意此时【对象集合参数】需要在 {@link Cacheable#key()} 中,需要有 @CacheKey 注解 |
| 119 | + * } |
| 120 | + * </code></pre> |
| 121 | + * </li></ol></p> |
| 122 | + * <p> |
| 123 | + * <b>与其他注解搭配使用时的说明:</b> |
| 124 | + * <ul> |
| 125 | + * <li>与 {@link CachePut Spring 的 CachePut} 搭配时,同样符合上面的例子。</li> |
| 126 | + * <li>与 {@link CacheEvict} 搭配时,若注解的 key 参数中没有 #result,对【方法】返回类型无要求;若 key 中有 #result,【方法】返回类型需要是 Map 或 List。</li> |
| 127 | + * <li>与 Spring 的 `@CachePut`、`@CacheEvict` 搭配时,若 key 参数中有 `#result`, 则可以没有【对象集合参数】的引用。</li> |
| 128 | + * <li>与 {@link CacheRemove} 搭配时,对【方法】返回类型无要求。</li> |
| 129 | + * <li>与 {@link javax.cache.annotation.CachePut JSR-107 的 CachePut} 搭配时,对【方法】返回类型无要求,可参照下面的示例: |
| 130 | + * <ul><li>单个参数做key,未配置 {@link CacheKey @CacheKey}: |
| 131 | + * <pre><code> |
| 132 | + * @CachePut(cacheName = "foo") |
| 133 | + * public void putFoo(Integer fooId, @CacheValue String value) { |
| 134 | + * // 用 fooId 参数生成缓存的 key,用 value 作为缓存值 |
| 135 | + * } |
| 136 | + * |
| 137 | + * @CachePut(cacheName = "foo") |
| 138 | + * public void putMultiFoo(@CacheAsMulti @CacheValue Map<Integer, String> fooIdValueMap) { |
| 139 | + * // 此时方法的 @CacheValue 参数必须为 Map 类型 |
| 140 | + * // 用 fooIdValueMap 中的每个 Entry 的 key 分别生成缓存的 key,用 Entry 的 value 作为缓存值 |
| 141 | + * } |
| 142 | + * </code></pre> |
| 143 | + * </li><li>多个参数做key,未配置 {@link CacheKey @CacheKey}: |
| 144 | + * <pre><code> |
| 145 | + * @CachePut(cacheName = "foo") |
| 146 | + * public void putFoo(Integer fooId, String arg1, @CacheValue String value) { |
| 147 | + * // 用 fooId 和 arg1 两个参数生成缓存的 key,用 value 作为缓存值 |
| 148 | + * } |
| 149 | + * |
| 150 | + * @CachePut(cacheName = "foo") |
| 151 | + * public void putMultiFoo(@CacheAsMulti @CacheValue Map<Integer, String> fooIdValueMap, String arg1) { |
| 152 | + * // 此时方法的 @CacheValue 参数必须为 Map 类型 |
| 153 | + * // 用 fooIdValueMap 中的每个 Entry 的 key 分别和 arg1 参数生成缓存的 key,用 Entry 的 value 作为缓存值 |
| 154 | + * } |
| 155 | + * </code></pre> |
| 156 | + * </li><li>只有【对象参数】上有 {@link CacheKey @CacheKey}: |
| 157 | + * <pre><code> |
| 158 | + * @CachePut(cacheName = "foo") |
| 159 | + * public void putFoo(@CacheKey Integer fooId, String arg1, @CacheValue String value) { |
| 160 | + * // 用 fooId 参数生成缓存的 key,用 value 作为缓存值 |
| 161 | + * } |
| 162 | + * |
| 163 | + * @CachePut(cacheName = "foo") |
| 164 | + * public void putMultiFoo(@CacheAsMulti @CacheKey @CacheValue Map<Integer, String> fooIdValueMap, String arg1) { |
| 165 | + * // 此时方法的 @CacheValue 参数必须为 Map 类型 |
| 166 | + * // 用 fooIdValueMap 中的每个 Entry 的 key 分别生成缓存的 key,用 Entry 的 value 作为缓存值 |
| 167 | + * } |
| 168 | + * </code></pre> |
| 169 | + * </li><li>若干参数上有 {@link CacheKey @CacheKey}: |
| 170 | + * <pre><code> |
| 171 | + * @CachePut(cacheName = "foo") |
| 172 | + * public void putFoo(@CacheKey Integer fooId, @CacheKey String arg1, String arg2, @CacheValue String value) { |
| 173 | + * // 用 fooId 和 arg1 两个参数生成缓存的 key,用 value 作为缓存值 |
| 174 | + * } |
| 175 | + * |
| 176 | + * @CachePut(cacheName = "foo") |
| 177 | + * public void putMultiFoo(@CacheAsMulti @CacheKey @CacheValue Map<Integer, String> fooIdValueMap, @CacheKey String arg1, String arg2) { |
| 178 | + * // 此时方法的 @CacheValue 参数必须为 Map 类型 |
| 179 | + * // 用 fooIdValueMap 中的每个 Entry 的 key 分别和 arg1 参数生成缓存的 key,用 Entry 的 value 作为缓存值 |
| 180 | + * } |
| 181 | + * </code></pre> |
| 182 | + * </li></li></ul> |
| 183 | + * </p> |
| 184 | + * <p> |
| 185 | + * <b>总结和补充:</b> |
| 186 | + * <ol> |
| 187 | + * <li>@CacheAsMulti 注解不能替代 Spring 缓存注解中的 key 参数,例如:{@link Cacheable#key()},也不能替代 {@link CacheKey}、{@link CacheValue} 注解。</li> |
| 188 | + * <li>如果使用自定义的 {@link KeyGenerator},则会用【对象集合参数】的每个【元素】和其他参数组成 Object[] 传入 {@link KeyGenerator#generate(Object, Method, Object...)} 计算缓存 key;自定义的 {@link CacheKeyGenerator} 也一样。</li> |
| 189 | + * <li>与生成缓存的注解搭配使用时,若方法的返回类型是 Map,【元素】在 Map 中对应的值为 null 就会缓存 null,【元素】在 Map 中不存在就不缓存。</li> |
| 190 | + * <li>与 {@link CachePut} 和 {@link CacheEvict} 搭配,注解的 key 参数配置了 #result 时,若方法的返回类型是 Map,对于 Map 中不存在的【元素】会使用 null 作为缺省值来计算缓存 key 和 condition、unless 条件。</li> |
| 191 | + * <li>{@link Cacheable#condition()}、{@link Cacheable#unless()} 等条件表达式是用【对象集合参数】中的每个【元素】分别计算,只将不符合的【元素】排除,而不是整个集合。</li> |
| 192 | + * </ol> |
| 193 | + * </p> |
| 194 | + * |
| 195 | + * @author zhumengshuai |
| 196 | + */ |
| 197 | +@Target(ElementType.PARAMETER) |
| 198 | +@Retention(RetentionPolicy.RUNTIME) |
| 199 | +public @interface CacheAsMulti { |
| 200 | + |
| 201 | +} |
| 202 | + |
| 203 | + |
0 commit comments