Home » Java » Enterprise Java » Spring vs Guice: The one critical difference that matters

About Joonas Javanainen

Joonas is a passionate software developer from Finland. He has worked on a multitude of problem domains, and focuses professionally on functional programming and JVM-based technologies.

Spring vs Guice: The one critical difference that matters

Spring objects are recognized based on their names
It doesn’t matter whether you use XML or Java config, a Spring scope is roughly like a Map<String, Object> structure. This means that you cannot have two objects with the same name. Why is this a bad thing? If you have a large application with lots of @Configuration classes or XML files, it’s very easy to accidentally use the same name twice.
The worst part of this is that using the same with several objects, they silently override each other until only one actually remains in the ApplicationContext. These objects can also be of different types and the declaration order is what really determines which object wins. The problem here is that if you want to make reusable modules based on Spring, you will basically be forced to use a prefix in the name or something else to ensure you won’t have a name clash.
Guice objects are recognized based on their classes
A Guice scope is basically like a Map<Class<?>, Object> structure. This means that you cannot have two objects of the same type without using extra metadata (e.g. qualifiers). This design choice has different pros and cons, but overall I think it’s the saner one. If you create reusable modules, you mostly have to make sure that you don’t export any objects of common types (e.g. String). With type-based scopes you can always create a wrapped class for common types, while with name-based scopes you would always have to use unique names based on lucky guesses. Guice also has PrivateModules so you can use Guice for all injection, but only export some of the objects in the scope.  
Example code
Here’s a naive example of a Spring application that breaks runtime because of silent bean overriding. 

Main.java

This class instantiates the application context, registers the configuration classes and tries to get a MyBean from the context.

package springbreak;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
  public static void main(String[] args) {
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();

    ctx.register(GoodConfig.class);
    ctx.register(EvilConfig.class);

    ctx.refresh();
    ctx.start();

    System.out.println(ctx.getBean(MyBean.class).getValue());

    ctx.stop();
  }
}

MyBean.java

This is just an example type of bean that we expect to get from the application context.

package springbreak;

public interface MyBean {
  String getValue();
}

GoodConfig.java

This is a configuration class that exports a MyBean

package springbreak;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class GoodConfig {

  private static class MyBeanImpl implements MyBean {
    public String getValue() {
      return "I'm a bean";
    }
  }

  @Bean
  public MyBean myBean() {
    return new MyBeanImpl();
  }

}

EvilConfig.java

This configuration class exports a String with the name myBean. It’s not a very realistic example but shows the basic idea.

package springbreak;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class EvilConfig {

  @Bean
  public String myBean() {
    return "I'm a string!";
  }

}
Analyzing the example
Can you guess what happens when you run the example? Here’s the basic idea:
  1. GoodConfig exports a MyBeanImpl with the name “myBean”
  2. EvilConfig exports a String with the name “myBean” replacing the one from GoodConfig even though the types won’t match
  3. Main gets a NoSuchBeanDefinitionException “No unique bean of type [springbreak.MyBean] is defined”
    So, basically a MyBeanImpl is replaced by a String and there won’t be a bean that implements MyBean. The worst part is that if you reverse the @Configuration class registration order, the code will work because then a String will be replaced by a MyBeanImpl. Now, imagine you have 20 nicely encapsulated modules with potentially conflicting names…I’ve banged my head against the wall several times trying to debug problems in a situation like that.
    Spring (as of version 3.0.6) offers no possibility to alter the naming of @Configuration class exported beans. If you want to create safely reusable modules, you will have to use some kind of fully qualified names in the methods that export beans (e.g goodConfigMyBean, evilConfigMyBean).
    I like Spring (especially non-DI-container parts), but in new projects I will refuse to use a library that is so fundamentally broken. And yes, using the same name twice is a developer error, but any library that is prone to such errors can be considered worse than an alternative that attempts to minimize them.

    Reference: Spring vs Guice: The one critical difference that matters from our JCG partner Joonas Javanainen at the Jawsy Solutions technical blog blog.

    Do you want to know how to develop your skillset to become a Java Rockstar?

    Subscribe to our newsletter to start Rocking right now!

    To get you started we give you our best selling eBooks for FREE!

    1. JPA Mini Book

    2. JVM Troubleshooting Guide

    3. JUnit Tutorial for Unit Testing

    4. Java Annotations Tutorial

    5. Java Interview Questions

    6. Spring Interview Questions

    7. Android UI Design

    and many more ....

    4 comments

    1. Interesting take, I have to say while I was reading my immediate reaction was that the Guice way was inferior. I have existing Spring projects that re-use the same class with different parameters – sounds like that would be difficult with Guice (or perhaps I misunderstand). As to the supposed scoping nightmare, Java already has to deal with it and does so with packages; there’s no reason one couldn’t do the same in the Spring context. So your concern seems overblown.

      But like I said that is my first reaction and I haven’t had the same experience as you have with Spring name conflicts.

    2. “Spring (as of version 3.0.6) offers no possibility to alter the naming of @Configuration class exported beans.”

      Even with version 3.0.6, you can alter the name with the “name” attribute of bean annotation:

      @Bean(name={“b1″”}) // bean available as ‘b1′, but not ‘myBean’
      public MyBean myBean() {
      // instantiate and configure MyBean obj
      return obj;
      }

    3. I wonder why Spring doesn’t have an option to blow up (by default) when it encounters duplicate declarations. Failing fast at runtime would be preferable to this situation.

    4. Funny thing is this “overwriting” is actually a very very positive feature that really helps developers and devops in many ways. Ways to overwrite the default database properties of the datasource so that I can have my own config that points to my local database instead. Sometimes you get a Third party jar with a Spring configuration where you want all 100 beans they have defined, except you need to overwrite one of them to use an implementation you created. I don’t want to have to figure a way around that.

      I have a huge list of reasons why this is the preferred way, and I know that the Spring folks (Yes, I did work for them for 6 months) is that they thoroughly thought this through and came to the same conclusion that overwriting offers way more benefits than not allowing it.

      But as the author wrote, it can get you into trouble too. Which is why there are naming conventions in Spring for bean names. Coding to interfaces contract. And why your developers really need to know the code and what will become beans. I also feel that xml can bring this type of problem more so than using Annotations for configuration.

      Mark

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    *


    two × = 18

    You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

    Do you want to know how to develop your skillset and become a ...

    Subscribe to our newsletter to start Rocking right now!

    To get you started we give you our best selling eBooks for FREE!
    Get ready to Rock!
    To download the books, please verify your email address by following the instructions found on the email we just sent you.

    THANK YOU!

    Close