당니의 개발자 스토리

스프링으로 전환하기 본문

스프링/스프링 핵심 원리 - 기본편

스프링으로 전환하기

clainy 2024. 1. 19. 18:35

스프링으로 전환하기

드디어 이번 시간부터 스프링을 써볼 거에요. 지금까지는 스프링 1도 없이 개발을 한 거죠.

프로젝트 세팅할 때야 그냥 스프링 하면 편하니까 했는데, 정말 순수한 Java 코드로 지금까지 짰는데 이제는 이거를 스프링으로 바꿔보겠습니다.

지금까지는 순수한 Java 코드만으로 Dependency Injection(의존관계 주입)을 적용했죠.

이제 이걸 스프링을 써서 해보겠습니다.


먼저, AppConfig를 스프링 기반으로 변경해보겠습니다.

AppConfig에다가 구성정보, 설정정보 라는 의미의 @Configuration 애노테이션을 적습니다.

그 다음에 스프링 빈이라는 의미의 @Bean

객체를 생성하는 곳마다 붙여주는 거에요.

@Configuration이 붙어있으면, 이 AppConfig가 애플리케이션의 설정 정보, 애플리케이션이 어떻게 구성되는지에 대한 구성 정보를 담당한다는 뜻입니다. 그래서 스프링에서는 이러한 설정 정보에 @Configuration을 적어주게 되어있습니다.

그리고 각 메소드에 @Bean 이라고 적어주시면 돼요.

그렇게 하면, 이 메서드들의 반환값(객체 인스턴스)이 다 스프링 컨테이너라는 곳에 스프링 빈으로 등록이 됩니다.


이렇게 AppConfig를 수정하고 그럼 이제 실제 스프링을 쓰도록 해볼게요.

MemberApp에 들어가서

AppConfig 버전에서 스프링을 사용하는 버전으로 한번 바꿔볼게요. 여기서 AppConfig를 사용하는 부분은 주석처리를 하고요.

그 다음에 스프링을 생성 해야하는데, 스프링은 모든 걸 ApplicationContext 라는 걸로 시작을 해요.

이게 스프링 컨테이너라고 보시면 돼요. ApplicationContext모든 걸 다 관리해주는 거에요. @Bean에서 봤던 객체들을 다 관리해줍니다.

그리고 ApplicationContext을 생성할 때는 AnnotationConfigApplicationContext로 생성해야 합니다.

왜냐면, 우리가 AnnotationConfig를 어디서 봤나요?

AppConfig 자체가 annotation을 기반으로 config를 하고 있죠.

그래서 AnnotationConfigApplicationContext의 파라미터로 AppConfig 클래스를 넣어주면 됩니다.

이렇게 하면, AppConfig에 있는 환경 설정 정보를 가지고, AppConfig 안에 있는 @Bean 붙은 애들을 스프링이 스프링 컨테이너에다가 스프링 빈으로 등록합니다.

찾아올 때는 기존에 어떻게 찾아왔나요? 원래는 appConfig.memberService() 이런 식으로 직접 찾아왔습니다.

이제는 스프링 컨테이너를 통해서 찾아와야 돼요.

ApplicationContext를 줄여서 ac라고도 하는데, ac는 스프링 컨테이너니까 getBean()으로 스프링 컨테이너에 등록된 객체를 꺼내올 수 있습니다.

먼저, AppConfig에서

memberService를 꺼내야하므로, 이 이름을 스프링한테 전달해줘야 합니다.

@Bean으로 등록될 때, 이름이 메서드 이름으로 등록됩니다. 그래서 memberService를 전달해주면서 '나는 스프링 컨테이너에 올라가 있는 것들 중 이 이름의 객체를 찾아올 거야' 라고 하고, 두 번째 인자로는 반환 타입을 전달해 줍니다.

"찾아올 객체 이름은 memberService고 반환 타입은 MemberService야." 라고 전달해 주는 겁니다. memberService를 가져오기만 해도, memberService()MemberService 객체를 반환해주므로, 이렇게만 하면 memberService가 스프링 컨테이너(ac)에서 가져온 memberService 객체로 할당되면서 잘 동작할 겁니다.

이제 돌려보면,

컴파일 오류가 안 납니다. 근데 기존이랑 다르게 뭔가 로그가 나왔어요.

이 다섯 개는 스프링이 내부적으로 필요해서 등록하는 스프링 빈이고,

얘네들은 @Bean 해놨던 애들이 스프링 빈으로 등록된 겁니다. 빈 이름을 '메서드 명'으로 한 것을 알 수 있습니다.

으로 올라갈 때 key메서드 명이고, value객체 인스턴스로 해서, 스프링 컨테이너에 등록이 됩니다. 그래서 꺼낼 때는 스프링 컨테이너한테 이름이랑 타입을 주고 꺼내면 돼요.


이번에는 OrderApp도 수정하겠습니다.

