How to Validate Spring Cloud Dynamic Configs with In‑Memory Java Compilation
This article explains how to build a runtime validator for Spring Cloud dynamic configuration by generating Java classes from .properties files, compiling them in memory with JavaCompiler, loading them via a custom ClassLoader, and integrating the result into the Spring context to catch configuration errors early.
Problem
When using Spring Cloud for dynamic configuration, values are injected with @Value into beans marked with @RefreshScope. After a change, ContextRefresher creates a new Spring Environment and lazy‑initialized scoped beans are rebuilt with the new settings. This flexibility introduces risks: configuration changes bypass formal QA, can cause obscure bugs, and Spring Cloud lacks a fallback mechanism, so type errors may render a service unavailable.
The author raised an issue with the Spring Cloud project, but the maintainers deemed the change too large to adopt.
To mitigate these risks, a validator is added that checks dynamic configurations before they are applied.
Overall Idea
The plan extracts the configuration, builds an independent Java class, and creates a separate ApplicationContext to instantiate the class. If bean creation fails, the configuration is considered invalid.
Dynamic Compilation
Generating Java Class from Configuration
The .properties file is parsed, and each entry is annotated with a custom comment that declares the Spring EL expression and the target field type. After parsing, the fields are inserted into a class template to produce a Config.java source string.
JavaCompiler
The generated source is compiled at runtime using javax.util.JavaCompiler, avoiding the traditional write‑compile‑load‑cleanup cycle.
JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
JavaFileManager fileManager = javaCompiler.getStandardFileManager(null, null, null);
CompilationTask task = javaCompiler.getTask(out, fileManager, diagnosticListener, options, classes, compilationUnits);
task.call();
FileObject outputFile = fileManager.getFileForOutput(null, null, null, null);
outputFile.getCharContent(true);The compilation flow uses getTask() to submit a CompilationTask, reads the source via getCharContent(), and writes the bytecode with openOutputStream().
Delegation Pattern
Because the default JavaCompiler implementation works with files, a memory‑only solution is needed. The author extends ForwardingJavaFileManager and SimpleJavaFileObject using the delegation pattern, overriding necessary methods.
Spring Bean Instantiation
To turn the compiled Config class into a Spring bean, a FileSystemXmlApplicationContext is defined in XML, and after compilation the context is created with a custom class loader.
Class Loader
A custom ClassLoader loads the in‑memory bytecode by overriding findClass:
class MemoryClassLoader extends ClassLoader {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// compiled bytecode stored in classBytes map
byte[] buf = classBytes.get(name);
if (buf == null) {
return super.findClass(name);
}
return defineClass(name, buf, 0, buf.length);
}
}Configuration and Execution
The dynamic properties are added to the Spring Environment as a new PropertySource. Then applicationContext.refresh() is called, and the lazy Config bean is retrieved to trigger validation.
FileSystemXmlApplicationContext applicationContext = new FileSystemXmlApplicationContext();
applicationContext.setClassLoader(memoryClassLoader);
applicationContext.setConfigLocation("classpath*:/test.xml");
Map<String, Object> propertyMap = buildDynamicPropertyMap();
MapPropertySource mapPropertySource = new MapPropertySource("validate_source", propertyMap);
applicationContext.getEnvironment().getPropertySources().addFirst(mapPropertySource);
applicationContext.refresh();
applicationContext.getBean("config");Summary
The prototype revisits many backend concepts—runtime code generation, in‑memory compilation, custom class loading, and Spring bean lifecycle—demonstrating a way to validate Spring Cloud dynamic configurations before they affect production services.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
