Spring Boot: Conditional on database type - java

I have a Spring Boot application and want to inject specific repository implementations based on the type of the underlying SQL data source (defined using the spring.datasource.* properties).
I tried to use a custom conditional here, but unfortunately, when it is evaluated I cannot get the data source in order to check for the database type.
My condition currently looks like this:
#Order(Ordered.LOWEST_PRECEDENCE - 10)
class OnDatabaseTypeCondition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
DataSource dataSource = context.getBeanFactory().getBean(DataSource.class);
// further matching code here
}
It should be used something like this:
#ConditionalOnDatabaseType(H2)
public class MyCustomImplementation implements MyRepository {
// Code
}
However, when the condition is evaluated, I get an exception that the data source is not defined:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:348)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:335)
I assume that this is happening because the condition is already checked before all the beans are constructed. Is there any way that I can tell Spring that the data source has to be created before this condition is evaluated? Or is this just no possible using Spring conditions?
The use case I want to solve by doing is the following: The application can run with different types of databases, and some (like H2) do not certain functions like windowing functions. So I want to provide special queries for certain databases that may be slower, but still functionally correct. The idea for this approach was that these JDBC repositories should be easy to mark without the necessity of introducing specific Spring profiles, but just by looking at the underlying database (using org.springframework.jdbc.support.JdbcUtils).
Thanks

Some conditions are evaluated when the bean is actually created. If you want to check for the presence of a bean, you need to be very careful because any attempt to get a bean at that stage will lead to an early initialization. That's the first problem.
The second problem is that your configuration (app configuration) always run completely before the auto-configuration. If Spring Boot has to decide if it must create a DataSource, it should give the app configuration a chance to provide one.
The only way you could implement that is via auto-configuration, making sure that your auto-configuration runs after the ones that are supposed to provide the bean you're looking for ( #AutoconfigureAfter). Regardless I wouldn't do a straight call to the context like that. Check OnBeanCondition to see how Spring Boot does that thing itself. So you can't add such condition to your app configuration or to your components scanned by component scanning.
Having said that, the use case looks quite weird to me. Maybe we could take a step back and you could explain why you need to do this.

As for the specific question, have you considered checking the JDBC connection string?
You could check the properties (spring.datasource.url) to see if it's h2 or not.
E.g. ${spring.datasource.url}.startsWith('jdbc:h2:')
The reason is that properties are available during autoconfiguration. In fact, H2 with a temporary database is instantiated as DataSource when the corresponding properties are not configured for a different database.

Related

Spring properties hot reloading

In a project, I have a org.apache.commons.configuration.PropertiesConfiguration object registered as a Bean, to provide configuration values around the application, with hot-reloading capabilities.
Example: I defined a DataSource singleton Bean. I then created a ReloadingDataSource object, which wraps and delegate to the "real" DataSource, and each time the configuration file changes, it is able to recreate it in a thread-safe manner.
I'd like to do something similar for simple properties values.
I'd like to create a simple, Autowireable object that delegate retrieval to the Apache PropertiesConfiguration Bean.
The usage should be similar to:
#Property("my.config.database")
private Property<String> database;
And the call site would simply be:
final String databaseValue = database.get()
You'll say, just pass around the PropertiesConfiguration object. Maybe you're right, but I'd like to provide another abstraction over that, a simpler-to-use one.
I know that with ProxyFactoryBean it is possible to create an AOP proxy for method calls. Is this the right path, or are there better alternatives? Maybe pure Spring AOP/AspectJ?
I don't want to use Spring Cloud or similar dependencies.
Spring Cloud will recreate the beans, so keep in mind whatever solution you come up with, if you have another bean which only reads this value once for instance when it is initiated, it won't re-initialize itself, that is the problem Spring Cloud Config takes care of.
AOP only works at the method level as I understand, so you can definitely intercept a call to somebean.getFoo(). But within somebean, there is no way to proxy calls to the variable itself: somebean.foo. You would have to reset foo every time your PropertiesConfiguration changed, and again keep in mind that, if anything else needs the new value of foo you would need to handle this or bite the bullet use Spring Cloud.
The overhead you have with changing stuff at run-time to avoid a re-deploy should really be thought carefully about. For Netflix, this makes sense because they have thousands and thousands of servers. But for smaller players I can't see the justification, the decision adds much complexity. Nightmare to test.
Do you test changing your configuration at run-time or accept the risk and assume it works?
Do you test changing from A -> B whilst under load of a user performing a transaction to the database?
Test other raise conditions where foo is changing?
Some things to think about.

