자바는 왜 main()을 찾을까? 스프링에서는 왜 잘 안 보일까?
자바를 처음 공부할 때 가장 많이 보는 코드 중 하나가 바로 main() 메서드이다.
public class App {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
문법책에서는 마치 모든 자바 클래스에 main()이 있어야 하는 것처럼 설명하는 경우가 많다. 하지만 실제로 스프링 프로젝트를 하다 보면 대부분의 클래스에는 main()이 존재하지 않는다.
그렇다면 자바는 왜 main()을 찾는 것이고, 스프링에서는 왜 잘 보이지 않는 것일까?
main()은 클래스의 필수 요소가 아니다
먼저 오해하기 쉬운 부분부터 정리하자.
main()은 모든 클래스에 반드시 있어야 하는 것이 아니다.
예를 들어 다음과 같은 클래스는 main()이 없어도 전혀 문제가 없다.
public class Calculator {
public int add(int a, int b) {
return a + b;
}
}
이 클래스는 계산 기능을 제공하는 역할만 할 뿐, 직접 실행되는 클래스가 아니기 때문이다.
즉,
- 실행을 시작하는 클래스 → main() 필요
- 기능만 제공하는 클래스 → main() 불필요
라고 이해하면 된다.
JVM은 왜 main()을 찾을까?
컴퓨터는 사람이 아니다.
코드 안에 메서드가 여러 개 존재해도 어떤 메서드부터 실행해야 하는지 스스로 판단할 수 없다.
public class Calculator {
public int add(int a, int b) {
return a + b;
}
public int minus(int a, int b) {
return a - b;
}
}
위 코드를 실행하라고 하면 JVM은 혼란스러워진다.
- add()를 실행해야 하는가?
- minus()를 실행해야 하는가?
- 둘 다 실행해야 하는가?
이 문제를 해결하기 위해 자바는 하나의 약속을 정했다.
프로그램 실행은 반드시 public static void main(String[] args)에서 시작한다.
즉, JVM은 프로그램을 실행할 때 가장 먼저 main() 메서드를 찾는다.
main()은 프로그램의 시작점(Entry Point)이다
main()은 흔히 “프로그램의 시작점”이라고 부른다.
public class App {
public static void main(String[] args) {
System.out.println("프로그램 시작");
}
}
실행 흐름은 다음과 같다.
JVM 실행
↓
App 클래스 로드
↓
main() 찾기
↓
main() 실행
↓
프로그램 시작
즉, main()은 JVM에게
“여기서부터 실행하세요.”
라고 알려주는 역할을 한다.
프로젝트에 main()은 하나만 있어야 할까?
그렇지도 않다.
프로젝트 안에 여러 개의 main()이 존재할 수 있다.
public class TestA {
public static void main(String[] args) {
System.out.println("A 실행");
}
}
public class TestB {
public static void main(String[] args) {
System.out.println("B 실행");
}
}
위 코드는 모두 정상적인 코드이다.
다만 실행할 때 JVM에게 어떤 클래스를 실행할 것인지 지정해 주어야 한다.
TestA 실행
또는
TestB 실행
즉,
프로젝트당 main() 하나가 아니라, 실행하려는 프로그램마다 하나의 main()이 필요하다.
스프링 프로젝트에서는 main()이 어디에 있을까?
많은 사람들이 스프링을 공부하다가 이런 의문을 가진다.
“Controller, Service, Repository에는 main()이 없는데 왜 실행되지?”
사실 스프링 부트 프로젝트에도 main()은 존재한다.
보통 다음과 같은 형태이다.
@SpringBootApplication
public class ShoppingMallApplication {
public static void main(String[] args) {
SpringApplication.run(
ShoppingMallApplication.class,
args
);
}
}
이 메서드가 바로 스프링 부트의 시작점이다.
일반 자바와 스프링의 차이
일반 자바
일반 자바에서는 개발자가 직접 객체를 생성하고 실행한다.
public static void main(String[] args) {
ProductService service =
new ProductService();
service.createProduct();
}
모든 실행 흐름을 개발자가 직접 관리한다.
스프링
스프링에서는 main()이 스프링 컨테이너를 실행시킨다.
SpringApplication.run(
ShoppingMallApplication.class, args
);
그 이후에는 스프링이 객체를 생성하고 관리한다.
@Service
public class ProductService {
}
스프링은 위 클래스를 발견하면
이 클래스는 Service구나.
내가 객체를 생성해서 관리해야겠다.
라고 판단한다.
따라서 Controller, Service, Repository 같은 클래스에는 main()이 필요하지 않다.
왜 자바 문법책에서는 main()을 중요하게 설명할까?
자바 문법책은 대부분 “순수 자바”부터 가르친다.
순수 자바에서는 스프링 같은 프레임워크가 존재하지 않는다.
따라서 프로그램을 실행하려면 반드시 시작점이 필요하다.
public static void main(String[] args)
그래서 문법책에서는 main()을 매우 중요하게 다룬다.
반면 실무에서는 스프링 부트가 대부분의 실행 흐름을 대신 관리하기 때문에 main()을 자주 수정할 일이 거의 없다.
정리
main()이란?
프로그램의 실행 시작점(Entry Point)
모든 클래스에 main()이 필요한가?
아니다.
실행을 시작하는 클래스에만 필요하다.
JVM은 왜 main()을 찾는가?
어디서부터 실행해야 할지 모르기 때문에 자바가 정한 약속된 시작점을 찾는다.
프로젝트에 main()은 몇 개까지 가능한가?
여러 개 가능하다.
실행할 때 어떤 main()을 사용할지만 선택하면 된다.
스프링에서는 왜 main()이 잘 안 보이는가?
스프링 부트 애플리케이션 클래스에 하나 존재하며, 이후 객체 생성과 실행 흐름은 스프링이 관리하기 때문이다.
한 문장으로 기억하기
main()은 클래스의 필수 요소가 아니라, JVM에게 프로그램을 어디서부터 실행해야 하는지 알려주는 약속된 시작점이다.
이 글 하나만 이해하면 나중에 “자바 실행 구조 → JVM → main() → 객체 생성 → 스프링 컨테이너” 흐름을 공부할 때 훨씬 쉽게 연결될 거야. 특히 스프링 시큐리티나 스프링 부트를 공부할 때도 결국 시작은 main()에서 SpringApplication.run()을 호출하는 것부터 시작한다는 점을 기억해두면 좋다.
'개발공부 > JAVA의 정석' 카테고리의 다른 글
| chapter 3) 자바 연산자 정리: 정수 나눗셈, 오버플로우, 형변환 주의점 (0) | 2026.06.08 |
|---|---|
| chapter 2-1) 변수 variable (0) | 2026.06.05 |
| chapter 2-2) 자주 사용되는 타입 간의 변환 (0) | 2026.06.05 |