Spring Framework Core - IoC Container and Dependency Injection
—
Spring Core provides comprehensive annotation processing capabilities that enable meta-annotation support, attribute overrides, and sophisticated annotation composition. This system forms the foundation for Spring's annotation-driven programming model.
Spring provides several key annotations and utilities for annotation processing.
Core Annotations
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Order {
int value() default Ordered.LOWEST_PRECEDENCE;
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AliasFor {
String value() default "";
String attribute() default "";
Class<? extends Annotation> annotation() default Annotation.class;
}Usage Examples
// Using @Order annotation
@Component
@Order(1)
public class HighPriorityService {
// Implementation
}
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CriticalService {
// Implementation
}
// Using @AliasFor for attribute aliasing
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface Service {
@AliasFor(annotation = Component.class)
String value() default "";
@AliasFor("value")
String name() default "";
}
@Service("userService") // Equivalent to @Service(name = "userService")
public class UserService {
// Implementation
}Spring's merged annotation system provides a powerful way to handle annotation composition, inheritance, and attribute overrides.
MergedAnnotations Interface
public interface MergedAnnotations extends Iterable<MergedAnnotation<Annotation>> {
<A extends Annotation> boolean isPresent(Class<A> annotationType);
boolean isPresent(String annotationType);
<A extends Annotation> boolean isDirectlyPresent(Class<A> annotationType);
boolean isDirectlyPresent(String annotationType);
<A extends Annotation> MergedAnnotation<A> get(Class<A> annotationType);
<A extends Annotation> MergedAnnotation<A> get(Class<A> annotationType,
Predicate<? super MergedAnnotation<A>> predicate);
MergedAnnotation<Annotation> get(String annotationType);
MergedAnnotation<Annotation> get(String annotationType,
Predicate<? super MergedAnnotation<Annotation>> predicate);
<A extends Annotation> Stream<MergedAnnotation<A>> stream(Class<A> annotationType);
Stream<MergedAnnotation<Annotation>> stream(String annotationType);
Stream<MergedAnnotation<Annotation>> stream();
// Static factory methods
static MergedAnnotations from(AnnotatedElement element);
static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy);
static MergedAnnotations from(Annotation... annotations);
static MergedAnnotations from(Object source, Annotation... annotations);
}
public enum SearchStrategy {
DIRECT,
INHERITED_ANNOTATIONS,
SUPERCLASS,
TYPE_HIERARCHY,
TYPE_HIERARCHY_AND_ENCLOSING_CLASSES
}MergedAnnotation Interface
public interface MergedAnnotation<A extends Annotation> {
Class<A> getType();
boolean isPresent();
boolean isDirectlyPresent();
boolean isMetaPresent();
int getDistance();
int getAggregateIndex();
Object getSource();
MergedAnnotation<?> getParent();
MergedAnnotation<A> getRoot();
List<Class<? extends Annotation>> getMetaTypes();
boolean hasAttribute(String attributeName);
boolean hasDefaultValue(String attributeName);
<T> Optional<T> getValue(String attributeName);
<T> Optional<T> getValue(String attributeName, Class<T> type);
<T> Optional<T> getDefaultValue(String attributeName);
<T> Optional<T> getDefaultValue(String attributeName, Class<T> type);
MergedAnnotation<A> filterAttributes(Predicate<String> predicate);
MergedAnnotation<A> withAttribute(String attributeName, Object value);
AnnotationAttributes asAnnotationAttributes();
AnnotationAttributes asAnnotationAttributes(Adapt... adaptations);
Map<String, Object> asMap();
Map<String, Object> asMap(Adapt... adaptations);
<T extends Map<String, Object>> T asMap(Function<MergedAnnotation<?>, T> factory, Adapt... adaptations);
A synthesize();
A synthesize(Predicate<String> condition) throws NoSuchElementException;
Optional<A> synthesize(Predicate<String> condition);
enum Adapt {
CLASS_TO_STRING,
ANNOTATION_TO_MAP
}
}Usage Examples
// Basic merged annotation usage
@Service
@Transactional
public class BusinessService {
public void processData() { }
}
Class<?> serviceClass = BusinessService.class;
MergedAnnotations annotations = MergedAnnotations.from(serviceClass);
// Check for annotation presence
boolean hasService = annotations.isPresent(Service.class);
boolean hasTransactional = annotations.isPresent(Transactional.class);
boolean hasComponent = annotations.isPresent(Component.class); // true due to @Service -> @Component
// Get merged annotation with attribute values
MergedAnnotation<Service> serviceAnnotation = annotations.get(Service.class);
String serviceName = serviceAnnotation.getValue("value", String.class).orElse("");
// Work with meta-annotations
MergedAnnotation<Component> componentAnnotation = annotations.get(Component.class);
boolean isMetaPresent = componentAnnotation.isMetaPresent(); // true
int distance = componentAnnotation.getDistance(); // 1 (via @Service)
// Stream all annotations
annotations.stream()
.forEach(annotation -> {
System.out.println("Found: " + annotation.getType().getSimpleName());
System.out.println("Distance: " + annotation.getDistance());
});
// Get annotation attributes
Method method = BusinessService.class.getMethod("processData");
MergedAnnotations methodAnnotations = MergedAnnotations.from(method);
MergedAnnotation<Transactional> txAnnotation = methodAnnotations.get(Transactional.class);
Map<String, Object> attributes = txAnnotation.asMap();
String propagation = txAnnotation.getValue("propagation", String.class).orElse("REQUIRED");Spring provides extensive utilities for working with annotations in various contexts.
AnnotationUtils Class
public abstract class AnnotationUtils {
// Find annotations
public static <A extends Annotation> A findAnnotation(Method method, Class<A> annotationType);
public static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType);
public static <A extends Annotation> A findAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType);
// Get annotation attributes
public static Map<String, Object> getAnnotationAttributes(Annotation annotation);
public static Map<String, Object> getAnnotationAttributes(Annotation annotation, boolean classValuesAsString);
public static Map<String, Object> getAnnotationAttributes(Annotation annotation, boolean classValuesAsString, boolean nestedAnnotationsAsMap);
// Synthesize annotations
public static <A extends Annotation> A synthesizeAnnotation(A annotation);
public static <A extends Annotation> A synthesizeAnnotation(A annotation, AnnotatedElement annotatedElement);
public static <A extends Annotation> A synthesizeAnnotation(Map<String, Object> attributes, Class<A> annotationType, AnnotatedElement annotatedElement);
// Utility methods
public static boolean isCandidateClass(Class<?> clazz, Class<? extends Annotation> annotationType);
public static boolean isCandidateClass(Class<?> clazz, Collection<Class<? extends Annotation>> annotationTypes);
public static boolean isCandidateClass(Class<?> clazz, String annotationName);
public static String getDefaultValue(Class<? extends Annotation> annotationType, String attributeName);
public static <A extends Annotation> A getAnnotation(Annotation annotation, Class<A> annotationType);
public static <A extends Annotation> A getAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType);
public static void clearCache();
}AnnotatedElementUtils Class
public abstract class AnnotatedElementUtils {
// Has annotation checks
public static boolean hasAnnotation(AnnotatedElement element, Class<? extends Annotation> annotationType);
public static boolean hasAnnotation(AnnotatedElement element, String annotationName);
// Find merged annotations
public static <A extends Annotation> A findMergedAnnotation(AnnotatedElement element, Class<A> annotationType);
public static <A extends Annotation> A findMergedAnnotation(AnnotatedElement element, String annotationName);
public static <A extends Annotation> Set<A> findAllMergedAnnotations(AnnotatedElement element, Class<A> annotationType);
public static Set<Annotation> findAllMergedAnnotations(AnnotatedElement element, Set<Class<? extends Annotation>> annotationTypes);
// Get merged annotation attributes
public static AnnotationAttributes findMergedAnnotationAttributes(AnnotatedElement element, Class<? extends Annotation> annotationType, boolean classValuesAsString, boolean nestedAnnotationsAsMap);
public static AnnotationAttributes findMergedAnnotationAttributes(AnnotatedElement element, String annotationName, boolean classValuesAsString, boolean nestedAnnotationsAsMap);
public static MultiValueMap<String, Object> getAllAnnotationAttributes(AnnotatedElement element, String annotationName);
public static MultiValueMap<String, Object> getAllAnnotationAttributes(AnnotatedElement element, String annotationName, boolean classValuesAsString, boolean nestedAnnotationsAsMap);
// Meta-annotation support
public static boolean isAnnotated(AnnotatedElement element, Class<? extends Annotation> annotationType);
public static boolean isAnnotated(AnnotatedElement element, String annotationName);
public static AnnotationAttributes getMergedAnnotationAttributes(AnnotatedElement element, Class<? extends Annotation> annotationType);
public static AnnotationAttributes getMergedAnnotationAttributes(AnnotatedElement element, String annotationName);
}Usage Examples
// Define custom annotation with meta-annotation support
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Service
@Transactional(propagation = Propagation.REQUIRED)
public @interface BusinessService {
@AliasFor(annotation = Service.class, attribute = "value")
String value() default "";
@AliasFor(annotation = Transactional.class, attribute = "timeout")
int timeout() default -1;
}
@BusinessService("orderService")
public class OrderService {
public void processOrder() { }
}
// Use AnnotationUtils
Class<?> orderServiceClass = OrderService.class;
// Find annotations (follows meta-annotation hierarchy)
Service serviceAnnotation = AnnotationUtils.findAnnotation(orderServiceClass, Service.class);
Transactional txAnnotation = AnnotationUtils.findAnnotation(orderServiceClass, Transactional.class);
// Get annotation attributes
Map<String, Object> businessServiceAttrs = AnnotationUtils.getAnnotationAttributes(
orderServiceClass.getAnnotation(BusinessService.class)
);
// Synthesize annotation with attribute overrides
BusinessService businessServiceAnn = orderServiceClass.getAnnotation(BusinessService.class);
Service synthesizedService = AnnotationUtils.synthesizeAnnotation(businessServiceAnn, orderServiceClass);
// Use AnnotatedElementUtils for more advanced processing
boolean hasService = AnnotatedElementUtils.hasAnnotation(orderServiceClass, Service.class); // true
boolean hasTransactional = AnnotatedElementUtils.hasAnnotation(orderServiceClass, Transactional.class); // true
// Find merged annotations with attribute overrides resolved
Service mergedService = AnnotatedElementUtils.findMergedAnnotation(orderServiceClass, Service.class);
String serviceName = mergedService.value(); // "orderService"
Transactional mergedTx = AnnotatedElementUtils.findMergedAnnotation(orderServiceClass, Transactional.class);
Propagation propagation = mergedTx.propagation(); // REQUIRED
int timeout = mergedTx.timeout(); // resolved from BusinessService.timeout
// Get merged annotation attributes
AnnotationAttributes serviceAttrs = AnnotatedElementUtils.findMergedAnnotationAttributes(
orderServiceClass, Service.class, false, false
);
AnnotationAttributes txAttrs = AnnotatedElementUtils.findMergedAnnotationAttributes(
orderServiceClass, Transactional.class, false, false
);Spring provides ordering support that respects the @Order annotation and Ordered interface.
AnnotationAwareOrderComparator Class
public class AnnotationAwareOrderComparator extends OrderComparator {
public static final AnnotationAwareOrderComparator INSTANCE = new AnnotationAwareOrderComparator();
public static void sort(List<?> list);
public static void sort(Object[] array);
@Override
protected Integer findOrder(Object obj);
public Integer getPriority(Object obj);
protected Integer findOrderFromAnnotation(Object obj);
}Usage Examples
// Components with different ordering
@Component
@Order(1)
public class FirstComponent { }
@Component
@Order(3)
public class ThirdComponent { }
@Component
public class UnorderedComponent implements Ordered {
@Override
public int getOrder() {
return 2;
}
}
// Sort components by order
List<Object> components = Arrays.asList(
new ThirdComponent(),
new FirstComponent(),
new UnorderedComponent()
);
AnnotationAwareOrderComparator.sort(components);
// Result: [FirstComponent(1), UnorderedComponent(2), ThirdComponent(3)]
// Check ordering at runtime
AnnotationAwareOrderComparator comparator = AnnotationAwareOrderComparator.INSTANCE;
Integer firstOrder = comparator.findOrder(new FirstComponent()); // 1
Integer thirdOrder = comparator.findOrder(new ThirdComponent()); // 3AnnotationAttributes Class
public class AnnotationAttributes extends LinkedHashMap<String, Object> {
public AnnotationAttributes();
public AnnotationAttributes(Class<? extends Annotation> annotationType);
public AnnotationAttributes(Map<String, Object> map);
public AnnotationAttributes(AnnotationAttributes other);
public Class<? extends Annotation> annotationType();
public String getDisplayName();
// Type-safe attribute access
public String getString(String attributeName);
public String[] getStringArray(String attributeName);
public boolean getBoolean(String attributeName);
public <N extends Number> N getNumber(String attributeName);
public <E extends Enum<?>> E getEnum(String attributeName);
public <T> Class<? extends T> getClass(String attributeName);
public Class<?>[] getClassArray(String attributeName);
public AnnotationAttributes getAnnotation(String attributeName);
public <A extends Annotation> A getAnnotation(String attributeName, Class<A> annotationType);
public AnnotationAttributes[] getAnnotationArray(String attributeName);
// Static factory methods
public static AnnotationAttributes fromMap(Map<String, Object> map);
}Usage Examples
// Create and populate annotation attributes
AnnotationAttributes attributes = new AnnotationAttributes(Service.class);
attributes.put("value", "myService");
attributes.put("qualifiers", new String[]{"primary", "default"});
// Type-safe access
String serviceName = attributes.getString("value"); // "myService"
String[] qualifiers = attributes.getStringArray("qualifiers"); // ["primary", "default"]
// From annotation
@Component("testComponent")
public class TestComponent { }
Annotation componentAnn = TestComponent.class.getAnnotation(Component.class);
Map<String, Object> attrMap = AnnotationUtils.getAnnotationAttributes(componentAnn);
AnnotationAttributes componentAttrs = AnnotationAttributes.fromMap(attrMap);
String componentName = componentAttrs.getString("value"); // "testComponent"AnnotationValueResolver
public interface AnnotationValueResolver {
Object resolve(Object value);
static AnnotationValueResolver none() {
return value -> value;
}
}
public final class AnnotationConfigUtils {
public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.context.annotation.internalConfigurationAnnotationProcessor";
public static final String AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.context.annotation.internalAutowiredAnnotationProcessor";
public static final String COMMON_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.context.annotation.internalCommonAnnotationProcessor";
public static final String EVENT_LISTENER_PROCESSOR_BEAN_NAME =
"org.springframework.context.event.internalEventListenerProcessor";
public static final String EVENT_LISTENER_FACTORY_BEAN_NAME =
"org.springframework.context.event.internalEventListenerFactory";
}RepeatableContainers Support
public final class RepeatableContainers {
public static RepeatableContainers standardRepeatables();
public static RepeatableContainers of(Class<? extends Annotation> container, Class<? extends Annotation> repeatable);
public static RepeatableContainers none();
public RepeatableContainers and(Class<? extends Annotation> container, Class<? extends Annotation> repeatable);
Annotation[] findRepeatedAnnotations(Annotation annotation);
}Usage Examples
// Define repeatable annotation
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Qualifiers.class)
public @interface Qualifier {
String value();
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Qualifiers {
Qualifier[] value();
}
// Use repeatable annotations
@Qualifier("primary")
@Qualifier("default")
@Component
public class MultiQualifiedComponent { }
// Process repeatable annotations
Class<?> componentClass = MultiQualifiedComponent.class;
MergedAnnotations annotations = MergedAnnotations.from(componentClass);
// Get all instances of repeatable annotation
Stream<MergedAnnotation<Qualifier>> qualifiers = annotations.stream(Qualifier.class);
List<String> qualifierValues = qualifiers
.map(q -> q.getValue("value", String.class).orElse(""))
.collect(Collectors.toList());
// Result: ["primary", "default"]This comprehensive annotation processing system enables Spring's powerful declarative programming model, allowing developers to use annotations not just as markers but as configuration vehicles with rich attribute processing and composition capabilities.
Install with Tessl CLI
npx tessl i tessl/maven-org-springframework--spring-core