Spring 4 Dynamic Bean Creation

Maybe I'm not using the right terminology and that's why i can't find an answer, but I want to know how can I take information from a database to create beans that I can inject into the application?
Here's an example, rather than having this coded in a configuration file, I would like to possibly loop some values stored in a database and build these beans based on that:
#Bean
public CronTriggerFactoryBean cronTriggerFactoryBean() {
CronTriggerFactoryBean factory = new CronTriggerFactoryBean();
factory.setJobDetail(jobDetailFactoryBean().getObject());
factory.setStartDelay(3000);
factory.setCronExpression("0 0/2 * 1/1 * ? *");
return factory;
}
How can I build beans like this and have them become a part of the application?
There are probably multiple ways how to achieve that, but all of them are pretty complex with a lots of pitfalls. I would say that in your example you should not create triggers as separate beans but rather have a single service to manage your schedules (and leave it out of Spring).
The thing with Spring is, that it is not designed to act as a dynamic container (like OSGi for example). This means that for example #Autowired dependencies are initialized during context startup and stays the same till the application context is destroyed.
However it is possible to construct bean definitions on the fly during initialization. Best place would be BeanFactoryPostProcessor. But this would be called during context initialization. This means you will have no other beans available (like EntityManager, DataSource, ...).
Another possibility is to somehow take advantage of context hierarchy. You can create and destroy application contexts on-the-fly. However implementing that would require deeper knowledge of Spring's internals.
Question for others: not sure if it is possible to reference initialized beans from parent context during child context initialization.
After you load the necessary bean properties from Database , use BeanDefinitionBuilder. You can refer this link

Quartz in Spring; jobDataAsMap serialization for multiple-use job bean

