diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotatedElementUtil.java b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotatedElementUtil.java index 62c81f338..34ee2974b 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotatedElementUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotatedElementUtil.java @@ -103,8 +103,8 @@ import java.util.stream.Stream; * 该属性类型为注解数组,且数组中注解被{@link java.lang.annotation.Repeatable}注解, * 则认为被包括的注解为可重复注解;
* eg:
- * A上存在注解X,该注解是一个容器注解,内部可重复注解Y, - * 包含解析后,得到注解X与它包含的可重复注解Y; + * A上存在注解X,该注解是一个容器注解,内部包含可重复注解Y, + * 解析X后,得到注解X与它包含的可重复注解Y; * *
  • * 若{@link AnnotatedElement}存在直接声明的注解,该注解与其他根注解皆有相同的元注解, @@ -115,6 +115,12 @@ import java.util.stream.Stream; *
  • * * + *

    缓存 + *

    为了避免注解以及{@link AnnotatedElement}层级结构解析过程中的大量反射调用, + * 工具类为{@link AnnotatedElement}及其元注解信息进行了缓存。
    + * 缓存功能默认基于{@link WeakConcurrentMap}实现,会在gc时自动回收部分缓存数据。 + * 但是若有必要,也可以调用{@link #clearCaches()}方法主动清空缓存。 + * * @author huangchengxing * @see ResolvedAnnotationMapping * @see GenericAnnotationMapping @@ -650,7 +656,7 @@ public class AnnotatedElementUtil { * @param element {@link AnnotatedElement} * @return {@link MetaAnnotatedElement}实例 */ - private static MetaAnnotatedElement getResolvedMetaElementCache(final AnnotatedElement element) { + static MetaAnnotatedElement getResolvedMetaElementCache(final AnnotatedElement element) { return RESOLVED_ELEMENT_CACHE.computeIfAbsent(element, ele -> MetaAnnotatedElement.create( element, (source, annotation) -> ResolvedAnnotationMapping.create(source, annotation, true) )); @@ -662,7 +668,7 @@ public class AnnotatedElementUtil { * @param element {@link AnnotatedElement} * @return {@link MetaAnnotatedElement}实例 */ - private static MetaAnnotatedElement getMetaElementCache(final AnnotatedElement element) { + static MetaAnnotatedElement getMetaElementCache(final AnnotatedElement element) { return ELEMENT_CACHE.computeIfAbsent(element, ele -> MetaAnnotatedElement.create( element, (source, annotation) -> GenericAnnotationMapping.create(annotation, Objects.isNull(source)) )); @@ -674,7 +680,7 @@ public class AnnotatedElementUtil { * @param element {@link AnnotatedElement} * @return {@link MetaAnnotatedElement}实例 */ - private static RepeatableMetaAnnotatedElement getResolvedRepeatableMetaElementCache(final AnnotatedElement element) { + static RepeatableMetaAnnotatedElement getResolvedRepeatableMetaElementCache(final AnnotatedElement element) { return RESOLVED_REPEATABLE_ELEMENT_CACHE.computeIfAbsent(element, ele -> RepeatableMetaAnnotatedElement.create( element, (source, annotation) -> ResolvedAnnotationMapping.create(source, annotation, true) )); @@ -686,7 +692,7 @@ public class AnnotatedElementUtil { * @param element {@link AnnotatedElement} * @return {@link MetaAnnotatedElement}实例 */ - private static RepeatableMetaAnnotatedElement getRepeatableMetaElementCache(final AnnotatedElement element) { + static RepeatableMetaAnnotatedElement getRepeatableMetaElementCache(final AnnotatedElement element) { return REPEATABLE_ELEMENT_CACHE.computeIfAbsent(element, ele -> RepeatableMetaAnnotatedElement.create( element, (source, annotation) -> GenericAnnotationMapping.create(annotation, Objects.isNull(source)) )); @@ -694,6 +700,26 @@ public class AnnotatedElementUtil { // endregion + /** + * 清空相关缓存,包括: + *

    + * + * @see AnnotationUtil#clearCaches() + * @see RepeatableAnnotationCollector#clearSingletonCaches() + */ + public static void clearCaches() { + ELEMENT_CACHE.clear(); + RESOLVED_ELEMENT_CACHE.clear(); + REPEATABLE_ELEMENT_CACHE.clear(); + RESOLVED_REPEATABLE_ELEMENT_CACHE.clear(); + RepeatableAnnotationCollector.clearSingletonCaches(); + AnnotationUtil.clearCaches(); + } + /** * 由一组注解聚合来的{@link AnnotatedElement} */ diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java index b5dd123c5..6691928d6 100755 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/AnnotationUtil.java @@ -354,4 +354,11 @@ public class AnnotationUtil { && !attribute.isSynthetic(); } + /** + * 清空相关缓存 + */ + public static void clearCaches() { + DECLARED_ANNOTATIONS_CACHE.clear(); + } + } diff --git a/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableAnnotationCollector.java b/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableAnnotationCollector.java index 1daae6cdb..cf6fe2bed 100644 --- a/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableAnnotationCollector.java +++ b/hutool-core/src/main/java/cn/hutool/core/annotation/RepeatableAnnotationCollector.java @@ -86,6 +86,14 @@ public interface RepeatableAnnotationCollector { return Full.INSTANCE; } + /** + * 清空单例缓存 + */ + static void clearSingletonCaches() { + Standard.INSTANCE.repeatableMethodCache.clear(); + Full.INSTANCE.repeatableMethodCache.clear(); + } + /** *

    若一个注解是可重复注解的容器注解,则尝试通过其属性获得获得包含的注解对象。 * 若包含的注解对象也是可重复注解的容器注解,则继续解析直到获得所有非容器注解为止。
    diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotatedElementUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotatedElementUtilTest.java index 5585b657e..7445efde8 100644 --- a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotatedElementUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotatedElementUtilTest.java @@ -37,6 +37,31 @@ public class AnnotatedElementUtilTest { ANNOTATION6, ANNOTATION5 // Interface.class's annotations }; + @Test + public void testClearCaches() { + AnnotatedElement type = Foo.class; + + AnnotatedElement element = AnnotatedElementUtil.getResolvedMetaElementCache(type); + Assert.assertSame(element, AnnotatedElementUtil.getResolvedMetaElementCache(type)); + AnnotatedElementUtil.clearCaches(); + Assert.assertNotSame(element, AnnotatedElementUtil.getResolvedMetaElementCache(type)); + + element = AnnotatedElementUtil.getMetaElementCache(type); + Assert.assertSame(element, AnnotatedElementUtil.getMetaElementCache(type)); + AnnotatedElementUtil.clearCaches(); + Assert.assertNotSame(element, AnnotatedElementUtil.getMetaElementCache(type)); + + element = AnnotatedElementUtil.getResolvedRepeatableMetaElementCache(type); + Assert.assertSame(element, AnnotatedElementUtil.getResolvedRepeatableMetaElementCache(type)); + AnnotatedElementUtil.clearCaches(); + Assert.assertNotSame(element, AnnotatedElementUtil.getResolvedRepeatableMetaElementCache(type)); + + element = AnnotatedElementUtil.getRepeatableMetaElementCache(type); + Assert.assertSame(element, AnnotatedElementUtil.getRepeatableMetaElementCache(type)); + AnnotatedElementUtil.clearCaches(); + Assert.assertNotSame(element, AnnotatedElementUtil.getRepeatableMetaElementCache(type)); + } + @Test public void testIsAnnotated() { Assert.assertTrue(AnnotatedElementUtil.isAnnotated(Foo.class, Annotation1.class)); diff --git a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java index a1f1eb380..6053d8851 100755 --- a/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/annotation/AnnotationUtilTest.java @@ -19,6 +19,9 @@ public class AnnotationUtilTest { Annotation[] annotations = AnnotationUtil.getDeclaredAnnotations(ClassForTest.class); Assert.assertArrayEquals(annotations, ClassForTest.class.getDeclaredAnnotations()); Assert.assertSame(annotations, AnnotationUtil.getDeclaredAnnotations(ClassForTest.class)); + + AnnotationUtil.clearCaches(); + Assert.assertNotSame(annotations, AnnotationUtil.getDeclaredAnnotations(ClassForTest.class)); } @Test