본문 바로가기

스프링

IOC_DI를위한_빈설정메타정보작성_Java,Configuration,Bean_4

이전에 DaoFactory 처럼 오브젝트 생성과 의존관계 주입을 담당하는 오브젝트를 오브젝트 팩토리라고 불렀고, 이 기능을 일반화 한 것이 지금의 스프링 컨테이너 이다.

> 일반적으로 XML처럼 간략한 표현이 가능한 문서를 이용해서 메타정보를 작성해두고, 컨테이너가 이를 참고해서 오브젝트를 생성하고 DI 해주도록 만드는 것이 효과적이다. 하지만 때로는 오브젝트 팩토리를 직접 구현했을 때처럼 자바 코드를 통해 오브젝트를 생성하고 DI 해주는게 유용할 때가 있다.

> 스프링은 코드를 이용해서 오브젝트를 생성하고 DI를 진행하는 방식으로 만들어진 오브젝트를 빈으로 사용할 수 있는 방법을 제공한다. 팩토리빈과 유사하지만 그 기능은 편리하고 강력하다.

 

1.     Spring-bean : 스프링 코어와 함께 의존성 주입 제공 (Core Container)

2.     Spring-context : 스프링 코어, BeanFactory를 확장한 어플리케이션 컨텍스트 구현, 리소스 로드 및 국제화 지원(Core Container)

3.     Spring-core : 다른 스프링 모듈이 사용하는 유틸리티(Core Container)

4.     Spring-expression : EL 확장 Bean속성(배열, 컬렉션 포함).(Core Container)

5.     Spring-aop : 스프링 기능 자체의 aop, Spring ProxyFactoryBean

6.     Spring-jcl : 뭔지 모르지만 다운받아짐

7.     Com.springsource.junit : junit > Java10 문제인지 Maven문제인지 잘 인식이 안되서 시스템 라이브러리르 등록함. 호환되는 junit5버전이 있지만 설명이 많이 없어서 걍 4

8.     Spring-jdbc : 스프링이 지원하는 jdbc(DataSource포함)

9.     Spring-tx : 스프링 트랜잭션. Spring-jdbc를 사용하면 필수로 써야함.

10.   Mysql-connector : Mysql JDBC

 

 

 

* 자바 코드에 의한 빈 등록

> XML 빈은 빈당 하나의 빈만 정의할 수 있다. 그에 반해서 자바 코드에 의한 빈 등록 기능은 하나의 클래스 안에 여러 개의 빈을 정의할 수 있다.

> 애노테이션을 이용해 빈 오브젝트의 메타정보를 추가하는 일도 가능하다.

> 클래스 자체가 자동인식 빈의 대상이 되기 때문에 XML을 통해 명시적으로 등록하지 않아도 된다.

6. @Configuration

> 빈 설정 메타정보를 담고 있는 자바코드는 해당 애노테이션이 달린 클래스를 이용해 작성한다. XML<beans>에 해당함. @Bean으로 정의된 메소드를 포함한다.

9. @Bean : 해당 애노테이션이 붙은 메소드를 정의할 수 있는데, 이 메소드를 통해 빈을 정의할 수 있다. XML <bean> 에 해당함.

* 애노테이션을 제외하고 보면 단순한 오브젝트 팩토리 기능의 메소드를 가진 클래스로 보이지만, @Configuration, @Bean이 붙으면 스프링 컨테이너가 인식할 수 있는 빈 메타정보 겸 빈 오브젝트 팩토리가 된다.

 

 

122. AnnotationConfigApplicationContext를 이용해 빈스캐닝, 생성자를 통해 패키지명 대신 @Configuration이 부여된 클래스를 넣어주면 된다.

125. 메소드 이름과 동일하게 annotatedHello 라는 이름의 빈이 등록됐음을 확인할 수 있다.

128. 메타정보에 해당하는 AnnotatedHelloConfig 클래스 자체도 하나의 빈으로 등록된다. 즉 독립적으로 메소드를 실행해도 문제될 것은 없다.

130~131. New를 통해 빈을 생성하므로 새로 만든 클래스와 달라야하지만 같다. 이것 역시 싱글톤이므로 컨테이너 안에서 단 한 번만 만들어져서 사용된다.

 

새로운 예제 시작

Printer 인터페이스를 구현한 클래스는 얼마든지 만들 수 있다(여러가지 기술로).

 

Printer를 구현한 각자 기능에 충실하게 독립적으로 설계된 POJO 클래스(구현체)를 만들고, 결합도가 낮은 유연한 관계를 가질 수 있도록 인터페이스를 이용해 연결해주는 것이 IOC컨테이너가 사용할 POJO를 준비하는 첫 단계 이다.

 

Hello 클래스는 Printer라는 인터페이스에만 의존한다. 실제로 런타임 시에 어떤 구체적인 오브젝트를 사용하게 될지 알지도 못하고, 관심도 없다.

 

 

위와 같이 3개의 빈을 정의했다고 보자.

29. 일반적인 자바코드라면 printer()를 실행할 때마다 매번 새로운 Printer 오브젝트가 생성된다. 하지만 스프링은 싱글톤으로 매번 동일한 오브젝트를 리턴한다. 메소드명 (printer, hello, hell2)이 빈 id가 된다.

16, 24. 때문에 printer() 메소드를 여러 번 호출해도 매번 동일한 오브젝트를 돌려받는다.

