Spring에서 의존성 주입(DI)을 자동으로 처리해주는 어노테이션
객체 간의 의존 관계를 설정할 때 직접 생성하는 대신, 스프링이 자동으로 의존 객체를 주입해준다.
// 개발자가 직접 의존성 주입 (spring 없이)
public class Dog {
private final Animal animal;
public Dog(Animal animal) { // 직접 주입
this.animal = animal;
}
}
// 사용하는 쪽에서 직접 주입
public class Main {
public static void main(String[] args) {
Animal animal = new Animal(); // 직접 생성
Dog dog = new Dog(animal); // 직접 주입
}
}
// 수동 세터 주입(spring 없이)
public class Dog {
private Animal animal;
public void setAnimal(Animal animal) {
this.animal = animal;
}
}
// 사용하는 쪽
public class Main {
public static void main(String[] args) {
Animal animal = new Animal(); // 직접 생성
Dog dog = new Dog();
dog.setAnimal(animal); // 직접 세터로 주입
}
}
// @Autowired 사용해서 의존성 자동 주입
@Component
public class Dog {
private Animal animal;
@Autowired // 생성자 주입
public Dog(Animal animal) {
this.animal = animal;
}
// 또는 필드 주입
// @Autowired
// private Animal animal;
}
| 역할 | 설명 |
|---|---|
@Component, @Service, @Repository, @Controller등 | 해당 클래스를 스프링 빈으로 등록 |
@Autowired | 등록된 빈을 다른 클래스에 주입 |
@Component
public class Animal {
// 이 클래스는 스프링 빈으로 등록됨
}
@Component
public class Dog {
private final Animal animal;
@Autowired // 등록된 Animal 빈을 자동으로 주입받음
public Dog(Animal animal) {
this.animal = animal;
}
}
스프링 4.3부터는 생성자가 1개일 경우 @Autowired 생략 가능
동일한 타입의 빈이 여러 개 있을 때, 스프링에게 그중 어떤 걸 주입할지 지정해주는 어노테이션
동일한 인터페이스를 구현한 클래스가 여러 개 있을 때, 스프링은 어떤 구현체를 주입해야 할지 모호해서 오류가 발생한다.
public interface Animal {
void sound();
}
@Component("dog") // 이름을 지정할 수도 있음
public class Dog implements Animal {
public void sound() {
System.out.println("멍멍");
}
}
@Component("cat")
public class Cat implements Animal {
public void sound() {
System.out.println("야옹");
}
}
// Animal 타입 빈이 2개(Dob, Cat) 생김 -> 모호성 발생
// @Qualifier로 특정 빈 지정
@Component
public class Zoo {
private final Animal animal;
// "dog"는 @Component("dog")에서 지정한 이름과 같음
@Autowired
public Zoo(@Qualifier("dog") Animal animal) {
this.animal = animal;
}
public void makeSound() {
animal.sound(); // 멍멍
}
}
// 필드 주입에서 @Qualifier 사용
@Component
public class Zoo {
@Autowired
@Qualifier("cat")
private Animal animal;
public void makeSound() {
animal.sound(); // 야옹
}
}
// 에러 예시
@Component
public class Zoo {
@Autowired
private Animal animal; // ❌ 오류: Animal 타입이 여러 개라서 선택 불가
}
@Configuration과@Bean으로 XML 설정을 대체하고, 코드 기반으로 의존성 주입을 구성할 수 있게 해준다.
스프링 설정 클래스임을 나타낸다.
이 클래스 안에서@Bean메소드를 사용해 직접 객체를 생성하고 빈으로 등록할 수 있다.
메소드에 붙여서 해당 메소드가 반환하는 객체를 스프링 빈으로 등록하게 한다.
직접 new 해서 만든 객체를 스프링이 관리하게 만든다.
// 스프링 컨테이너 안에서 수동 주입
// @Bean으로 수동 설정
@Configuration
public class AppConfig {
@Bean
public Animal animal() {
return new Animal(); // 수동 생성
}
@Bean
public Dog dog() {
return new Dog(animal()); // 직접 주입
}
}
Spring 애플리케이션이 실행될 때 내부적으로 동작하는 전체 흐름
web.xml을 읽고 서블릿들을 로딩하며 Spring 애플리케이션을 부팅한다.
web.xml의 설정대로 DispatcherServlet을 초기화한다. <servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Spring의 프론트 컨트롤러로 동작하며, 모든 요청을 가로채서 처리한다.
contextConfigLocation에 설정된 XML을 읽는다.WebApplicationContext라는 스프링 컨텍스트를 생성한다. 설정 파일(XML) 기반으로 Bean을 생성 및 관리하는 핵심 컨테이너
applicationContext.xml파일을 읽어 Bean 등록@ComponentScan으로 클래스 스캔<context:annotation-config />로 어노테이션 DI 활성화<context:component-scan base-package="com.example" />
<context:annotation-config />
이 단계에서 Spring은 IoC 컨테이너로 동작하기 시작한다.
객체 생성, 생명주기 관리, 의존성 주입까지 모두 처리한다.
Bean 간의 의존 관계를 주입해서 객체 간 결합도를 낮춘다.
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
}
Spring 3에서는 @Autowired를 쓰려면 반드시 <context:annotation-config /> 또는 <context:component-scan />이 있어야 작동한다.
횡단 관심사(로그, 보안, 트랜잭션 등)를 비즈니스 로직에서 분리해서 처리한다.
<aop:aspectj-autoproxy /><tx:annotation-driven transaction-manager="txManager" />어떤 URL이 어떤 Controller의 어떤 메서드에 매핑되는지를 결정한다.
HandlerMapping이 URL → Controller 메서드 매핑을 수행하고,
HandlerAdapter가 실제 메서드를 실행시켜주는 역할을 한다.
컨트롤러가 반환한 논리적 이름을 실제 JSP 등 뷰로 매핑해준다.
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/"/> <property name="suffix" value=".jsp"/> </bean>
/WEB-INF/views/home.jsp를 응답으로 포워딩한다.사용자의 요청을 받아 Controller → Service → DAO → DB 등으로 요청 처리
개념만 듣고는 잘 와닿지 않아, 예제를 많이 찾아보며 직접 실습해 이해하려고 노력했다. 그러다 보니 점점 내부 구조까지 궁금해져서 공부하게 되었고, 자연스럽게 스프링의 시작 흐름 전반을 정리해보게 되었다. 정리하면서 나중에 더 깊이 공부해야 할 내용도 발견했는데, 아직은 전체적으로 잘 이해되지 않는 부분이 많아 여러 번 읽고 반복하면서 익히고 외워야 할 것 같다.