Spring 7기 프로젝트/아웃소싱 팀 프로젝트

내가 프로젝트에서 사용한 Java & Spring 문법 총 정리 및 개념 재정립

JuNo_12 2025. 6. 18. 14:34

목차

  1. Java 기본 문법
  2. Spring 핵심 개념
  3. Spring Security + JWT
  4. 면접 예상 질문과 답변

1. Java 기본 문법

1.1 생성자 (Constructor)

포인트: "생성자가 무엇이고 언제 호출되나요?"

public class Person {
    private String name;
    private int age;
    
    // 기본 생성자
    public Person() {
        this.name = "Unknown";
        this.age = 0;
    }
    
    // 매개변수 생성자
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

// 사용
Person person = new Person("홍길동", 25); // 생성자 자동 호출

 

핵심 답변:

  • 생성자는 객체가 생성될 때 자동으로 호출되는 특별한 메서드
  • 클래스 이름과 동일하며 반환 타입이 없음
  • 객체의 초기 상태를 설정하는 역할
  • 기본 생성자는 매개변수 생성자가 없을 때만 자동 생성됨

1.2 접근 제어자

포인트: "private, public의 차이와 캡슐화의 이점은?"

public class BankAccount {
    private int balance;        // 외부 접근 차단
    public String accountNumber; // 외부 접근 가능
    
    public void deposit(int amount) {
        if (amount > 0) {       // 검증 로직
            this.balance += amount;
        }
    }
    
    public int getBalance() {   // 통제된 접근
        return balance;
    }
}

 

핵심 답변:

  • private: 클래스 내부에서만 접근 가능
  • public: 어디서든 접근 가능
  • 캡슐화의 이점: 데이터 보호, 검증 로직 적용, 내부 구현 변경 시 외부 코드 영향 최소화

1.3 static 키워드

포인트: "static 변수와 인스턴스 변수의 차이는?"

public class Counter {
    private static int totalCount = 0;  // 클래스 변수 (모든 인스턴스 공유)
    private int instanceCount = 0;      // 인스턴스 변수 (객체마다 독립)
    
    public Counter() {
        totalCount++;       // 모든 객체가 공유
        instanceCount++;    // 각 객체마다 독립
    }
    
    public static int getTotalCount() {  // 객체 생성 없이 호출 가능
        return totalCount;
    }
}

 

핵심 답변:

  • static: 클래스 로딩 시 메모리에 할당, 모든 인스턴스가 공유
  • 인스턴스 변수: 객체마다 독립적인 메모리 공간
  • static 메서드는 객체 생성 없이 클래스명으로 직접 호출 가능

1.4 인터페이스와 추상 클래스

포인트: "인터페이스와 추상 클래스의 차이점은?"

// 인터페이스 - 계약서 역할
interface Drawable {
    void draw();                    // 추상 메서드
    default void print() {          // Java 8+ default 메서드
        System.out.println("Drawing...");
    }
}

// 추상 클래스 - 공통 기능 + 강제 구현
abstract class Animal {
    protected String name;          // 공통 필드
    
    public Animal(String name) {    // 공통 생성자
        this.name = name;
    }
    
    public void sleep() {           // 구현된 메서드
        System.out.println(name + " is sleeping");
    }
    
    public abstract void makeSound(); // 추상 메서드
}

 

핵심 답변:

  • 인터페이스: 다중 구현 가능, 계약서 역할, 모든 메서드가 기본적으로 추상
  • 추상 클래스: 단일 상속, 공통 기능 제공 + 강제 구현 메서드

1.5 제네릭 (Generics)

포인트: "제네릭을 사용하는 이유는?"

// 제네릭 없이
List list = new ArrayList();
list.add("문자열");
list.add(123);
String str = (String) list.get(0);  // 형변환 필요, 런타임 에러 위험

// 제네릭 사용
List<String> stringList = new ArrayList<>();
stringList.add("문자열");
// stringList.add(123);                // 컴파일 에러!
String str = stringList.get(0);        // 형변환 불필요

핵심 답변:

  • 타입 안전성: 컴파일 타임에 타입 체크
  • 형변환 제거: 명시적 캐스팅 불필요
  • 코드 재사용성: 하나의 코드로 여러 타입 처리

2. Spring 핵심 개념

2.1 의존성 주입 (Dependency Injection)

포인트: "의존성 주입이 무엇이고 왜 사용하나요?"

 

핵심 답변:

  • 정의: 객체 간 의존 관계를 외부에서 주입하는 방식
  • 장점:
    • 느슨한 결합으로 유연성 증대
    • 테스트 용이성 (Mock 객체 주입 가능)
    • 코드 재사용성 향상
    • 관심사 분리

2.2 생성자 주입을 권장하는 이유

포인트: "필드 주입 vs 생성자 주입의 차이는?"

// ❌ 필드 주입 (권장하지 않음)
@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;
    
    // 의존성이 없어도 객체 생성 가능 (NullPointerException 위험)
}

// ✅ 생성자 주입 (권장)
@Service
@RequiredArgsConstructor
public class UserService {
    private final UserRepository userRepository; // final 사용 가능
    
    // 생성자 호출 시 의존성 필수 보장
}

핵심 답변:

  • 불변성: final 키워드로 변경 불가능
  • 필수 의존성 보장: 객체 생성 시 반드시 주입
  • 테스트 용이성: 생성자로 Mock 객체 주입 가능
  • 순환 의존성 방지: 컴파일 타임에 발견

 @Autowired 란?