* 자바코드에 의한 빈설정 장점

- 컴파일러나 IDE를 통한 타입(클래스 이름 오타, 프로퍼티 이름 오타 등)이 가능하다. 물론 SpringIDE가 제공하는 XML 에디터를 사용하면 되지만 서버환경이나 SpringIDE가 없는 환경에서는 컴파일 에러를 뱉는 자바코드가 유리하다.

- 자동완성 IDE를 통해 설정하는 것이 편하게 느껴질 수 있고, 작성 속도도 빠르다.

- 스프링에 익숙하지 않는 개발자들에게도 이해하기 쉽다.

- 복잡한 빈 설정이나 초기화 작업을 손쉽게할 수 있다.

 > 팩토리 빈을 만든다고 치면 팩토리 빈의 독립적인 클래스를 만들어야 하고 XML로 등록해

프로퍼티 정보를 설정해줘야 하지만, @Bean은 메소드를 이용해 하나의 클래스 안에 여러 개  

의 빈을 만들 수 있고, new 키워드 대신 스태틱 팩토리 메소드를 이용해 빈 오브젝트 생성도

가능하다.

* 주의사항

> HelloConfig를 스프링 컨테이너 밖에서 사용하면 hello()hello2()에 의해 만들어지는 hello 오브젝트는 매번 새로운 인스턴스가 만들어진다. 따라서 순수한 오브젝트 팩토리 클래스라기 보다는 자바 코드로 표현되는 메타정보라고 이해하는 것이 좋다.

 

 

* 스프링의 @Configuration

- @Component가 있기 때문에 빈 스캐너에 의해 빈으로 등록된다.

* @Componet : 해당 클래스를 bean으로 만든다. @Configuration@Bean을 사용하기도 함.

 

자바 코드를 이용한 빈 등록은 단순한 빈 스캐닝을 통한 자동인식으로는 등록하기 힘든 기술 서비스 빈의 등록이나 컨테이너 설정용 빈을 XML 없이 등록하려고 할 때 유용하다.

* dataSource빈을 자바코드로 전환할 수 있을까?

> 이름 패턴 필터(Annotation~~Context)에 클래스를 등록하면되지만 매번 등록되는 프로퍼티가 문제다.

> SimpleDriverDataSource를 상속해서 MySimple~DataSource 같은 새로운 이름의 클래스를 만들고, 자동인식이 되도록 @Component를 붙이고, 생성자에서 기본 프로퍼티 값을 미리 넣어줘서 등록되게 할 수 있다.

 

하지만 설정이 일반 애플리케이션 클래스에 숨어 있게 하는 것보다는 아예 빈 설정 메타정보를 담는 것을 목적으로 하는 @Configuration 클래스로 만드는게 훨씬 깔끔하다.

> 이처럼 자바 코드를 이용하면 프로퍼티 값을 지정하는 것을 비롯해서 어떤 종류의 빈 설정이라도 손쉽게 만들 수 있으며, 빈스캐너에 의해 자동인식 대상이 되므로 XML 없이도 등록할 수 있어서 편리하다.

 

* 일반 빈 클래스에서도 @Bean 메소드 선언가능

> @Configuration이 붙지 않는 일반 POJO 클래스에서도 @Bean을 사용할 수 있다.

> @Configuration이 붙지 않는 클래스에 @Bean을 사용했을 때는 다른 @Bean을 사용한 경우 매번 다른 Printer 오브젝트를 받게 된다.(싱글톤 안됨)

> Printer를 싱글톤 빈으로 만드려면????

 

Printer 빈을 직접 DI 받은 뒤에 이를 hellohello2 가 사용하게 하면 된다.

> 일반 클래스에서 @Bean을 사용할 경우 이런 위험성이 있기 때문에 함부로 남용해서는 안된다.

> @Bean 메소드가 정의된 클래스 밖에서 실수로라도 메소드를 호출할 수 없도록 private으로 선언해두고, 클래스 내부에서도 DI를 통해 참조해야지 메소드를 직접 호출하지 않도록 주의를 기울여야 한다.

* 일반 빈에 @Bean을 언제쓰나?

> @Bean 메소드는 클래스 내부에 정의되어 있으므로 클래스의 모든 정보에 접근이 가능하다. 따라서 설정정보 등을 공유할 수 있으며, 동시에 XML 설정정보 등을 통해서는 외부로 빈의 존재가 노출되지 않으므로 빈의 존재를 감출 수 있다. 물론 일반 빈으로 등록 되므로 외부에서 참조 할 수 도 있다. 게다가 자바 코드로 등록하는 빈이므로 세밀한 설정이나 복잡한 초기화도 손쉽게 가능하다. 이렇게 밀접한 의존관계를 갖는 종송적인 빈을 정의할 때 유용하게 쓸 수 있다.

> 그렇지만 설정정보가 일반 애플리케이션 코드와 함께 존재하기 때문에 유연성이 떨어진다. @Configuration은 비록 자바 코드이긴 하지만 그 자체로 독립적인 설정정보로 분리가 가능하지만, 일반 빈 클래스의 @Bean에 담긴 설정정보는 수정을 위해 빈 클래스를 직접 수정해야 하는 불편이 뒤따른다는 점을 기억하자.

 

 

27. 빈으로 등록된 메서드에 인자값은 즉 userRepositoryboardRepository가 빈으로 등록되어 있으면 주입 가능.