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();
....
}
}