Java config를 이용한 설정을 위한 어노테이션
@Configuration
@Bean
@ComponentScan
- @Controller, @Service, @Repository, @Component 어노테이션이 붙은 클래스를 찾아 컨테이너에 등록
@Component
- 컴포넌트 스캔의 대상이 되는 애노테이션 중 하나로써 주로 유틸, 기타 지원 클래스에 붙이는 어노테이션
@Autowired
- 주입 대상이되는 bean을 컨테이너에 찾아 주입하는 어노테이션
Java Config를 이용해 설정하기
ApplicationConfig.java
package kr.or.connect.diexam01;
import org.springframework.context.annotation.*;
@Configuration
public class ApplicationConfig {
@Bean
public Car car(Engine e) {
Car c = new Car();
c.setEngine(e);
return c;
}
@Bean
public Engine engine() {
return new Engine();
}
}
@Configuration 은 스프링 설정 클래스라는 의미를 가집니다.
JavaConfig로 설정을 할 클래스 위에는 @Configuration가 붙어 있어야 합니다.
ApplicationContext중에서 AnnotationConfigApplicationContext는 JavaConfig클래스를 읽어들여 IoC와 DI를 적용하게 됩니다.
이때 설정파일 중에 @Bean이 붙어 있는 메소드들을 AnnotationConfigApplicationContext는 자동으로 실행하여 그 결과로 리턴하는 객체들을 기본적으로 싱글턴으로 관리를 하게 됩니다.
ApplicationContextExam03.java
package kr.or.connect.diexam01;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class ApplicationContextExam03 {
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(ApplicationConfig.class);
Car car = (Car)ac.getBean("car");
car.run();
}
}
파라미터로 요청하는 class 타입으로 지정 가능합니다.
Car car = ac.getBean(Car.class);
ApplicationConfig2.java
package kr.or.connect.diexam01;
import org.springframework.context.annotation.*;
@Configuration
@ComponentScan("kr.or.connect.diexam01")
public class ApplicationConfig2 {
}
기존 JavaConfig에서 빈을 생성하는 메소드를 모두 제거했습니다.
단, @Configuration아래에 @ComponentScan이라는 어노테이션을 추가했습니다.
@ComponentScan어노테이션은 파라미터로 들어온 패키지 이하에서 @Controller, @Service, @Repository, @Component 어노테이션이 붙어 있는 클래스를 찾아 메모리에 몽땅 올려줍니다.
기존의 Car클래스와 Engine클래스 위에 @Component를 붙이도록 하겠습니다.
Engine.java
package kr.or.connect.diexam01;
import org.springframework.stereotype.Component;
@Component
public class Engine {
public Engine() {
System.out.println("Engine 생성자");
}
public void exec() {
System.out.println("엔진이 동작합니다.");
}
}
Car.java
package kr.or.connect.diexam01;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Car {
@Autowired
private Engine v8;
public Car() {
System.out.println("Car 생성자");
}
public void run() {
System.out.println("엔진을 이용하여 달립니다.");
v8.exec();
}
}
수정된 JavaConfig를 읽어들이여 실행하는 클래스를 보도록 하겠습니다.
ApplicationContextExam04.java
package kr.or.connect.diexam01;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class ApplicationContextExam04 {
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(ApplicationConfig2.class);
Car car = ac.getBean(Car.class);
car.run();
}
}
Spring에서 사용하기에 알맞게 @Controller, @Service, @Repository, @Component 어노테이션이 붙어 있는 객체들은 ComponentScan을 이용해서 읽어들여 메모리에 올리고 DI를 주입하도록 하고, 이러한 어노테이션이 붙어 있지 않은 객체는 @Bean어노테이션을 이용하여 직접 생성해주는 방식으로 클래스들을 관리하면 편리합니다.
생각해보기
- 다루는 빈(Bean)이 많아질수록 xml로 설정하는 것과 @ComponentScan, @Component, @Autowired를 이용하는 것 중 어떤 것이 유지보수에 좋을 것 같습니까?
- @AutoWired 는 Field, Constructor, Setter Method 에 사용할 수 있습니다. 각각의 방식에 장단점에 대해서 더 생각해보세요.
참고 자료
comment
21.8.3
기존 방식의 문제점을 통해 기능의 발전과정을 보여주어서 이해가 굉장히 잘됐던 강의였어요 !
Cannot load configuration class 관련 오류가 나는 경우 찾아보니 보통 jdk 9 이상을 사용할 때 나타나는 오류라고 합니다. 그러나 저는 jdk 8 을 쓰고 있는데도 같은 오류가 발생했습니다. 이 부분은 아마 제가 설치한 jdk 8이 최신버전이라 그런 게 아닐까 추측하고 있습니다.
해결방법은 이 오류가 spring 5.1에서 고쳐졌기 때문에 스프링 버전을 그에 맞게 높이는 거라고 합니다. 스프링 버전을 변경하여 실행하니 오류없이 잘 돌아가는 것을 확인했습니다. 출처: https://okky.kr/article/671668
Cannot load configuration class: kr.or.connect.text.ApplicationConfig
라는 오류가 나네요
1. xml이 적은 객체들을 관리하기는 더 편리하지만 객체의 수가 많아지면 가독성이 좋지 않고
xml은 단지 문서이기 때문에 에러를 알아챌 수 있는 시점이 늦어진다고 생각합니다.
또한 스프링 설정 파일을 따로 관리할 필요가 없어지기 때문에 xml보단 더욱 관리가 편해집니다.
JavaConfig나 어노테이션을 이용한 빈 관리가 가장 좋다고 생각합니다.
안녕하세요 저는 @Configuration 실습 할 때 car랑 engine클래스를 car2 engine2 로 새로 만들어서 실행을 했는데요.기존 @bean으로 작성된 객체들까지 생성이 되어버리는데 왜 그런건가요? 아래 순서입니다.
Car2 생성자
Engine2 생성자
Engine 생성자
Car 생성자
2.엔진을 이용하여 달립니다.
2.엔진이 동작합니다.
Xml설정은 마치 목차처럼, 관리되는 Bean들의 정보를 비교적 쉽게 파악할 수 있지만, 계속해서 목차를 update해야한다는 것은 양이 많아질수록 부담스러울 것 같습니다.
어노테이션 방식은 Xml을 계속해서 현행화 하지않아도 되기 때문에 편리할 수 있지만, Xml방식에 익숙한 개발자는 어색하게 느껴질 수 도 있을 것 같습니다..
저는 유지 보수라는 측면을 보았을때는 오히려 전자가 더 나을 것 같습니다. 유지 보수라는 것은 클래스를 변경할 필요가 있을 때인데 어노테이션으로 지정을 하게 되면 어디에 컴퍼넌트가 붙어있는지 일일이 클래스를 열어서 찾아봐야 하니까요. 하지만 xml은 어느 디렉토리에 빈들이 있는지 다 나와있으니까 더 편할 것 같네요.
그러나 코드를 짜는 입장에서는 전자가 더 낫겠죠.
1. 후자의 경우가 좀 더 유지보수하기에 좋을 것같습니다. xml로 설정하게될경우 우선순위는 좀 더 높지만 일일이 id를 지정해줘야하고 그에맞게 연결해줘야하는데 이건 여간 힘든작업이란 생각이 듭니다.
2. 아직은 좀 더 와닿지는않지만 아래의 URL에 설명이 잘되어있더군요.
https://yaboong.github.io/spring/2019/08/29/why-field-injection-is-bad/
전강의서 Engine클래스를 어디서 언제 연결해가지고 Car Class든 다른 파일이든 쓰는지 혼란의 구덩이에 이것저것 뚜둘겼었는데 바로 소화되네요! 최곱니다.
감사합니다.
만약 Car라는 bean을 여러개 생성하고싶으면 컴포넌트 스캔으론 불가능한가요?
예를들어 @bean 을 사용해 생성할때는 Car객체를 반환하는 bean을 여러개 만드는 방법을 쓸 수 있을것 같은데 컴포넌트 스캔에서 이런기능은 불가능할까요?
수업 들으면서 이렇게 저렇게 바꿔보면서 알아내는것도 많은것 같네요. 주석도 어느정도 달아 뒀는데 틀린부분이 있을수도 있으니 맹신하지는 말아주시기 바랍니다.
ApllicationConfig.java에서 Engine객체의 호출시점이 궁금합니다! Engine 생성자가 먼저 호출되는 이유를 알수 있을까요?