[Spring (2)] 객체 의존성 주입, @Test/@Getter 작동원리 (Day 48)

코딩기록·2024년 12월 13일
post-thumbnail

[ 객체 의존성 주입 ]

  • 객체 생성을 개발자가 직접 'new 객체'에서 생성/관리하지 않고, spring이 자동으로 해줬으면 좋겠어. 어떻게 할 수 있을까?

    1) @Configuration, @Bean을 이용한 객체 의존성 주입
     2) @ComponentScan, @Component, @Autowired를 통한 객체 의존성 주입
     3) 예전방식인 xml

- 1. @Configuration, @Bean을 이용한 객체 의존성 주입

  • 개괄적 설명
    -- ApplicationContext이라는 객체 자동 생성/관리를 담당해주는 스프링 컨테이너에 spring이 관리하기 원하는 객체들을 전달해 주면돼. 어떻게????

  • 원리

   1) 클래스를 하나 만들어서 @Configurator을 해서 '이 클래스에서 bean(스프링 컨테이너에서 생성 관리하는 객체)를 만들거야'라고 선언하고
   2) @Bean을 단 메소드를 만들어서, 메소드에서 원하는 객체를 만들어줘
   3 그렇게 하면, 스프링 컨테이너가 애플리케이션 시작 시 이 설정 클래스를 읽고, @Bean 메소드에서 반환된 객체를 빈으로 등록해.
   4) 그럼 이후에 실행 파일에서
     4-1. 설정 클래스를 읽어와서 스프링 컨테이너를 초기화하고 빈을 생성해.
          이 때 bean이 생성되는 원리는, 스프링 컨테이너가 초기화 되면서 @Bean으로 적은 method가 호출되는 거야.
          
           ApplicationContext context
            = new AnnotationConfigApplicationContext(AppConfig.class);
     4-2.context.getBean() 메소드를 사용해서 생성된 빈을 가져오고 필요한 값을 불러오면 돼
  • 예시 코드
// @ Configuration : Spring아, 이 class에서 니가 bean 자동으로 관리해줘야 할 bean(객체)들을 줄게.
//                   (나중에 app 실행 시 자동으로 @Configuration이 있는 클래스를 읽고 @bean에 있는 객체를 spring container로 전달해줌.)
@Configuration
public class AppConfig2 {

    // @Bean : spring아, 내가 여기에 니가 관리해줘야 할 객체들 메소드 안에다가 넣어 줄게.
    //         나중에 내가 AnnotationConfigApllicationContext 객체 만들면 그 때 니가 이 메소드 호출하면서 객체도 생성해줘
    @Bean
    GreetingServiceImpl methodForContainerCall() {
        return new GreetingServiceImpl("미돌");
    }
 
  /* @Test :
        - JUnit(자바 애플리케이션에서 단위 테스트를 작성하고 실행하는 데 널리 사용되는 테스트 프레임워크)의 애노테이션으로,
        - 작동원리 :
          1) JUnit 프레임 워크를 Spring의 dependency에 추가한다.
          2) 코드 짤 때 @Test라는 Junit의 annotation를 붙이고
          3) 그 바로 밑에 아무 이름으로나 method를 작성하고
          4) 개발자가 play 버튼을 누르면 JUnit이 실행되면서 해당 메서드가 자동으로 호출된다.
    */

    @Test
    public void randomTest() {
        //내가 다른 클래스 파일에서 @configuration @bean 사용해서 bean을 등록해놨거든?
        // AnnotationConfigApplicationContenxt야, 그 클래스 불러오고 자동으로 @bean 붙은 메소드 생성해서 객체도 생성해줘.
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig2.class);
        // 그럼 생성된 객체 중에서, 00 객체를 가져와줘.
        GreetingServiceImpl midol = context.getBean(GreetingServiceImpl.class);
        // 그럼 내가 생성된 객체로 뭔가를 테스트 해볼게
        midol.getGreet();


    }
}

