개발서적/토비 스프링 3.1-Vol.2

[토비의 스프링 - Vol.2] 1장 - 1.2.2 빈 등록 방법

1. XML: <bean> 태그

 - <bean>태그를 사용하는 건 가장 단순하면서 강력한 설정 방법.
 - 기본적으로 id와 class라는 두개의 어트리뷰트가 필요 (id 생략 가능)

 <bean id="hello" class="springbook.leaningtest.spring.ioc.bean.Hello">
 ...
 </bean>

 - <bean>은 다른 빈의 <property> 태그 안에 정의가 가능 (이때는 id, 이름을 지정하지 않음)
   이러한 빈을 내부 빈(inner bean)이라 하며, 다른 빈에서는 참조할 수 없음. 강한 결합이 필요한 경우에 사용

<bean id="hello" class="springbook.leaningtest.spring.ioc.bean.Hello">
	<property name="printer">
		<bean class="springbook.leaningtest.spring.ioc.bean.StringPrinter"/>
	</property>
</bean>

2. XML: 네임스페이스와 전용 태그

 - <bean> 태그 외에 전용 태그를 사용해 빈을 등록하는 방법
 - 스프링의 빈의 두가지 분류

  1. 애플리케이션의 핵심 코드를 담은 컴포넌트
  2. 서비스 또는 컨테이너 설정을 위한 빈

 - 스프링은 DI의 원리로 애플리케이션 컨텍스트 자신에게 필요한 정보도 오브젝트 형태로 DI해서 사용
 - 이를 통해 컨테이너의 유연한 확장이 가능
 - 애플리케이션 로직을 담은 빈이 동일하게 <bean>이라는 태그를 사용해서 만들면 구분이 안됨
     -> 의미가 잘 드러나는 네임스페이스와 태그를 가진 설정 방법을 제공

 - 전용 태그 하나로 동시에 여러개의 빈을 만들수 있다는 장점
     -> ex) <context:annotaion-config> 이 태그 하나로 보통 5개의 빈이 선언
  * 스프링이 제공해주는 것 외에도 개발자가 스스로 커스텀 태그를 만들어서 적용할 수도 있음.

장점 
1. 내용이 매우 분명하게 드러나고 선언 자체도 깔끔
2. 다른 빈 설정과 혼동 되지도 않는다. 

 

<bean> 태그를 이용한 AOP 설정
<bean id="mypoint" class="org.springframework.aop.aspectj.AspectJExpressionPoinrCut">
	<property name="expression" value="execution(* *.. *ServiceImp.upgrade*(..)")
</bean>

 

<aop> 전용 태그를 이용한 AOP 설정
 <aop:pointcut id="mypointcut" expression="execution(* *..*ServiceImpl.upgrade*(..))" />

3. 자동인식을 이용한 빈 등록: 스트레오타입 애노테이션과 빈 스캐너

 XML을 통한 빈 관리의 단점
  1. 애플리케이션의 규모가 커지고 빈의 개수가 많아지면 XML 파일을 관리하기가 번거로움
  2. 여러 개발자가 설정파일을 공유해서 개발하다 동시에 수정을하면 충돌이 일어나는 경우가 발생

 - 빈 스캐닝을 통한 자동인식 빈 등록: 애노테이션이 붙은 클래스를 자동으로 찾아서 빈으로 등록하는 방식
 - 빈 스캐너: 스캐닝 작업을 담당하는 오브젝트
 - 빈 스캐너는 지정된 클래스패스 아래에 있는 모든 패키지의 클래스를 대상으로 함
 - 스테레오타입 애노테이션@Component를 포함해 디폴트 필터에 적용되어 있는 애노테이션
 - 빈 스캐너는 기본적으로 클래스 이름을 빈의 아이디로 사용 (첫 글자만 소문자로 바꿈)
 - 모든 클래스를 다 검색하는 것은 비효율적이며, 패키지를 지정하는 것이 바람직. 

  지정된 패키지와 그 서브패키지의 클래스들이 자동 검색 대상

 @Component("myAnnotatedHello")
 public class AnnotatedHello{
 ...
 }
빈의 이름을 클래스 이름과 다르게 지정해야 하는 경우
 1. 같은 빈이 이미 존재하여 충돌을 피해야 하는 경우
 2. 좀 더 의미있는 이름을 사용하고 싶은 경우
