The @ContextHierarchy annotation allows us to define a hierarchy of application contexts in Spring tests. This is useful when we need to create parent-child context relationships where child contexts can access beans from parent contexts, but not vice versa.
Why Use @ContextHierarchy?
In complex applications, we often need to organize beans into layers. For example, a parent context might contain shared infrastructure beans (database, security), while child contexts contain specific service or controller beans. The hierarchy ensures:
- Child contexts can inject parent beans
- Parent contexts remain isolated from child beans
- Better modularity and reusability of configurations
Java source and doc
Definition of ContextHierarchyVersion: 7.0.4 package org.springframework.test.context;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface ContextHierarchy {
ContextConfiguration[] value(); 1
}
Example
Parent Configuration
First, let's create a parent context configuration with a shared bean:
package com.logicbig.example;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ParentConfig {
@Bean
@Qualifier("sharedBean")
public String sharedBean() {
return "Parent Context Bean";
}
}
Child Configuration
The child configuration can access beans from the parent context:
package com.logicbig.example;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ChildConfig {
@Bean
@Qualifier("childBean")
public String childBean() {
return "Child Context Bean";
}
@Bean
@Qualifier("combinedBean")
public String combinedBean(@Qualifier("sharedBean")
String sharedBean) {
return "Child uses: " + sharedBean;
}
}
Test with Context Hierarchy
Now we'll create a test that demonstrates the parent-child relationship:
package com.logicbig.example;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.ContextHierarchy;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@ExtendWith(SpringExtension.class)
@ContextHierarchy({
@ContextConfiguration(classes = ParentConfig.class),
@ContextConfiguration(classes = ChildConfig.class)
})
class ContextHierarchyTest {
@Autowired
private ApplicationContext context;
@Autowired
@Qualifier("childBean")
private String childBean;
@Autowired
@Qualifier("combinedBean")
private String combinedBean;
@Test
public void testContextHierarchy() {
System.out.println("Child bean: " + childBean);
System.out.println("Combined bean: " + combinedBean);
ApplicationContext parent = context.getParent();
Assertions.assertNotNull(parent);
System.out.println("Parent exists: true");
System.out.println("Parent has sharedBean: " + parent.containsBean("sharedBean"));
System.out.println("Parent has childBean: " + parent.containsBean("childBean"));
}
}
Output$ mvn test [INFO] Scanning for projects... [INFO] [INFO] ---------------< com.logicbig.example:context-hierarchy >--------------- [INFO] Building context-hierarchy 1.0-SNAPSHOT [INFO] from pom.xml [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- resources:3.3.1:resources (default-resources) @ context-hierarchy --- [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] skip non existing resourceDirectory D:\example-projects\spring-core-testing\context-hierarchy\src\main\resources [INFO] [INFO] --- compiler:3.13.0:compile (default-compile) @ context-hierarchy --- [INFO] Recompiling the module because of added or removed source files. [WARNING] File encoding has not been set, using platform encoding windows-1252, i.e. build is platform dependent! [INFO] Compiling 2 source files with javac [debug target 17] to target\classes [INFO] [INFO] --- resources:3.3.1:testResources (default-testResources) @ context-hierarchy --- [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] skip non existing resourceDirectory D:\example-projects\spring-core-testing\context-hierarchy\src\test\resources [INFO] [INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ context-hierarchy --- [INFO] Recompiling the module because of changed dependency. [WARNING] File encoding has not been set, using platform encoding windows-1252, i.e. build is platform dependent! [INFO] Compiling 1 source file with javac [debug target 17] to target\test-classes [INFO] [INFO] --- surefire:3.2.5:test (default-test) @ context-hierarchy --- [INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider [WARNING] file.encoding cannot be set as system property, use <argLine>-Dfile.encoding=...</argLine> instead [INFO] [INFO] ------------------------------------------------------- [INFO] T E S T S [INFO] ------------------------------------------------------- [INFO] Running com.logicbig.example.ContextHierarchyTest Child bean: Child Context Bean Combined bean: Child uses: Parent Context Bean Parent exists: true Parent has sharedBean: true Parent has childBean: false [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.362 s -- in com.logicbig.example.ContextHierarchyTest [INFO] [INFO] Results: [INFO] [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 2.595 s [INFO] Finished at: 2026-02-09T19:00:23+08:00 [INFO] ------------------------------------------------------------------------
Conclusion
The output confirms that the child context successfully accessed the parent bean to create the combined message. The test also verifies that the parent context exists and contains its own bean, but cannot see beans defined in the child context. This demonstrates the unidirectional visibility in context hierarchies - children can see parent beans, but parents remain isolated from their children's beans.
Example ProjectDependencies and Technologies Used: - spring-context 7.0.4 (Spring Context)
Version Compatibility: 5.0.0.RELEASE - 7.0.4 Version compatibilities of spring-context with this example: Versions in green have been tested.
- spring-test 7.0.4 (Spring TestContext Framework)
- junit-jupiter-engine 6.0.2 (Module "junit-jupiter-engine" of JUnit)
- JDK 25
- Maven 3.9.11
|