Spring Annotation Processing

Last update: 2025-09-25 03:47:26 +0800 +0800
Available translations: 日本語 / 中文(简体) / 中文(繁體)

Spring uses annotations as declarative metadata for component discovery, configuration, dependency injection, transactions, web request mapping, and other framework services. Java reflection exposes the raw annotations; Spring adds a consistent model for composed annotations, aliases, search strategies, and metadata reading without loading classes.

Java Annotation Semantics #

An annotation declaration is itself an interface whose implicit superinterface is java.lang.annotation.Annotation:

java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Audited {
}

Runtime reflection can inspect @Audited when it is directly present on a class. Meta-annotations such as @Retention, @Target, and @Documented describe an annotation declaration but do not cause arbitrary transitive lookup.

SOURCE, CLASS, and RUNTIME retention determine whether metadata remains in source only, in the class file, or available through reflection. @Target restricts declaration or type-use locations. A repeatable annotation names a container through @Repeatable; reflection and Spring can expose either the logical repeated annotations or their physical container.

@Inherited is a narrow exception. Selected Class lookup methods can find an inherited annotation on a superclass when the annotation declaration carries @Inherited. The rule does not apply through interfaces, does not cover methods or fields, and is distinct from Spring’s composed-annotation model.

Composed Annotations #

Spring interprets annotations placed on other annotation declarations. For example, @Service is meta-annotated with @Component:

java
@Component
public @interface Service {
    @AliasFor(annotation = Component.class)
    String value() default "";
}

A class annotated with @Service is consequently a component candidate even though plain reflection would not report @Component as directly present. Applications can use the same mechanism to create domain-specific annotations:

java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Service
@Transactional(readOnly = true)
public @interface ReadOnlyService {
}

The result is a programming model rather than a Java language rule. Spring code must perform the traversal, cycle detection, filtering, and attribute synthesis.

Merged Annotations #

MergedAnnotations is Spring’s central query model for directly present, inherited, and meta-present annotations. Its SearchStrategy controls which type relationships are traversed:

  • DIRECT examines only annotations directly declared on the element.
  • INHERITED_ANNOTATIONS follows Java’s @Inherited rules.
  • SUPERCLASS searches the superclass hierarchy.
  • TYPE_HIERARCHY searches superclasses and implemented interfaces.

Use the narrowest strategy that matches the framework feature. A broad hierarchy search can produce metadata that Java reflection alone would not expose.

MergedAnnotation<T> represents one discovered annotation together with its distance, aggregate position, source, and synthesized attributes. Synthesis resolves Spring alias relationships declared with @AliasFor. It can therefore present a coherent attribute view across a composed annotation and its meta-annotations.

Alias declarations must remain consistent. Within one annotation, aliased attributes need compatible return types and defaults. Cross-annotation aliases must identify an attribute reachable in the meta-annotation hierarchy.

Metadata Abstractions #

Spring separates general annotated-element metadata from class- and method-specific metadata:

AnnotAantniootnaMteetdaTdyapteaMetaMdeatthaodMetadata
  • AnnotatedTypeMetadata exposes annotation queries common to types and methods.
  • AnnotationMetadata adds class information and access to annotated methods.
  • MethodMetadata adds declaring-class, return-type, and method properties.

Reflection-backed implementations inspect loaded classes. Class-reading implementations use bytecode metadata, allowing infrastructure such as component scanning and configuration parsing to inspect a class without initializing it. Avoiding class loading prevents static initialization side effects and permits metadata discovery before every optional dependency is resolvable.

For a loaded class, use the supported introspection entry point:

java
AnnotationMetadata metadata =
    AnnotationMetadata.introspect(ExampleConfiguration.class);

boolean configuration =
    metadata.hasAnnotation(Configuration.class.getName());

Framework internals can instead obtain a MetadataReader from a MetadataReaderFactory to read a .class resource.

Configuration-Class Processing #

ConfigurationClassParser consumes class metadata while processing @Configuration, component scans, imports, property sources, conditions, and @Bean methods. @Import can contribute configuration classes, selectors, or registrars. @Conditional implementations can veto configuration during the applicable parsing or bean-registration phase. The broad flow is:

  1. Discover candidate bean definitions.
  2. Read class metadata.
  3. Determine whether each candidate is a configuration class.
  4. Evaluate conditions and traverse imports and component scans.
  5. Discover bean methods and register the resulting bean definitions.

Annotation parsing describes definitions; later bean-factory phases instantiate and initialize beans. Keeping those phases distinct explains why finding an annotation does not immediately execute the annotated behavior.

Choosing an API #

Use Java reflection when direct Java annotation semantics are sufficient. Use MergedAnnotations when implementing infrastructure that must honor Spring’s composed annotations or aliases. Use AnnotationMetadata or MetadataReader when class-level and method-level metadata must be inspected during container startup, especially when loading the class would be premature.

Application code should normally consume the higher-level Spring facility—such as component scanning, transaction management, or MVC mapping—rather than reproduce its annotation search rules.

Comments

Read or comment on GitHub (sign-in required to comment)