Class AnnotationLookupCache<A extends Annotation>
- Type Parameters:
A- the annotation type this cache answers for
AopAdvisor for one annotation type.
Both walk the superclass chain, and both run on every intercepted invocation - from the
advisor's match test and again from the interceptor that reads the annotation's attributes. On a
Minecraft server that is tick-rate work for answers that cannot change once the classes are
loaded. This is the split Spring uses between AbstractFallbackTransactionAttributeSource's
caching getTransactionAttribute and its uncached computeTransactionAttribute.
The class-level cache is keyed on the method's declaring class, the only input that
lookup reads. The method-level cache has to be keyed on the method itself, because the answer
depends on the whole override chain; the generated proxy hands the same Method instance
to every invocation, so the key is cheap.
Instances are deliberately not static. A cache holds Class and Method
references, and a static one would pin every module's classes for the lifetime of the JVM,
defeating the plugin class loader's release on unload. One instance per advisor or interceptor
means the cache dies with the container that owns it.
One shared instance per annotation type, not one per consumer (D-38). The annotation
advisor and ExceptionInterceptor used to each construct their own cache for the same
annotation type, duplicating the class-level and inherited-method maps for no reason - the
answers do not depend on which consumer is asking. PluginManager.wireAop now builds one
instance per annotation type and injects it into both at the seam where the advisor is
constructed and registered. Public so that seam, in a different package, can construct and pass
one; this type does not exist in the released 6.2.5 artifact (D-34), so widening its visibility
costs nothing today.
Sharing the cache does not merge what each consumer asks it. The advisor's match collapses
own-and-inherited into a single presence check; ExceptionInterceptor needs
own-method, then class-level, then inherited-method, with class-level ranking between the
other two. Both keep asking their own question - only the memoized answers are shared.
- Since:
- 6.3.0
- Author:
- wisdomme
-
Field Summary
FieldsModifier and TypeFieldDescriptionprivate static final ObjectStands in for "looked up, found nothing", so a miss is cached as cheaply as a hit. -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescription(package private) AclassLevel(Method method) (package private) Class<?> classLevelOwner(Method method) The class whose type-level annotation governs the method, cached the same wayclassLevel(Method)is - same key, same walk, just returning the owner instead of the annotation instance.(package private) AinheritedMethod(Method method) (package private) AmethodLevel(Method method) (package private) A(package private) static <A extends Annotation>
AnnotationLookupCache<A> standalone(Class<A> annotationType) An unshared cache for a caller that is not wired throughPluginManager.wireAop's shared seam (D-38) - standalone construction, or a consumer exercised in isolation.private A
-
Field Details
-
NONE
Stands in for "looked up, found nothing", so a miss is cached as cheaply as a hit. -
annotationType
-
methodLevel
-
inherited
-
classLevel
-
classLevelOwner
-
-
Constructor Details
-
AnnotationLookupCache
- Parameters:
annotationType- the annotation type this cache answers for
-
-
Method Details
-
standalone
An unshared cache for a caller that is not wired throughPluginManager.wireAop's shared seam (D-38) - standalone construction, or a consumer exercised in isolation. Production wiring never calls this: it builds one instance and injects it into both the advisor andExceptionInterceptorexplicitly, so the two share it instead of each building their own.- Type Parameters:
A- the annotation type- Parameters:
annotationType- the annotation type this cache answers for- Returns:
- a new, unshared cache instance
-
ownMethod
- Parameters:
method- the method being considered, may be null- Returns:
- the annotation on this method or on a declaration it overrides, or null
-
inheritedMethod
- Parameters:
method- the method being considered, may be null- Returns:
- the annotation on a declaration this method overrides, or null
-
methodLevel
-
classLevel
- Parameters:
method- the method being considered, may be null- Returns:
- the governing class-level annotation, or null
-
classLevelOwner
The class whose type-level annotation governs the method, cached the same wayclassLevel(Method)is - same key, same walk, just returning the owner instead of the annotation instance.AopProxyResolver.locateAnnotationused to callAopAdvisor.findClassLevelAnnotationOwnerdirectly here, uncached, on every method of every unavailable-annotation entry (D-38).- Parameters:
method- the method being considered, may be null- Returns:
- the class carrying the governing class-level annotation, or null
-
unwrap
-