6

I was wondering if there was a sort of compromise that allowed you to emulate/leverage the Google Guice style EDSL way of writing modules which binds interfaces to implementations in Spring.

For example, say I had a Google Guice Module that looked like this:

public class BillingModule extends AbstractModule {
    protected void configure() {
        bind(BillingService.class).to(RealBillingService.class);
    }
}

This binds the BillingService interface to the RealBillingService implementation.

One way that I think I can do utilizing Spring's Java configuration class is something that looks like this

@Configuration
public class BillingConfiguration {
  @Bean
  public BillingService getRealBillingService() {
    return new RealBillingService();
  }
}

I was wondering if there was a better way to do this or if this broke down with increasingly complex usage.

I really like Google Guice and how it does Dependency Injection but that's kind of all it does. Spring does a lot more (yes, its dependency injection mechanism is still not 'as-nice' as Guice) but undeniably has some great projects that we would like to utilize like Spring Data, Spring Data REST, etc. which eliminate the need for writing a ton of boilerplate code.

durron597
  • 31,968
  • 17
  • 99
  • 158
Cal
  • 734
  • 1
  • 9
  • 25
  • 1
    You can check out [spring-guice](https://github.com/spring-projects/spring-guice). Though I can't find any evidence of it ever being released :-( – Paul Samsotha Sep 08 '15 at 14:07
  • @peeskillet It is a compromise to use both. But unfortunately this compromise creates confusion to for my poor colleagues ;-( – Cal Sep 09 '15 at 01:08
  • just for the reference, here is an opposite question spring profiles -> guice http://stackoverflow.com/questions/18112299/mimicking-spring-profiles-in-guice – Vad1mo Oct 11 '16 at 11:56
  • @PaulSamsotha As of December 2020, there have been a few releases of spring-guice: https://mvnrepository.com/artifact/org.springframework.guice/spring-guice – raner Dec 21 '20 at 01:39

2 Answers2

3

I've used both Guice and Spring a fair bit. As far as I know, the spring usage you show in the question is the only way to achieve the same as the binding in Guice with Spring. If you need to inject dependencies you can always include those as arguments to the @Bean method and have spring inject them for you.

It's definitely not as clean but it works the same way. One key thing to watch out for is that the default scope in spring is Singleton rather than a new instance every time (spring calls this scope prototype)

leeor
  • 17,041
  • 6
  • 34
  • 60
3

The way to do this is to use @Profile to include different implementations of the same interface.

A simple example would be DataSource. This can however easily be extended to any other interfaces with multiple implementations.

As an example:

@Configuration
public class LocalDataConfig {
@Bean
    public DataSource dataSource() {
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.HSQL)
            .addScript("classpath:com/bank/config/sql/schema.sql")
            .addScript("classpath:com/bank/config/sql/test-data.sql")
            .build();
    }
}

and then for use in production:

@Configuration
@Profile("production")
public class JndiDataConfig {

    @Bean
    public DataSource dataSource() throws Exception {
        Context ctx = new InitialContext();
        return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
    }

}

Then all you need to do is declare which profiles are active when you start your application context and @Inject/@Autowire DataSource where you need it.

Alex Barnes
  • 7,174
  • 1
  • 30
  • 50
  • 1
    Unfortunately, this answer does not address two important elements of the original question: (1) how to producing configurations in Spring programmatically (i.e., by calling binder methods as in Guice), and (2) how to put object creation firmly in the hands of the DI framework (an `@Bean` method that returns `new RealBillingService()` is still not the same as Guice's `bind(BillingService.class).to(RealBillingService.class)`, which does not involve creating any objects) – raner Dec 21 '20 at 01:45