목차
0. 환경
- m1 macbook
- IntelliJ IDEA(m1) - 202102
- java 11(AdoptOpenJDK-11.0.11)
- 자바를 설치하지 않았다면 아래의 링크를 활용해주세요.
1. Controller 생성
- 도메인, 리포지토리, 서비스는 개발을 했고 다음 차례로 뷰랑 연결을 위해 컨트롤러가 필요하게 됩니다.
- 컨트롤러에서는 서비스의 기능이 필요하게 되는데 이 관계를 의존관계라고 합니다.
- 회원 컨트롤러가 회원서비스와 회원 리포지토리를 사용할 수 있게 의존관계를 준비합니다.
package hello.hellospring.controller;
import hello.hellospring.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
}
1.1. @Controller
- 컨트롤러를 스프링 빈으로 등록하기 위해 사용합니다.
1.2. @Autowired
- 생성자에 @Autowired 가 있으면 스프링이 연관된 객체를 스프링 컨테이너에서 찾아서 넣어줍니다.
- 객체 의존관계를 외부에서 넣어주는 것을 DI (Dependency Injection), 의존성 주입이라 합니다.
- 이전 테스트에서는 개발자가 직접(new) 주입했고, 여기서는 @Autowired에 의해 스프링이 주입해줍니다.
- @Autowired를 통한 DI는 helloConroller , memberService 등과 같이 스프링이 관리하는 객체에서만 동작합니다.
- 스프링 빈으로 등록하지 않고 내가 직접 생성한 객체에서는 동작하지 않습니다.
- 생성자가 1개만 있으면 생략 가능합니다.
1.3. 소스 설명
- MemberService 기능을 사용하기 위해(의존 관계) 생성자를 이용해 연결(@Autowired)합니다.
- 스프링 컨테이너가 생성될 때 @Controller로 등록된 MemberController 객체를 생성해 스프링 빈으로 컨테이너에 등록합니다.
- MemberController 객체를 생성하면서 생성자를 호출하게 되는데, 생성자에 @Autowired를 등록해두면 컨테이너에 스프링 빈으로 등록된 MemberService 객체를 연결시켜줍니다.
- DI (의존 관계 주입)를 스프링이 대신해줍니다.
- 의존 관계의 객체를 new로 직접 생성할 수도 있지만 스프링 컨테이너에 스프링 빈으로 등록해두면 여러 이점이 많으므로 스프링 컨테이너에 등록해서 받아서 쓰도록 변경해야 합니다.
- 스프링 빈으로 등록하게 되면 인스턴스를 여러 개 생성할 필요도 없게 되고 공용으로 사용하면 됩니다.
1.4. 실행
- MemberController를 작성 후 스프링 부트를 실행하게 되면 다음과 같은 에러가 출력됩니다.
- MemberService가 스프링 빈으로 등록되어 있지 않아서 나오는 에러입니다. 서비스와 리포지토리를 스프링 빈으로 등록해줍니다.
Consider defining a bean of type 'hello.hellospring.service.MemberService' in your configuration.
1.5. 스프링 빈을 등록하는 2가지 방법
- 컴포넌트 스캔과 자동 의존관계 설정
- 자바 코드로 직접 스프링 빈 등록하기
2. 스프링 빈 등록하기 (컴포넌트 스캔과 자동 의존관계 설정)
2.1. 스프링 빈 등록 방식 (컴포넌트 스캔과 자동 의존관계 설정)
- 스프링 실행 파일로 스프링을 실행합니다.
- 스프링 컨테이너가 생성됩니다.
- @Component 어노테이션이 붙은 클래스를 스캔 후 싱글톤으로 객체를 생성해 스프링 컨테이너에 스프링 빈으로 자동 등록합니다. (컴포넌트 스캔)
- 싱글톤 패턴: 오직 하나의 인스턴스만 생성합니다.
- 싱글톤으로 등록하기 때문에 같은 스프링 빈이면 모두 같은 인스턴스입니다.
- 기본으로 싱글톤으로 등록하게 됩니다. 설정으로 싱글톤이 아니게 설정할 수 있지만, 특별한 경우를 제외하면 대부분 싱글톤을 사용합니다.
- @Autowired를 사용한 생성자의 객체에 맞게 스프링 컨테이에서 스프링 빈을 찾아서 주입합니다. (자동 의존관계 설정)
- 생성자가 1개만 있으면 생략 가능합니다.
- @Autowired를 통한 DI는 helloConroller , memberService 등과 같이 스프링이 관리하는 객체에서만 동작합니다.
- 스프링 빈으로 등록하지 않고 내가 직접 생성한 객체에서는 동작하지 않습니다.
- 등록된 스프링 빈은 스프링이 관리해 줍니다. (이에 따라 다양한 이점이 생기게 됩니다.)
2.2. 컴포넌트 스캔
- @Component
- @Controller
- @Service
- @Repository
- @Controller, @Service, @Repository는 @Component 어노테이션이 아닌데 어떻게 스캔이 되나요?
- @Controller, @Service, @Repository 어노테이션 소스 안에 @Component 어노테이션이 등록되어 있습니다.
-
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Controller { /** * The value may indicate a suggestion for a logical component name, * to be turned into a Spring bean in case of an autodetected component. * @return the suggested component name, if any (or empty String otherwise) */ @AliasFor(annotation = Component.class) String value() default ""; } @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Service { /** * The value may indicate a suggestion for a logical component name, * to be turned into a Spring bean in case of an autodetected component. * @return the suggested component name, if any (or empty String otherwise) */ @AliasFor(annotation = Component.class) String value() default ""; } @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Repository { /** * The value may indicate a suggestion for a logical component name, * to be turned into a Spring bean in case of an autodetected component. * @return the suggested component name, if any (or empty String otherwise) */ @AliasFor(annotation = Component.class) String value() default ""; }
- @SpringBootApplication를 가지고 있는 스프링 부트 실행 파일에는 @ComponentScan이 있는 것을 확인할 수 있습니다. 따라서 스프링 부트를 실행하면서 컴포넌트를 스캔하게 됩니다.
-
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication { ( ... ) //생략 }
-
2.3. 스프링 빈 등록 범위
- @SpringBootApplication과 public static void main(String[] args)를 가지고 있는 스프링 부트 실행파일과 같은 패키지 그리고 하위 패키지에 있는 컴포넌트만 기본적으로 스캔해서 등록하게 됩니다.
- 초록 박스(스프링 부트 실행파일), 파란 박스(등록 가능한 범위), 빨간 박스(등록 불가능한 범위)
2.4. Why @Controller, @Service, @Repository
컴포넌트를 가지고 있는 어노테이션명이 다음과 같은 이유는 "컨트롤러로 외부의 요청을 받고 서비스에서 비즈니스 로직을 만들고 레포지토리에서 데이터를 저장"하는 정형화된 패턴이기 때문입니다.
3. 회원 서비스 스프링 빈 등록
@Service
public class MemberService {
private final MemberRepository memberRepository;
@Autowired
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
( ... ) //생략
}
4. 회원 리포지토리 스프링 빈 등록
@Repository
public class MemoryMemberRepository implements MemberRepository {
( ... ) 생략
}
'Backend > 코드로 배우는 스프링 부트' 카테고리의 다른 글
[코드로 배우는 스프링 부트] 6. 스프링 빈과 의존관계 (의존성 주입 방식) (0) | 2021.11.02 |
---|---|
[코드로 배우는 스프링 부트] 5. 스프링 빈과 의존관계 (자바 코드로 직접 스프링 빈 등록하기) (0) | 2021.11.01 |
[코드로 배우는 스프링 부트] 3-2. 회원 관리 예제 (서비스, DI) (0) | 2021.10.25 |
[코드로 배우는 스프링 부트] 3-1. 회원 관리 예제 (도메인, 리포지토리) (0) | 2021.10.24 |
[코드로 배우는 스프링 부트] 2. Spring 웹 개발 기초(정적 컨텐츠, MVC, API) (0) | 2021.10.17 |