이번주 위클리 페이퍼의 주제는
웹 서버(Web Server)와 WAS(Web Application Server)의 차이를 설명하고, Spring Boot의 내장 톰캣이 이 둘 중 어디에 해당하는지 설명해보자
Spring Boot에서 사용되는 다양한 Bean 등록 방법들에 대해 설명하고, 각각의 장단점을 비교해보자
웹서버와 WAS
웹서버
웹 브라우저 클라이언트가 HTTP 요청을 하면 그것을 받아서 정적인 컨텐츠 (.html, .jpeg, 이미지 등)을 제공하는 서버이다.
또한 동적 컨텐츠 요청을 받으면 WAS에게 요청(request)을 넘기고, WAS의 처리 결과를 클라이언트에게 전달(response)해준다.
대표적인 웹서버로는 Apache, Nginx가 있다.
WAS (Web Application Server)
웹 서버와 웹 컨테이너가 합쳐진 형태다.
DB 조회하거나 다양한 로직 처리를 필요로 하는 동적인 컨텐츠를 제공하기 위해 만들어진 애플리케이션 서버이다.
웹 서버는 동적 컨텐츠 요청을 받을 경우 웹 컨테이너에게 전송한다.
* 웹 컨테이너는 서블릿(Servlet)과 같은 웹 애플리케이션 컴포넌트를 실행하고 관리하는 환경을 제공하는 소프트웨어이다.
대표적인 WAS로는 Tomcat, Jetty 등이 있다.
WAS만으로도 정적 요청을 처리할 수 있지만 웹서버를 구별하는 이유는 역할의 분리와 효율성 때문이다.
정적 요청까지 WAS를 사용하게 되면 리소스를 사용하게 되고, 동적 요청 처리 로직의 성능이 저하될 수 있다.
또한 WAS는 JVM 기반으로 작동하기 때문에 웹서버가 정적 요청 처리 속도가 훨씬 빠르다.
따라서 정적 요청은 웹 서버가 처리하고, WAS에는 동적 요청만 넘겨줘서 WAS의 부하를 줄이기 위함이다.
Spring Boot의 내장 톰캣
Spring Boot의 내장 톰캣은 WAS에 해당한다.
Spring Boot의 내장 톰캣은 Spring Boot 애플리케이션 실행 시 함께 구동되는 서블릿 컨테이너(WAS)다. 덕분에 별도의 웹서버를 설치할 필요 없이 애플리케이션을 실행시킬 수 있다.
(WAR로 배포하여 실행하려면 외부 톰캣을 깔고 설정해야 하지만 내장 톰캣을 통해 애플리케이션과 서버를 하나로 패키징 한 Jar 파일로 배포가 가능하다.)
따라서 Spring Boot의 내장톰캣은 WAS에 속한다.
Spring Boot Bean 등록 방법
Bean을 등록하는 방법은 2가지 방법이 주로 쓰인다
컴포넌트 스캔 방식
클래스에 @Component 또는 그 파생 어노테이션(@Service, @Repository, @Controller)을 붙이면 Spring이 자동으로 Bean등록 해주는 방식.
@SpringBootApplication에 포함된 @ComponentScan이 클래스 경로를 탐색하며 스캔한다.
(경로를 지정해주지 않으면 @SpringBootApplication 하위의 경로를 스캔하기 때문에 스캔 범위에 해당하지 않는 곳에 컴포넌트 어노테이션을 불였다면 경로를 지정해줘야 한다.)
<장점>
코드가 간결해진다.
클래스 추가 시 별도의 설정을 할 필요 없다.
<단점>
프로젝트의 규모가 커질 수록 Bean 등록 대상을 관리하기 어렵다.
필요한 경우 스캔 범위를 별도로 설정해야 한다.
예시
CarRepository.java
@Repository
public class CarRepository {
public String findCar() {
return "아반떼";
}
}
CarService.java
@Service
public class CarService {
private final CarRepository carRepository;
// 생성자 주입
public CarService(CarRepository carRepository) {
this.carRepository = carRepository;
}
public void printCar() {
System.out.println(carRepository.findCar());
}
}
MainApplication.java
@SpringBootApplication // @ComponentScan를 포함하고 있다.
public class MainApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(MainApplication.class, args);
CarService carService = context.getBean(CarService.class); // 자동으로 주입
carService.printCar();
}
}
1. @SpringBootApplication에 포함된 @ComponentScan이 CarRepository, CarService에 붙은 @Repository, @Service를 인식하고 자동으로 Bean 등록을 한다.
2. CarService 객체 생성 시 자동으로 CarRepository를 주입해준다.
-> 개발자가 new로 객체를 생성할 필요 없다.
Configuration 방식
@Configuration를 달아준 클래스 내의 @Bean 메서드로 객체를 리턴하여 Bean을 등록한다.
수동 등록 방식이다.
<장점>
등록 대상이 명시적이다.
의존 관계를 세밀하게 제어할 수 있다
<단점>
설정 코드를 별도로 작성해야 한다.
관리할 Bean이 증가할 수록 Config 클래스도 복잡해진다.
예시
CarRepository.java
public class CarRepository {
public String findCar() {
return "아반떼";
}
}
CarService.java
public class CarService {
private final CarRepository carRepository;
// 생성자 주입
public CarService(CarRepository carRepository) {
this.carRepository = carRepository;
}
public void printCar() {
System.out.println(carRepository.findCar());
}
}
(설정파일) AppConfig.java
@Configuration
public class AppConfig {
@Bean
public CarRepository carRepository() {
return new CarRepository();
}
@Bean
public CarService carService() {
return new CarService(carRepository());
}
}
MainApplication.java
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(MainApplication.class, args);
CarService carService = context.getBean(CarService.class);
carService.printCar();
}
}
1. @Configuration 클래스 안의 @Bean 메서드로 직접 객체를 생성하고 반환한다.
2. 스프링이 이 메서드들을 실행해 반환된 객체를 Bean으로 등록한다.
3. CarService() 메서드를 호출 시 이미 등록된 CarRepository() Bean을 주입해준다.
-> 컴포넌트 자동 스캔 없이 개발자가 직접 Bean 등록 대상을 지정한다.
(참고)
지금은 잘 사용하지 않는 XML 설정 방식도 있다.
XML 파일에 <bean> 태그로 Bean을 수동 등록해주는 것이다.
'Weekly Paper' 카테고리의 다른 글
| [위클리 페이퍼] REST API의 장단점과 HTTP 요청 처리 과정 (2) | 2025.05.25 |
|---|---|
| [위클리 페이퍼] AOP, @Controller와 @RestController (0) | 2025.05.19 |
| [위클리 페이퍼] 스프링 프레임워크와 일반 자바 라이브러리 (0) | 2025.04.27 |
| [위클리 페이퍼] HashSet, O(n)과 O(log n) (0) | 2025.04.18 |
| [위클리 페이퍼] Java 고급 과정 / SRP, OCP, .map(), .flatMap() (1) | 2025.04.12 |