스프링 빈 (bean)
스프링은 경량 컨테이너로서 객체 생성, 소멸과 같은 Life Cycle을 관리하며 스프링 컨테이너로부터 필요한 객체를 얻을 수 있다.
스프링 컨테이너에 의해서 자바 객체가 만들어지게 되면 이 객체를 스프링은 스프링 빈(Bean)이라고 부른다.
스프링부트에서 bean 생성 & 사용
스프링부트의 경우
@Component, @Service, @Controller, @Repository, @Bean, @Configuration 등으로 필요한 빈들을 등록하고 필요한 곳에서 @Autowired를 통해 주입받아 사용하는 것이 일반적이다.
Dependency Injection (의존 주입)
필요한 객체는 누가 만드나?
방법1] 직접 new 생성
방법2] 외부에서 만들어서 주입
설계 변경이 발생하면?
msg 변수에 담을 객체가 변경되어야 한다면?
즉, Main 이 ‘의존’하는 MessageBean 객체가 변경되어야 한다면?
기존 방식
만약 msg 를 수정하게 될 일이 있다면..
DI1Main 을 손 안대도 가능한가?
돌아가게 하려면 DI1Main 을 다시 컴파일 해야 한다. (즉 손을 대야 한다)
1. 필요한 객체를 직접 만드는 경우
SW 설계에 있어 다음과 같이 2개의 구성요소가 있고 Main 은 MessageBean 이 필요하다 (즉 의존한다)
그래서, MessageBean 쪽 설계에 변화가 생긴다면, Main도 수정/ 재컴파일 해야 한다?
만약 수백, 수천개의 구성요소 (그것도 제작사가 한군데가 아닌 여러 업체가 협업을 통해 만들어진)로 구성되어
서로 의존하는 구성의 SW 라면 어떻게 유지 보수 할 것인가?
2. 필요한 객체를 ‘외부’ 에서 생성 ‘주입’
그래서 SW 공학적으로 필요한 객체를 ‘외부’에서 생성해서 주입하는 방식이 유지 보수 측면에서 이로운 점이 많다.
스프링 프레임 워크에서 제공하는 ‘의존주입 (Dependency Injection)’ 기능을 통해 이를 배워보도록 하자.
비록 Main 이 MessageBean 객체를 필요(의존) 하지만, 외부에서 주입되는 MessageBean 객체가 변경되었다고 해서 Main 을 수정하거나 재컴파일 할 필요는 없다!
연습 2-1 : 빈 객체 생성 연습
컨테이너에서 객체를 생성한뒤 이를 의존주입받아 동작하는 코드 만들기
패키지 : base-package.ex2_1
인터페이스 : OperatorBean
클래스 : DIApp main() 포함
다음 요구사항을 만족하는 프로그램을 작성
- 클래스 구조도가 오른쪽과 같이 구성되도록 작성하기
- 클래스
- DIApp ( main() )
- OperatorBean( interface )
- PlusOp, MinusOp (OperatorBean 구현체)
- Config.java (@Configuration)
main() 에서의 operator 와 각 operand1, operand2 값 지정은 Config.java 을 통해 외부 주입 될수 있도록 설정
MessageBean.java
package com.lec.spring.beans;
public interface MessageBean {
public abstract void sayHello();
}
Score.java
package com.lec.spring.beans;
import lombok.Data;
@Data
public class Score {
int kor;
int eng;
int math;
String comment;
public Score() {
System.out.println("Score() 생성");
}
public Score(int kor, int eng, int math, String comment) {
super();
System.out.printf("Score(%d, %d, %d, %s) 생성\n", kor, eng, math, comment);
this.kor = kor;
this.eng = eng;
this.math = math;
this.comment = comment;
}
}
Student.java
package com.lec.spring.beans;
import lombok.Data;
@Data
public class Student {
String name;
int age;
Score score;
public Student() {
super();
System.out.println("Student() 생성");
}
public Student(String name, int age, Score score) {
super();
System.out.printf("Student(%s, %d, %s) 생성\n", name, age, score.toString());
this.name = name;
this.age = age;
this.score = score;
}
}
MessageEng.java
package com.lec.spring.di01;
import com.lec.spring.beans.MessageBean;
public class MessageEng implements MessageBean {
String msgEng = "Good Morning";
// 생성자 : 언제 생성되는지 예의주시
public MessageEng() {
System.out.println("MessageEng() 생성");
}
@Override
public void sayHello() {
System.out.println(msgEng);
}
} // end MessageBean
MessgaeKor.java
package com.lec.spring.di01;
import com.lec.spring.beans.MessageBean;
public class MessageKor implements MessageBean {
String msgKor = "안녕하세요";
// 생성자 : 언제 생성되는지 주목
public MessageKor() {
System.out.println("MessageKor() 생성");
}
@Override
public void sayHello() {
System.out.println(msgKor);
}
}
DiMain01.java
package com.lec.spring.di01;
import com.lec.spring.beans.MessageBean;
/*
Dependency Injection (DI, 의존주입)
필요한 객체는 누가 만들어 사용하나?
방법1 : 직접 생성하여 사용
문제점 : MessageBean 객체의 설계가 바뀐다면????
결국 --> 사용하는 쪽에서의 코드수정 발생 -> 재컴파일
*/
public class DiMain01 {
public MessageBean msg;
public void setMsg(MessageBean msg) {
this.msg = msg;
}
public static void main(String[] args) {
System.out.println("Main 시작");
DiMain01 app = new DiMain01();
app.test();
System.out.println("Main 종료");
}
private void test() {
// 필요한 MessageBean 객체를
// msg = new MessageKor(); // 직접 만들어(new) 사용
// msg.sayHello();
// 필요한 MessageBean 객체의 설계 변경이 발생되면
msg = new MessageEng(); // 직접 만들어(new) 사용
msg.sayHello();
// 결국 --> 사용하는 쪽에서의 코드수정 발생 -> 재컴파일
}
}
용어
스프링 프레임워크에서 작업하면서 “컨테이너(Container)”, “스프링 컨테이너”, “,IoC 컨테이너”,
“Application Context 객체” “빈(bean) 컨테이너” .모두 (거의) 같은 말.
IOC : Inversion Of Control 의 약자
결국 스프링이란?
부품을 생성하고 조립하는 라이브러리 집합체 라고도 할 수 있음.
* 스프링 빈 (bean)
스프링은 경량 컨테이너로서 객체 생성, 소멸과 같은 Life Cycle을 관리하며 스프링 컨테이너로부터 필요한 객체를 얻을 수 있다.
스프링 컨테이너에 의해서 자바 객체가 만들어지게 되면 이 객체를 스프링은 스프링 빈(Bean)이라고 부른다.
* 스프링부트에서 bean 생성 & 사용
스프링부트의 경우
@Component, @Service, @Controller, @Repository, @Bean, @Configuration 등으로 필요한 빈들을 등록하고 필요한 곳에서 @Autowired를 통해 주입받아 사용하는 것이 일반적이다.
* 의존 자동 주입 : @Autowired 사용하기
‘컨테이너 안’에 이미 생성된 빈(bean)객체, 그리고 이를 의존하는 다른 빈 객체들로 하여금
자동적으로 참조 하여 주입될수 있게 하는 것이 Autowired(자동주입)를 구현하기 위해서는 아래와 같이 한다.
1. ‘자동주입 대상’에 @Autowired 애노테이션 사용
- 자동주입 대상 : 생성자, 멤버변수, setter메소드
★ Autowired(자동주입)는 세군데 발생
- 생성자 (Constructor injection)
- 멤버변수 (field injection)
- setter (setter injection)
@Autowired 검색순위
타입(다형성 적용) → 이름 → @Qualifier → @Primary
검색 실패시 예외 처리 또는 null 처리
@Autowired(required=false) : 빈이 존재하지 않으면 null 주입하여 처리
package com.lec.spring.di05;
import com.lec.spring.beans.MessageBean;
public class MessageEng implements MessageBean {
String msgEng = "Good Morning";
// 생성자 : 언제 생성되는지 예의주시
public MessageEng() {
System.out.println("MessageEng() 생성");
}
@Override
public void sayHello() {
System.out.println(msgEng);
}
} // end MessageBean
package com.lec.spring.di05;
import com.lec.spring.beans.MessageBean;
public class MessageKor implements MessageBean {
String msgKor = "안녕하세요";
// 생성자 : 언제 생성되는지 주목
public MessageKor() {
System.out.println("MessageKor() 생성");
}
@Override
public void sayHello() {
System.out.println(msgKor);
}
}
package com.lec.spring.di05;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import com.lec.spring.beans.MessageBean;
import com.lec.spring.beans.Score;
import com.lec.spring.beans.Student;
@Configuration
public class Config05 {
public Config05() {
System.out.println("Config05() 생성");
}
@Bean
public Score scoreA() {
return new Score(77, 55, 89, "괜찮아요");
}
@Bean(name = "Park")
public Student stu1() {
return new Student("박주찬", 19, scoreA());
}
@Bean(name = "Hong")
public Student stu2() {
return new Student("홍길동", 25, scoreA());
}
@Bean(name="eng")
public MessageBean msg1() {
return new MessageEng();
}
@Bean
@Primary // 동일한 타입의 빈이 여러개 있을때 autowired 되는 우선순위
public MessageBean msg2() {
return new MessageKor();
}
}
package com.lec.spring.di05;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.lec.spring.beans.MessageBean;
import com.lec.spring.beans.Student;
/*
* Autowired (자동주입) 는 세군데 발생
* - 생성자 (constructor injection)
* - 멤버변수 (field injection)
* - setter (setter injection)
*/
@SpringBootApplication
public class DIMain05 implements CommandLineRunner {
Student stu1;
Student stu2;
@Autowired // construcgtor injection
// Sprig 4.3 <= 부터는
// 생성자가 '하나만' 있는 경우 생성자 @Autowired 생략가능
// 기본적으로 자동주입(autowired) 는
// 1. 같은 타입의 bean 이 주입
// 2. 같은 타입이 여러개 이면, name 이 같거나 (혹은 유사) 한것이 주입
// 3. @Qualifier, @Primary 등으로 특정 이름의 bean 주입
public DIMain05(@Qualifier("Park") Student stu1, @Qualifier("Hong") Student stu2) { // 동일 타입의 Student bean 이 복수개 있는데도 동작한다?!!
System.out.println("DIMain05(Student, Student) 생성");
this.stu1 = stu1;
this.stu2 = stu2;
}
@Autowired // filed injection
MessageBean msg1; // 동일한 이름의 bean 자동주입
MessageBean msg2;
@Autowired // setter injection
public void setMsg2(MessageBean msg) {
this.msg2 = msg;
}
MessageBean msg3;
@Autowired // setter injection
@Qualifier("eng")
public void setMsg3(MessageBean msg) {
this.msg3 = msg;
}
public static void main(String[] args) {
System.out.println("Main 시작");
SpringApplication.run(DIMain05.class, args);
System.out.println("Main 종료");
}
@Override
public void run(String... args) throws Exception {
System.out.println("- run() ----------------------------");
System.out.println(stu1);
System.out.println(stu2);
msg1.sayHello();
msg2.sayHello();
msg3.sayHello();
System.out.println("-----------------------------");
}
}
'Spring' 카테고리의 다른 글
[Spring Boot] Validation (0) | 2022.05.12 |
---|---|
[SpringBoot] Request Parameter (0) | 2022.05.12 |
[SpringBoot] RequestMapping (0) | 2022.05.12 |
[SpringBoot] MVC (0) | 2022.05.12 |
[Spring] Spring이란 (0) | 2022.05.11 |