Like many java projects these days, we use Spring in Outbrain for configuring our java dependencies wiring. Spring is a technology that started in order to solve a common, yet not so simple, issue – wiring all the dependencies in a java project. This was done by utilizing the IoC (Inversion of Control) principles. Today Spring does a lot more than just wiring and bootstrapping, but in this post I will focus mainly on that.
When Spring just started, the only way to configure the wirings of an application, was to use XMLs which defined the dependencies between different beans. As Spring had continued to develop, 2 more methods were added to configure dependencies – the annotation method and the @Configuration method. In Outbrain we use XML configuration. I found this method has a lot of pain points which I found remedy to using spring @Configuration
What is this @Configuration class?
You can think of a @Configuration class just like XML definitions, only defined by code. Using code instead of XMLs allows some advantages over XMLs which made me switch to this method:
- No typos – You can’t have a typo in code. The code just won’t compile
- Compile time check (fail fast) – With XMLs it’s possible to add an argument to a bean’s constructor but to forget to inject this argument when defining the bean in the XML. Again, this can’t happen with code. The code just won’t compile
- IDE features come for free – Using code allows you to find usages of the bean’s constructor to find out easily the contexts that use it; It allows you to jump back and forth between beans definitions and basically everything you can do with code, you get for free.
- Feature flags – In Outbrain we use feature-flags a lot. Due to the continuous-deployment culture of the company, a code that is pushed to the trunk can find itself in production in a matter of minutes. Sometimes, when developing features, we use feature flags to enable/disable certain features. This is pretty easy to do by defining 2 different implementations to the same interface and decide which one to load according to the flag. When using XMLs we had to use the alias feature which makes it not intuitive enough to create feature-flags. With @Configuration, we can create a simple if clause for choosing the right implementation.
Our example case
Step 1: Migrate <beans> to @Configuration
Step 2: Create a method for each Bean
A few things to notice:
- Each method is defined to return an interface type. In the method body we create the concrete class.
- The name that’s defined in the @Bean annotation is the same as the id that is defined in the XML for the beans.
- The bean anotherBean is injected with someBean in the XML. In the scenario here, we just call the getSomeClass() method. This doesn’t create another bean, this just uses the bean someBean (the same as it was in the XML).
We notice that we’re missing the property someInterestingProperty and the bean beanFromSomewhereElse.
Step 3: Import other XMLs or other @Configuration classes
If this bean resides in another @Configuration class you can use a different annotation @Import to import it:
In order to complete the picture, here’s how you can import a @Configuration class from an XML configuration file:
<context:annotation-config/> <bean class="some.package.ByeXmlApplicationContext"/>
The <context:annotation-config/> needs to be defined once in the context in order to make spring aware to @Configuration classes
Step 4: Import beans from other XMLs (or @Configuration class, or @Component etc… classes)
I usually prefer the first method as it is less verbose. But of course, that’s just a matter of taste.
Just remember – the beans you import must be loaded to the application context – either by @Import or @ImportResource from this class, or using any other method from anywhere else (XML, @Configuration or annotations).
Step 5: Import properties
Step 6: Import @Configuration from web.xml
- Split to different @Configuration classes and don’t put all of your beans in one class
- Give meaningful names and even decide on a naming convention
- Avoid any logic inside the @Configuration classes. Aside maybe for things like feature-flags.
This post is based on a tech-talk I gave in Outbrain. You can find the slides here.
You can find it also in my personal blog
Find me on Twitter: @AviEtzioni