Using the @Configuration annotation

Dev.Hammy·2024년 2월 24일
0

@Configuration은 객체가 Bean 정의의 소스임을 나타내는 클래스 수준 어노테이션입니다. @Configuration 클래스는 @Bean 어노테이션이 달린 메소드를 통해 Bean을 선언합니다. @Configuration 클래스의 @Bean 메소드에 대한 호출은 Bean 간 종속성을 정의하는 데 사용될 수도 있습니다. 일반적인 소개는 기본 개념: @Bean@Configuration을 참조하세요.

Injecting inter-bean Dependenncies

Bean이 서로 종속성을 갖는 경우 해당 종속성을 표현하는 것은 다음 예제와 같이 하나의 Bean 메소드가 다른 Bean 메소드를 호출하는 것만큼 간단합니다.

@Configuration
public class AppConfig {

	@Bean
	public BeanOne beanOne() {
		return new BeanOne(beanTwo());
	}

	@Bean
	public BeanTwo beanTwo() {
		return new BeanTwo();
	}
}

앞의 예제에서 beanOne은 생성자 주입을 통해 beanTwo에 대한 참조를 받습니다.

[Note]
bean 간 종속성을 선언하는 이 방법은 @Bean 메서드가 @Configuration 클래스 내에서 선언된 경우에만 작동합니다. 일반 @Component 클래스를 사용하여 Bean 간 종속성을 선언할 수 없습니다.

Lookup Method Injection

앞서 언급했듯이 lookup 메서드 주입은 거의 사용하지 않는 고급 기능입니다. 이는 싱글톤 범위의 Bean이 프로토타입 범위의 Bean에 종속되는 경우에 유용합니다. 이러한 타입의 구성에 Java를 사용하면 이 패턴을 구현하기 위한 자연스러운 수단이 제공됩니다. 다음 예에서는 조회 메서드 주입을 사용하는 방법을 보여줍니다.

public abstract class CommandManager {
	public Object process(Object commandState) {
		// grab a new instance of the appropriate Command interface
		Command command = createCommand();
		// set the state on the (hopefully brand new) Command instance
		command.setState(commandState);
		return command.execute();
	}

	// okay... but where is the implementation of this method?
	protected abstract Command createCommand();
}

Java 구성(configuration)을 사용하면 추상 createCommand() 메서드가 새(프로토타입) 명령 객체를 찾는 방식으로 재정의되는 CommandManager의 하위 클래스를 만들 수 있습니다. 다음 예에서는 그 방법을 보여줍니다.

@Bean
@Scope("prototype")
public AsyncCommand asyncCommand() {
	AsyncCommand command = new AsyncCommand();
	// inject dependencies here as required
	return command;
}

@Bean
public CommandManager commandManager() {
	// return new anonymous implementation of CommandManager with createCommand()
	// overridden to return a new prototype Command object
	return new CommandManager() {
		protected Command createCommand() {
			return asyncCommand();
		}
	}
}

Further Information About How java-based Configuration Works Internally

@Bean 어노테이션이 달린 메서드가 두 번 호출되는 것을 보여주는 다음 예제를 고려해보세요.

@Configuration
public class AppConfig {

	@Bean
	public ClientService clientService1() {
		ClientServiceImpl clientService = new ClientServiceImpl();
		clientService.setClientDao(clientDao());
		return clientService;
	}

	@Bean
	public ClientService clientService2() {
		ClientServiceImpl clientService = new ClientServiceImpl();
		clientService.setClientDao(clientDao());
		return clientService;
	}

	@Bean
	public ClientDao clientDao() {
		return new ClientDaoImpl();
	}
}

clientDao()clientService1()에서 한 번, clientService2()에서 한 번 호출되었습니다. 이 메소드는 ClientDaoImpl의 새 인스턴스를 생성하고 이를 반환하므로 일반적으로 두 개의 인스턴스(각 서비스당 하나씩)가 있을 것으로 예상합니다. 그것은 분명히 문제가 될 것(problematic)입니다. Spring에서 인스턴스화된 Bean은 기본적으로 singleton 범위를 갖습니다. 이것이 마법이 일어나는 곳입니다. 모든 @Configuration 클래스는 시작 시 CGLIB를 사용하여 하위 클래스로 분류됩니다. 서브클래스에서 하위 메소드는 상위 메소드를 호출하고 새 인스턴스를 생성하기 전에 먼저 컨테이너에서 캐시된(범위가 지정된) Bean을 확인합니다.

[Note]
Bean의 범위에 따라 동작이 다를 수 있습니다. 여기서는 싱글톤에 대해 이야기하고 있습니다.

[Note]
CGLIB 클래스는 org.springframework.cglib 패키지 아래에 다시 패키지되고 spring-core JAR 내에 직접 포함되므로 클래스패스에 CGLIB를 추가할 필요가 없습니다.

[Tip]
CGLIB가 시작 시 기능을 동적으로 추가한다는 사실로 인해 몇 가지 제한 사항이 있습니다. 특히 구성 클래스는 final 클래스가 아니어야 합니다. 그러나 @Autowired 사용이나 기본 주입을 위한 non-default 단일 생성자 선언을 포함하여 구성 클래스에서는 모든 생성자가 허용됩니다.

CGLIB에 의해 부과된 제한을 피하려면 @Configuration이 아닌 클래스(예: 일반 @Component 클래스)에서 @Bean 메서드를 선언하거나 구성 클래스에 @Configuration(proxyBeanMethods = false) 어노테이션을 추가하는 것을 고려하세요. @Bean 메서드 간의 메서드 간 호출은 가로채지 않으므로 생성자 또는 메서드 수준에서 종속성 주입에만 의존해야 합니다.

0개의 댓글