자바 기반 설정의 가장 중요 애너테이션
@Configuration
@Bean
메서드가 Spring 컨테이너에서 관리할 새 객체를 인스턴스화, 구성 및 초기화한다는 것을 나타내는 데 사용된다.
// DependencyConfig 클래스
컨텍스트를 인스턴스화할 때
@Configuration
public class DependencyConfig {
@Bean
public MyService myService() {
return new MyServiceImpl();
}
}
애너테이션을 이용해 Config 클래스 설정하는 방법
Spring 3.0에 도입된 AnnotationConfigApplicationContext
ApplicationContext 구현은 아래와 같은 애너테이션이 달린 클래스로 파라미터를 전달 받고 있다.
@Configuration
클래스@Component
클래스@Configuration
클래스가 입력으로 제공되면 @Configuration
클래스 자체가 Bean
정의로 등록되고 클래스 내에서 선언된 모든 @Bean
메서드도 Bean
정의로 등록된다.
@Component
클래스와 JSR-330 클래스가 제공되면 빈 정의로 등록되며 필요한 경우 해당 클래스 내에서 @Autowired
또는 @Inject
와 같은 DI 메타데이터가 사용되는 것으로 가정한다.
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(DependencyConfig.class);
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(MyServiceImpl.class, Dependency1.class, Dependency2.class);
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
@Autowired
- MyServiceImpl, Dependency1, Dependency2에서 스프링 의존성 주입 애너테이션을 사용한 예제
@Bean은 메서드-레벨 애너테이션이며, <bean />
에서 제공하는 일부 속성을 지원한다.
@Bean
애너테이션은 @Configuration-annoted
또는 @Component-annoted
클래스에서 사용할 수 있다.
@Bean
애너테이션을 메서드에 추가해서 Bean으로 정의(선언)할 수 있다.
@Configuration
public class DependencyConfig {
@Bean
public TransferServiceImpl transferService() {
return new TransferServiceImpl();
}
}
빈 정의가 있는 인터페이스를 구현하여 Bean configuration을 설정할 수 있다.
public interface BaseConfig {
@Bean
default TransferServiceImpl transferService() {
return new TransferServiceImpl();
}
}
@Configuration
public class DependencyConfig implements BaseConfig {
}
@Bean
애너테이션이 추가된(@Bean-annotated) 메서드는 빈을 구축하는데 필요한 의존성을 나타내는데 매개 변수를 사용할 수 있다.
@Configuration
public class DependencyConfig {
@Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
}
@Configuration
은 해당 객체가 Bean definitions의 소스임을 나타내는 애너테이션이다.
@Configuration
은 @Bean-annoted
메서드를 통해 Bean을 선언한다.
@Configuration
클래스의 @Bean
메서드에 대한 호출을 사용하여 Bean 사이의 의존성을 정의할 수도 있다.
빈이 서로 의존성을 가질 때, 의존성을 표현하는 것은 다른 bean 메서드를 호출하는 것처럼 간단하다.
beanOne
은 생성자 주입을 통해 beanTwo
에 대한 참조를 받는다.@Configuration
public class DependencyConfig {
@Bean
public BeanOne beanOne() {
return new BeanOne(beanTwo());
}
@Bean
public BeanTwo beanTwo() {
return new BeanTwo();
}
}
@Configuration
public class DependencyConfig {
@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()
메서드에서 1번씩 호출되었다.
이 메서드는 ClientDaoImpl
의 새 인스턴스를 만들고 이를 반환하므로 일반적으로 두 개의 인스턴스(각 서비스마다 하나씩)가 있어야 한다.
하위 클래스의 하위 메서드는 상위 메서드를 호출하고 새 인스턴스를 만들기 전에 먼저 컨테이너에 캐시된(범위 지정) Bean이 있는지 확인한다.
Spring의 자바 기반 구성 기능 특징인 애너테이션을 사용해 구성의 복잡성을 줄일 수 있다.
@Import
애너테이션
@Configuration
public class DependencyConfigA {
@Bean
public A a() {
return new A();
}
}
@Configuration
@Import(DependencyConfigA.class)
public class DependencyConfigB {
@Bean
public B b() {
return new B();
}
}
DependencyConfigB
만 제공하면 된다.public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(DependencyConfigB.class);
// now both beans A and B will be available...
A a = ctx.getBean(A.class);
B b = ctx.getBean(B.class);
}
DependencyConfigB.class
사용으로 인해 ctx.getBean(A.class)가 가능해진다.@Configuration
클래스를 기억할 필요 없이 하나의 클래스만 처리하면 된다.추가한 @Bean 애너테이션에서 의존성 주입
문제점 :
@Import
받지 않고 여러 구성 클래스 간에 걸쳐 서로 의존성을 갖는다.ref=”some Bean”
을 선언하여 스프링으로 해결할 수 있어 문제가 되지 않는다.@Configuration
public class ServiceConfig {
@Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
}
@Configuration
public class RepositoryConfig {
@Bean
public AccountRepository accountRepository(DataSource dataSource) {
return new JdbcAccountRepository(dataSource);
}
}
@Configuration
@Import({ServiceConfig.class, RepositoryConfig.class})
public class SystemTestConfig {
@Bean
public DataSource dataSource() {
// return new DataSource
}
}
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
// everything wires up across configuration classes...
TransferService transferService = ctx.getBean(TransferService.class);
transferService.transfer(100.00, "A123", "C456");
}
해결방법
@Autowired
및 @Valu
e 주입 및 다른 Bean과 동일한 기능을 사용할 수 있다.@Configuration
의 생성자 주입은 스프링 프레임워크 4.3에서만 지원된다.@Autowired
지정할 필요가 없다.@Configuration
public class ServiceConfig {
@Autowired
private AccountRepository accountRepository;
@Bean
public TransferService transferService() {
return new TransferServiceImpl(accountRepository);
}
}
@Configuration
public class RepositoryConfig {
private final DataSource dataSource;
public RepositoryConfig(DataSource dataSource) {
this.dataSource = dataSource;
}
@Bean
public AccountRepository accountRepository() {
return new JdbcAccountRepository(dataSource);
}
}
@Configuration
@Import({ServiceConfig.class, RepositoryConfig.class})
public class SystemTestConfig {
@Bean
public DataSource dataSource() {
// return new DataSource
}
}
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
// everything wires up across configuration classes...
TransferService transferService = ctx.getBean(TransferService.class);
transferService.transfer(100.00, "A123", "C456");
}
References