의존관계 주입
의존관계 주입을 하는 방법으로 생성자 주입, setter 주입, 필드 주입, 메서드 주입 총 4가지 방법이 존재한다.
@Autowired 는 의존성을 자동으로 주입할 때 사용하는 Annotation 이다.required = true)public interface MyService {
void doSomething();
}
// Spring Bean으로 등록
@Service
public class MyServiceImpl implements MyService {
@Override
public void doSomething() {
System.out.println("MyServiceImpl 메서드 호출");
}
}
// 생성자 주입 방식
@Component
public class MyApp {
// 필드에 final 키워드 필수! 무조건 값이 있도록 만들어준다.(필수)
private final MyService myService;
// 생성자를 통해 의존성 주입, 생략 가능
@Autowired
public MyApp(MyService myService) {
this.myService = myService;
}
public void run() {
myService.doSomething();
}
}
@ComponentScan(basePackages = "com.example.springdependency.test")
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(Main.class);
// 등록된 MyApp 빈 가져오기
MyApp myApp = context.getBean(MyApp.class);
// 빈 메서드 호출
myApp.run();
}
}
// 생성자가 두개인 경우 생략이 불가능하다.
@Component
public class MyApp {
// 필드에 final 키워드 필수! 무조건 값이 있도록 만들어준다.(필수)
private final MyService myService;
public MyApp(MyService myService, String myRepository) {
this.myService = myService;
}
// 생성자를 통해 의존성 주입
// @Autowired를 생략하기 위해서는 생성자가 하나여야 한다.
public MyApp(MyService myService) {
this.myService = myService;
}
public void run() {
service.doSomething();
}
}
@Component
public class MyApp {
private MyService myService;
// Setter 주입
@Autowired
public void setMyService(MyService myService) {
this.myService = myService;
}
public void run() {
myService.doSomething();
}
}
// MyService가 Spring Bean으로 등록되지 않은 경우에도 주입이 가능하다.
@Autowired(required = false)
public void setMyService(MyService myService) {
this.myService = myService;
}
// 실행 도중 인스턴스를 바꾸고자 하는 경우
// setMyService(); 메서드를 외부에서 호출하면 된다.(이런 경우는 거의 없음
@Component
public class MyApp {
@Autowired
private MyService myService; // 필드에 직접 주입
public void run() {
myService.doSomething();
}
}
// Spring을 사용하지 않는 경우 실행이 불가능하다.
public class MainV2 {
public static void main(String[] args) {
MyApp myApp = new MyApp();
myApp.run();
}
}
myService 값을 설정하거나 변경할 방법이 없다.@SpringBootTest 테스트 코드나 Spring에서만 사용하는 @Configuration 같은 곳에서 주입할 때 주로 사용한다.@Component
public class MyApp {
private MyService myService;
// 일반 메서드 주입
@Autowired
public void init(MyService myService) {
this.myService = myService;
}
public void run() {
myService.doSomething();
}
}
의존관계를 자동으로 주입할 객체가 Spring Bean으로 등록되어 있어야 @Autowired 로 주입이 가능하다.
생성자 주입
과거 setter, 필드 주입도 사용했지만 현재는 DI를 가지고 있는 대부분의 Framework가 생성자 주입 방식을 권장한다.
public 으로 설정되어 누구나 수정할 수 있게된다.// 생성자 주입 방식
@Component
public class MyApp {
// 필드에 final 키워드 필수! 무조건 값이 있도록 만들어준다.(필수)
private final MyService myService;
// 생성자를 통해 의존성 주입, 생략 가능
@Autowired
public MyApp(MyService myService) {
this.myService = myService;
}
public void run() {
myService.doSomething();
}
}
public class Main {
public static void main(String[] args) {
// MyService가 매개변수로 꼭 들어가야 한다.
MyApp myApp = new MyApp();
myApp.run();
}
}
@RequiredArgsConstructor
실제 Web Application을 개발하면 대부분이 불변 객체이고 생성자 주입 방식을 선택하게 된다. 이런 반복되는 코드를 편안하게 작성하기 위해 Lombok에서 제공하는 Annotation 이다.
final 필드를 모아서 생성자를 자동으로 만들어 주는 역할Annotation Processor 가 동작하며 컴파일 시점에 자동으로 생성자 코드를 만들어준다.@Component
@RequiredArgsConstructor
public class MyApp {
// 필드에 final 키워드 필수! 무조건 값이 있도록 만들어준다.(필수)
private final MyService myService;
// Annotation Processor가 만들어 주는 코드
// public MyApp(MyService myService) {
// this.myService = myService;
// }
public void run() {
myService.doSomething();
}
}
생성자를 하나 만들고 @Autowired 를 사용한 코드와 똑같이 동작한다.