✍️
dodeon
  • 개발왕, 도던
  • 스프링 시큐리티 인 액션
    • 오늘날의 보안
    • 안녕! 스프링 시큐리티
    • 사용자 관리
    • 암호 처리
    • 인증 구현
    • 실전: 작고 안전한 웹 애플리케이션
    • 권한 부여 구성: 액세스 제한
    • 권한 부여 구성: 제한 적용
    • 필터 구현
    • CSRF 보호와 CORS 적용
    • 실전: 책임의 분리
    • OAuth 2가 동작하는 방법
    • OAuth 2: 권한 부여 서버 구현
  • 스프링 고급편
    • 스레드 로컬
    • 템플릿 메서드 패턴과 콜백 패턴
    • 프록시 패턴과 데코레이터 패턴
  • 스프링 입문
    • 프로젝트 환경설정
    • 스프링 웹 개발 기초
    • 회원 관리 예제 - 백엔드
    • 스프링 빈과 의존 관계
    • 회원 관리 예제 - MVC
    • 스프링 DB 접근 기술
      • JDBC
      • JPA
    • AOP
  • 스프링 핵심 원리
    • 객체 지향 설계와 스프링
      • 스프링의 탄생
      • 객체 지향 프로그래밍
      • 좋은 객체 지향 설계의 원칙
      • 객체 지향 설계와 스프링
    • 스프링 핵심 원리 이해
      • 회원 도메인 개발
      • 주문 도메인 개발
    • 객체 지향 원리 적용
      • 관심사의 분리
      • 새로운 구조와 정책 적용
      • 정리
      • IoC, DI, 컨테이너
      • 스프링으로 전환하기
    • 스프링 컨테이너와 스프링 빈
      • 스프링 빈 기본 조회
      • 동일 타입이 둘 이상일 때 조회
      • 상속일 때 조회
      • BeanFactory와 ApplicationContext
      • 다양한 설정 형식
      • 스프링 빈 설정 메타 데이터
    • 싱글턴 컨테이너
      • @Configuration과 싱글턴
    • 컴포넌트 스캔
      • 탐색 위치와 기본 탐색 대상
      • 필터와 중복 등록
    • 의존 관계 자동 주입
      • 롬복과 최신 트렌드
      • 조회 빈이 2개 이상일 때
      • 애너테이션 직접 만들기
      • 조회한 빈이 모두 필요할 때
      • 올바른 실무 운영 기준
    • 빈 생명 주기 콜백
      • 인터페이스 방식
      • 메서드 지정 방식
      • 애너테이션 방식
    • 빈 스코프
      • 프로토타입 스코프
      • Provider
      • 웹 스코프
  • 스프링 MVC
    • 웹 애플리케이션 이해
      • 서버
      • 서블릿
      • 멀티 스레드
      • HTML, HTTP API, CSR, SSR
      • 자바 백엔드 웹 기술 역사
    • 서블릿
      • HttpServletRequest
      • HTTP 요청 데이터
      • HttpServletResponse
      • HTTP 응답 데이터
    • 서블릿, JSP, MVC 패턴
      • 서블릿으로 만들기
      • JSP로 만들기
      • MVC 패턴
    • MVC 프레임워크 만들기
      • 프론트 컨트롤러 패턴
      • View 분리
      • Model 추가
      • 단순하고 실용적인 컨트롤러
      • 유연한 컨트롤러
      • 정리
    • 스프링 MVC의 구조 이해
      • 스프링 MVC 전체 구조
      • 핸들러 매핑과 핸들러 어댑터
      • 뷰 리졸버
      • 스프링 MVC 시작하기
      • 스프링 MVC 컨트롤러 통합
      • 스프링 MVC 실용적인 방식
    • 스프링 MVC 기본 기능
      • 프로젝트 생성
      • 로깅
      • 요청 매핑
      • HTTP 요청의 기본 및 헤더 조회
      • HTTP 요청 파라미터
      • HTTP 요청 메시지
      • HTTP 응답
      • HTTP 메시지 컨버터
      • 요청 매핑 핸들러 어댑터
    • 스프링 MVC 웹 페이지 만들기
    • 메시지, 국제화
      • 스프링 메시지 소스
    • Validation
      • BindingResult
      • FieldError, ObjectError
      • 오류 코드와 메시지 처리
      • Validator 분리
    • Bean Validation
      • Form 전송 객체 분리
      • HTTP 메시지 컨버터
    • 로그인
      • 쿠키
      • 세션
      • 서블릿 HTTP 세션
      • 서블릿 필터
      • 스프링 인터셉터
      • ArgumentResolver 활용
    • 예외 처리와 오류 페이지
      • 오류 화면 제공
      • 필터
      • 인터셉터
      • 스프링 부트 오류 페이지
    • API 예외 처리
      • 스프링 부트 기본 오류 처리
      • HandlerExceptionResolver
      • ExceptionResolver
      • ControllerAdvice
    • 스프링 타입 컨버터
      • Converter
      • ConversionService
      • 뷰 템플릿에 적용하기
      • Formatter
    • 파일 업로드
      • 서블릿과 파일 업로드
      • 스프링과 파일 업로드
      • 파일 업로드 및 다운로드 예제
  • 자바 ORM 표준 JPA 프로그래밍
    • JPA 소개
    • JPA 시작하기
    • 영속성 관리
      • 영속성 컨텍스트
      • 플러시
      • 준영속 상태
    • Entity 매핑
      • 객체와 테이블 매핑
      • 데이터베이스 스키마 자동 생성
      • 필드와 칼럼 매핑
      • 기본 키 매핑
      • 실전 예제
    • 연관 관계 매핑
      • 단방향 연관 관계
      • 양방향 연관 관계
      • 실전 예제
    • 다양한 연관 관계 매핑
      • 다대일
      • 일대다
      • 일대일
      • 다대다
      • 실전 예제
    • 고급 매핑
      • 상속 관계 매핑
      • 매핑 정보 상속
      • 실전 예제
    • 프록시와 연관관계 관리
      • 프록시
      • 즉시 로딩과 지연 로딩
      • 영속성 전이와 고아 객체
      • 실전 예제
    • 값 타입
      • 기본값 타입
      • 임베디드 타입
      • 값 타입과 불변 객체
      • 값 타입의 비교
      • 값 타입 컬렉션
      • 실전 예제
    • 객체 지향 쿼리 언어 - 기본
      • 기본 문법과 쿼리 API
      • 프로젝션
      • 페이징
      • 조인
      • 서브 쿼리
      • JPQL 타입 표현과 기타 식
      • 조건식
      • JPQL 함수
    • 객체 지향 쿼리 언어 - 중급
      • 경로 표현식
      • fetch join
      • 다형성 쿼리
      • Entity 직접 사용
      • Named 쿼리
      • 벌크 연산
  • 스프링 부트와 JPA 활용 - 웹 애플리케이션 개발
    • 프로젝트 환경설정
    • 도메인 분석 설계
      • 도메인 분석 설계
      • Entity 클래스 개발
      • Entity 설계 시 주의점
    • 애플리케이션 아키텍처
    • 회원 도메인 개발
    • 상품 도메인 개발
    • 주문 도메인 개발
      • Entity, 리포지토리, 서비스 개발
      • 주문 기능 테스트
      • 주문 검색 기능 개발
    • 웹 계층 개발
      • 변경 감지와 병합
  • 스프링 부트와 JPA 활용 - API 개발과 성능 최적화
    • API 개발 기본
      • 회원 등록 API
      • 회원 수정 API
      • 회원 조회 API
    • 지연 로딩과 조회 성능 최적화
      • Entity 직접 노출
      • Entity를 DTO로 변환
      • JPA에서 DTO 직접 조회
    • 컬렉션 조회 최적화
      • Entity 직접 노출
      • Entity를 DTO로 변환: 페치 조인
      • Entity를 DTO로 변환: 페이징과 한계 돌파
      • DTO 직접 조회
      • DTO 직접 조회: 컬렉션 조회 최적화
      • DTO 직접 조회: 플랫 데이터 최적화
      • 정리
    • OSIV와 성능 최적화
  • 스프링 데이터 JPA
    • 예제 도메인 모델
    • 공통 인터페이스 기능
      • 순수 JPA 기반 리포지토리
      • 공통 인터페이스 설정
    • 쿼리 메서드 기능
      • JPA Named Query
      • @Query
      • 파라미터 바인딩
      • 반환 타입
      • 페이징과 정렬
      • 벌크성 수정 쿼리
      • @EntityGraph
      • JPA Hint & Lock
    • 확장 기능
      • 사용자 정의 리포지토리
      • Auditing
      • Web 확장
    • 스프링 데이터 JPA 분석
    • 나머지 기능
      • Specifications
      • Query By Example
      • Projections
      • Native Query
  • Querydsl
    • 프로젝트 환경 설정
    • 예제 도메인 모델
    • 기본 문법
      • JPQL vs Querydsl
      • Q-Type 활용
      • 검색 조건
      • 결과 조회
      • 정렬
      • 페이징
      • 집합 함수
      • 조인
      • 서브 쿼리
      • Case 문
      • 상수, 문자 더하기
    • 중급 문법
      • 프로젝션과 결과 반환
      • 동적 쿼리
      • 수정, 삭제 벌크 연산
      • SQL Function 호출
    • 순수 JPA와 Querydsl
      • 순수 JPA 리포지토리와 Querydsl
      • 동적 쿼리와 성능 최적화 조회
      • 조회 API 컨트롤러 개발
    • 스프링 데이터 JPA와 Querydsl
      • 스프링 데이터 페이징 활용
      • 스프링 데이터 JPA가 제공하는 Querydsl 기능
  • 데이터 접근 핵심 원리
    • JDBC 이해
      • JDBC와 최신 데이터 접근 기술
      • 데이터베이스 연결
      • JDBC 개발
  • 백엔드 시스템 실무
    • CPU bound 애플리케이션
      • CPU를 극단적으로 사용하는 애플리케이션
      • 스트레스 테스트 툴로 성능 측정
      • Dockerized 애플리케이션 GCP 배포
      • Jenkins를 이용한 배포
    • CPU bound 애플리케이션 무중단 배포
      • nginx를 통한 로드밸런싱 구성
      • 서버를 늘려서 성능 측정
    • 배포 자동화와 협업을 위한 Git
      • GitHub Webhook과 jenkins로 배포 자동화
      • 머지할 때 발생하는 충돌 해결하기
      • 실무에서 유용한 Git 꿀팁
    • I/O bound 애플리케이션
    • Message Queue를 도입하여 데이터 유실 방지
      • 스트레스 테스트
    • 검색과 분석을 위한 저장소 ElasticSearch
    • Kubernetes
  • 모든 개발자를 위한 HTTP 웹 기본 지식
    • 인터넷 네트워크
      • IP
      • TCP, UDP
      • PORT
      • DNS
    • URI와 웹 브라우저 요청 흐름
    • HTTP 기본
      • 클라이언트-서버 구조
      • stateful, stateless
      • 비 연결성
      • HTTP 메시지
    • HTTP 메서드
    • HTTP 메서드 활용
    • HTTP 상태 코드
    • HTTP 헤더 - 일반
      • 표현
      • 콘텐츠 협상
      • 전송 방식
      • 정보
      • Authorization
      • 쿠키
    • HTTP 헤더 - 캐시
      • 검증 헤더와 조건부 요청
      • 조건부 요청 헤더
      • 프록시 캐시
      • 캐시 무효화
  • 김영한의 실전 자바
    • 제네릭
  • 예제로 배우는 스프링 입문
    • 예제로 배우는 스프링 입문(개정판)
      • PetClinic 예제
      • 스프링 IoC
      • 스프링 AOP
      • 스프링 PSA
  • 스프링 프레임워크 핵심 기술
    • 스프링 프레임워크 핵심 기술
      • IoC 컨테이너와 빈
        • 스프링 IoC 컨테이너와 빈
        • ApplicationContext와 빈 설정
        • @Autowired
        • @Component와 컴포넌트 스캔
        • 빈의 스코프
        • Environment
        • MessageSource
        • ApplicationEventPublisher
        • ResourceLoader
      • Resource/Validation
        • Resource 추상화
        • validation 추상화
      • 데이터 바인딩 추상화
      • SpEL
      • 스프링 AOP
      • Null-Safety
  • 스프링 부트 개념과 활용
    • 스프링 부트 원리
      • 자동 설정
      • 내장 서버
        • 컨테이너와 서버 포트
        • HTTPS와 HTTP2
      • 독립적으로 실행 가능한 JAR
    • 스프링 부트 활용
      • Spring Application
      • 외부 설정
      • 프로파일
      • 로깅
      • 테스트
      • Spring Boot Devtools
    • 스프링 웹 MVC
      • 소개
      • HttpMessageConverters
      • ViewResolver
      • 정적 리소스
      • 웹 JAR
      • index 페이지와 파비콘
      • ExceptionHandler
      • Spring HATEOAS
      • CORS
  • THE JAVA
    • JVM 이해하기
      • 자바, JVM, JDK, JRE
      • JVM 구조
      • 클래스 로더
      • Heap
      • Garbage Collector
    • 리플렉션
      • 클래스 정보 조회
  • The Java - Test
    • JUnit 5
      • JUnit 시작하기
      • JUnit 시작하기
    • Mockito
