Are annotations better than XML for configuring Spring?
위의 질문은 Spring 공식 문서에서 해당 파트에서 가장 처음에 등장하는 질문이다.
과연 어노테이션으로 설정하는 것이 XML로 설정하는 것 보다 더 좋은 방법일까??
① XML 설정 방식의 장점
- XML만 보고도 스프링의 설정을 한눈에 확인 가능
- 설정과 소스코드의 분리 가능 -> POJO(Plain Old Java Object)
② XML 설정 방식의 단점
- 'XML 헬' 이라고 불릴 정도로 XML이 너무 커진다.
- 방대해진 XML을 관리하기 힘들어진다.
위의 XML 단점을 보면 어노테이션이 더 나은 방법이 아닌가? 라는 생각이 든다.
하지만!
어노테이션을 사용하면 소스코드와 설정의 분리가 애매해진다. -> 완벽한 POJO가 아님
따라서 상황에 따라 다르다.
1. @Required
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Required
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}
위의 예제 코드를 보면 Required는 '필수'라는 뜻 그대로 해당 코드에서는 movieFinder 값이 들어오지 않으면 예외를 발생시킨다.
@Required 는 Spring Framework 5.1부터 사용되지 않으므로 대충 넘어가자.
2. @Autowired
빈과 빈 사이의 관계에서 스프링 컨테이너가 자동으로 관계를 연결시켜줌
빈의 이름 or 타입 등 여러 정보로 연결시켜준다.
public class A {
private B b;
//@Autowired(required=false)
@Autowired
public A(B b){
this.b = b;
}
@Autowired
public void setB(B b) {
this.b = b;
}
}
위의 예제로 보면 생성자주입과 Setter주입 방식으로 주입을 받는다.
Debuging 모드로 보면 모두 B객체를 주입받는 것을 확인할 수 있다.
@Autowired 할 때 빈이 하나 없으면 프로그램이 종료된다.
이렇게 프로그램 종료되는 것을 막기 위해 @Autowired(required = false) 로 해준다
(required = true)가 default 임.
잘 사용되지는 않지만 가끔 의도에 의해서 사용
※Spring이 버전이 올라가면서 생성자 주입의 경우 @Autowired를 쓰지 않아도 자동으로 주입된다.
public class A {
@Autowired private B b;
@PostConstruct
void init(){
log.info(""+b);
}
}
위의 예제와 같이 필드에도 어노테이션을 붙일 수 있다.
@PostConstruct 는 뒤에서 확인할 예정이다. 미리 대충 설명하자면 어노테이션의 라이프사이클 관련된 어노테이션이다.
@PostConstruct를 이용해서 필드의 어노테이션이 잘 되는지 확인할 수 있다.
public class A_applicationContextAware implements ApplicationContextAware {
private ApplicationContext applicationContext;
public void init(){
log.error("applicationContext::::"+applicationContext);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
또한 위의 예제 코드처럼
특정 bean에서 applicationContext를 사용할 경우 ApplicationContextAware 인터페이스를 implements하고 setApplicationContext을 구현하는 대신
public class A_applicationContextAware implements ApplicationContextAware {
@Autowired
private ApplicationContext applicationContext;
public void init(){
log.error("applicationContext::::"+applicationContext);
}
}
다음과 같이 @Autowired를 통해 코드를 간단히 할 수 있다.
3. @Primary
@Configuration
public class AppConfig {
@Bean
@Primary
public B b1(){
return new B();
}
@Bean
public B b2(){
return new B();
}
}
@Configuration : 빈 설정으로 등록이 되면서 동시에 이것은 스프링 설정에 관련있는 빈이다라는것을 의미 해준다
@Bean : xml에서 빈을 설정하는것 대신 자바에서 어노테이션으로 빈을 설정
@Primary
위에서 같은 타입의 Bean이 있어서 다른 곳에서 해당 Bean을 주입할 때 어떤것을 주입해야 할 지 모르기 때문에
어떤걸 먼저 주입할지 스프링에게 알려주는 어노테이션
(xml에서는 primary=true설정)
4. @Qualifier
@Configuration
public class AppConfig {
@Bean
@Qualifier("b1")
public B b1(){
return new B();
}
@Bean
@Qualifier("b2")
public B b2(){
return new B();
}
}
public class A {
@Autowired
@Qualifier("b2")
private B b;
@PostConstruct
void init(){
log.info(""+b);
}
}
@primary와 비슷하게 내가 원하는 빈을 주입할 때 사용한다.
위의 예제에서는 b2를 주입받고 있다.
5. @Resource
@Configuration
public class AppConfig {
@Bean
@Qualifier("b1")
public B appB1(){
return new B();
}
@Bean
@Qualifier("b2")
public B appB2(){
return new B();
}
}
public class A {
@Resource(name="appB1")
private B b;
@PostConstruct
void init(){
log.info(""+b);
}
}
Autowired와 똑같은 효과 차이점 = > name이라는 파라미터를 가지고
함수의 이름을 넣어주면 해당 빈을 설정한다. (@autowired + @qualifier 느낌)
6. @Value
어플리케이션에서 xml 말고 application.properties 파일을 만들어서 그안의 properties 파일을 읽어드린다.
보통 main인 경우 java, resources 폴더에 application.properties 잡힌다. 설정을
resources에서 하므로 거기에다가 application.properties파일을 만들어서 사용
catalog.name = MovieCatalog
↑ application.properties 설정 (properties 파일은 key = value 이런 식으로 사용된다)
public class A {
@Value("${catalog.name}") String catalogName;
}
public class A {
@Value("${catalog.name}") String catalogName;
@Value("${catalog.aljksdhfljk}") String test;
@PostConstruct
void init(){
log.info(""+catalogName); //출력 값 : MovieCatalog
log.info(""+test); //출력 값 : ${catalog.aljksdhfljk}
}
}
※여기서 주의해야할 사항이 있다!!
위의 예제에서 String test의 @Value값을 확인해보자.
@Value() 파라미터에 제대로 된 key값을 넣지 않으면 null이 아니라 파라미터값이 들어가게된다.
'Spring' 카테고리의 다른 글
[Spring] 예제로 보는 Using JSR 330 Standard Annotations (0) | 2020.05.19 |
---|---|
[Spring] 예제로 보는 Classpath Scanning and Managed Components (0) | 2020.05.18 |
[Spring] 예제로 보는 Ioc Container - Customizing the Nature of a Bean (0) | 2020.04.30 |
[Spring] 예제로 보는 Bean Scope (Feat. 동일성, 동등성) (0) | 2020.04.29 |
[Spring] 예제로 공부하는 IoC - Dependecies (제어의 역전 - 의존성) (0) | 2020.04.19 |