7

I have quite a complex Spring Boot application (including Spring MVC and Security), which among other things requires a database configuration (url, username and password). The requirement is to let end-user configure the DB with the help of the application itself, like the following:

  1. User starts the application, which has no DB configuration yet
  2. Application notices the absence of DB configuration and presents user with configuration screen
  3. User enters url and credentials
  4. Application starts using this DB

The obvious problem is that I cannot create any beans that require a DataSource which requires DB configuration until that configuration is known.

Is there any way to postpone the initialisation of the majority of the application's beans until first configuration step is performed?

-- Update -- Several of application's beans initialise their state from the DB in their @PostConsutrct methods. So I either need to really delay their creation or have a method of refreshing (potentially) all beans in the application context after configuration is provided.

Nikem
  • 5,716
  • 3
  • 32
  • 59
  • This seems very interesting...have you seen the [Spring - Bean Post Processors](http://www.tutorialspoint.com/spring/spring_bean_post_processors.htm) – KlajdPaja May 26 '16 at 17:42
  • Yes, I have. But cannot see how they can be used here – Nikem May 26 '16 at 17:43
  • Not sure if this would work or not, but you could implement your own version of DataSource that is basically a Dummy implementation at startup. Then after the proper Database credentials have been entered try and change the DataSource in the ApplicationContext. – hooknc May 26 '16 at 17:46
  • @hooknc I thought about that. But I am afraid I will have to implement dummy `java.sql.Connection` as well. And `java.sql.Statement` etc – Nikem May 26 '16 at 17:48
  • Well at the link I sent you can see that you can control the registering of a bean. My idea would be to create a DataSource class with the key value properties you need and register that bean when you decide – KlajdPaja May 26 '16 at 17:51
  • @KLajdPaja What about other hundreds of beans in the application? They cannot be created without the data source. And Bean Post Processors cannot delay bean creation. They can only augment them – Nikem May 26 '16 at 17:52
  • I don't know if you would have to also create Dummy `java.sql.Connection` and `java.sql.Statement` objects. You could just throw exceptions from the Dummy DataSource that deals with those methods. – hooknc May 26 '16 at 18:15
  • this could help http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/datasource/DelegatingDataSource.html . – Lari Hotari May 26 '16 at 19:26
  • an answer to a different but related question http://stackoverflow.com/questions/25160221/how-do-i-create-beans-programmatically-in-spring-boot/25175780#25175780 – Lari Hotari May 26 '16 at 19:27
  • 1
    That's probably lamer's idea - but what if you have a separate small script or program that will launch first, get and save values printed by the user to application.properties file and then start your main program (which would read application.properties file)? – lenach87 May 26 '16 at 21:50
  • @lenach87 that in fact may be an interesting idea... I will think it through... – Nikem May 27 '16 at 03:48
  • @LariHotari I belive my problem is not so much of dynamic creation of the DS, but of delaying the creating of all other beans. – Nikem May 27 '16 at 03:49
  • @lenach87 Care to make an answer from your comment? This is certainly worth an upvote from me :) – Nikem May 27 '16 at 05:51
  • @Nikem I'm glad my idea might be helpful :) Maybe this could be helpful to you regarding external configuration - so that you could place your application.properties outside your jar and you script or another module of your application has access to it - http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html I'll try to make an answer, thank you! – lenach87 May 27 '16 at 07:58
  • 1
    You can also use AbstractRoutingDataSource - Go through this link to know more : https://spring.io/blog/2007/01/23/dynamic-datasource-routing/ – Aditya Khajuria Mar 22 '17 at 06:35

2 Answers2

2

I suggest you could think about having another module/program or a simple script that would ask to provide all details like database etc, store this information to your application.properties file (may be useful re externalized configuration Spring boot external configuration) and then launch your main program with already available information on datasource. This might be a bit easier approach.

lenach87
  • 949
  • 3
  • 11
  • 18
0

As you probably have expected, you need an instance of javax.sql.DataSource at the time when the Spring Application Context is created.

I suggest you subclass Spring's org.springframework.jdbc.datasource.DelegatingDataSource and override afterPropertiesSet with an empty method (the default implementation throws an error if you haven't supplied a datasource). When the user supplies the details you need to select the db, you can inject the final datasource at a later time into DelegatingDataSource.

Source: https://github.com/spring-projects/spring-framework/blob/master/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/DelegatingDataSource.java

gogstad
  • 3,607
  • 1
  • 29
  • 32
  • I have added some explanation, why I somewhat sceptical. But I will give it a try. – Nikem May 27 '16 at 03:48
  • 1
    As lenach87 commented above, you may be better off having two separate applications instead of fighting spring like this. One that gets the database info, and another that uses it. Better with two applications running with consistent state, than one starting in a broken state. – gogstad May 27 '16 at 05:26