자동 스캔으로 빈을 등록할 때의 장/단점
 <장점>
 1. 복잡한 XML문서 생성과 관리에 수고를 덜어주어 개발속도 향상

 <단점>
 1. 애플리케이션에 등록될 빈의 유무와 정의를 파악하기 힘듬
 2. XML처럼 상세한 메타정보 항목을 지정할 수 없음
 3. 클래스당 1개 이상의 빈을 등록할 수 없다는 제한

<단점의 해결방안>
 1. 생산성을 위해 빈 스캐닝을 사용하여 빈 등록
 2. 어느 정도 마무리가 되면, 세밀한 관리와 제어가 필요한 운영 시점에 XML형태의 빈 선언을 적용
자동인식을 통한 빈 등록을 사용하기 위한 2가지 방법
 1. XML을 이용한 빈 스캐너 등록
 - 모든 빈을 스캔하고 싶다면 XML 설정 파일에 <context:component-scan> 태그를 이용
 <context:component-scan base-package="springbook.learningtest.spring.ioc.bean" />

 2. 빈 스캐너를 내장한 애플리케이션 컨텍스트 사용
 - AnnotationConfigApplicationContext, 등을 이용
 - web.xml안에 컨텍스트 파라미터 설정 변경 필요
@Component 외에 스테레오타입 애노테이션
1. @Repository : 데이터 엑세스 계층의 DAO또는 리포지토리 클래스에 사용
2. @Service: 서비스 계층의 클래스에 사용
3. @Controller: 프레젠테이션 계층읠 MVC컨트롤러에 사용
 * 특정 계층으로 분류하기 힘든 경우 @Component를 사용하는 것이 바람직

4. 자바 코드에 의한 빈 등록: @Configuration 클래스의 @Bean 매소드

 

- 오브젝트 팩토리: 오브젝트 생성과 의존관계를 주입을 담당하는 오브젝트
- 팩토리 빈은 <bean> 태그를 이용해 빈으로 등록 또 팩토리 빈당 하나의 빈만 정의 가능
- 그에 반해 자바코드에 의한 빈 등록 기능은 하나의 클래스 안에 여러 개의 빈을 정의
- 빈 설정 메타정보를 담고 있는 자바 코드는 @Configuration 애노테이션
- @Bean 메소드를 통해 빈을 정의

 

XML 문서와 대칭 구조
  <beans> - @Configuration
  <bean> - @Bean
@Configuration
public class AnnotatedHelloConfig{
	@Bean
	public AnnotatedHello annotatedHello(){
		return new AnnotatedHello();
	}
}

 

 * 설정을 담은 자바 코드에 해당하는 AnnotatedHelloConfig 클래스 자체도 하나의 빈으로 등록 됨


  - new AnnotatedHello() 코드가 존재해도 싱글톤이므로 단 한 번만 만들어짐
  - 스프링은 @Bean이 붙은 메소드를 이용해 빈을 만들면 새로운 오브젝트가 만들어지지 않도록 @Bean 메소드를 조작

 

@Configuration
public class HelloConfig{
	@Bean
	public Hello hello(){
		Hello hello = new Hello();
		hello.setPrinter(printer());
        return hello;
	}

	@Bean
	public Hello hello2(){
		Hello hello = new Hello();
		hello.setPrinter(printer());
		return hello;
	}

	@Bean
	public Printer printer(){
		return new StringPrinter();
	}
}

 

-> hello(), hello2()에서 사용된 printer()는 모두 동일한 객체(1번만 만들어짐)

 

 - 등록하기 힘든 기술 서비스 빈의 등록이나 컨테이너 설정용 빈XML 없이 등록할때 유용
 - 프로퍼티 값을 지정하는 것을 비롯해 어떤 종류의 빈 설정이라도 손쉽게 만듬
 - 동시의 빈 스캐너의 자동인식 대상

 

자바 코드 설정이 XML같은 외부 설정보다 유용한 점
 1. 컴파일러나 IDE를 통한 타입 검증이 가능하다.
  - XML은 텍스트 문서다. 이름, 프로퍼티, 등에 오류를 검증할 수 없음
  -> 자바 코드는 클래스나 프로퍼티 이름이 정확하지 않으면 컴파일 에러가 발생

 2. 자동완성과 같은 IDE 지원 기능을 최대한 이용할 수 있다.
  - 자바 에디터의 자동완성을 통해 작성 속도가 향상된다.

 3. 이해하기 쉽다.

 4. 복잡한 빈 설정이나 초기화 작업을 손쉽게 적용할 수 있다.
  - @Bean 메소드를 이용해 빈을 저의하는 경우 여러개 빈을 만들기 쉽다.
  - 자바코드를 통한 초기화 작업이 가능하며, new 키워드 대신 스태틱 팩토리 메소드 등을 이용해 빈 오브젝트 생성이 가능