- 2. @ComponentScan, @Component, @Autowired를 통한 객체 의존성 주입

  • 개괄적 설명
    -- ApplicationContext이라는 객체 자동 생성/관리를 담당해주는 스프링 컨테이너에 spring이 관리하기 원하는 객체들을 전달해 주면돼. 어떻게????
  • 원리
   1) @Component("닉네임")
     - 설명 : 일단 내가 스프링 컨테이너에서 알아서 객체 생성 관리해줬으면 하는 클래스에, @Component를 붙여.
              그럼 '이 객체는 spring에서 관리할거야'라고 공표하는 거야., 1번 방식의 @Bean와 같은 기능이지.
              나중에 어플리케이션이 실행됨과 동시에 얘는 컨테이너에 객체가 등록이 될 거야.
              참고로 이 때 ("닉네임")은 생략 가능해.
                   
     - 예시코드 :
       // @Component : StudentController 객체의 생성 및 관리는 spring에 일임하겠다.              
       @Component
       public class StudentController {
         코드 구현...
       }
                   
   2) @ComponentScan(basePackages = "프로젝트 내 @component 있는 경로")
                 : 클래스를 하나 생성해서, 클래스 위에 위의 코드를 붙여.
                   이렇게 함으로써 '나중에 내가 이 클래스를 특정 방식으로 부르면 해당 경로의 @component로 등록되어 있는 클래스를 bean으로 등록해줘' 라고 공표해.
                   
   3-1) @Autowired
      - 설명 : spring이 자동 생성한 객체를 클래스 내에서 사용하고 싶을 때는,
              자동 생성 객체가 포함된 메서드에 @Autowired를 적어주면 돼.
      - 예시 코드 : 3-2의 예시코드 참고
      
   3-2) @Qualifier("Component의 Nickname")
      - 설명 : @Autowired 관련해서, 고모듈 클래스에서 저모듈 클래스에 의존할 때,
              저모듈 클래스가 interface라면 @Autowired의 객체의 종류가 달라지는 경우도 있잖아?
             이런 경우에는 @Qualifier를 써서 어떤 객체를 받을 건지 선택하면 돼.	
          
      - 예시 :
        public StudentController(@Qualifier("memoryRepo") StudentRepository studentRepository) {
           System.out.println("생성자 주입!");
           this.studentRepository = studentRepository;
        }
   
   3-3) @Profile("Profile의 닉네임") 
      - 설명 : Spring에서 관리하는 객체의 생성자가
              parameter로 여러 타입의 객체를 받을 수 있을 때, 그 중 하나만 받으려먼
              1) 클래스 위에 @Component + @Profile 조합 쓰고
              2) Resource폴더 -> Application.properties 파일에 
                 spring.profiles.active = dev <- 이런 식으로 써서 선택도 가능
          
  • 겪었던 에러

    -> 문제인식 : StudentController 클래스의 생성자는 StudentRepository 객체를 parameter로 받는데(StudentController(StudentRepository studentRepo) {}), StudentRepository는 인터페이스이기 때문에 객체를 StudentDBRepository 객체 혹은 StudnetMemoryRepository 둘 중 하나를 받을 수 있다. 그런데 어떤 객체를 받을지 안 정해져 있다.
    -> 해결방안 : StudentController(@Qualifier("DBRepo") StudentRepository studentRepo) {} 이런식으로 @Qualifier("받을 Component 객체 닉네임") 를 추가해서 어떤 객체를 받을 것일지 명시





[ @Getter, @Setter 등 작동 원리 ]

1. 소개

  • annotation tag로 @Getter, @Setter 등의 boilerplate 코드를 쉽게 작성할 수 있게 해주는 lombok 라이브러리

2. 작동원리

  1) Build 도구 dependencies에 lombok 라이브러리 추가
  2) 위의 설정에 의해, 자바 컴파일러가 실행될 때 lombok의 annotation 처리기가 실행됨
  3) -> lombook Aannotation(@) 처리기에 의해 getter 자동 생성됨
  - FYI. Java SE ver. 16 이후로는 record로 클래스 생성하면 됨

0개의 댓글