개요
Bean으로 등록한 객체의 타입이 같지만 다른 이름일 때, 스프링 컨테이너 객체인 ApplicationContext는 타입으로만 Bean을 탐색하려 하면 어떻게 될까를 보기 위해 테스트를 진행했다. 이때 중첩 클래스를 사용하여 진행했고, 실행 중 오류를 맛보게 되었다. 어떤 문제가 있을까?
본문
다음은 내가 작성한 코드이다.
// 변경 전
public class ApplicationContextSameBeanFindTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SameBeanConfig.class);
@Test
@DisplayName("타입으로 조회 시 같은 타입이 둘 이상 있으면, 중복 오류가 발생한다")
void findBeanByTypeDuplicate() {
ac.getBean(MemberRepository.class);
}
@Configuration
class SameBeanConfig {
@Bean
MemberRepository memberRepository1() {
return new MemoryMemberRepository();
}
@Bean
MemberRepository memberRepository2() {
return new MemoryMemberRepository();
}
}
}
기존에 정의한 Config 파일이 아닌 테스트용 Config 파일인 SameBeanConfig 클래스를 중첩 클래스로 테스트 클래스 내부에 정의했다. 그리고 이를 사용하여 필드를 초기화했는데 다음과 오류가 발생했다.
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'applicationContextSameBeanFindTest.SameBeanConfig': Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'basic.core.beanfind.ApplicationContextSameBeanFindTest' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:798)
at
.....
정리하면 중첩 클래스는 외부에 있는 클래스에 종속된다. 때문에 외부 클래스가 인스턴스화가 되지 않았다면 이를 외부 클래스의 인스턴스 메서드에서 사용할 수 없다. 결국 필드를 초기화하는 것도 생성자에서 초기화하는 것이라 가정하면 이도 인스턴스 메서드로 사용하는 것이기 때문에 사용 불가능하다.
하지만 할 수 있는 방법이 있다. 가능하도록 하려면 내부 class를 static으로 변경하면 된다. static으로 중첩 클래스를 선언하면 이는 외부 클래스가 인스턴스가 되지 않아도 된다. 말 그대로 정적으로 사용할 수 있는 존재가 되는 것이다.
결론
중첩 클래스(Nested class)를 필드나 메서드에서 사용하기 위해선 외부 클래스가 인스턴스가 먼저 되어야 하고, 이것이 컴파일 시부터 정해져야 하는데 이것이 불가능하므로 내부 클래스는 static 클래스로 선언해야 한다.
// 변경 후
public class ApplicationContextSameBeanFindTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SameBeanConfig.class);
@Test
@DisplayName("타입으로 조회 시 같은 타입이 둘 이상 있으면, 중복 오류가 발생한다")
void findBeanByTypeDuplicate() {
ac.getBean(MemberRepository.class);
}
// static이 추가됨.
@Configuration
static class SameBeanConfig {
@Bean
MemberRepository memberRepository1() {
return new MemoryMemberRepository();
}
@Bean
MemberRepository memberRepository2() {
return new MemoryMemberRepository();
}
}
}
'JAVA' 카테고리의 다른 글
JAVA의 enum에 대한 고찰 (4) | 2024.02.11 |
---|
개요
Bean으로 등록한 객체의 타입이 같지만 다른 이름일 때, 스프링 컨테이너 객체인 ApplicationContext는 타입으로만 Bean을 탐색하려 하면 어떻게 될까를 보기 위해 테스트를 진행했다. 이때 중첩 클래스를 사용하여 진행했고, 실행 중 오류를 맛보게 되었다. 어떤 문제가 있을까?
본문
다음은 내가 작성한 코드이다.
// 변경 전
public class ApplicationContextSameBeanFindTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SameBeanConfig.class);
@Test
@DisplayName("타입으로 조회 시 같은 타입이 둘 이상 있으면, 중복 오류가 발생한다")
void findBeanByTypeDuplicate() {
ac.getBean(MemberRepository.class);
}
@Configuration
class SameBeanConfig {
@Bean
MemberRepository memberRepository1() {
return new MemoryMemberRepository();
}
@Bean
MemberRepository memberRepository2() {
return new MemoryMemberRepository();
}
}
}
기존에 정의한 Config 파일이 아닌 테스트용 Config 파일인 SameBeanConfig 클래스를 중첩 클래스로 테스트 클래스 내부에 정의했다. 그리고 이를 사용하여 필드를 초기화했는데 다음과 오류가 발생했다.
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'applicationContextSameBeanFindTest.SameBeanConfig': Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'basic.core.beanfind.ApplicationContextSameBeanFindTest' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:798)
at
.....
정리하면 중첩 클래스는 외부에 있는 클래스에 종속된다. 때문에 외부 클래스가 인스턴스화가 되지 않았다면 이를 외부 클래스의 인스턴스 메서드에서 사용할 수 없다. 결국 필드를 초기화하는 것도 생성자에서 초기화하는 것이라 가정하면 이도 인스턴스 메서드로 사용하는 것이기 때문에 사용 불가능하다.
하지만 할 수 있는 방법이 있다. 가능하도록 하려면 내부 class를 static으로 변경하면 된다. static으로 중첩 클래스를 선언하면 이는 외부 클래스가 인스턴스가 되지 않아도 된다. 말 그대로 정적으로 사용할 수 있는 존재가 되는 것이다.
결론
중첩 클래스(Nested class)를 필드나 메서드에서 사용하기 위해선 외부 클래스가 인스턴스가 먼저 되어야 하고, 이것이 컴파일 시부터 정해져야 하는데 이것이 불가능하므로 내부 클래스는 static 클래스로 선언해야 한다.
// 변경 후
public class ApplicationContextSameBeanFindTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SameBeanConfig.class);
@Test
@DisplayName("타입으로 조회 시 같은 타입이 둘 이상 있으면, 중복 오류가 발생한다")
void findBeanByTypeDuplicate() {
ac.getBean(MemberRepository.class);
}
// static이 추가됨.
@Configuration
static class SameBeanConfig {
@Bean
MemberRepository memberRepository1() {
return new MemoryMemberRepository();
}
@Bean
MemberRepository memberRepository2() {
return new MemoryMemberRepository();
}
}
}
'JAVA' 카테고리의 다른 글
JAVA의 enum에 대한 고찰 (4) | 2024.02.11 |
---|