Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to write a Guice-like module in Spring Framework with Java configuration?

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.

like image 280
Cal Avatar asked Sep 08 '15 02:09

Cal


2 Answers

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.

like image 110
Alex Barnes Avatar answered Nov 07 '22 06:11

Alex Barnes


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)

like image 40
leeor Avatar answered Nov 07 '22 08:11

leeor