1. 클래스와 객체, 참조 개념
public class Car {
private String brand;
public Car(String brand){
this.brand = brand;
}
public String getBrand(){
return brand;
}
}
public class CarOwner {
private Car car;
public CarOwner(Car car) {
this.car = car;
}
public void displayCarInfo() {
System.out.println("I Own a " + car.brand();
}
public static void main(String[] args) {
Car car = new Car("BMW");
CarOwner owner = new CarOwner(car); "객체 주입"
owner.displayCarInfo(); // I Own a BMW
}
}
* CarOwner는 Car 객체를 직접 생성하지 않고 외부에서 주입 받는다. 스프링 DI가 이런 방식으로 동작
2.인터페이스와 다형성
public interface GreetingService {
void greet(String name);
}
public class CasualGreetingService implements GreetingService {
@Override
public void greet(String name){
System.out.println("Hi, " + name);
}
}
public class FormalGreetingService implements GreetingService {
@Override
public void greet(String name){
System.out.println("Good day, " + name);
}
}
public class GreetingApp {
private GreetingService greetingService;
public GreetingApp(GreetingService greetingService) {
this.greetingService = greetingService;
}
public void run(String name) {
greetingService.greet(name);
}
public static void main(String[] args) {
GreetingService casual = new CasualGreetingService();
GreetingService formal = new FormalGreetingService();
GreetingApp app = new GreetingApp(casual);
app.run("박병천"); "Hi, 박병천"
app = new GreetingApp(formal);
app.run("병천"); "Good day, 병천"
}
}
* 인터페이스를 활용하면 구현체를 쉽게 바꿀 수 있다. 스프링에서 이 인터페이스를 사용해 유연한 객체 주입을 구현한다.
3. 자바 컬렉션과 스트림 활용
public class NumberProcessor {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
numbers.add(10);
numbers.add(15);
numbers.add(10);
numbers.add(20);
List<Integer> distinctEvenNumber = numbers.stream()
.distinct()
.filter(i -> i % 2 == 0)
.sorted()
.collect(Collectors.toList());
System.out.println("중복 제거 및 짝수 : " + distinctEvenNumber);
}
}
* 컬렉션과 스트림은 데이터를 처리하는 강력한 도구로, 스프링에서 데이터 처리를 위해 자주 사용
자바 코드와 스프링 코드에서의 차이는 객체 주입(Dependency Injection, DI) 이라는 개념에 있다.
자바 코드에서는 객체를 직접 생성하고 사용.
public class GreetingApp {
public static void main(String[] args) {
GreetingService casual = new CasualGreetingService(); // 객체 직접 생성
GreetingApp app = new GreetingApp(casual); // 객체 주입 (직접)
app.run("John");
}
}
위의 자바 코드에서는 GreetingService의 구현체인 CasualGreetingService 객체를 직접 생성한 후, 생성자에서 해당 객체를 수동으로 주입하고 있다.
스프링 코드에서는 Spring Framework가 자동으로 객체를 관리하고, 필요한 객체를 주입해준다.
@Component
class GreetingApp {
private final GreetingService greetingService;
@Autowired // 스프링이 DI를 통해 객체를 주입
public GreetingApp(GreetingService greetingService) {
this.greetingService = greetingService;
}
public void run(String name) {
greetingService.greet(name);
}
}
@SpringBootApplication
public class SpringApp {
public static void main(String[] args) {
var context = SpringApplication.run(SpringApp.class, args); // 스프링 컨텍스트 실행
GreetingApp app = context.getBean(GreetingApp.class); // 스프링이 GreetingApp 객체를 생성하고 주입
app.run("Alice");
}
}
1. @Component 애노테이션
- @Component는 스프링에게 이 클래스의 인스턴스를 스프링 컨테이너에 등록하라는 지시를 준다.
이 클래스는 스프링 빈이 되어 의존성 주입을 받을 수 있다.
- 즉, GreetingService와 GreetingApp 클래스는 스프링 애플리케이션 컨텍스트에 등록되어 스프링이 관리하는 객체가 된다.
2. 의존성 주입 (Dependency Injection)
- GreetingApp 클래스의 생성자에서 GreetingService 객체를 주입받고 있다.
- @Autowired 애노테이션은 GreetingApp의 생성자에서 GreetingService 객체를 자동으로 주입해준다. 스프링 컨테이너가 GreetingService 빈을 찾아 GreetingApp의 생성자에 주입한다.
3. 스프링 애플리케이션 컨텍스트
- SpringApplication.run(SpringApp.class, args)는 스프링 애플리케이션 컨텍스트를 시작한다. 이 컨텍스트에서 @Component가 붙은 클래스들은 모두 스프링 빈으로 등록되고 관리된다.
4. context.getBean(GreetingApp.class)
- SpringApplication.run()이 반환하는 애플리케이션 컨텍스트에서 GreetingApp 빈을 가져온다. 스프링은 GreetingApp 빈을 관리하며, 그 내부의 GreetingService 빈도 이미 주입된 상태이다.
나의 질문
Q: 근데 이미 @Component 애노테이션으로 스프링 빈에 등록이 되었는데 또 컨텍스트에서 빈을 등록해?
A : @Component로 클래스가 자동으로 빈으로 등록되면, 일반적으로 getBean()을 사용하지 않고 @Autowired를 통해 의존성 주입을 받는다. context.getBean()은 특정 시점에 빈을 동적으로 가져오거나, 빈을 직접 관리하고자 할 때 사용하는 방식이다.
주요 차이점:
1. 스프링은 객체를 자동으로 관리한다. 즉, 개발자가 직접 객체를 생성하지 않아도 되고, 대신 스프링이 관리하는 “빈(Bean)” 객체를 사용한다.
스프링은 기본적으로 스프링 빈으로 등록된 객체만 관리한다! (@Component가 달려있으면 빈이 해당 객체를 관리해줌)
2. @Autowired 어노테이션을 사용하면 스프링이 필요한 의존성을 자동으로 주입해줍니다.
3. SpringApplication.run()을 통해 스프링 애플리케이션을 실행하고, 스프링 컨텍스트가 자동으로 객체들을 관리하고 DI를 수행합니다.
정리
자바에서는 직접 객체를 생성하고, 필요한 객체를 생성자의 매개변수로 넘겨준다.
하지만 스프링에서는 객체 생성을 스프링이 관리하고, 필요한 객체를 자동으로 주입해준다. 이 방식은 개발자가 객체 생성 및 관리에 신경 쓸 필요 없이, 응집력 있고 유지보수 가능한 코드를 작성할 수 있게 해준다.
그럼 생각이 들 수 있을 것이다. 어? 스프링에서는 new를 쓰질 않고 객체 생성을 하네?? 라고
스프링은 의존성 주입 덕분에 객체 생성을 스프링 프레임워크가 자동으로 처리해준다!!
그럼 왜 new를 직접 쓰지 않느냐? 라는 생각이 든다.
스프링에서는 객체를 직접 new로 생성하는 대신, 스프링 컨테이너가 객체를 관리한다. 이를 통해 객체 간의 의존성을 자동으로 주입하고, 객체의 생명 주기도 관리한다.
그럼 스프링에서는 어케 생성해? 라는 생각이 또 들것이다.
스프링에서 객체를 생성하는 방식
스프링에서는 객체를 생성할 때 new를 직접 호출하는 대신, 스프링 컨테이너(ApplicationContext)가 객체를 관리하고 자동으로 주입한다. 이 과정에서 @Component, @Service, @Repository 등의 어노테이션이 사용된다 .
회고 : 머리아픔 ㅋㅋ
'Back-End > Spring' 카테고리의 다른 글
| IOC / DI (0) | 2024.12.06 |
|---|---|
| Spring Container와 Spring Bean (0) | 2024.12.06 |
| 객체 지향 설계(SOLID 원칙) (1) | 2024.12.06 |
| Spring DI(의존성 주입)에 대해서 (1) | 2024.12.01 |
| Spring Annotation (0) | 2024.12.01 |