더보기

Spring이 필요한 객체(Bean)를 자동으로 찾아서 주입해주는 기능입니다. 개발자가 직접 객체를 생성하지 않아도 Spring이 알아서 필요한 객체를 찾아 연결해줍니다.

 


2.3 Spring Bean 생명주기와 @PostConstruct

포인트: "@PostConstruct를 언제 사용하나요?"

Spring Bean 생명주기:

  1. 객체 생성 (생성자 호출)
  2. 의존성 주입 (필드, setter 주입 등)
  3. @PostConstruct 메서드 실행 ← 여기서 안전한 초기화!
  4. 빈 사용 가능
  5. @PreDestroy 메서드 실행
  6. 객체 소멸

핵심 답변:

  • 외부 설정값에 의존하는 복잡한 초기화에 사용
  • 생성자에서는 의존성이 완전히 준비되지 않을 수 있음
  • 한 번만 실행되며 Spring이 실행 타이밍 보장

2.4 주요 어노테이션

포인트: "@Component, @Service, @Repository의 차이는?"

@Component              // 일반적인 Spring Bean
public class FileUtil { }

@Service               // 비즈니스 로직 (@Component + 의미)
public class UserService { }

@Repository            // 데이터 접근 (@Component + 예외 변환)
public class UserRepository { }

@Controller            // 웹 MVC 컨트롤러
public class UserController { }

@RestController        // REST API (@Controller + @ResponseBody)
public class ApiController { }

 

핵심 답변:

  • 모두 @Component를 기반으로 하는 특화된 스테레오타입
  • 의미적 구분: 코드 가독성과 AOP 적용 시 구분 가능
  • @Repository: DataAccessException 변환 기능 추가

3. Spring Security & JWT

3.1 JWT 토큰의 구조와 동작 원리

포인트: "JWT가 무엇이고 어떻게 동작하나요?"

JWT 구조:

  • Header: 토큰 타입과 해시 알고리즘
  • Payload: 실제 데이터 (Claims)
  • Signature: 무결성 검증용 서명

핵심 답변:

  • Stateless: 서버가 세션 상태를 저장하지 않음
  • Self-contained: 토큰 자체에 사용자 정보 포함
  • 확장성: 마이크로서비스 환경에 적합 

 


3.2 Spring Security 인증 흐름

포인트: "Spring Security의 인증 과정을 설명해주세요"

인증 흐름:

  1. 클라이언트가 JWT 토큰과 함께 요청
  2. JwtAuthenticationFilter에서 토큰 추출
  3. 토큰 유효성 검증 (만료, 서명, 블랙리스트)
  4. 유효하면 SecurityContext에 인증 정보 저장
  5. 컨트롤러에서 @AuthenticationPrincipal로 사용자 정보 접근

핵심 답변:

  • Filter Chain: 요청이 컨트롤러에 도달하기 전 보안 검사
  • SecurityContext: 현재 스레드의 인증 정보 저장소
  • Stateless Session: 세션 대신 토큰으로 상태 관리

4. 면접 예상 질문과 답변

Q1. "Spring에서 Bean은 언제 생성되나요?"

답변:

  • Singleton (기본): 애플리케이션 시작 시 생성, 하나의 인스턴스만 존재
  • Prototype: 요청할 때마다 새로운 인스턴스 생성
  • Lazy: @Lazy 어노테이션 시 실제 사용할 때 생성

 

Q2. "생성자 주입이 필드 주입보다 좋은 이유는?"

답변:

  1. 불변성: final 키워드 사용 가능
  2. 테스트 용이성: 생성자로 Mock 주입
  3. 필수 의존성 보장: 의존성 없으면 객체 생성 불가
  4. 순환 의존성 방지: 컴파일 타임에 발견

 

Q3. "@PostConstruct는 언제 사용하나요?"

답변:

사용 시기:

  • 외부 설정값(@Value, @ConfigurationProperties)에 의존하는 초기화
  • 다른 Bean에 의존하는 복잡한 초기화
  • 외부 리소스 연결 (DB, Redis, API 클라이언트)

 

Q4. "JWT의 보안 취약점과 대응 방안은?"

답변:

취약점:

  1. 토큰 탈취: XSS, Man-in-the-middle 공격
  2. 만료되지 않은 토큰: 장기간 유효한 토큰 위험
  3. 무효화 불가: 로그아웃 시 토큰 무효화 어려움

대응 방안:

 

Q5. "Spring에서 예외 처리는 어떻게 하나요?"

답변:

 

 

포인트:

  • 도메인별 예외 분리: 명확한 예외 계층
  • @RestControllerAdvice: 전역 예외 처리
  • 일관된 응답 형식: 클라이언트 처리 용이

자가 질문! 스스로에게 물어보는 시간

1. @Value vs @ConfigurationProperties

더보기

"설정이 많아질수록 @ConfigurationProperties가 유리합니다. 타입 안전성과 IDE 지원이 뛰어나고, Bean Validation으로 검증도 가능합니다."

2. Builder 패턴 성능

더보기

"미미한 성능 차이는 있지만, 실제 비즈니스 로직에서는 무시할 수준입니다. 가독성과 유지보수성이 더 중요한 경우가 많습니다."

3. Spring Bean 생명주기

더보기

"미미한 성능 차이는 있지만, 실제 비즈니스 로직에서는 무시할 수준입니다. 가독성과 유지보수성이 더 중요한 경우가 많습니다."