A Spring JPA Configuration for Multiple Profiles

My Spring-Data application on GitHub goes to v0.0.8 with the JPA Configuration redesigned to support multiple profiles with a bonus extensible design. Version 0.0.7 of the app supported multiple profiles, but I knew it could be improved. I found the design I liked in the work of Gordon Dickens’ Spring-Data-Demos GitHub application.

Here are some of the interesting features of Gordon’s JPA Configuration for multiple profiles that I employed in my Spring-Data app.

Enumerator and Database-Oriented Profiles

Rather than use strings for profile names we’re using an enumerator. An insignificant feature, perhaps, but something I like. The less use of string identifiers the better. You’ll also notice that rather than “dev” and “production” for profile names used in v0.0.7 we’re using Gordon’s approach of using the data source. I may want to go back to more environment-based profile naming, but data source naming works well for now.

The profile annotation then would be

@Profile(DataConfigProfile.MYSQL) // rather than @Profile("mysql")

As a side note, we can still use string profile identifiers where we need to as I continue to do in the Gradle :bootRun task.

bootRun {
addResources = false
systemProperty 'spring.profiles.active', 'mysql'
main = 'com.nixmash.springdata.jpa.Launcher'
}

Extending a JpaCommonConfig class

Each data source/profile config class extends from a base JpaCommonConfig class.

The H2Config and MySqlConfig subclasses set the DataSource bean and optionally pass properties to the Entity Manager Factory in JpaCommonConfig.

The base JpaCommonConfig completes the JPA configuration by creating the Entity Factory and Transaction Manager.

Shared GetProperty Construction

Another smart aspect of Gordon’s multiple data source JPA configuration is how properties are handled. In his Spring-Data Profiles app he supports perhaps 8 different data sources where I currently am using only two. Here is where the extensibility of this design comes into play, because it is very easy to add more data sources or profiles. Each data source has its own properties file, with @PropertySource(“…mysql.properties”) shown in the MySqlConfig class above. All properties files have the same property names, making it possible for the base JpaCommonConfig class the retrieve each property with a getPropertyName() the subclasses can leverage.

@Override
@Bean
public DataSource dataSource() {
	BasicDataSource dataSource = new BasicDataSource();
	dataSource.setDriverClassName(getDriverClassName());
	dataSource.setUrl(getUrl());
	dataSource.setUsername(getUser());
	dataSource.setPassword(getPassword());
	...
	return dataSource;
}

Optional Entity Manager Factory Properties

Another design feature that makes it easy to add different types of data sources is the getJpaProperties() override. If the data source class has JPA Properties it needs to add to the Entity Manager Factory those are passed along when the factory is created through the getJpaProperties() override.

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {

	LocalContainerEntityManagerFactoryBean factory =
	    new LocalContainerEntityManagerFactoryBean();
	factory.setJpaVendorAdapter(vendorAdapter);
	...
	factory.setDataSource(dataSource());
	if (getJpaProperties() != null) {
		factory.setJpaProperties(getJpaProperties());
	}
	return factory;
}

If you’re interested in seeing the source for this you’ll find it in my Spring-Data app v0.0.8 or in the app on which it was based in Gordon Dickens’ Spring-Data “Profiles.”