오늘도 스프링 공부를 시작하자
금요일이기 때문에 좀더 열심히 ㅎ…

주말에 개념공부 조금 더해서 다음주에 차질없도록해야겠다!










스프링이 나에게도 주입됐으면…


@Configuration

이 어노테이션을 단 클래스는
빈 설정을 담당하는 클래스가 된다. 담당된 클래스 안에서
@Bean 어노테이션을 메소드에 선언해주면
그 매소드의 반환된 객체를 통해 빈을 정의하고 생명주기를 설정하게된다.

@Configuration
public class AppConfig {
    @Bean
    public MemberService memberService (){
        return new MemberService(memberRepository());
    }
    @Bean
    public MemberRepository memberRepository() {
        return new MemberRepository();
    }
}

AppConfig라는 클래스를 빈 설정 담당 클래스로 정하고
안에 정의된 매소드를 @Bean 어노테이션을 달아
스프링 컨테이너에서 객체로 관리할 수 있다.

@ComponentScan

@Component가 붙은 모든 클래스를 스프링이 빈으로 자동등록해준다.
설정 정보와 같이 붙여주면되고, 의존관계를 자동주입해주는 @Autowired 기능을 제공해준다.
기본적으로 @Component가 붙으면 자동으로 스캔하면서 빈을 등록하고
이외에 부가기능을 수행하면서 스캔까지 하는
어노테이션들(@Service,@Controller, @Configuration, Reposiotry)이 있다.

컴포넌트 스캔 용도와 부가기능을 수행하는 애노테이션들
@Service : 특별한처리는 하지 않음. 비지니스로직이 여기에 있구나라는 주석정도의 기능
@Controller : 스프링 MVC 컨트롤러로 인식
@Repository : 스프링 데이터 접근 계층으로 인식하고, 데이터 계층의 예외를 스프링 예외로 변환해줌.
@Configuration : 스프링 설정정보 인식, 스프링 빈이 싱글톤으로 유지하도록 추가 처리해줌

1). 구성정보설정 + 컴포넌트스캔

@Configuration
@ComponentScan
public class AutoAppConfig {
}

현재는 탐색위치 default와 필터는 적용되지 않음 (아래에 설명)


2). 컴포넌트 + 오토와이어드

@Component
public class MemberserviceImpl{
    private final MemberRepositroy memberRepositroy;

    @Autowired // getBean(MemberRepository memberRepository) 와 같은기능
    public MemberserviceImpl(MemberRepositroy memberRepositroy) {
        this.memberRepositroy = memberRepositroy;
    }
}

@Autowired란?

간단하게 스프링 컨테이너안에 우리가 등록해 놓은 Bean을
자동으로 같은 이름을 찾아서 불러와 주입해주는 것이다.
즉 우리가 getBean(MemberRepository memberRepository); 와 같은 형식으로
객체를 확인할 수 있었다면, 이 행위를 Autowired가 매개변수를 보고
자동으로 찾아서 값을 주입해주는 것이다.

ComponentScan의 기능들

@ComponentScan(
    basePackages = "hello.core.member",
    basePackageClasses = AutoConFig.class,
    excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class)
) // AppConfig의 수동으로 등록한 것을 제외시킴

basePackage
탐색 시작위치를 정한다. 이패키지를 포함해서 하위 패키지를 모두 탐색함

basePackageClasses
지정한 클래스의 패키지를 탐색 시작 위로 지 정한다.

default
basePackage, basePackageClasses를 지정을안했을경우
ComponentScan이 붙은 설정 정보 클래스의 패키지가 시작 위치가 된다.

** ComponentScan은 SpringBootApplication 안에 포함되어있어
SpringBootApplication을 패키지 상위에 두는 것이 관례이다.
즉, 패키지 상위에 둘 경우 패키지 안에 있는 내용을 확인한다.

Filter
위의 코드로만 보면 Configuration애노테이션이 붙은 클래스는
컴포넌트 스캔을 하지 않는 다는 뜻이다.
(기본적으로 Configureation도 @Component가 붙어있어 스캔대상이다.)

includeFilters : 컴포넌트 스캔 대상을 추가로 지정
excludeFilters : 컴포넌트 스캔에서 제외할 대상을 지정

FilterType 옵션

옵션 내용
ANNOTATION 기본값, 애노테이션을 인식해 동작
ASSIGNABLE_TYPE 지정한 타입과 자식 타입을 인식해 동작
ASPECTJ AspectJ 패턴 사용
REGEX 정규 표현 사용
CUSTOM TypeFilter라는 인터페이스를 구현해서 처리


자동 빈등록 vs 자동 빈등록 시 충돌 날 경우

Component 이름이 충돌날경우 ex) @Component(“memberService”) 두개가 존재할때
이름 변경외에는 충돌날일이 거의 없다.
만약 충돌이 날경우에 아래와 같은 런타임 에러가 발생한다.





수동 빈 빈동록 vs 자동 빈등록 충돌 날 경우
오버라이딩된다. 수동 빈이 자동빈을 오버라이딩해버린다.