Powered by GitBook
On this page
  • 일반적인 (의존성에 대한) 제어권
  • IoC
  • 빈
  • 의존성 관리
  • 스프링 IoC 컨테이너
  • BeanFactory
  • ApplicationContext
  • 빈 스코프
  • 빈
  • 빈 등록하기
  • Component Scanning
  • 직접 등록하기
  • 빈 사용하기
  • 의존성 주입
  • 생성자
  • 필드
  • Setter

Was this helpful?

  1. 예제로 배우는 스프링 입문
  2. 예제로 배우는 스프링 입문(개정판)

스프링 IoC

일반적인 (의존성에 대한) 제어권

내가 사용할 의존성은 내가 만든다.

class OwnerController {
    private OwnerRepository repository = new OwnerRepository();
}

일반적으로는 이렇게 쓰고 싶은 의존성 new OwnerRepository()를 자기가 직접 만들어 사용한다. 제어권이 자기 자신인 OwnerController에 있어서 자기가 관리한다.

IoC

내가 사용할 의존성은 누군가 알아서 해주겠지.

내가 사용할 의존성의 타입(또는 인터페이스)만 맞으면 어떤 것이든 상관없다. 그래야 내 코드 테스트 하기도 편하지.

의존성 주입도 IoC의 일종이다. 의존성을 관리하는 것 자체를 다른 곳에 위임했기 때문이다.

