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.
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
/@Autowir
e DataSource
where you need it.
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
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With