R+7
[TIL] 차근차근 Java (1) - Java와 Spring 본문

Today I Learned
Java와 JVM
Java는 프로그래밍 언어. _한 번 작성하면 어디서나 실행된다(Write Once, Run Anywhere)_는 철학을 기반으로 만들어짐. 코드를 컴파일하면 기계어가 아니라 바이트코드로 변환되고, 이 바이트코드를 JVM(Java Virtual Machine)이 해석해서 실행하는 구조다. 그래서 Windows에서 짠 Java 코드가 Linux 서버에서도 그대로 돌아간다. 이 부분은 상당히 편리.
프레임워크
프레임워크는 애플리케이션의 뼈대(구조)를 미리 짜놓고, 개발자에게 그 빈칸(비즈니스 로직)만 채우게 하는 방식의 도구다. 내가 필요할 때 불러다 쓰는 라이브러리와 다르다. 프레임워크는 본인이 흐름을 쥐고 있고 내 코드를 필요할 때만 불러주는 식이다. 전자는 내가 주인이라면 후자는 프레임워크가 주인. 이는 Java에서 매우 중요한 개념인 제어의 역전(IoC, Inversion of Control) 이라고 부르는데, 스프링의 가장 핵심적인 설계 철학이기도 하다.
IoC란, 객체를 누가 생성하고 관리하느냐의 주도권이 '내 코드'에서 '프레임워크'로 넘어가는 것을 의미한다. 그중 DI(Dependency Injection, 의존성 주입)는 IoC를 구현하는 구체적인 방법 중 하나다. 객체가 필요한 다른 객체(의존성)를 자기가 직접 new로 만들지 않고, 외부(스프링)로부터 주입받는 것을 말한다. 비유하자면 DI 없이 만든다면 내가 직접 특정 원두를 사와서 커피를 내리는 방식(new)인 거고, DI를 적용한다면 나는 '원두'라는 규격만 요청해 두고 오늘 브라질산이 올지 케냐산이 올지 결정하는 것은 스프링에게 맡겨 공급받는 방식이라 보면 된다.
// DI 없이 — 내가 직접 만듦, BlockService가 BlockRepository 구현체를 강하게 알아야 함
public class BlockService {
private BlockRepository repository = new BlockRepositoryImpl();
}
// DI 적용 — 스프링이 만들어서 넣어줌, BlockService는 "어떤 구현체인지" 몰라도 됨
@Service
public class BlockService {
private final BlockRepository repository;
public BlockService(BlockRepository repository) { // 생성자로 주입받음
this.repository = repository;
}
}
※ final: 한 번 값이 대입되면 다시는 바꿀 수 없는 변수 선언.
스프링 컨테이너 (IoC 컨테이너)
애플리케이션을 구성하는 객체(Bean)의 생성, 구성(설정), 조립, 생명주기 관리를 애플리케이션 코드 대신 수행하는 소프트웨어 컴포넌트다. 스프링 프레임워크의 핵심이며, org.springframework.context.ApplicationContext 인터페이스(및 그 상위인 BeanFactory)로 구현되어 있다.
빈 (Bean)
스프링이 직접 생성하고 생명주기를 관리하는 객체. @Service, @Repository, @Controller, @Component 같은 어노테이션이 붙은 클래스는 스프링이 알아서 객체로 만들어 자기 창고(IoC 컨테이너)에 등록한다. 이후 다른 곳에서 그 타입이 필요하면 스프링이 창고에서 꺼내 주입해주는 시스템.
예를 들자면 BackendApplication.java의 @SpringBootApplication에 포함된 @ComponentScan이 바로 "이 패키지 밑을 다 뒤져서 빈 후보(어노테이션 붙은 클래스)를 찾아 등록해"라는 지시다.
Spring과 Spring Boot의 차이
Spring은 Java로 웹 애플리케이션을 만들기 위한 기반 프레임워크로, IoC 컨테이너, DI, AOP 등을 제공한다. 원래는 설정(XML)이 굉장히 많고 복잡했다고. Spring Boot는 Spring 위에 얹은 설정 자동화 도구다. 이런 의존성이 있으면 이런 설정이 필요하겠지... 를 추론해 자동으로 세팅해주는 역할이다. Spring Boot 덕분에 톰캣 서버 설정이나 DB 커넥션풀 설정 같은 걸 손으로 일일이 작업하지 않고 의존성만 추가하면 알아서 동작한다고 한다.
※ Tomcat: 아파치에서 개발한 오픈 소스 자바 서블릿 컨테이너이자, WAS. Java로 작성된 웹 애플리케이션을 서버 상에서 실행하고 관리해 주는 소프트웨어다. 일반 웹 서버가 정적 콘텐츠를 주로 다룬다면 Tomcat은 동적 콘텐츠 처리가 주 목적이며, 자체적으로 정적 콘텐츠를 처리하는 웹 서버 기능도 내장하고 있다.
어노테이션(Annotation)
@으로 시작하는 표식. 코드에 이 클래스, 메서드는 이런 역할이다라고 메타데이터를 붙이는 Java 문법이다. 어노테이션 자체는 로직이 없고, 스프링(또는 다른 프레임워크)이 실행 시점에 이 표식을 읽고 동작을 결정한다.
@SpringBootApplication= 이 클래스는 앱의 시작점이다@RestController= 이 클래스는 HTTP 요청을 받아 JSON으로 응답하는 클래스다@Service= 이 클래스는 비즈니스 로직 담당이다@Repository= 이 클래스는 DB 접근 담당이다@Entity= 이 클래스는 DB 테이블 한 줄(row)과 매핑된다@Autowired= 이 필드에 스프링이 Bean을 넣는다@GetMapping,@PostMapping= 이 메서드가 어떤 HTTP 요청(GET/POST)에 응답할지
Gradle
Spring에서 소스코드를 컴파일하고, 필요한 외부 라이브러리(의존성)를 내려받고, 테스트를 돌리고, 실행 가능한 파일(jar)로 묶는 과정을 자동화하는 도구. npm의 package.json, Python의 requirements.txt와 같은 역할이라 보면 쉽다.
gradlew(Gradle Wrapper)는 팀원마다 빌드 도구인 Gradle 자체의 버전이 달라서 생기는 문제를 막기 위해 올바른 빌드 도구 버전을 찾아주는 부트스트래퍼(Bootstrapper).
계층형 아키텍처 (MVC)
스프링 웹 앱은 보통 역할을 층으로 나눈다. 이렇게 나누는 이유는 관심사 분리 때문. 각 부분이 자기 역할만 책임지게 해서, 한 부분을 고쳐도 다른 부분에 영향이 안 가게 하기 위함이다.
[클라이언트] → Controller → Service → Repository → Entity ↔ DB
↑ ↑ ↑ ↑
요청/응답만 비즈니스 DB 접근만 테이블과
담당, 로직X 로직 담당 (JPA가 대부분 1:1 매핑
자동 구현)
참고로 각 계층이 무엇을 의미하는지는 (당연히) 알아둬야 한다.
| 계층 | 설명 | 비유 |
|---|---|---|
| Controller | HTTP 요청의 진입점. URL과 메서드를 매핑하고, 요청/응답 형식만 다룸 | 식당의 홀 직원. 주문만 받고 요리는 안 함 |
| Service | 실제 비즈니스 로직("이 예산이 팀 총액인지 1인 금액인지 계산" 같은 것) | 주방장. 실제 요리(로직) 담당 |
| Repository | DB에 데이터를 저장/조회하는 인터페이스. Spring Data JPA를 쓰면 인터페이스만 선언해도 구현체를 스프링이 자동 생성 | 창고 관리인. 재료(데이터) 입출고만 |
| Entity | DB 테이블 하나에 대응하는 Java 클래스. @Entity 붙이면 JPA가 테이블과 매핑 | 재료 명세서 양식 |
| DTO (Data Transfer Object) | 계층 간, 또는 클라이언트-서버 간 주고받는 데이터 형태를 정의한 클래스. Entity를 그대로 노출하지 않기 위해 씀 | 포장 용기 |
ORM / JPA
ORM은 Object-Relational Mapping이라는 뜻으로 SQL문을 직접 안 쓰고, Java 객체를 다루는 것만으로 DB를 조작하게 해주는 기술이다. JPA는 Java의 ORM 표준 규격(인터페이스)이고, Hibernate가 그 규격의 실제 구현체. JPA라는 표준 명세를 실제로 구현한 자바 ORM 프레임워크라고 보면된다. 살짝 새로운 용어가 많이 등장해서 헷갈릴 수 있는데, Java의 객체지향 프로그래밍과 RDB 사이 패러다임 불일치를 해결하기 위해 객체와 DB 테이블을 자동으로 매핑해 주는 기술이자, 객체-관계 매핑 프레임워크라 보면 된다.
Today I Listened to
'TIL' 카테고리의 다른 글
| [TIL] 차근차근 CS (10) - Cookie, HttpOnly, LocalStorage (0) | 2026.07.27 |
|---|---|
| [TIL] 차근차근 CS (9) - Auth와 OAuth (0) | 2026.07.24 |
| [TIL] 차근차근 CS (7) - 웹소켓 (0) | 2026.07.16 |
| [TIL] 차근차근 CS (6) - 흐름 제어 기법 (0) | 2026.07.15 |
| [TIL] 차근차근 데이터 (2) - 낙관적 락과 비관적 락 (0) | 2026.07.14 |