class OwnerController {
   // OwnerController는 OwnerRepository를 사용은 하지만 만들진 않는다.
   // OwnerController 밖에서 누군가가 주입시켜준다.
   private OwnerRepository repo;

   // 즉, 생성자를 통해 그것을 파라미터로 받아온다.
   // 더 이상 의존성을 만드는 일은 OwnerController가 하는 게 아니다.
   public OwnerController(OwnerRepository repo) {
       this.repo = repo;
   } 

   // repo를 사용한다.
}

class OwnerControllerTest {
   @Test
   public void create() {
         OwnerRepository repo = new OwnerRepository();
         OwnerController controller = new OwnerController(repo);
   }
}

이제 의존성은 OwnerController 밖에서 만들어 주입(Dependency Injection) 해준다. DI는 일종의 Inversion of Control이다. 의존성을 관리하는 그 자체, 제어권이 역전되었기 때문이다. 자기 자신이 아니라 외부의 누군가가 제어하기 때문이다.

의존성 주입과 IoC는 스프링만의 개념은 아니다. 스프링을 사용하면 스프링이 제공하는 IoC 기능을 사용할 수 있다.

빈

스프링이 관리하는 객체

의존성 관리

특정 생성자나 애너테이션 등을 통해 필요한 의존성을 주입해주는 것.

