'Why are singleton beans created twice in Spring?
I have a spring-boot project that contains a BookMapper
bean:
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface BookMapper {
// some CRUD methods here...
}
The bean is created by mybatis
, and it's a Singleton
. Usually, I use the bean with @Autowired
:
@Service
public BookService {
@Autowired
private BookMapper bookMapper;
}
I also have a file like this:
@Component
public class BeanUtil implements ApplicationContextAware {
private static ApplicationContext ac;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ac = applicationContext;
}
public static <T> T getBean(Class<T> clazz){
return ac.getBean(clazz);
}
public static <T> T getBean(String name, Class<T> clazz){
return ac.getBean(name, clazz);
}
}
Sometimes I just fetch the bean using the BeanUtil
class:
BookMapper bookMapper = BeanUtil.getBean(BookMapper.class);
That is convenient because I can get a bean from a static method.
Now the problem is, when I run integration tests, I find that BookMapper
fetched using the above two ways (@Autowired
and BeanUtil
) are sometimes different (and they are sometimes the same, I cannot reproduce the problem). Why? It shouldn't happen because BookMapper
is a Singleton
. Is there a possible reason for it?
Solution 1:[1]
I have kind of similar problem.
In my case beens are created multiple times because couple of tests have different configuration (different profiles, or overriding bean with mock) so when running all integration tests spring context is started multiple times
You have static ApplicationContext ac
in BeanUtil
so spring may creates different BeanUtil
durring creating new context but they store ApplicationContext
in static
so there may be some wierd interactions between those contexts
Solution 2:[2]
After debugging for a long time, I found out the reason. I use @MockBean
in my test. In this case, spring-test
will create a second ApplicationContext
, which is different from the one used by BeanUtil
in my question's code. When you have two contexts, you will have two beans for each class.
I'm not a heavy user of @MockBean
, so I just remove it for now, then the problem disappeared.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Searene |