[spring] Bean 등록 메타정보 구성 전략
🍈 Bean 등록 메타정보 구성 전략 🥑
- Spring 프레임워크에서 객체간의 의존성을 줄이고 유지보수를 더 쉽게하는 DI(의존성 주입) 을 실행 할 경우 크게 세 가지의 방법으로 수행가능
- Bean을 등록하고 환경을 설정하는 방법에 따라 나눠짐
🤟 Bean 등록 및 메타정보를 구성하는 세 가지 전략
1. XML 설정 단독 사용
2. Annotation & XML 혼용
3. Annotaion 단독 사용 (XML 사용 X)
1. XML 설정 단독 사용
- 모든 Bean을 명시적으로 XML에 등록
- 모든 Bean을 XML에서 확인 할 수 있으나, 객체가 많아질수록 관리가 어려워짐
- 여러 개발자가 하나의 설정파일을 공유하여 동시 작업하는 경우 충돌 가능성이 높음
- DI에 필요한 적절한 setter매소드 또는 Constructor가 코드내에 반드시 존재해야함
[XML 설정파일] spring_beans.xml
<!-- StringPrinter Class를 Beans로 등록 -->
<bean id="strPrinter" class= "myspring.di.xml.StringPrinter" ></bean>
<!-- HelloClass를 Beans로 등록 -->
<!-- Hello 클래스의 id를 주고, class로 클래스 위치를 전달 -->
<bean id="hello" class="myspring.di.xml.Hello" scope="singleton">
<!-- setName(), setPrinter() 매소드 => property로 설정 -->
<!-- value는 값 전달 setName(value) == setName("spring")과 같은 기능-->
<property name="name" value="spring" />
<!-- ref는 strPrinter라는 id를 가진 bean을 참조한다는 뜻 -->
<property name="printer" ref="strPrinter" />
</bean>
[Hello class] Hello.java
public class Hello {
String name;
Printer printer;
List<String> names;
public Hello() {
System.out.println("Hello ! defualt constructor called");
}
public Hello(String name, Printer printer) {
System.out.println("Overloaded Hello Constructor called" +
name + " " + printer.getClass().getName());
this.name = name;
this.printer = printer;
}
public void setName(String name) {
System.out.println("Hello setName method called " + name);
this.name = name;
}
public void setPrinter(Printer printer) {
System.out.println("Hello setPrinter method called " +
printer.getClass().getName());
this.printer = printer;
}
public String sayHello() {
return "Hello " + name;
}
public void print() {
this.printer.print(sayHello());
}
}
[StringPrinter Class] StringPrinter Class.java
package myspring.di.xml;
public class StringPrinter implements Printer {
private StringBuffer buffer = new StringBuffer();
//print override
public void print(String message) {
this.buffer.append(message);
}
public String toString() {
return this.buffer.toString();
}
}
2. Annotation & XML 혼용
- Bean으로 사용될 클래스에 특별한 Annotation을 부여해주면 클래스를 자동으로 찾아서 Bean으로 등록
- @Component가 선언된 클래스를 자동으로 찾아서 Bean으로 등록해주는 빈 스캐닝(Bean Scanning) 을 통한 자동인식 Bean 기능
- Annotation으로 빈 자동등록시 XML문서 생성과 관리의 수고를 덜고 개발속도 향상
- Bean들을 한번에 볼 수 없고 의존관계를 한 눈에 파악하기 힘듬
[Bean 등록 Annotation]
Annotation | 기능 |
---|---|
@Component | - 컴포넌트를 나타내는 일반적인 스테레오 타입 - Bean 태그와 동일한역할 |
@Repository | - @Component와 같은 기능 - Persistance 레이어 (DB연결 등) - 영속성을 갖는 속성(파일, 데이터베이스)을 갖는 클래스 |
@Service | - 서비스 레이어, 비지니스 로직을 갖는 클래스 |
@Controller | - 프레젠테이션 레이어 - 웹 어플리케이션의 요청과 응답 처리 |
[의존관계 주입 Annotation]
Annotation | 기능 |
---|---|
@Autowired | - 의존하는 객체 자동 주입 (타입으로 연결) - 정밀한 의존관계주입이 필요한 경우 유용 - 변수, setter매소드, 생성자, 일반 매소드에 모두 적용 가능 |
@Resource | - 의존하는 객체 자동 주입 (이름으로 연결) - 변수, setter매소드에 적용 가능 |
@Value | - 단순한 값 주입시 사용 |
@Qualifier | - @Autowired와 같이 사용 - @Autowired가 타입으로 찾아서 주입하므로 동일한 타입의 특정 Bean객체를 지정해줄 때 사용 |
<context:component-scan> 태그 |
- @Component로 자동으로 빈 등록 후 @Autowired로 의존관계를 주입받는 클래스를 사용할 때 - 클래스가 위치한 패키지를 명시해주기위해 사용 |
[XML 설정파일] spring_beans.xml
<!-- Component AutoScanning을 위한 설정 -->
<context:component-scan base-package="myspring.di.annotaion" />
[Hello class] Hello.java
@Component("hello")
public class Hello {
@Value("스프링")
String name;
@Autowired
@Qualifier("stringPrinter")
Printer printer;
public void setName(String name) {
System.out.println("Hello setName method called " + name);
this.name = name;
}
public String sayHello() {
return "Hello " + name;
}
public void print() {
this.printer.print(sayHello());
}
}
[StringPrinter Class] StringPrinter Class.java
@Component("stringPrinter")
public class StringPrinter implements Printer {
private StringBuffer buffer = new StringBuffer();
//print override
public void print(String message) {
this.buffer.append(message);
}
public String toString() {
return this.buffer.toString();
}
}
3. Annotaion 단독 사용 (XML 사용 X)
- Spring JavaConfig 프로젝트로 XML없이 자바 코드만으로 컨테이너 설정
- @Configuration과 @Bean을 통해 스프링컨테이너에 빈 객체 제공 가능
- Spring3.0 부터는 XML전혀 사용 X
[Bean등록과 설정 Annotaion]
Annotaion | 기능 |
---|---|
@Bean | - 새로운 빈 객체 제공시 사용 - @Bean이 적용된 매소드의 이름이 Bean의 ID가 됨 - @Component와 같은 역할이나 @Component는 클래스위에, @Bean은 매소드 위에 선언 |
@Configuration | - config Class 생성시 XML을 대체하는 역할 - @Component처럼 빈 스캔으로 자동 검색됨 - @Configuration을 선언한 클래스도 Bean으로 정의됨 (스프링 IoC로 인해) |
[Hello class] Hello.java
public class Hello{
String name;
Printer printer;
public Hello(){
}
public void setName(String name){
this.name = name
}
public void setPrinter(Printer printer){
this.printer = printer;
}
public String sayHello(){
return "Hello" + name;
}
public void print(){
this.printer.print(sayHello());
}
}
[HelloConfig class] HelloConfig.java
@Configuration
public class HelloConfig{
@Bean
public Hello hello(){
Hello hello = new Hello();
hello.setName("자바 컨피그");
hello.setPrinter(printer());
return hello;
}
@Bean
@Qualifiter("stringPrinter")
public Printer priter(){
Printer printer = new StringPrinter();
return printer;
}
@Bean
@Qaulifer("consolePrinter")
public Printer cPrinter(){
Printer printer = new ConsolePrinter();
return printer;
}
}
- Sprng-test에서 테스트를 지원하는 어노테이션: @ContextConfiguration
- Bean의 메타 설정파일의 위치를 지정할 때 사용되는 어노테이션
- 경로를 지정하지 않으면 테스트 클래스가 있는 패키지내에서 설정파일 사용
[configuration과 componentScan]
[XML을 @Configuration과 @ComponentScan으로 대체]
<!-- Component AutoScanning을 위한 설정 -->
<context:component-scan base-package="myspring.di.annotaion" />
@Configuration
@ComponentScan(basePackages = {"myspring.di.annotaion"})
public class HelloBeanConfig {
}
- 프로퍼티 파일을 이용한 설정방법
- 환경에 따라 자주 변경되는 내용을 분리하여 프로퍼티 파일에 따로 관리 (key= value)구조
- XML에 저장되는 Bean 메타정보는 어플리케이션 구조가 바뀌지 않으면 바뀌지 않음
- 하지만 프로퍼티 값으로 제공되는 일부 설정정보는 어플리케이션 동작환경에 따라 자주 바뀔수 있음
Annotion | 기능 |
---|---|
@PropertySource | - .properties 파일 경로를 지정해줌 - “classpath:경로” |
[values.propterties] 확장자 : .properties
myName = \uC5B4\uB178\uD14C\uC774\uC158\ \uC0DD\uC131\uC790
myPrinter = stringPrinterBean
configName = JAVA CONFIG
@Configuration
@PropertySource("classpath:config/values.properties")
public class HelloConfig {
//Enviorment import
@Autowired
private Environment env;
@Bean
public Hello hello() {
Hello hello = new Hello();
hello.setName(env.getProperty("configName"));
hello.setPrinter(strPrinter());
return hello;
}
}