Reference

스프링 IoC 컨테이너

빈을 만들고, 서로의 의존성을 엮어주고, 그렇게 만들어진 빈을 제공한다. 프로젝트에 있는 모든 클래스가 빈으로 등록되는 것은 아니다.

의존성 주입은 빈끼리만 가능하다. 즉, IoC 컨테이너 안에 들어있는 객체끼리만 의존성 주입이 가능하다.

BeanFactory

사실상 IoC 컨테이너

ApplicationContext

BeanFactory를 상속하면서 그밖의 다양한 일들도 함께 수행한다.

public class BeanTest {
    @Test
    public void getBean() {
        // 애플리케이션 컨텍스트에 있는 모든 빈의 이름을 가져올 수 있다.
        applicationContext.getBeanDefinitionNames();
        // 존재하는 빈 이름을 넣고 체크해보면 null이 아닌 것을 알 수 있다.
        OwnerController bean = applicationContext.getBean(OwnerController.class);
        assertThat(bean).isNotNull();
    }   
}

하지만 이렇게 직접 applicationContext를 사용할 일은 없다. application context가 가지고 있는 빈을 알아서 주입해주기 때문이다.

빈 스코프

@Controller
class OnwerController{
    private final OwnerRepository owners;

    @GetMapping("/bean")
    @ResponseBody
    public String bean() {
        // 둘은 같은 해시 값을 출력한다.
        return applicationContext.getBean(OwnerRepository.class) + "\n" + this.owners;
     }
}