I have an extension to QuartzJobBean that takes two parameters:
public class FileListProcessorJob extends QuartzJobBean
{
transient static final Logger logger = Logger.getLogger(FileListProcessorJob.class);
FileListProcessor fileProcessor; // with setter
FileListProcessor fileProcessor2; // with setter
// ...
}
I have 4 quartz jobs in this application that use this bean; it is the number of times I have that processes a set of files from a folder, then does another set.
It works fine in my test environment, but when I moved it to development, I had to configure Quartz for a database datasource since it was to work in a cluster. When I did that, the runtime started telling me that "fileProcessor" was not serializable. I've tried to make it serializable, but the message is still there.
There are three different bean classes and four different beans loaded under fileProcessor; I've been over all of them to ensure they are serializable, but the message still appears. The message also appears to indicate that the log4j Logger is the non-serializable entity, but I can't see how that is. I made it transient in one pass, no difference.
The standard answers to the serializable problem I find on SO and elsewhere involve moving making a call within the job bean to the job execution context, passing in the reference through SchedulerContextAsMap. But, as near as I can tell, this depends on having globally unique names for the parameters to which to load the globally unique bean names, which doesn't work as I have this set up. I re-use the parameters since I re-use the bean itself.
I'm new to Spring design, but I thought this was the way it was supposed to work -- reusable components, configured with XML to avoid having similar classes slightly modified to do different things. So how can I make my 4 jobs work? Do I have to copy-and-paste them, then slightly modify the names so they're different, and unique in the configuration? Or is there some other piece I am missing and can use here?
There were two levels of problem to be solved; getting something to be serialized takes some painstaking examination and alteration of code, and the clustered environment writes serialized forms of the beans to the database and then uses them in preference to (or in place of, or addition to, I'm not sure) the spring/quartz configuration files. Once I got ALL the serialization necessaries done, and wiped the database records of all the jobs that had been stored there, it worked more like I had expected.

Why is buildSessionFactory() deprecated?

Why is buildSessionFactory() replaced by buildSessionFactory(ServiceRegistry)? What is the importance of ServiceRegistry?
The reasons for this are explained on Hibernate's Jira
https://hibernate.onjira.com/browse/HHH-2578
Currently a SessionFactory is built by throwing a bunch of stuff into a Configuration object, stirring it, letting it come to a boil, and then pulling out the SessionFactory. In seriousness, there are a few problems with the way we currently operate within a Configuration and how we use it to build a SessionFactory:
The general issue that there is no "lifecycle" to when various pieces of information will be available. This is an important omission in a number of ways:
1) consider schema generation. currently we cannot even know the dialect when a lot of db object names are being determined. this would be nice because it would allow us to transparently handle table/column names which are also keywords/reserved-words in the dialect, for example.
2) static-ness of types and the type-mappings. Because we currently have nothing to which to scope them. Ideally a type instance would be aware of the SessionFactory to which it is bound. Instead, what we have now is to change API methods quite a lot of the time to add in the SessionFactory as a passed parameter whenever it is discovered that it is needed.
3) also, most (all?) of the "static" configuration parameters in Hibernate are currently required to be so because of their use from within these static types; thus scoping types would allow us to also scope those config parameters (things like bytecode-provider, use of binary streams, etc).
Ideally what I see happening is a scheme where users build a org.hibernate.cfg.Settings (or something similiar) instance themselves. Additionally they would apply metadata to a registry of some sort (lets call it MetadataRegistry for now). Then in order to build a SessionFactory, they would supply these two pieces of information (via ctor? via builder?). The important aspect though is that the information in MetadataRegistry would not be dealt with until that point in time, which would allow us to guarentee that resolving schema object names, types, etc would have access to the runtime Settings (and specifically the dialect)
You can read also comments on this one: https://hibernate.onjira.com/browse/HHH-7580
Its too much to copy paste and I guess Jira won't go down so this answer should be valid.

Using Dependency Injection in Spring to replace Factory pattern

I am currently working on an application in which the an instance of the domain object D is injected in to the application. The domain object can contain many classes together in different combinations and permutations as defined by its bean and hence leading to many different final objects D, which I refer to as different versions of D. For a given version of D, I have to fill up the primitive values in it and then save it to the database. Saving it to the database is pretty simple using JPA and Hibernate. The problem is filling up the values in D. The values are fetched over the network using SNMP and then filled up. For each version of D, there is different a strategy to follow, since each version of D may have a different MIB. I are currently following the factory pattern. The factory takes a version of D and returns a valueRetriever for specific to that version of D, which is then used to fetch the values and fill D.
The other obvious way is to inject a configuration retriever in with D and then use it to retrieve the configuration. But I also need to use the retriever during runtime to re-fetch the configurations, so that makes it necessary to store the retriever too in the database, hence creating a new table for each retriever, which seems to an overhead currently.
My question is: Can there be a better way to retrieve the configurations i.e. have a valueRetriever given the above scenario using dependency injection.
Edit: Can AOP be of any use here?
It seems that some of the objects you needing to create have a complex creation logic. You may wont to look at the Spring FactoryBean interface, since a FactoryBean can get all the complex details over the network while allowing you to create an instance and then inject it into other beans.
The basis for Spring's DI is the Bean Factory/Application Context, so it's entirely possible to replace what you're doing.
The difference will be that you'll have to be able to put all your permutations into the Spring configuration and give control over to the application context. If you can't do that, perhaps the solution you've got is preferred.
UPDATE: I would start to fear that your Spring solution is adding in too many unfamiliar technologies into what might be an overly complicated situation.
Take a breath and think "simple".
I wouldn't worry about the database for now. The Spring application context will be the database if you can get all the combinations you need into the bean factory. I'm assuming these configurations are read-only and not altered once you declare them. If that's not the case all bets are off.

Categories