-
Chapter 2. 스프링의 특징과 의존성 주입코드로 배우는 스프링 웹 프로젝트_intellij 2021. 4. 13. 15:28
학습할 내용
이번 장에서는 스프링 프레임워크에 대한 이론적인 부분을 살펴보게 됩니다. 살펴볼 내용은 크기 3가지로 구분할 수 있는데, 첫번째 Java 관련 프레임워크들이 추구했던 목표, 두번째 스프링 프레임워크가 살아남은 이유 마지막 세번째 스프링의 가장 중요한 특징으로 말하는 의존성 주입
스프링 프레임워크의 간략한 역사
프레임 워크란?
- '뼈대나 근간을 이루는 코드들의 묶음'
- 개발자는 각 개개인의 능력 차이가 큰 직종이라 개발자의 구성에 따라 프로젝트의 결과 역시 큰 차이를 낳기 때문에 이러한 상황을 극복하기 위한 결과물입니다. 프레임워크를 이용한다는 의미는 프로그램의 기본 흐름이나 구조를 정하고 모든 팀원이 이 구조에 자신의 코드를 추가하는 방식으로 개발하게 된다는 것입니다.
- 프레임 워크의 장점
-> 개발에 필요한 구조를 이미 코드로 만들어 놓았기 때문에 실력이 부족한 개발자라 하더라도 반쯤 완성한 상태에서 필요한 부분을 조립하는 형태의 개발이 가능하다는 점이다. 또한 회사 입장에서는 프레임워크를 사용하면 일정한 품질이 보장된다는 장점이 있다. 개발자 입장에서는 완성된 구조에 자신이 맡은 코드를 넣어주는 형태이므로 개발 시간을 크게 단축할 수 있다.
스프링의과 다른 프레임워크들의 차이점(*다른 프레임워크 -> 과거의 프레임워크를 말하며 스프링은 이때 경량 프레임워크로 성공을 했다.)
1. 복잡함의 반기를 들어 만들어진 프레임워크
+Java의 클래스와 인터페이스를 이용하는 구조이기에 진입장벽이 낮음
2. 프로젝트의 전체 구조를 설계할 때 유용한 프레임워크
+스프링은 어느 한 분야에 집중하지 않고, 전체를 설계하는 용도로 사용이 가능하고 OOP 구조를 뒷받침하며 이에 대한 설명은 DI 설명과 같다.
3. 다른 프레임워크들을 포용
+스프링은 전체 구조에 집중을 했기 때문에 최소한의 수정이 가능했다. 즉 기본 뼈대를 흔들지 않고, 여러 종류의 프레임워크를 혼용해서 사용할 수 있다는 점이다.
4. 개발 생산성과 개발도구의 지원
+스프링은 이론적으로 개발자가 제대로 이해해야하는 부분은 많았지만 결과적으로 코드의 양은 줄 수 있었다. 또한 STS, Eclipse, Intellij 등의 플러그인의 지원 역시 다른 프레임워크들에 비해서 빠른 업데이트가 되었다.
스프링의 주요 특징
1. POJO 기반의 구성
- 객체 간의 관계를 구성할 수 있는 특징을 가지고 있습니다. 다른 프레임워크들과 달리 관계를 구성할 때 별도의 API 등을 사용하지 않는 POJO(Plain Old Java Object)의 구성만으로도 가능하게 제작되었다. 즉 일반적인 자바 코드를 사용해서 객체를 구성하는 방식을 그대로 사용할 수 있어 생산성에 유리하다.
2. DI(의존성 주입, Dependency Injection)과 스프링
- 스프링에서 중요한 개념은 의존성 주입(DI, Dependency Injection)과 제어의 역행(IOC, Inversion Of Control)입니다. 제어의 역행은 메소드나 객체의 호출 작업을 개발자가 결정하는 것이 아니라 외부에서 결정되는 것을 의미하는데 이 방식은 대부분의 프레임워크에서 사용하는 방법으로 개발자느 필요한 부분을 개발해서 끼워넣는식으로 개발하도록 되었습니다.
- 의존성 주입은 제어의 역행이 일어날 때 스프링 내부의 객체(이하 빈)들 간의 관계를 관리할 때 사용하는 기법으로서 의존적인 객체를 직접 생성하거나 제어하는 것이 아니라 제어의 역행으로 특정 객체에 필요한 객체를 외부에서 결정해서 연결시키는 것을 의미. 외부에서 필요한 객체를 결정하기 때문에 개발자는 의존적인 객체들 간의 관계를 직접 처리할 필요가 없고 인터페이스를 활용해서 유연한 구조를 사용할 수 있습니다.
-의존성 주입의 종류는 생성자를 통한 주입 / set 메서드를 이용한 주입으로 구분할 수 있고 스프링은 두 방식 모두 사용이 가능하며 이에 대한 처리 또한 간단한 어노테이션으로도 가능하다.
- 의존성(Dependency)라는 것은 '하나의 객체가 다른 객체 없이 제대로 된 역할을 할 수 없다.'라는 것을 의미한다. 예를 들어 음식점에서 홀 서빙을 하는 직원이 있어도 주방에서 일하는 직원이 없다면 장사를 할 수 없는 것처럼 이런 관계를 '의존성을 가진다'리고 표현한다. 즉 A객체가 B객체 없이 동작이 불가능한 상황을 'A가 B에 의존적이다.'라고 표현한다.
- 주입(Injection)은 외부에서 밀어넣음을 의미한다.
- 의존성과 주입을 결합해서 생각해 보면 '어떤 객체가 필요한 객체를 외부에서 밀어 넣는다'라는 의미가 된다. 그러면 왜 외부에서 객체를 주입하는 방식을 사용하는것일까? 왜냐하면 주입을 받는 입장에서 어떤 객체인지 신경 쓸 필요가 없다, 어떤 객체에 의존하든 자신의역할은 변하지 않는다.라는 뜻으로 해석할 수 있다.
- 이처럼 이러한 과정을 거칠려면 두 객체 이외의 존재가 필요하게 되는데 이때 등장하는 것이 ApplicationContext이다. 스프링에서는 ApplicationContext가 필요한 객체들을 생성하고, 주입하는 역할을 수행한다. 따라서 기존의 프로그래밍과 달리 객체와 객체를 분리해서 생성하고 이러한 객체드를 엮는(Wiring) 작업을 하는 개발을 하게 된다.
- ApplicationContext이 관리하는 객체들을 Bean이라는 용어로 부르고 빈과 빈 사이의 의존관계를 처리하는 방식으로 XML, 설정, 어노테이션 설정, Java 설정 방식을 사용할 수 있다.
3. AOP(Aspect Orineted Programming)의 지원
- 반복적인 코드의 제거-> 스프링은 프레임워크를 이용한 개발에도 이러한 반복적인 코드를 줄이고 핵심 비즈니스 로직에만 집중할 수 있는 방법을 제공하는데 대부분의 시스템이 공통으로 가지고 있는 보안이나, 로그, 트랜잭션과 같이 비즈니스 로직은 아니지만 반드시 처리가 필요한 부분을 스프링에서는 횡단 관심사라고 하는데 이러한 횡단 관심사를 분리해서 제작하는 것이 가능합니다. 이를 통해 개발자는
- 핵심 비즈니스 로직에만 집중해서 코드를 개발할 수 있게 되었다.
- 각 프로젝트마다 다른 관심사를 적용할 때 코드의 수정을 최소화시킬 수 있었다.
- 원하는 관심사의 유지보수가 수월한 코드를 구성할 수 있다.
4. 트랜잭션의 지원
- DB를 이용할 떄 반드시 신경써야 하는 부분은 하나의 업무가 여러 작업으로 이루어지는 경우의 트랜잭션 처리입니다. 이 트랜잭션 처리는 복잡하게 처리될 수도, 간단하게 처리될 수도 있는데 이를 코드로 처리하는 것은 상당히 개발자에게는 부담인 영역이기 때문에 스프링은 이런 트랜잭션의 관리를 어노테이션이나 XML로 설정할 수 있기 때문에 개발자가 매번 상황에 맞는 코드를 작성할 핑료악 없도록 설계되었습니다.
의존성 주입 테스트
예제를 구성할 내용 ) Restaurant 객체를 만들고 Chef 객체를 주입하는 예제 작성
* 목표 : 의존성 주입을 코드를 통해서 이해해볼려고 하는 것
- 스프링에서는 생성자를 이용한 주입과 setter 메서드를 이용한 주입으로 의존성 주입을 구현하는데 설정 방식은 주로 XML이나 어노테이션을 이용해서 처리합니다. 예제는 Lombok을 이용해서 setter 메서드를 자동으로 구현되도록 할 것이고, 스프링의 동작을 테스트할 것이므로 pom.xml에서 Lomnok 라이브러리를 추가하고 spring-test 라이브러리를 이용합니다.
pom.xml 수정
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>SpringStarter_0412</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.7.RELEASE</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.0</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!--test--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> </project>
pom.xm에 springframework와 lombok log4j junit 라이브러리를 설정하였다.
Restaurant와 Chef 클래스 생성
* 일반적으로 스프링에서 의존성 주입은 클래스가 아닌 인터페이스로 설계하는 것이 좋지만 지금은 최소한의 코드만을 이용해서 의존성 주입을 테스트해보기 위한 것이므로 클래스로 설계합니다.
package org.mido.sample; import lombok.Data; import org.springframework.stereotype.Component; @Component @Data public class Chef { }
@Component : Spring Container에 Bean을 등록하도록 하는 메타데이터를 기입하는 어노테이션
- 스프링에게 클래스가 스프링에서 관리해야하는 대상임을 표시하는 어노테이션
@Data가 갖는 기능
- @ToString
- @EqualsAndHashCode
- @Getter : 모든 필드
- @Setter : 정적 필드가 아닌 모든 필드
- @RequiredArgsConstructor
package org.mido.sample; import lombok.Data; import lombok.Setter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component @Data public class Restaurant { @Setter(onMethod_= @Autowired) private Chef chef; }
@Setter : setChef()를 컴파일 할 때 생성된다. @Setter에 사용된 onMethod속성은 생성되는 setChef()에 @Autowired 어노테이션을 추가하도록 한다.
@Autowired : 이 어노테이션을 부여하면 각 상황의 타입에 맞는 IOC 컨테이너 안에 존재하는 Bean을 자동으로 주입.
XML을 이용하는 의존성 주입 설정
스프링은 클래스에서 객체를 생성하고 객체들이 의존성에 대한 처리 작업까지 내부에서 모든 것이 처리됩니다. 스프링에서 관린되는 객체를 흔히 Bean이라 하고 이에 대한 설정은 XML과 Java를 이용해서 처리할 수 있습니다.
* XML 방식이 많이 선호되지만 최근 몇 년 동안 Java를 이용하는 설정도 많이 사용되고 있다.
교재에서는 root-context.xml이지만 Intellij에서는 applicationContext.xml이다. applicationContext.xml은 스프링 프레임 워크에서 관리해야하는 객체(이후 빈)을 설정하는 설정 파일입니다.
스프링 설정 XML 방식 : root-context.xml 파일
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <!-- Root : Context: defines shared resources visible to all other web componenets--> <context:component-scan base-package="org.mido.sample"></context:component-scan> </beans>
만약 스프링 설정을 XML을 이용하는 방식 대신에 Java를 이용하고 싶은 경우에는 전혀 다른 방식으로 설정하므로 프로젝트 초기에 정해야합니다.
스프링 설정 Java 방식 : RootConfig.class 파일
package org.mido.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan(basePackages = {"org.mido.sample"}) public class RootConfig { }
Java 설정을 이용하는 경우에는 'root-context.xml'을 대신해서 RootConfig 클래스를 이용하도록 합니다. XML로 설정된 내용은 @ComponenetScan 어노테이션을 통해 처리할 수 있는데
@Component : @Compinent 어노테이션 및 streotype(@Service, @Repository, @Controller) 어노테이션이 부여된 Class들을 자동으로 Scan하여 Bean으로 등록해주는 역할을 수행
= <context:component-scan base-package="org.mido.sample"/>과 같은 역할을 수행한다.
@Configuration : 어노테이션 환경구성을 돕는다. 이 어노테이션을 구현함으로써 클래스가 하나 이상의 @Bean 메소드를 제공하고 스프링 컨테이너가 Bean 정의를 생성하고 런타임식 그 Bean들이 요청들을 처리할 것을 선언하게 된다.
스프링이 동작하면서 생기는 일
작성된 Restaurant와 Chef 클래스 application-context.xm이 어떻게 동작하는지 이해하기 위해서는 스프링과 함께 시간의 순서대로 고민을 해보아야 합니다. 스프링이 동작한다는 가정하에 스프링에서 어떤 일이 벌어지는지는 아래와 같습니다.
- 스프링 프레임워크가 시작이 되면 스프링이 사용하는 메모리 영역을 Context라고 함 / ApplicationContext라는 이름의 객체가 만들어짐
- 스프링은 root-context.xml로 자신이 객체를 생성하고 관리해야 하는 객체들에 대한 설정이 필요
- root-context.xml에 <context:component-scan>태그의 내용을 통해서 지정한 패키지를 scan
- 해당 패키지에 있는 클래스들 중에서 @Component라는 어노테이션이 존재하는 클래스의 인스턴스 생성
- Restaurant 객체는 Chef 객체가 필요하다는 어노테이션 설정이 있으므로 스프링은 Chef 객체의 레퍼런스를 Restaurant에 주입
위의 과정이 진짜 맞는지 체크해보기 위해 테스트 코드를 작성해 보겠습니다.
테스트 코드
src/test/java 폴더 내에 org.mido.sample.SampleTests 클래스를 추가합니다. SampleTests 클래스는 spring-test 모듈을 이용해서 간단하게 스프링을 가동시키고 위에서 설명된 동작들이 일어나게 합니다.
import lombok.Setter; import lombok.extern.log4j.Log4j; import org.junit.Test; import org.junit.runner.RunWith; import org.mido.sample.Restaurant; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("file:/main/web/WEB-INF/applicationContext.xml") @Log4j public class SampleTests { @Setter(onMethod_={@Autowired}) private Restaurant restaurant; @Test public void testExist(){ org.junit.Assert.assertNotNull(restaurant); log.info(restaurant); log.info("---------------"); log.info(restaurant.getChef()); } }
@RunWith ; JUnit 프레임워크의 테슽트 실행 방법을 확장할 때 사용하는 어노테이션이다. / 현재 테스트 코드가 스프링을 실행하는 역할을 할 것이다.
@ContextConfiguration : 자동으로 만들어줄 ApplicationContext를 만들고 관리하는 작업을 진행 / 지정된 클래스나 문자열을 이용해서 필요한 객체들을 스프링 내에 객체로 등록(Spring의 Bean으로 등록) @ContextConfiguration에 사용하는 문자열은 'classpath:'나 'file:'을 이용할 수 있으므로 applicationContext.xml을 지정할 수 있다.
- 즉 @RunWith에 Runner 클래스를 설정하면 JUnit에 내장된 Runner 대신 그 클래스를 싱행한다. 여기서는 스프링 테스트를 위해 SpringJUnit4ClassRunner라는 Runner 클래스를 설정해 준것. 한 클래스 내에 여러 개의 테스트가 있더라도 ApplicationContext는 초기 한 번만 로딩하여 사용하기 때문에 여러 개의 테스트가 있더라도 처음 테스트만 조금 느리고 그 뒤의 테스트는 빠르다.
@Autowired : 해당 인스턴스 변수가 스프링으로부터 자동으로 주입해 달라는 표시이고, 스프링은 정상적으로 주입이 가능하다면 obj변수에 Restaurant 타입의 객체를 주입하게 됩니다.
@Log4j : Lombok을 이용해서 로그를 기록하는 Logger를 변수로 생성합니다. 별도의 Logger 객체의 선언이 없이도 Log4j 라이브러리와 설정이 존재하나면 바로 사용할 수 있습니다.
(*이클립스는 'Spring Legacy Project'로 생성하면 Log4j의 설정이 되어있지만 우리가 사용하는 Intellij는 안되있기에 pom.xml에 의존성을 부여한다.)
@Test : JUnit에서 테스트 대상을 표시하는 어노테이션입니다. 해당 메서드를 선택하고 JUnit Test 기능을 실행
assertNotNull() : restauratnt 변수가 null이 아니어야만 테스트가 성공한다는 것을 의미
* 테스트 작업은 프로젝트 초기에 설정해 두고 사용하는 습관을 기르기.
코드의 실행 결과를 보면 정상적으로 객체가 생성된 것을 확인할 수 있습니다.
(만일 테스트 자체가 실행되지 않는다면 JUnit 버전을 다시 확인하고 spring-test라이브러리가 포함되어 있는지 확인해야합니다.)
* 이 부분에서 에러가 발생한다면 에러코드를 참고하세요
에러코드
log4j:WARN No appenders could be found for logger (org.springframework.test.context.junit4.SpringJUnit4ClassRunner).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
코딩 중 이러한 에러와 부딪히게 되었는데 구글링해서 얻은 해답들로도 해결되지 않아서 log4j.xml파일을 전 장에서 말했던 src>java>resources에 넣으니 정상 출력이 되었다.
실행 결과를 주목해서 봐야하는데
new Restaurant()와 같이 Restaurant 클래스에서 객체를 생성한 적이 없는데 객체가 만들어 졌다.
-> 스프링은 Bean(관리가 필요한 객체)를 어노테이션 등을 이용해서 객체를 생성하고 관리하는 일종의 '컨테이너'나 '팩토리'의 기능을 가지고 있다.
Restaurant 클래스의 @Data 어노테이션으로 Lombok을 이용해서 여러 메서드가 만들어졌다
-> Lombok은 자동으로 getter/setter 등을 만들어주는데 스프링은 생성자 주입 혹은 setter 주입을 이용해서 동작합니다. Lombok을 통해서 getter / setter 등을 자동으로 생성하고 'onMethod' 속성을 이용해서 작성된 setter에 @Autowired를 추가합니다.
Restaurant 객체의 Chef 멤버 변수에 Chef 타입의 객체가 주입되어 있다는 점.
-> 스프링은 @Autowired와 같은 어노테이션을 이용해서 개발자가 직접 객체들과의 관계를 관리하지 않고 자동으로 관리됩니다.
*@Autowired는 필요한 의존 객체의 타입에 해당하는 빈을 찾아 주입한다. (생성자, setter, 필드)
즉, 테스트 결과가 의미하는 것은
1) 테스트 코드가 실행하기 위해서 스프링 프레임워크가 동작
2) 동작하는 과정에서 객체들이 스프링에 등록
3) 의존성 주입이 필요한 객체는 자동으로 주입
코드에 사용되는 어노테이션
Lombok 관련 Spring 관련 테스트 관련 @Setter
@Data
@Log4j@Autowired
@Component@Runwith
@ContextConfiguration
@Testㅇ. Lombok 관련
- Lombok은 컴파일시 흔하게 코드를 작성하는 기능들을 완성해주는 라이브러리이다.
- @Setter 어노테이션은 setter 메소드를 만들어주는 역할을 합니다
속성명 의미 value 접근 제한 속성을 의미
기본 값은 lombok.AccessLevel.PUBLIConMethod setter 메서드의 생성시 메서드에 추가할 어노테이션을 지정 onParam setter 메서드의 파라미터에 어노테이션을 사용하는 경우에 적용 - @Data 는 Lombok에서 가장 자주 사용되는 어노테이션으로서 @ToString, @EqualsAndHashCode, @Getter, @Setter, @RequiredArgsConstructor를 모두 결합한 형태로 한 번에 자주 사용되는 모든 메서드를 생성할 수 있다는 장점이 있습니다. 세부적인 설정이 필요 없는 경우라면 @Data를 주로 사용합니다.
- @Log4j 어노테이션은 로그 객체를 생성하게 됩니다. @Log4j 설정을 이용하고, Log4j가 존재하지 않을 경우에는 @Log를 이용할 수 있습니다.
- @Log를 클래스에 붙여주면 내부적으로 static final로 Logger 객체가 생성되므로 개발 시 별도의 로그를 설정할 필요 없이 필요한 코드를 만들어 낼 수 있습니다.
(STS를 이용해서 Spring Legacy Project로 생성한 경우에는 기본적으로 Log4j 설정이 있기 때문에 추가적인 설정 없이 @Log4j만으로 로그 객체를 사용할 수 있습니다.)
ㅇ. Spring 관련
- @Component는 해당 클래스가 스프링에서 객체로 만들어서 관리하는 대상임을 명시하는 어노테이션입니다. @Component가 있는 클래스를 스프링이 읽어주로고 @ComponenetScan을 통해서 지정되어 있으므로 해당 패키지에 있는 클래스들을 조사하면서 @Component가 존재하는 클래스들을 객체로 생성해서 빈으로 관리하게 됩니다.
- @Autowired는 스프링 내부에서 자신이 특정한 객체에 의존적이므로 자신에게 해당 타입의 빈을 주입해주라는 표시입니다. 즉 스프링은 @Autowired를 보고 스프링 내부에 관리되는 객체 중에서 적당한 것이 있는지 확인하고 자동으로 주입합니다.
* 적당한 객체가 존재하지 않는다면 에러가 발생합니다.
예를 들면 위의 예제에서 Chef 클래스에 @Component가 없다면 스프링은 Chef 객체를 스프링에서 관리하지 않으므로 실행 시 에러가 발생하게 됩니다.
* NoSuchBeanDefinitionException 발생(Chef 타입의 객체를 찾을 수 없다. 1개 이상의 해당 타입의 객체가 필요하다.)
ㅇ. Test 관련
- @ContextConfiguration는 테스트 관련한 어노테이션 중 가장 중요한 것으로서 스프링이 실행되면서 어떤 설정 정보를 읽어 들여야 하는지를 명시하는 어노테이션입니다. 속성으로는 locations를 이용해서 문자열의 배열로 XML 설정 파일을 명시할 수도 있고 classes 속성으로 @Configuration이 적용된 클래스를 지정해줄 수도 있습니다.
- @Runwith는 테스트 시 필요한 클래스를 지정합니다 스프링은 SpringJUnit4ClassRunner클래스가 대상이 됩니다.
- @Test 는 JUnit에서 해당 메서드가 단위테스트임을 알려줍니다.
스프링 4.3 이후 단일 생성자의 묵시적 자동 주입
스프링의 의존성 주입은
- 생성자 주입
- Setter 주입
을 사용하는데 Setter 주입은 앞의 예제와 같이 setXXX()와 같은 메서드를 작성하고 @Autowired 어노테이션을 통해 스프링으로부터 자신이 필요한 객체를 주입하도록 합니다.
생성자 주입은 생성자를 통해서 의존성을 주입하게 되는데 생성자 주입 방식의 장점은 객체 생성 시 의존성 주입이 필요하므로 좀 더 엄격하게 의존성 주입을 체크하는 장점이 있습니다. 기존에 스프링에서는 생성자를 정의하고 @Autowired를 추가해야 생성자 주입이 이루어졌지만 스프링 4.3 이후에는 묵시적으로 생성자 주입이 가능합니다.
import lombok.Getter; import lombok.ToString; import org.mido.sample.Chef; import org.springframework.stereotype.Component; @Component @ToString @Getter public class SampleHotel { private Chef chef; public SampleHotel(Chef chef){ this.chef =chef; } }
코드를 보면 기존과 달리 생성자를 선언하고 Chef를 주입하도록 작성되어 있는데 기존의 예제와 다른 점은 @Autowired 어노테이션 없이 처리되고 있다는 것입니다.
import lombok.Setter; import lombok.extern.log4j.Log4j; import org.junit.Test; import org.junit.runner.RunWith; import org.mido.sample.SampleHotel; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @Log4j @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("file:web/WEB-INF/applicationContext.xml") public class HotelTests { @Setter(onMethod_={@Autowired}) private SampleHotel hotel; @Test public void testExist(){ org.junit.Assert.assertNotNull(hotel); log.info(hotel); log.info("------------------"); log.info(hotel.getChef()); } }
위 코드를 실행시키면 나오는 내용입니다.
생성자 자동 주입과 Lombok을 결합하면 SampleHotel을 이렇게 바꿀 수 있습니다.
package org.mido.sample; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.ToString; import org.springframework.stereotype.Component; @Component @ToString @Getter @AllArgsConstructor public class SampleHotel { private Chef chef; }
@AllArgsConstructor는 인스턴스 변수로 선언된 모든 것을 파라미터로 받는 생성자를 작성하게 됩니다.
즉 Chef를 파라미터로 받는 생성자가 만들어진 것입니다.
public SampleHotel(Chef chef){ }
만일 특정 변수만 해당하는 생성자를 작성하고 싶다면 @NonNull과 @RequiredArgsConstructor 어노테이션을 이용할 수 있습니다.
package org.mido.sample; import lombok.*; import org.springframework.stereotype.Component; @Component @ToString @Getter @RequiredArgsConstructor public class SampleHotel { @NonNull private Chef chef; }
@RequiredArgsConstructor는 @NonNull이나 final이 붙은 인스턴스 변수에 대한 생성자를 만듭니다.
'코드로 배우는 스프링 웹 프로젝트_intellij' 카테고리의 다른 글
Chapter 4. MyBatis 스프링 연동 (0) 2021.04.15 Chapter 3. 스프링과 Oracle Database 연동 (0) 2021.04.14 Chapter 1. 스프링 개발 환경 구축 (0) 2021.04.12 코드로 배우는 스프링 웹 프로젝트 1) 개발환경 (0) 2021.04.12