Taking the risk that my answer is too general.
Roughly saying you can think Guice modules as equivalent a configuration class with @Configuration annotation, that contains @Bean etc.
The Guice injector can be considered as equivalent to the Spring ApplicationContext.
So for example if we have two configuration files:
@Configuration
public class ConfigA {
@Bean
ExampleClass1 exampleClass1(){
return new ExampleClass1();
}
@Bean
ExampleClass2 exampleClass2(){
return new ExampleClass2();
}
}
@Configuration
public class ConfigB {
@Bean
ExampleClass1 exampleClass1(){
return new ExampleClass1();
}
@Bean
ExampleClass3 exampleClass2(){
return new ExampleClass3();
}
}
And Services ExampleClass4 that you want as alternative of ExampleClass3.
You may use the @Primary annotation
public class ExampleClass4 extends ExampleClass3 {
@Override
public String toString() {
return "ExampleClass4{}";
}
}
@Configuration
public class ConfigC {
@Bean
@Primary
ExampleClass3 exampleClass3(){
return new ExampleClass4();
}
}
So rewriting the app to Spring (core 5.2, not Spring boot) will be:
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext ap = initAppContext();
overrideBinding(ap);
System.out.println(ap.getBean(ExampleClass3.class));
//prints ExampleClass4{}
}
private static AnnotationConfigApplicationContext initAppContext() {
AnnotationConfigApplicationContext ap = new AnnotationConfigApplicationContext();
ap.register(ConfigA.class, ConfigB.class);
return ap;
}
private static void overrideBinding(AnnotationConfigApplicationContext ap) {
ap.register(ConfigC.class);
ap.refresh();
}
}
This technic of overriding a binding will work only because ExampleClass3 wasn't defined as primary, if it doesn't that would not work and you need to consider a different approach.
For more information:
https://www.baeldung.com/spring-application-context
https://docs.spring.io/spring-javaconfig/docs/1.0.0.m3/reference/html/modularizing-configurations.html
Override bean definition in java config