역시 주석처리를 해주고,

OrderApp을 이렇게 수정하면 됩니다. 돌려보면,

결과가 그대로 똑같이 나옵니다.

MemberApp, OrderApp 모두 스프링 관련 로그가 몇줄 실행되면서 기존과 동일한 결과가 출력 됩니다.


정리를 해보면,

먼저 ApplicationContext스프링 컨테이너라고 하는데, Context라는 단어는 문맥이죠. 내 전체 애플리케이션의 어떤 문맥이라고 보시면 돼요. 이거를 스프링 컨테이너 라고 합니다.

기존에는 개발자가 AppConfig를 사용해서 appConfig.메서드() 이런 식으로 직접 객체를 생성하고 DI를 했지만, 이제부터는 스프링 컨테이너를 통해서 사용해야합니다.

그리고 스프링 컨테이너는 @Configuration이 붙은 AppConfig설정(구성) 정보로 사용합니다. 여기서 @Bean이라고 적힌 메서드를 모두 호출해서 반환된 객체를 스프링 컨테이너에 등록해요.

이렇게 스프링 컨테이너에 등록된 객체 스프링 빈이라 합니다.

그리고 이 Spring Bean은 @Bean이 붙은 method의 이름을 스프링 빈의 이름으로 사용합니다. 물론 이름을 바꿀 수 있습니다.

이런 식으로 이름을 바꾸면,

getBean의 파라미터인 "memberService"와 매칭이 안돼서 오류가 날거에요. 그런데 특별한 경우가 아니면, 관례를 따르는 게 좋습니다. 디폴트를 따르는 게 좋아요.

이전에는 appConfig.memberService()처럼 개발자가 필요한 객체를 AppConfig를 사용해서 직접 조회했지만, 이제부터는 스프링 컨테이너를 통해서 필요한 스프링 빈(객체)를 찾아야 돼요.

@Bean을 보고 메서드를 호출해서 반환된 객체를 스프링 빈으로 올려두는데, 이러한 스프링 빈은 applicationContext.getBean() 메서드를 사용해서 찾을 수 있습니다.

이름 그대로, "빈 가져와!" 라고 하는 거죠. 그러면 "memberService라는 이름의 Bean을 가져오고, type은 MemberService야" 라고 알려주면 스프링 컨테이너에서 싹 빼옵니다.

또 기존에는 개발자가 직접 자바 코드로 모든 것을 했다면, 이제부터는 스프링 컨테이너에 객체를 스프링 빈으로 등록 하고, 스프링 컨테이너에서 스프링 빈을 찾아서 사용하도록 바꼈습니다.

이제는 Spring한테 환경정보를 던져주고 찾을 때는 getBean으로 스프링 컨테이너를 통해서 가져오는 거에요.

스프링은 환경 정보를 가지고 필요한 것들을 다 읽어서 스프링 컨테이너에서 다 관리를 하고요. 나중에 나올 @Autowired도 다 똑같은 겁니다. 스프링 컨테이너에서 다 꺼내게 됩니다.

그런데 스프링을 잘 모르는 개발자라면, "코드가 약간 더 복잡해진 것 같은데, 스프링 컨테이너를 사용해서 어떤 장점이 있을까?" 라고 궁금할 수 있습니다.

결론부터 말씀드리면 어마어마한 장점이 있습니다.

엔터프라이즈에서 개발해보면 여기서 끝나는 게 아니거든요. 진짜 할게 엄청 많아요. 그런데 이 스프링 컨테이너가 관리해줌으로써, 해줄 수 있는 기능이 어마어마해요.

어쨌든 스프링에 대한 핵심 원리, 스프링이 어떻게 동작하는지, 그리고 DIP, OCP, 다형성 이런 것들을 버무려서 왜 스프링 컨테이너가 나오게 됐는지는 설명을 드렸어요.

AppConfig 같은 걸 개발자들이 직접 만드는 게 아니라, 스프링 컨테이너라는 걸 통해서 어떤 프로젝트에도 Dependency Injection이나 이런 것들을 스프링 컨테이너가 되게 편리하게 해주도록 범용의 프레임워크가 생긴 거에요.

지금까지는 객체지향 원리랑 다형성을 가지고 '아, 다형성만으로는 안되는구나. DIP랑 OCP를 둘 다 지키려면 뭔가가 더 필요하구나' 라고 해서 AppConfig처럼 구성 정보를 만들어봤던 거고, 이제부터는 'AppConfig보다 Spring Container가 뭔가 더 낫대.' 라고 하는데, 뭐가 더 나은지는 지금부터 쭉 설명드릴 겁니다. 스프링 컨테이너핵심 기능들을 설명하면서요.


그래서 다음 시간부터는 본격적으로 스프링 빈과 스프링 컨테이너에 대해서 알아보겠습니다.


스프링 부트 3.1 이상 - 로그 출력 안되는 문제 해결