Falling in love with Spring Java Configuration

Spring guys spent significant effort to give us alternatives to original XML configuration. Hats off, they have it all thought out – starting with the fact that runtime representation is not directly tied to any particular format of configuration file. Or configuration class for that matter. We have many annotations for like… forever now. And then there is the possibility of pure Java config. This post is not tutorial, but rather a short discussion why it is cool with little bonus annotation at the end.

Going Java Config? Why?

I can’t exactly remember pros/cons of one or the other (XML) right now, you can mix them anyway if needed. But recently I decided to give it a go – as our current project has not that complicated application context – mostly typical JPA stuff, transaction manager, property placeholder – and that’s it. Reason? Better control. And who loves XML anyway. 🙂 We can also discuss compile time safety, but dependencies are resolved later anyway, then there is component scan that finds stuff not mentioned directly, Spring’s FactoryBean also adds some fog… so compile time safety is not the main win here, especially if you had good tool for Spring XML before (IntelliJ IDEA is one). So better control is the main reason.

Sure we have a lot of control in Spring already. There are profiles I use for couple of years for configuration adjustments. Let’s say I have a standalone app configured with Spring. During development I run my main class from test scope and my test master configuration contains many profile sections where my datasource is pointed to various testing databases. Because it is test scope it doesn’t go into production JAR, so I can lower my guard and commit DB user/password into this test configuration. (Not that people sometimes doesn’t commit IPs and user/passwords into production code/configurations too – but that’s another story altogether. :-))

The rest of the configuration is imported from main resources, so I don’t repeat myself. All I have to do is to add various run configurations with various -Dspring.profiles.active=XXX VM parameters (or one and change it on fly, your choice). Sure, you can do this with property placeholder, but profile is easier – one switch and all “properties” can have different names. Actually I never tried putting property placeholder configuration into profile, but that would be also interesting ways how to externalize this configuration.

Now this works, but with Java configuration you don’t have to use profile. You use some kind of if/switch in your @Bean annotated method. You may control anything – what is set, what is instantiated (as long as return type fits, e.g. any implementation of DataSource), whether you go for URL/name/password configuration or pull your resource from JNDI… It’s all up to you and you can do it in language that allows you to execute – which XML is not.

First impression? Awesome!

Well, I’m not complete greenhorn with Spring and I know annotation based configuration pretty well. Also it wasn’t the first time I wrote @Configuration over the class. But it was the first time I did it without XML altogether. First time I called new AnnotationConfigApplicationContext(MyConfig.class). And the result was good. I got stuck for some time because entityManagerFactory method that used class LocalContainerEntityManagerFactoryBean (which is a FactoryBean, which I know) didn’t work when I naively returned factoryBean.getObject(). But when I changed it to return factoryBean itself (returning type FactoryBean<EntityManagerFactory>), everything was fine.

Second problem we encountered was reusing some @Configuration class that needed Spring properties in project with XML based master configuration. XML configuration contained context:property-placeholder element, but injected @Autowired private Environment env; didn’t contain these properties. (They seem to be somewhere deep in the environment, but were not returned by env.getProperty. Now these are things I don’t understand fully (Spring is big!) but using @PropertySource on our @Configuration class that autowired environment fixed it.

Those were hardly any problems at all when you consider the big change in the way how the configuration is expressed – and think about possibilities.

Composing configurations and Master configurations

Any serious configuration gets bigger after some time – and I prefer to split it into numerous files, mostly related to specific technical aspect. With Java configuration you can @Import another configuration class (or @ImportResource XML configuration) too. Or you can go to autopilot and using @ComponentScan (equivalent of XML’s context:component-scan) let Spring find all other @Configurations.

But imagine having something I call “master configuration” – which is the only class you mention to your bootstrap code. You most likely have one for production code (src/main) – it contains default configuration that works OK for production. All other partial configurations are auto-discovered and applied. Mine looks simple:

@Configuration
@ComponentScan(basePackages = "com.acme.project")
@EnableScheduling
public class MasterConfig {
// something may be here
}

Now you want to run alternative master configuration – as mentioned I put these into test code (src/test). What I don’t want is to include my production master configuration. While the one up here looks harmless, I may have my reasons why I don’t want to apply @EnableScheduling for instance. For automatic test I actually don’t want any @Scheduled methods firing up at all. The reasons can be many, let’s not argue here. My test configuration may look like this:

@Configuration
@ComponentScan(basePackages = "com.acme.myproject",
  excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = MasterConfig.class))
public class MasterTestConfig {
// something else
}

Code speaks for itself – we have the same component scan – but excluding production config. And omitting scheduling, and possibly doing something else in the body of the config. We may read different properties (using annotations), etc.

This works, but can we somehow streamline it? Yes we can…

ConfigurationMaster annotation

I hope I’m not reinventing wheel here, but my solution was ultra-simple and it not only made me happy, but it just plain underlines the beauty of Java Configuration. It is ConfigurationMaster annotation that looks like this:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Configuration
@ComponentScan(basePackages = "com.acme.myproject",
    excludeFilters = {@ComponentScan.Filter(value = ConfigurationMaster.class)})
public @interface ConfigurationMaster {
}

This time we excluded classes annotated by… whow isn’t it a bit self-centered? 🙂 Yup, probably the most egocentric annotation I created. You place this annotation over any “entry-point” configuration you want to load in your bootstrap code. Other configurations for your other project components are auto-discovered (it’s up to you to keep only necessary stuff in your classpath). And should it happen you want alternative configurations, you just mark them as @ConfigurationMaster as well.

Annotation is part of the project – you see the base package for component scan there. Of course it is not universal solution to everything, but it works for many cases. Our previous configurations would now look like this – first the production one:

@ConfigurationMaster
@EnableScheduling
public class MasterConfig {
// something may be here
}

And the test one:

@ConfigurationMaster
public class MasterTestConfig {
// something else
}

It may be unlikely you want to have many master configurations in main code, but it is quite expected in test code. At least I have one for automatic tests and then some to run my application in development mode. This can use different property files (can be loaded from test scope and have different name explicitly stating they are test properties), different bean implementations – or (don’t tell anyone) hardcoded JDBC URL/username/passwords. The point is – only the one you bootstrap apply – other master configs are excluded.

Don’t know how about you, but I love this Java Configuration stuff. I may encounter new problems of course, but at least it’s really fun. You can even actually debug how it loads your configuration!

Advertisements

About virgo47
Java Developer by profession in the first place. Gamer and amateur musician. And father too. Naive believer in brighter future. Step by step.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s