이 글은 스프링 [핵심원리 - 기본편]을 듣고 정리한 내용입니다
@Component
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
}
@Autowired
생략해도 자동 주입된다.@Component
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
// @Autowired - 생성자 딱 1개니까 생략해도 자동주입 됨.
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
}
setter
라 불리는 수정자 메서드를 통해서 의존관계를 주입하는 방법이다.@Component
public class OrderServiceImpl implements OrderService {
private MemberRepository memberRepository;
private DiscountPolicy discountPolicy;
@Autowired //수정자 주입
public void setMemberRepository(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
@Autowired //수정자 주입
public void setDiscountPolicy(DiscountPolicy discountPolicy) {
this.discountPolicy = discountPolicy;
}
}
@Autowired
의 기본동작은 주입할 대상이 없으면 오류남.@Autowired(required = false)
로 지정하면 주입할 대상없어도 동작한다.자바빈 프로퍼티 규약이란?
-> 자바에서는 과거부터 필드의 값을 직접 변경하지 않고 (Data.aa=aa), setXxx, getXxx 메서드를 통해서 값을 읽거나 수정하는 규칙을 만들었다.
class Data {
private int age;
public void setAge(int age){
this.age=age;
}
public int getAge(){
return age;
}
}
@Configurtaion
(설정 관련) 같은곳에서만 특별한 용도로 사용할 수 있다.@Component
public class OrderServiceImpl implements OrderService {
@Autowired
private MemberRepository memberRepository;
@Autowired
private DiscountPolicy discountPolicy;
}
* 참고
- 순수한 자바코드에서는 당연히
@Autowired
가 동작하지 않는다.@SpringBootTest
처럼 스프링 컨테이너를 테스트에 통합한 경우에만 가능!- 예를 들어, 스프링 빈이 아닌(
@Component
가 붙지 않은 혹은@bean
수동등록도 되어있지 않은)Member
같은 클래스에서@Autowired
를 적용해도 아무런 기능도 동작하지 않는다.
@Component
public class OrderServiceImpl implements OrderService {
private MemberRepository memberRepository;
private DiscountPolicy discountPolicy;
//일반 메서드를 통해 주입받는 예시
@Autowired
public void init(MemberRepository memberRepository, DiscountPolicy discountPolicy){
this.memberRepository=memberRepository;
this.discountPolicy=discountPolicy;
}
}
@Autowired
는 required
옵션의 기본값이 true
이므로, 자동 주입 대상이 없으면 오류가 발생한다.package hello.core.autowired;
public class AutowiredTest {
@Test
void AutowiredOption() {
ApplicationContext ac = new AnnotationConfigApplicationContext(TestBean.class);
}
static class TestBean {
//호출 자체가 안됨.
//Member는 스프링 빈이 아니다.
@Autowired(required=false)
public void setNoBean1(Member noBean1){
System.out.println("noBean1 = " + noBean1);
}
//null 호출
@Autowired
public void setNoBean2(@Nullable Member noBean2){
System.out.println("noBean2 = " + noBean2);
}
//Optional.empty 호출
@Autowired
public void setNoBean3(Option al<Member> noBean3){
System.out.println("noBean3 = " + noBean3);
}
}
}
@Autowired(required=false)
: 자동 주입할 대상이 없으면 메서드 자체가 호출이 안된다.org.springframework.lang.@Nullable
: 자동 주입할 대상이 없으면 Null
이 입력된다.Optional<>
: 자동 주입할 대상이 없으면 Optional.empty
가 입력된다.
- 참고
@Nullable, Optional은 스프링 전반에 걸쳐서 지원된다.
예를들어, 생성자 자동 주입에서 특정 필드에만 사용해도 된다.
@Test //컴파일 오류 발생
void createOrder() { //memberRepository, discountPolicy가 누락됨.
OrderServiceImpl orderService = new OrderServiceImple();
orderService.createOrder(1L, "itemA", 10000);
}
@Component
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
@Autowired// 생성자 딱 1개니까 생략해도 자동주입 됨.
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
//discountPolicy값이 설정되지 않음
//this.discountPolicy = discountPolicy;
}
}
discountPolicy
값을 설정하는 부분이 누락 되어서 다음 오류가 발생한다.java: variable discountPolicy might not have been initialized
- 컴파일 타임이란?
- 개발자에 의해 개발 언어로 소스코드가 작성 된 뒤, 컴파일 과정을 통해 컴퓨터가 인식할 수 있는 기계어 코드로 변환되어 실행 가능한 프로그램이 되는 과정
- 컴파일 에러란?
- 소스코드가 컴파일 되는 과정 중에 발생하는 Syntax error, 파일 참조 오류 등과 같은 문제들로 인해 컴파일이 방해되어 발생하는 오류.
- 컴파일 에러 발생 시, 문제가 되는 소스코드를 알려준다. (그래서 좋음)
- 런타임이란?
- 컴파일 과정을 마친 응용프로그램이 사용자에 의해서 실행되어지는 때를 의미한다.
- 런타임 에러란?
- 이미 컴파일이 완료되어 프로그램일 실행중임에도 불구하고, 의도치 않은 예외 상황으로 인해 프로그램 실행 중에 발생하는 오류.
개발을 하다보면 대부분이 불변으로 해야되어서 final 키워드를 사용한다.
그러나 final방식은 생성자도 만들어야하고, 주입 해주는 코드도 만들어야 하고 귀찮다.
final 방식의 기본 코드
@Component
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy
discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
}
@Autowired
생략 가능@Component
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
//@Autowired 생략
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy
discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
}
롬복 적용
@RequiredArgConstructor
어노테이션을 사용하면 final
이 붙은 필드를 모아서 생성자를 자동으로 만들어준다.
생성자가 만들어졌는지는 command+f12
를 통해 보면 확인 가능하다.
롬복 사용한 코드
롬복이 자바의 어노테이션 프로세서 라는 기능을 이용해서 컴파일 시점에 생성자 코드를 자동으로 생성해주는 것이다.
@Component
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
}
@Autowired
를 생략하거나Lombok
라이브러리의 @RequiredArgsConstructor
를 사용한다.plugins {
id 'org.springframework.boot' version '2.6.5'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'hello'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
//lombok 설정 추가 시작
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
//lombok 설정 추가
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
//lombok 라이브러리 추가 시작
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
//lombok 라이브러리 추가 끝
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
tasks.named('test') {
useJUnitPlatform()
}
package hello.core;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.boot.autoconfigure.cache.CacheProperties;
@Getter
@Setter
@ToString
public class HelloLombok {
private String name;
private int age;
public static void main(String[] args) {
HelloLombok helloLombok = new HelloLombok();
helloLombok.setName("aaaaaa");
//@ToString 어노테이션을 통해 스트링으로 바로 출력할 수 있다.
System.out.println("helloLombok = " + helloLombok);
}
}