스프링 빈을 등록하는 방법은 두가지
① (@Component)로 자바 클래스들을 설정하고 component scan 으로 자동 스프링빈에 등록되게 끔한다.
※ component scan 범위는 @SpringBootApplication 패키지 하위 범주 내 이고, 디폴트로 싱글톤 패턴으로 빈에 등록
② 자바 코드로 직접 스프링 빈에 등록하기
DI 방법은 세가지
① 필드 주입 : Java Reflection API를 사용하면, 접근 제한자를 무시하고 필드에 직접 접근할 수 있다. Spring Framework는 이를 이용하여 private으로 선언된 필드에서도 의존성을 주입할 수 있는 것
" 필드 주입은 의존성을 주입받는 클래스의 필드에 직접 의존성을 주입하는 방법입니다. 이 방법은 코드가 간결하다는 장점이 있지만, 의존성이 변경될 가능성이 있고 테스트하기 어렵다는 단점이 있습니다."
[필드 주입을 지양하는 이유]
필드 주입을 사용하면 순환, 참조 문제가 발생할 가능성
불변성을 해칠 수 있으므로 객체의 안정성을 보장하기 어려움
의존성 주입을 위해 Spring Container가 필요하게 되므로 테스트가 어려
@Autowired private final MemberRepository memberRepository;
② setter 주입 : 주입 대상 클래스에서 setter을 생성을 하여 꺼내쓰는 것 -> setter가 public 으로 되어있어야 되기 때문에, 캡슐화/정보은닉에 문제가 된다
" Setter 주입은 의존성을 주입받는 클래스의 setter 메서드를 통해 의존성을 주입하는 방법입니다. 이 방법은 객체가 생성된 후에도 의존성을 변경할 수 있다는 점에서 유연성을 제공하지만, 의존성이 변경될 가능성이 있기 때문에 불변성을 확보하기 어렵습니다."
<< Service >>
private MemberService memberService;
public setMemberService(MemberService memberService) {
this.memberService = memberService;
}
③ 생성자 주입 : 의존관계가 실행 중에 동적으로 변하는 경우는 거의 없으므로 생성자 주입을 권장.
생성자 주입은 의존성을 주입받는 클래스의 생성자를 통해 의존성을 주입하는 방법입니다. 이 방법은 객체가 생성될 때 의존성을 한번에 주입받기 때문에 의존성 주입 후에 변경이 불가능하다는 점에서 불변성을 확보할 수 있다는 장점이 있습니다.
private final MemberRepository memberRepository;
@Autowired
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
§ 참고
Dependencies Injection 은 크게 IOC 범주에 들어간다 IOC = DL(찾아가지고 넣는 것, look up : 찾아오면 Object 타입으로 받아온다) + DI(코드단에서 직접 주입) |
@Autowired를 통한 DI는 스프링에서 관리하는 객체에서만 동작한다, 스프링 빈에 등록하지 않고 내가 생성한 객체에서는 동작하지 않는다. |
스프링 빈을 등록하는 방법 ① ComponentScan를 이용한 자동 의존관계 설정
1. bean 등록
ⓐ 객체별 메서드 생성 : @Bean 으로 등록 및 @Scope 으로 생명주기 설정 ( singleTon / prototype )
: @SpringBootApplication 클래스에서 설정하며, 객체 인스턴스 호출 메서드를 생성하여 @Bean으로 등록한다.
@SpringBootApplication
public class Ex1Application2 {
@Bean // A객체를 반환하여 Spring Bean pool에 등록한다. ( pool 자료구조 : Collection )
@Scope("singleton")
A getA() {
return new A();
}
}
ⓑ 컴포넌트로 선언할 타입의 클래스 별 @Component으로 선언한다.
: @ SpringBootApplication 으로 선언된 클래스에서 @ConponentScan 애노테이션도 같이 쓰여야 한다.
@SpringBootApplication
@ComponentScan(basePackages = "com.example.ex1")
public class Ex1Application2 {
.....
}
- @ComponentScan(basePackages = "com.example.ex1") 애노테이션
: com.example.ex1 패키지 안에 있는 클래스 중에 bean pool에 등록가능한 클래스(Component Class)를 자동으로 등록해준다.
- Component Scan 으로 대상 클래스가 되는 조건 |
: 클래스를 @Component / @Component의 자식 애노테이션(@Controller, @Service, @Repository 등) 선언 : @Mapper는 인터페이스대상으로 선언하는 애노테이션이라 @Component를 상속받지 않는다. 컴포넌트처럼 이용이 가능한 이유는 매퍼 인터페이스를 구현한 클래스가 @repository 선언이 되기 때문이다. - @ComponentScan 을 쓰더라도 @Bean 사용하는 경우가 있음 : 외부 라이브러리를 사용하는 경우 (컴파일 된 소스코드의 경우 각 클래스마다 컴포넌트 애노테이션을 붙일수없으므로 생성) |
@Service, @Repository 등 인터페이스들은 @Component를 선언하였다, 그러므로 상속받은 상태이며 ComponentScan 대상
2. DI
의존성 주입의 개념과 필요성
@SpringBootApplication 클래스의 메인메서드가 실행되기 전에,
객체를 Spring Bean Pool에 등록을 하고, 이를 이용하여, 각 클래스간 Coupling 을 약화시키는 것
(협업 / 유지보수 : deCoupling일 수록 유리)
Spring Bean Pool 활용 없이 객체를 호출하면(= ex) 컨트롤러 클래스에 new 연산자 사용)
객체의 클래스와 컨트롤러의 클래스 간 의존성이 높아진다.
빈에서 객체를 꺼내 사용하는 방법으로 Autowired 사용한다
(디폴트 : 싱글톤 패턴이므로 인스턴스가 같다.)
1. 의존성 주입 대상객체 클래스에 @Component를 선언 2. @Autowired로 객체를 DI ※ 문제는 Spring Bean Pool 에 등록될 당시 하나의 인스턴스만 등록이 되므로, 같은 타입 2개 이상의 참조값이 필요한 경우 @Autowired를 따로 사용하여 DI를 하더라도 같은 인스턴스를 참조하게된다. (new 연산자를 완벽하게 방지할 순 없다.) |
종류
ⓐ 필드 주입 : Java Reflection API를 사용하면, 접근 제한자를 무시하고 필드에 직접 접근할 수 있다. Spring Framework는 이를 이용하여 private으로 선언된 필드에서도 의존성을 주입할 수 있는 것
" 필드 주입은 의존성을 주입받는 클래스의 필드에 직접 의존성을 주입하는 방법입니다. 이 방법은 코드가 간결하다는 장점이 있지만, 의존성이 변경될 가능성이 있고 테스트하기 어렵다는 단점이 있습니다."
[필드 주입을 지양하는 이유]
필드 주입을 사용하면 순환, 참조 문제가 발생할 가능성
불변성을 해칠 수 있으므로 객체의 안정성을 보장하기 어려움
의존성 주입을 위해 Spring Container가 필요하게 되므로 테스트가 어려
@Autowired private final MemberRepository memberRepository;
@Autowired A t1; @Autowired InterfaceA t2;\
// 인터페이스 활용하여 A타입과의 커플링 해소하는 방법도 있다.
ⓑ 생성자 주입 : 의존관계가 실행 중에 동적으로 변하는 경우는 거의 없으므로 생성자 주입을 권장.
생성자 주입은 의존성을 주입받는 클래스의 생성자를 통해 의존성을 주입하는 방법입니다. 이 방법은 객체가 생성될 때 의존성을 한번에 주입받기 때문에 의존성 주입 후에 변경이 불가능하다는 점에서 불변성을 확보할 수 있다는 장점이 있습니다.
private final MemberRepository memberRepository;
@Autowired // 생략가능
public MemberService(MemberRepository memberRepository) {// 파라미터값을 Bean pool에서 꺼내서 호출
// new 연산자가 없어도 @Autowired로 인해서 NullpointException이 일어나지 않는다.
this.memberRepository = memberRepository;
}
ⓒ setter 주입 : 주입 대상 클래스에서 setter을 생성을 하여 꺼내쓰는 것
-> setter가 public 으로 되어있어야 되기 때문에, 캡슐화/정보은닉에 문제가 된다
" Setter 주입은 의존성을 주입받는 클래스의 setter 메서드를 통해 의존성을 주입하는 방법입니다. 이 방법은 객체가 생성된 후에도 의존성을 변경할 수 있다는 점에서 유연성을 제공하지만, 의존성이 변경될 가능성이 있기 때문에 불변성을 확보하기 어렵습니다."
<< Service >>
private MemberService memberService;
@Autowired
public setMemberService(MemberService memberService) {
this.memberService = memberService;
}
스프링 빈을 등록하는 방법 ② 자바 코드로 직접 스프링 빈에 등록하기
1. @Configuration 으로 @Bean 등록 설정하기
@Configuration
public class SpringConfig {
@Bean
public MemberService memberService() {
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository() { // 해당 인터페이스는 Optional 구현
return new MemoryMemberRepository(); // 인터페이스를 구현한 클래스인스턴스르르 주입
}
}
-> memberRepository와 memberService는 스프링 빈에 등록이 되었고, 그중 memberService는 memberRepository를 사용하는 로직을 가지고 빈에 등록이 되었다
spring 이 뜰 때 @Configuration을 읽고, 해당 클래스 내의 @Bean 메서드의 로직들을 읽고 스프링 빈에 등록을 해준다.
2. DI
public class MemberService {
private final MemberRepository memberRepository;
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
참고 : 실무에서는 정형화된 MVC 같은 경우 컴포넌트 스캔을 이용하고, 정형화되지 않거나 상황에 따라 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈으로 등록한다.
내용 일부 출처 : https://inf.run/hivx6
[지금 무료]스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 강의 | 김영한 - 인프런
김영한 | 스프링 입문자가 예제를 만들어가면서 스프링 웹 애플리케이션 개발 전반을 빠르게 학습할 수 있습니다., 스프링 학습 첫 길잡이! 개발 공부의 길을 잃지 않도록 도와드립니다. 📣 확
www.inflearn.com
'SPRING' 카테고리의 다른 글
[LOMBOK]@AllArgsConstructor (롬복기능) (0) | 2024.12.10 |
---|---|
[Rest API] JSON과 XML로 반환 방법 (0) | 2024.12.10 |
Filter / Interceptor / AOP (0) | 2024.12.09 |
POST-Redirect-GET (PRG) 패턴 (0) | 2024.11.30 |
[Service & MySQL 에러] SQLIntegrityConstraintViolationException (0) | 2024.11.13 |