프로젝트 내 개발 진행 중 발생한 에러인데 아직 명확한 해결책은 나지 않았지만 우선 정리해 둔다.
@Autowired private GenericDao<Map<String, Object>> dao;
@Autowired private SampleListDao<Map<String, Object>> sampleListDao; |
우선 소스코드에 위와 같이 선언하여 service 구현체에 dao를 가져다 쓰려했다. 서버를 구동시키자 아래와 같은 에러가 떨어졌다.
1) 에러 메세지
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [xxx.orm.mybatis.GenericDao] is defined: expected single matching bean but found 2: sampleListDao,genericDao at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:172) |
- 확인해보니, 찾으려는 bean에대해 한 개 이상의 bean이 존재하여 발생하는 에러였다.
- 에러에 대해 알아보기 위해 GenericDao와 SampleListDao 소스에 각각 들어가 살펴보았다.
GenericDao는 SqlSessionDaoSupport를 extends 한 class 였고, SampleListDao는 그 GenericDao를 extends하고 있는 class였다. (내가 그렇게 만듬...ㅎ)
2) 원인
- @Autowired로 주입하고 있기 때문에 Type을 검색하여 연결하는데, SampleListDao와 GenericDao의 생성 type이 결국 조상 class인
SqlSessionDaoSupport로 type이 같기 때문에 @Autowired가 누굴 찾아 주입해야하는지 명확히 알 수 없기 때문이다.
이러한 경우 name 을 주어 어떤 bean을 주입할 지 결정해주곤 한다.
- 그래서 아, name 으로 구분하면 되겠네 하고 name을 주어 @Resource로 빈 주입을 시도했다.
- 하지만 예상과 다르게 계속 같은 에러가 발생했다....충격
음 아직 명확한 답은 모르겠으나, 'extends' 가 문제인 것 같다. SampleListDao가 SqlSessionDaoSupport를 extends 하여 맨위와 같이 선언하면
문제없이 돌아간다. (참고로 SqlSessionDaoSupport는 abstract class)
- SqlSessionDaoSupport를 extends 하면 name 기반으로도 주입이 잘 된다.
3) 해결
- 명확한 해결방법은 좀 더 연구해보아야 할 것 같다... 자료도 더 찾아보고
4) 보충 자료
먼저 @Autowired 와 @Resource.
@Autowired 와 @Resource는 모두 의존관계를 자동으로 주입하기 위한 설정이다.
비슷한 기능을 하지만 약간의 차이가 존재하는데, 이 둘의 차이점은 아래와 같다.
@Autowired |
@Resource |
|
공통점 |
의존관계를 자동으로 주입하기 위한 설정 |
|
차이점1: 지원 | Spring Framework | Java |
차이점2: 검색 | bean의 Type으로 검색하여 의존성 주입 | bean의 Name으로 검색하여 의존성 주입 |
옵션 | @Autowired는 타입을 이용해서 자동적으로 값을 설정하기때문에 해당 타입의 빈 객체가 존재하지 않거나 또는 2개이상 존재할 경우 빈객체를 생성할때 예외를 발생시킨다.이 경우를 대비하여 @Autowired(required=false) 옵션을 설정할 수 있다. 해당 옵션을 설정하면 연결할 bean을 찾지 못해도 예외를 발생시키지 않는다. | name 속성을 이용하여 명시적으로 bean name을 줄 수 있다. |
단점 | type으로 검색하여 연결하기 때문에 같은 타입이 2개 이상 존재하는 경우, 예외가 발생한다. --> 보완: @Qualifier (동일한 type의 bean 객체들 중 name을 사용하여 특정 bean 을 연결하도록 설정 가능) |
- @Autowired는 spring에서 제공하는 annotation이기 때문에 spring을 쓰지 않고 다른 framework를 쓰는 경우
더이상 사용할 수 없다는 단점이 있다. 반면, @Resource는 JAVA에서 제공하는 annotation이기 때문에
framework에 관계없이 계속 사용할 수 있다는 장점이 있다.
- @Autowired는 생성 Type으로 연결하지만, @Resource는 name으로 연결하기 때문에 주입하려는 bean에 name을 설정해주어야 한다.
예를 들면,
@Service("sampleService") public class SampleServiceImpl implements SampleService { ... @Resource(name="sampleService") private SampleService sampleService; |
- 위의 예제와 같이 주입하려는 bean (@Service)에 name(sampleService)을 설정해주고 해당 bean을 가져다 쓰려는 곳에서
@Resource(name="sampleService") 로 검색하여 찾아 연결한다.
- @Qualifier는 @Autowired를 보완하기 위해 나온 annotation으로, 동일한 type의 빈 객체들 중 name을 기반으로 특정 빈을 사용할 수 있도록
설정해준다.
@Autowired @Qualifier("genericDao") private GenericDao<Map<String, Object>> dao;
@Autowired @Qualifier("sampleListDao") private SampleListDao<Map<String, Object>> sampleListDao; |
__________________________________________________________________________________________________________________________________________________________
** 본 포스팅에 대해 수정해야할 부분이나 추가 의견 등이 있으신 분들은 댓글 달아주세요. 언제나 환영입니다 :)
** 본 포스팅을 reference 자료로 참고하실 분들은 출처를 꼭 밝혀주시기 바랍니다.