5. 자바 코드에 의한 빈 등록: 일반 빈 클래스의 @Bean 메소드


- @Configuration이 붙은 클래스가 아닌 일반 POJO 클래스에도 @Bean을 사용할 수 있음
- @Bean 메소드를 가진 클래스는 어떤 방법으로든지 빈으로 등록 필요
- @Configuration이 붙은 @Bean과 아닌 @Bean의 미묘한 차이점이 존재

public class HelloConfig{
	@Bean
	public Hello hello(){
		Hello hello = new Hello();
		hello.setPrinter(printer());
		return hello;
	}

	@Bean
	public Hello hello2(){
		Hello hello = new Hello();
		hello.setPrinter(printer());
		return hello;
	}

	@Bean
	public Printer printer(){
		return new StringPrinter();
	}
}

 *printer()가 싱글톤이 아닌 새로운 객체로 생성, @Configuration 클래스 안에서만 싱글톤
 


 - 싱글톤으로 사용하기 위한 방법은 클래스에서 직접 DI를 받은 뒤 사용

public class HelloConfig{
	//---- 변경한 영역----
	private Printer printer;

	public void setPrinter(Printer printer){
		this.printer = printer;
	}
	//---- 변경한 영역----

	@Bean
	public Hello hello(){
		Hello hello = new Hello();
		hello.setPrinter(this.printer); //DI 받음
		return hello;
	}

	@Bean
	public Hello hello2(){
		Hello hello = new Hello();
		hello.setPrinter(this.printer); //DI 받음
		return hello;
	}

	@Bean
	public Printer printer(){
		return new StringPrinter();
	}
}

 - 일반 빈 클래스에 @Bean 메소드 사용하는 경우
  -> 빈과 매우 밀접한 관계를 가진 경우
 - 일반 빈 클래스에 @Bean 메소드 사용에 단점
  -> 설정정보가 일반 애플리케이션 코드와 함께 존재하기 때문에 유연성이 떨어짐

 

빈 등록 메타정보 구성 전략
1. XML 단독 사용
 - 모든 빈을 명시적으로 XML 등록하는 방법
 - <bean>과 스키자에 정의된 전용태그를 이용하는 방식
 - 모든 설정정보를 자바 코드에 분리, 순수한 POJO코드를 유지하고 싶을때 좋은 선택
 - 기존에 개발된 애플리케이션에서 코드에 손대지 않고 재사용하고 싶을 경우에 유용
 - 특화된 커스텀 스키마와 전용 태그를 만들어서 사용하는 경우 좋은 이점을 가짐

2. XML과 빈 스캐닝의 혼용
  - 기술 서비스, 컨테이너 설정은 XML + 개발이 진행되면서 만들어지는 애플리케이션 빈들은 애노테이션을 부여해 자동스캔
  - 단 스캔 대상이 되는 클래스를 위치시킬 패키지를 미리 결정해둬야 함
   -> 최상위 패키지를 지정하므로 클래스를 중복해서 빈으로 등록할 수 있음
   -> 잘못된 패키지 스캐닝 + 트랜잭션 AOP 설정이 겹치면 AOP적용이 되지 않는 현상이 발생
   -> 컨텍스트 계층구조 내에서 같은 클래스의 빈이 중복 등록되는 것을 스프링이 문제삼지 않음

3. XML 없이 빈 스캐닝 단독 사용
 - 애플리케이션 컴포넌트(Java) + 각종 기술 서비스와 컨테이너 설정용 빈(Java) 스캔으로 자동 등록
 - 애노테이션을 부여할 수 있는 컴포넌트 클래스는 빈 스캔 대상
 - 성격이 다른 @Configuration 자바 코드는 적절히 패키지를 구분해 주는 것이 좋음

 <장점>
 1. 모든 빈의 정보가 자바코드로 담겨있으므로 타입에 안전한 방식으로 작성
 <단점>
 1. 정의된 전용 태그를 사용할 수 없음