Backend Development 13 min read

Performance Comparison Between JDK Reflection and Spring's ReflectionUtils

This article analyzes the performance differences between native Java reflection and Spring Framework's ReflectionUtils by running benchmark tests, examining source code caching mechanisms, and explaining why ReflectionUtils can be faster for repeated method and field access in backend applications.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Performance Comparison Between JDK Reflection and Spring's ReflectionUtils

Preface – A developer named Xiao Cai needed to use reflection for a generic requirement and was warned by the technical lead that native reflection can be slow, suggesting the use of Spring's ReflectionUtils utility.

Performance Test of Native Reflection – An entity class is created, and native reflection is used to instantiate objects, invoke methods, and modify fields. The benchmark results show that invoking reflection 10,000 times takes about 12 ms, 1,000,000 times takes 285 ms, and 10,000,000 times takes 3.198 s.

Native Reflection Benchmark

Invocation Count

1

1_000

10_000

1_000_000

10_000_000

Time (ms)

2

4

12

285

3198

Although the numbers look acceptable for occasional use, large‑scale reflection can still impose noticeable overhead, especially on production servers without high‑end hardware.

Spring ReflectionUtils Benchmark – Using ReflectionUtils to perform the same operations yields the following results, showing a higher cost on the first call but better performance on subsequent calls.

ReflectionUtils Benchmark

Invocation Count

1

1_000

10_000

1_000_000

10_000_000

Native Time (ms)

2

4

12

285

3198

ReflectionUtils Time (ms)

49

4

8

74

495

The comparison reveals that ReflectionUtils incurs a heavy initialization cost but becomes faster than native reflection when the method count reaches millions, achieving more than a six‑fold speedup.

Source Code Analysis – The key to the performance gain lies in caching. ReflectionUtils maintains strong‑reference caches such as private static final Map , Method[]> declaredMethodsCache and private static final Map , Field[]> declaredFieldsCache , avoiding repeated native lookups. Native reflection uses ReflectionData with soft references, which can be cleared by the GC, forcing re‑introspection.

Native Class.getDeclaredMethod and Class.getDeclaredField first check the security manager, then retrieve method/field arrays via privateGetDeclaredMethods or privateGetDeclaredFields . These methods consult ReflectionData ; if the cache is missing, they invoke native VM calls and store the results in a soft‑reference cache.

Spring's ReflectionUtils.findMethod and ReflectionUtils.findField directly access the cached arrays (or populate them once) and perform simple linear scans, eliminating the extra factory copy step that native reflection performs ( getReflectionFactory().copyMethod(...) ).

Conclusion – For backend projects that heavily rely on reflection, using Spring's ReflectionUtils can reduce the overhead of repeated method/field lookups because its caches are strong references and it avoids the costly factory copy operations. However, the initial cache warm‑up is expensive, so the utility shines only after the first few thousand invocations.

backendJavaperformancereflectionSpringcaching
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.