@Component
public class MemoryMemberRepository {

}
@Configuration
@ComponentScan
public class AutoAppConfig {
    @Bean(name = "memoryMemberRepository")
    MemberRepositroy memberRepositroy(){
        return new MemoryMemberRepository();
    }
}

예를 들어 @Componet 애노테이션이 붙은
클래스 MemoryMemberRepository는 자동으로 빈등록이된다.
(name = memoryMemberRepository , 첫문자는 소문자로 저장됨)

@Bean을 통해 수동으로 등록해준빈의 이름을
동일하게 memoryMemberRepository로 바꾸었을때




위와 같이 오러라이딩 되었다고 하고 정상 실행된다.
하지만 스프링 프레임워크에서는 오류가 나질 않고 오버라이딩 되지만
스프링 부트로 실행 시킬 경우에는 에러가 발생하게끔 default로 설정되어있다.

스프링 부트를 실행시킬때 발생하는 에러

The bean 'memoryMemberRepository', defined in class path resource [hello/core/AutoAppConfig.class], could not be registered. A bean with that name has already been defined in file [/Users/ljh/Desktop/Study/인프런_김영한/1. Spring 핵심 원리/1. 객체지향 설계와 스프링_자료/progrma_spring/core/build/classes/java/main/hello/core/member/MemoryMemberRepository.class] and overriding is disabled.

Action:

Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

위에서 명시하기로는 오버라이딩의 경우가 있어 에러가 발생한 것이다.
아래에서 spring.main.allow-bean-definition-overriding=trure 셋팅을 해주면
오버라이딩된채로 사용할 수 있다고 한다.








위 사진과 같이 애플리케이션 속성에 동일하게 설정하면
에러를 실행하지 않고 정상적으로 실행되는 모습을 볼 수 있다.


@Bean 과 @Component의 차이점?

여기서 Bean과 Component의 중요한 차이점이 보이는데

@Bean은 메서드 레벨에서 선언하며, 반환되는 객체를 개발자가
수동으로 등록하는 애노테이션이다.

@Component는 클래스 레벨에서 선언함으로 스프링이 런타입시에
컴포넌트스캔을 하여 자동으로 빈을 찾고 등록하는 애노테이션이다.

이말은 무슨말이냐.
만약 외부라이브러리를 사용한다고 가정할떄
@Component 애노테이션을 그 해당 외부라이브러리 클래스 위에
붙여주지 못한다. 우리가 건드릴 수 없기 때문이다.
그렇기에 @Bean을 이용해 외부라이브러리 클래스의
메소드로 반환되는 객체를 수동으로 Spring 컨테이너에 등록해주는 것이고

@Component는 위에서 얘기했듯이
우리가 자바코드로 작성중인 클래스위에 붙여서 많이 쓴다.

즉, Bean = 외부라이브러리 사용시 사용 / Component = 내부 클래스에서 사용


여러 주입 방법

의존성을 주입하는 방법은 크게 4가지가있다
성자 주입, setter 주입, 필드 주입, 일반 메서드 주입

그 중 우리가 계속 사용하게될거는 생성자 주입이다.
간단하게 3가지 정도를 알아보자

1). 생성자 주입

@Component
public class MemberserviceImpl{
    private final MemberRepositroy memberRepositroy;

    @Autowired
    public MemberserviceImpl(MemberRepositroy memberRepositroy) {
        this.memberRepositroy = memberRepositroy;
    }
}

위와 같이 생성자를 통해서
참조변수에 객체를 넣어주는게 생성자 주입이다.

2). setter 주입

@Component
public class MemberserviceImpl{
    private final MemberRepositroy memberRepositroy;

    @Autowired
    public setMemberRepositroy (MemberRepositroy memberRepositroy) {
        this.memberRepositroy = memberRepositroy;
    }
}

생성자주입과 유사하지만 setter주입은
setter 메서드를 생성하여 의존 관계를 주입하게된다.

3). 필드주입

@Component
public class MemberserviceImpl{
	@Autowired
	private final MemberRepositroy memberRepositroy;
}

필드 변수에 @Autowired 애노테이션을달아 주입하는 방법이다.
코드가 간결해지지만 외부에서 변경이 불가능하다.


오늘은 의존성 주입에 여러 형태와
@ComponentScan 어노테이션에 대한 여러가지를 알아보았다.
어느정도 이해가간다. Componet를 이용해
클래스를 빈으로 만들고 컨테이너에서 관리함으로
@Autowired를 사용해 그 객체를 주입해준다!! 라는 흐름은 어느정도
이해한 것 같다. 공부하면서 여러가지 개념들과
심도있는 지식들이 나올때 집중력을 잃었지만
주말을 통해서 오늘까지 배웠던 내용을 좀더 정리를하고 다음주를 맞이해야겠다

오늘 공부는 여기서 끝!!


오늘의 커피량: ☕️ ☕️ ☕️ ☕️
오늘의 점심: 삽겹살, 밥