스프링은 빈을 매번 새로 만들지 않고 재사용 한다. 멀티 스레드 상황에서 싱글턴을 사용하는 건 번거롭고 조심스럽다. 하지만 IoC를 이용하면 특별한 코드를 넣지 않아도 IoC에 등록된 빈으로 편하게 싱글턴 스코프를 구현할 수 있다.

Reference

빈

스프링 IoC 컨테이너가 관리하는 객체

OwnerController ownerController = new OwnerController();

위 코드는 직접 new를 해서 만든 인스턴스이므로 빈이 아니다.

OwnerController ownerController = applicationContext.getBean(OwnerController.class);

위 객체는 애플리케이션 컨텍스트에 등록된 빈이다. 스프링이 얘기하는 빈에 해당한다.

그럼 어떻게 하면 객체를 빈으로 등록할 수 있을까?

빈 등록하기

Component Scanning

애너테이션으로 등록하는 방식. 애너테이션은 그 자체가 애너테이션을 처리하는 것은 아니다. 그냥 애너테이션일 뿐이다.

  • @Component

    • @Repository

    • @Service

    • @Controller

    • @Configuration

애너테이션 프로세서 중에 스프링 IoC 컨테이너가 사용하는 여러가지 인터페이스가 있다. 이 인터페이스를 라이프 사이클 콜백이라고 부른다.

라이프 사이클 콜백에는 @Component 애너테이션이 붙어있는 모든 클래스를 찾아서 그 클래스의 인스턴스를 빈으로 등록하는 애너테이션 프로세서가 등록되어 있다.

@SpringBootApplication(proxyBeanMethods = false)
public class PetClinicApplication {
    public static void main(String[] args) {
        SpringApplication.run(PetClinicApplication.class, args);
    }
}
@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 {
    ...
}

@SpringBootApplication에는 @ComponentScan이 있다. @ComponentScan은 어디부터 어디까지 찾아보라고 알려준다. 그러면 @ComponentScan의 모든 하위 클래스를 훑어보면서 @Repository, @Service, @Controller 등등 다양한 애너테이션을 찾는다.

즉, 우리가 하나하나 빈으로 등록하지 않아도 스프링이 알아서 IoC 컨테이너가 만들어질 때 @ComponentScan에 따라 해당 클래스를 빈으로 등록해준다.

public interface OwnerRepository extends Repository<Owner, Integer> {
    ...
}

Repository 는 조금 특이한 방식으로 등록된다. 스프링 JPA에 의해 등록되기 때문에 애너테이션이 없어도 된다.

특정 인터페이스(Repository)를 상속하면, 해당 인터페이스를 상속받는 인터페이스(OwnerRepository)를 찾는다. 그리고 그 인터페이스의 구현체를 내부적으로 생성해서 빈으로 등록한다.

