@Configuration 클래스에서 @Bean 어노테이션을 사용한 메서드는 다른 Bean 에 의존하여 초기화될 수 있다.
쉽게 말해 @Bean 어노테이션이 사용된 메서드의 파라미터에 다른 Bean 을 주입하여 사용할 수 있다.
Spring 에서 @Bean 메서드 매개변수를 사용하여 Bean 종속성을 전달할 수 있는 메커니즘으로 인해 가능하다.
1. @Bean 메서드의 반환 타입별 주입
주입 대상 지점에 주입할 수 있는 Bean 인스턴스가 하나만 있는 경우 타입별로 성공적 주입된다.
아래는 예시 코드이다.
@Bean
public HikariDataSource dataSource1() {
return new HikariDataSource(hikariConfig());
}
@Bean
public HikariDataSource dataSource2() {
return new HikariDataSource(hikariConfig());
}
@Bean
public SqlSessionFactory sqlSessionFactory(HikariDataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:com/obo/mapper/xml/**/*.xml"));
return bean.getObject();
}
위 코드를 보면 특정 @Bean 어노테이션을 사용하는 메서드에서 매개변수로 주입을 하기 위해 @Bean 으로 등록된
HikariDataSource 매개변수로 받았다.
하지만 @Bean 으로 등록된 HikariDataSource 의 타입을 리턴하는 Bean 이 2개이기 때문에 에러가 발생한다.
에러 내용은 아래와 같다.
Description:
Parameter 0 of method sqlSessionFactory in com.obo.config.DBConfig required a single bean, but 2 were found:
- dataSource1: defined by method 'dataSource1' in class path resource [com/obo/config/DBConfig.class]
- dataSource2: defined by method 'dataSource2' in class path resource [com/obo/config/DBConfig.class]
This may be due to missing parameter name information
Action:
Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
Ensure that your compiler is configured to use the '-parameters' flag.
You may need to update both your build tool settings as well as your IDE.
(See https://github.com/spring-projects/spring-framework/wiki/Upgrading-to-Spring-Framework-6.x#parameter-name-retention)
정의된 메서드가 2개라면서 에러가 발생한다.
즉, 타입별 주입을 하기 위해선 @Bean 으로 등록된 메서드는 하나여야 타입별 주입을 할 수 있다.
2. @Bean 메서드의 이름별 주입
1번에서 나온 타입별 주입은 같은 타입의 메서드가 2개면 에러가 발생했다. 이 경우 Spring 은 어떤 인스턴스를 주입해야 할지
알 수 없다. @Bean 으로 등록된 메서드의 이름과 동일한 경우 주입은 이름으로 해결한다.
성공 코드
@Bean
public HikariDataSource dataSource1() {
return new HikariDataSource(hikariConfig());
}
@Bean
public HikariDataSource dataSource2() {
return new HikariDataSource(hikariConfig());
}
@Bean
public SqlSessionFactory sqlSessionFactory(HikariDataSource dataSource1) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource1);
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:com/obo/mapper/xml/**/*.xml"));
return bean.getObject();
}
3. @Qualifier 어노테이션을 사용한 매개변수 주입
@Qualifier 어노테션을 사용해서 Bean 의 이름과 일치하는걸로 주입한다.
@Bean
public HikariDataSource dataSource1() {
return new HikariDataSource(hikariConfig());
}
@Bean
public HikariDataSource dataSource2() {
return new HikariDataSource(hikariConfig());
}
@Bean
public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource1") HikariDataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:com/obo/mapper/xml/**/*.xml"));
return bean.getObject();
}
4. @Bean 메서드에 @Qualifier 를 사용하여 이름 지정
@Bean 메서드에 @Qualifier 어노테이션을 통해 Bean 이름을 지정하고 해당 이름을 불러 주입한다.
@Qualifier("datasourceTest")
@Bean
public HikariDataSource dataSource1() {
return new HikariDataSource(hikariConfig());
}
@Bean
public HikariDataSource dataSource2() {
return new HikariDataSource(hikariConfig());
}
@Bean
public SqlSessionFactory sqlSessionFactory(@Qualifier("datasourceTest") HikariDataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:com/obo/mapper/xml/**/*.xml"));
return bean.getObject();
}
위 소스를 보면 @Bean 메서드에 @Qualifier 어노테이션을 통해 Bean 이름을 지정했다.
지정한 이름을 메서드 매개변수에 @Qualifier("지정한 이름") 으로 호출하여 주입한다.