Dependency Injection Container Shootout

Posted by Uwe Schaefer on Tue, Mar 8, 2016
In: Java
Tags: spring guice di dependency injection container

Aesthetics

I love Guice – always did. A tiny little lib doing one thing right!

This probably is the primary reason why i ignored Spring for the last 7 years.

There are plenty more, though:

  • Spring’s xml heritage is disgusting to say the least
  • The quality of available spring-ish modules differs
  • It lacks a compact definition of Beans (Bindings) from java
  • It drags you into the Spring Universe, as bloated as it seems, so that one day, you may even find yourself using spring-data etc.

So, as my boss put it, i ignored spring for aesthetic reasons.

Recently i took another look at Spring. I did not spend a lot of time, so forgive me if i am just stating the obvious and correct me where i am wrong.


Bindings compared

Guice
bind(Foo.class).to(FooImpl.class);
Spring
@Bean public Foo createSomeFoo(SomeRequestId reqId){
	return new FooImpl();
} 

Looks like the provider Method approach is the only reasonable way to define Beans programmatically – Hell, that’s a lot of unnecessary boilerplate.

I do not say, it is impossible to do in Spring, but sadly, it involves lots and lots of hoop-jumping ending up in much more boilerplate compared to a provider method.


Stupid Defaults

There are some defaults, i donot agree with. Sometimes unconventient, sometimes plain wrong. Here is a taste:

Singletons

Guice
bind(Foo.class).to(FooImpl.class);

creates a new FooImpl every time it needs to inject one, whereas

Spring
@Bean public Foo create(){
	return new FooImpl();
} 

declares a singleton. Did I mention that the singleton pattern is the one most harmful pattern you can find in the GOF Book, as it obviously creates global state in your software? (Where contention is the smallest of your concerns) 1 2 3


Weird automatic MultiBindings

Here’s a quiz:

@Configuration
public class N {
	public static void main(String[] args) {
		SpringApplication.run(N.class).getBean(N.class).check();
	}

	interface I {}
	class A implements I {}
	class B implements I {}
	class C implements I {}

	@Autowired
	List<I> l;

	@Bean
	List<I> createL() { return Arrays.asList( (I) new C() ); }

	@Bean
	I createA() { return new A(); }

	@Bean
	I createB() { return new B(); }

	private void check() {
		for (Object o : l) {
			System.out.println(o.getClass());
		}
	}
}

Turns out, that the Output of the above is

class x.N$A
class x.N$B

where every sane person would probably expect N$C as the list is explicitly bound.

And even if you’d create a multibinding, best you can do is a Set instead of a List, because the beans have no particular order (as they might come from different configuration classes), or have they?


There are some more WTFs in the core Spring DI Engine, at least when you come from Guice. So comparing these two as DI Containers, clearly Guice wins single-handed.

To conclude, the DI Engine is not why i switched my focus from Guice to Spring. But that is enough meat for another blog post.