(타협) Spring IoC 컨테이너 추가 + 빈 이름 추론 문제해결

Jang990·2026년 3월 26일

타협하기

Spring IoC 컨테이너를 만드는 과정이 쉽진 않을 것 같다.

빈을 생성해야하고, Autowired 같이 빈이 필요한 부분에 직접 주입을 해주어야하고,
의존성 루프가 발생할 때는 오류를 일으키고 등등 꽤나 해야할 일이 많아보인다.

그래서 Spring IoC 컨테이너는 Spring을 그대로 가져와서 사용하기로 했다.

Spring IoC 의존성 추가

build.gradle에 다음 의존성을 추가했다.

	/* Spring IoC 컨테이너 + Mockito 테스트를 위한 의존성 추가 */
	
    // @Bean, @Configuration, @Component, @Service, @Repository 등등
	implementation 'org.springframework:spring-context:6.1.5'
	
    // Spring Test (ApplicationContext 로딩, @ExtendWith 등)
	testImplementation 'org.springframework:spring-test:6.1.5'
	
    // Mockito
	testImplementation 'org.mockito:mockito-core:5.11.0'
    
	/* ****************************************************** */

IoC 컨테이너 적용하기

2가지 파일을 추가했다.

  • AppConfig: IoC 컨테이너에 등록할 빈들을 설정하는 파일
  • MySpringServerApplication: Spring IoC 컨테이너가 돌아갈 Main 파일
// 의미있는 최상위 패키지를 basePackages로 설정했다.
@Configuration
@ComponentScan(basePackages = "com.example.my_spring_server")
public class AppConfig {
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MySpringServerApplication {

	public static void main(String[] args) {
		ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

		System.out.println("Hello World");
	}

}

이제 내가 만든 클래스들을 Bean으로 등록하면 된다.

오류 (빈 충돌)

Bean을 등록하는 과정에서 이런 오류가 발생했다.

WARNING: ...
'myTransactionManager' defined in file [C:\...\MyTransactionManager.class]:
Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'com.example.my_spring_server.my.datasource.MyDataSource' available: 
expected single matching bean but found 2: driverManagerDataSource,myTransactionAwareDataSourceProxy

문제의 코드

@Component
public class MyTransactionManager {
    private final MyDataSource myDataSource;

    public MyTransactionManager(MyDataSource myDataSource) {
        this.myDataSource = myDataSource;
    }
    
    ...
}

해당 클래스에서 오류가 발생했는데
내가 만든 MyDataSource에는 2가지 구현체가 있었기 때문이다.

public interface MyDataSource {
    Connection getConnection() throws SQLException;
}

@Component
public class DriverManagerDataSource implements MyDataSource {
	// DriverManager.getConnection 사용 구현체
}

@Component
public class MyTransactionAwareDataSourceProxy implements MyDataSource {
	// 트랜잭션 + 커넥션 관리 구현체
}

해결방법

사용하고 싶은 빈이 정확하게 들어갈 수 있도록 설정해 주면된다.

SpringBoot 3.2.x부터는 파라미터명 추론을 지원하지 않는다.

기존에 Spring에서 .class 파일을 직접 뒤져서 파라미터명 추론해주는 구현체가 제거됐다. (성능 저하 + 쓰임 없음)
그래서 파라미터명을 찾는데 기본 JDK의 리플렉션을 사용해서, 파라미터명 추론을 할 수 없어진 것이다.
자세한 원인 분석은 다음 글을 참고하자.
참고) https://jtechtalk.tistory.com/38

SpringBoot 3.2.x 이전 버전에서 파라미터로 받는 변수명과 빈 이름을 맞추면,
알아서 주입이 됐지만 현재 버전에선 약간의 추가적인 설정이 필요하다.

결과적으로 3가지 해결방법이 있다.

1. Qualifier 사용

@Component
public class MyTransactionManager {
    private final MyDataSource myDataSource;
    //
    public MyTransactionManager(
            @Qualifier("myTransactionAwareDataSourceProxy") // 추가
            MyDataSource myDataSource
    ) {
        this.myDataSource = myDataSource;
    }
    ...
}

단순한 해결방법이지만 충돌이 발생할 수 있는 모든 주입에 설정해줘야 한다.

2. gradle로 빌드하기

설정에서 빌드 및 실행을 Gradle로 설정해야한다.

@Component
public class MyTransactionManager {
    private final MyDataSource myDataSource;
	//
    public MyTransactionManager(
            MyDataSource myTransactionAwareDataSourceProxy
    ) {
        this.myDataSource = myTransactionAwareDataSourceProxy;
    }
}
// gradle.build에 코드 추가
tasks.withType(JavaCompile).configureEach {
    // getParameterNames() 사용을 위한 설정
    options.compilerArgs.add("-parameters")
}

3. 인텔리제이로 빌드하기

3번 방식을 사용했을 때 오류가 그대로였다.
out 폴더를 제거하고 다시하면 된다는 글도 봤던거 같은데
그냥 2번 방식을 권장한다고 해서 그냥 2번 방식으로 해결했다.

참고) 인프런 - 토비 스프링, Springboot 3.2 이상에서 파라미터 추론관련 질문

profile
개발 기록 아카이브

0개의 댓글