I am creating a custom AutoConfiguration for Spring Boot. One of the features I was attempting to create was to create one or more Beans dynamically and adding them to the ApplicationContext at runtime.
The problem I ran into was with Autowiring. My @SpringBootApplication class autowires those beans, and since they do not exist yet, autowire fails.
My first solution was to put @Lazy on the autowire, and that solved my problem.
However, I ran into something interesting. I added two beans that I was looking for into the AutoConfiguration code, and of course, it worked. By accident, I only removed one of the beans and re-ran my code. It worked.
@SpringBootApplication
public class SpringBootDemoApplication {
@Autowired
@Qualifier("some_name")
private MyClass myClass;
@Autowired
@Qualifier("another_name")
private MyClass anotherClass;
...
}
@Configuration
public class MyAutoConfigurationClass {
@Bean(name="some_class")
public MyClass myClass () {
return null;
}
}
So the short of it is this. If I defined only one of the beans in my autoconfiguration class, this seems to satisfy Autowired and it does not blow up and when I dynamically add my other beans, both beans are found.
The stipulation is that the Autowired bean that is first, must be the bean that is defined in my autoconfiguration class.
I am running the following:
- Spring Boot Starter 1.5.7-RELEASE
- Various Spring Framework 4.3.11-RELEASE
Is this a bug? Or is this the way Autowired is supposed to work?
@SpringBootApplication
public class SpringBootDemoApplication {
@Autowired
@Qualifier("myclass")
private MyClass myClass;
@Autowired
@Qualifier("anotherMyClass")
private MyClass anotherMyClass;
...
}
@Configuration
public class MyAutoConfiguration {
private ConfigurableApplicationContext applicationContext;
private final BeanFactory beanFactory;
@Autowired
private MyClassFactory myClassFactory;
public MyAutoConfiguration(ApplicationContext applicationContext, BeanFactory beanFactory) {
this.beanFactory = beanFactory;
this.applicationContext = (ConfigurableApplicationContext) applicationContext;
}
@PostConstruct
public void init() throws IOException, SQLException {
this.myClassFactory.create(this.applicationContext);
}
// without this @Bean definition SpringBoot will recieve the following error and stop
// AnnotationConfigEmbeddedWebApplicationContext - Exception encountered during context initialization
@Bean(name="myClass")
public DataSource anyNameWillDoItDoesntMatter() {
return null;
};
}
@Component
class MyClassFactory {
public void create(ConfigurableApplicationContext applicationContext) {
applicationContext.getBeanFactory().registerSingleton(name, value);
}
}
So is this expected behavior of @Autowired?