직접 등록하기

XML이나 자바 설정 파일이 직접 하나하나 등록하는 방식.

@Configuration
public class SampleConfig {
    @Bean
    public SampleController sampleController() {
        // 리턴하는 이 객체 자체가 IoC 컨테이너의 빈으로 등록된다.
        return new SampleController();
    }
}

// 그럼 더 이상 이 클래스에 @Controller를 붙일 필요가 없다.
public class SampleController {
    ...
}

요즘 추세는 자바 설정 파일을 사용하는 것이다. @Configuration 애너테이션을 붙인 클래스에 빈으로 등록하고 싶은 내용을 추가하면 된다.

@RunWith(SpringRunner.class)
@SpringBootTest
public class SampleControllerTest {
    @Autowired
    ApplicationContext applicationContext;

    @Test
    public void testDI() {
        SampleController bean = applicationContext.getBean(SampleController.class);
        assertThat(bean).isNotNull();
    }
}

따라서 위의 테스트는 성공적으로 실행된다. 직접 설정한 빈도 애플리케이션 컨텍스트에 등록되어 있는 것이다.

빈 사용하기

class OwnerController {
    @Autowired
    private OwnerRepository owners;
}

생성자로 주입받는 대신 @Autowired나 @Inject를 사용하면 IoC 컨테이너에 들어있는 빈을 주입받아 사용할 수 있다.

SampleController bean = applicationContext.getBean(SampleController.class);

물론 이렇게 직접 주입받을 수도 있지만 @Autowired를 자주 쓰게 될 것이다.

의존성 주입

필요한 의존성을 어떻게 받아올까? @Autowired나 @Inject를 어디에 붙여야 할까?

생성자

스프링에서 제일 권장하는 방법이다. 필수적으로 사용해야 하는 레퍼런스가 없으면 인스턴스를 만들지 못하도록 강제하기 때문이다.

경우에 따라 A가 B를 참조하고 B가 A를 참조하는 순환 참조(Circular Dependency)가 발생할 수 있다. 만약 둘 다 생성자 주입을 사용하고 있다면 인스턴스를 생성할 수가 없다. 이런 경우에는 필드나 Setter 주입을 사용할 수 있다. 하지만 되도록 순환 참조가 발생하지 않도록 설계하는 것이 제일 좋다.

@Controller
class OwnerController {
    // 생략 가능
    @Autowired
    public OwnerController(OwnerRepository clinicService) {
        this.owners = clinicService;
    }
}

스프링 4.3 부터 클래스에 생성자가 하나 뿐이고 그 생성자가 주입받는 레퍼런스 변수가 빈으로 등록되어 있다면, 그 빈을 자동으로 주입한다. 따라서 위의 @Autowired를 생략할 수 있다.

필드

@Controller
class OwnerController {
    @Autowired
    private OwnerRepository owners;
}

필드 주입엔 final을 붙일 수 없다. final은 오직 생성자 주입만을 이용해 초기화할 수 있다. 생성자 주입에 꼭 써야하는 것은 아니지만, 한 번 주입받은 후 레퍼런스가 바뀌지 않게 하기 위함이다.

Setter

@Controller
class OwnerController {
    private OwnerRepository owners;

    @Autowired
    public void setOwners(OwnerRepository owners) {
        this.owners = owners;
    }
}

스프링 IoC가 OwnerController 인스턴스를 만들고 나서, Setter를 통해 IoC 컨테이너에 있는 빈 중에 OwnerRepository 타입을 찾아 owners에 넣어준다.

public class SampleRepository {

}

@Controller
public class SampleController {
    @Autowired
    private SampleRepository sampleRepository;
}

이렇게 Repository를 빈으로 등록하지 않고 주입하려고 하면 애플리케이션 빌드 자체가 되지 않는다. NoSuchBeanDefinitionException이 발생하며 No qualifying bean이라는 메시지가 출력된다.

PreviousPetClinic 예제Next스프링 AOP

Last updated 5 years ago

Was this helpful?

Inversion of Control Containers and the Dependency Injection pattern
Interface BeanFactory
Interface ApplicationContext