자바 기반 설정의 가장 중요 애너테이션 두 가지는 다음과 같다.
// DependencyConfig 클래스
컨텍스트를 인스턴스화할 때
@Configuration
public class DependencyConfig {
@Bean
public MyService myService() {
return new MyServiceImpl();
}
}
애너테이션을 이용해 Config 클래스를 설정하는 방법이다.
//@Configuration 클래스를 입력으로 사용 (DependencyConfig.class)
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(DependencyConfig.class);
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
// @Component 또는 JSR-330 주석이 달린 클래스는 다음과 같이 생성자에 입력으로 사용
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(MyServiceImpl.class, Dependency1.class, Dependency2.class);
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
@Bean은 메서드-레벨 애너테이션이며, <Bean/>에서 제공하는 일부 속성을 지원한다.
빈 선언
@Bean 애너테이션을 메서드에 추가해서 Bean으로 정의(선언)할 수 있다.
@Configuration
public class DependencyConfig {
@Bean
public TransferServiceImpl transferService() {
return new TransferServiceImpl();
}
}
<beans>
<bean id="transferService" class="com.acme.TransferServiceImpl"/>
</beans>
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);
}
}
Bean 사이에 의존성 주입
빈이 서로 의존성을 가질 때, 의존성을 표현하는 것은 다른 bean 메서드를 호출하는 것처럼 간단하다.
// beanOne은 생성자 주입을 통해 beanTwo에 대한 참조를 받는다
@Configuration
public class DependencyConfig {
@Bean
public BeanOne beanOne() {
return new BeanOne(beanTwo());
}
@Bean
public BeanTwo beanTwo() {
return new BeanTwo();
}
}
Java를 기반으로 설정되어 있는 환경에서 내부적으로 작동하는 방식에 대한 정보
@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();
}
}
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();
}
}
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);
}
추가한 @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");
}
해결 방법
@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");
}