In a Spring Boot project, we access our non managed DAO classes through a static method:
MyDao myDao = DaoProvider.getMyDao();
We use this in Spring managed @Service classes:
@Service
public class MyService {
public void foo() {
MyDao myDao = DaoProvider.getMyDao();
myDao.bar();
....
}
}
This makes it hard to write unit tests. Static mocks are no option, because they are slowing down our build pipeline.
We would rather have a solution with @Autowired or constructor dependency and some kind of configuration, that decides which class to inject:
@Service
public class MyService {
@Autowired
MyDao myDao;
public void foo() {
myDao.bar();
....
}
}
Obviously, someone has to tell Spring what class to inject, is there a way to do so?:
public class NonManagedSpringInjectionConfiguration {
@Bean
MyDao getMyDao() {
return DaoProvider.getMyDao();
}
}
CodePudding user response:
You just have to specify the profil for example :
@Configuration
public class NonManagedSpringInjectionConfiguration {
@Bean
@Profile("dev")
MyDao getMyDao() {
return DaoProvider.getMyDao();
}
}
CodePudding user response:
Option 1
If you don't want to turn your MyDao into a Spring-managed Bean, your simpler and probably best option is to instead create the MyService Spring-managed Bean programmatically instead of relying on @Service annotation. First, just remove @Service from MyService and adjust its constructor to accept MyDao:
public class MyService {
MyDao myDao;
public MyService(MyDao myDao) {
this.myDao = myDao;
}
public void foo() {
myDao.bar();
....
}
}
And now you just need to register a MyService bean using @Bean in a Configuration class as follows:
@Configuration
public class WhateverConfiguration {
@Bean
MyService myService() {
return new MyService(DaoProvider.getMyDao());
}
}
Option 2
If instead there is a possibility to make MyDao a Spring-managed Bean, then just keep your NonManagedSpringInjectionConfiguration as is:
@Configuration
public class NonManagedSpringInjectionConfiguration {
@Bean
MyDao getMyDao() {
return DaoProvider.getMyDao();
}
}
But then rely on constructor injection instead of on @Autowired. It makes MyService easier to unit test and also explicitly defines that MyDao is mandatory for MyService to work properly. In this case you would keep @Service and rely on Spring to instantiate it:
@Service
public class MyService {
MyDao myDao;
public MyService(MyDao myDao) {
this.myDao = myDao;
}
public void foo() {
myDao.bar();
....
}
}
