: 클래스의 인스턴스를 오직 하나만 생성하도록 보장하는 디자인 패턴
즉, "같은 객체를 계속 새로 만들지 말고, 한 번 만든 것을 재사용하자!" 라는 뜻
public class Singleton {
// static으로 미리 한 개 생성
private static final Singleton instance = new Singleton();
// 생성자 private → 외부에서 new로 생성 못함
private Singleton() {}
// 인스턴스 반환하는 유일한 메서드
public static Singleton getInstance() {
return instance;
}
}
Singleton obj1 = Singleton.getInstance();
Singleton obj2 = Singleton.getInstance();
System.out.println(obj1 == obj2); // true (같은 인스턴스!)
Spring 은 기본적으로 모든 Bean 을 Singleton Scope 으로 관리
@Service
public class MemberService {
// 이 클래스는 싱글톤으로 관리됨
}
Spring 에서 객체를 관리하는 핵심 엔진(컨테이너)
: 개발자가 직접 객체를 생성하고 관리하는 대신,
Spring 이 대신 객체를 생성하고 생명주기를 관리해줌
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = context.getBean(MemberService.class);
여기서 context
--> Spring Container
Spring Container 가 생성하고 관리하는 객체
즉, Bean = Spring 에 의해 관리되는 객체이고,
Spring Container
는 그 객체(Bean) 를 만들고, 넣고, 꺼내주고, lifecycle 을 관리
@Service // or @Component, @Repository, @Controller
public class MemberService {
}
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberService();
}
}
@Service
public class OrderService {
private final MemberService memberService;
public OrderService(MemberService memberService) {
this.memberService = memberService; // 자동 주입!
}
}
@Autowired
private MemberService memberService;
Dependency Injection, DI
: 객체 간의 관계를 외부에서 주입해주는 방식
: Spring 에서는 객체 간의 결합도를 낮추고, 유연하게 설계하기 위해 DI 를 적극 활용함
@Service
public class OrderService {
private final MemberService memberService;
public OrderService(MemberService memberService) {
this.memberService = memberService;
}
}
@Autowired
생략 가능 (Spring 4.3 이상)final
키워드로 불변성 유지 가능클라이언트(브라우저) 에 저장되는 작은 데이터 조각
Set-cookie
응답 헤더로 저장📌 주의사항
HttpOnly
, Secure
, SameSite
속성 활용 필요서버가 클라이언트를 식별하기 위해 세션 ID 를 발급하고 서버에 상태를 저장
📌 특징
HttpSession session = request.getSession();
session.setAttribute("sessionKey", memberId);
Spring에서는 HttpSession
으로 쉽게 사용 가능
인증 정보를 자체적으로 포함하는 JSON 기반의 토큰
📌 장점
📌 단점
[1] 로그인 요청 (ID/PW) →
[2] 서버에서 사용자 인증 후 JWT 생성 →
[3] JWT를 클라이언트에 응답 →
[4] 클라이언트는 JWT를 요청 헤더(Authorization)에 포함시켜 요청 →
[5] 서버는 JWT를 검증 후 사용자 인가 처리
클라이언트의 HTTP 요청과 서블릿(Controller) 사이에서 동작
요청/응답을 가로채어 사전/사후 처리하는 컴포넌트
즉, Spring Controller 진입 전에 동작하고,
필요하면 응답(Response) 도 조작 가능
: 특히 로그인, 인증, 로깅 등에 자주 사용됨
[클라이언트] → [Filter] → [DispatcherServlet] → [Controller]
↑
(응답 시 다시 거침)
필터 --> 인터셉터 --> AOP 순으로 더 세분화되고 구체적인 처리 가능
📌 주의사항
chain.doFilter()
꼭 호출해야 요청이 다음 단계로 넘어감 !HttpServletRequest
, HttpServletResponse
로 다운캐스팅해야 header, session 등 다룰 수 있어요.JPA 가 관리할 수 있는 객체임을 선언하는 어노테이션
즉, 해당클래스는 DB 테이블과 매핑되며,
Spring Data JPA 가 이 클래스의 인스턴스를 통해
데이터베이스 CRUD 작업을 자동으로 처리할 수 있게 됨
: JPA 가 등장하게 된 배경 !
: 왜 객체지향 프로그래밍에서 JPA 쓰는지 알 수 있음
"객체(Object)" vs "관계형 데이터베이스(Relational DB)" 간의 생각 방식 차이
즉, 객체는 계층적이고 참조 기반,
RDB는 평면적이고 키 기반이기 때문에 이 둘을 바로 연결해서 쓰기 어려움
class Member {
private String name;
private Team team; // 객체 간 참조
}
이걸 MySQL 에 저장하려면
CREATE TABLE member (
id BIGINT AUTO_INCREMENT,
name VARCHAR(255),
team_id BIGINT, -- 외래키
PRIMARY KEY (id)
);
team
필드가 객체를 참조하는데,team_id
가 외래 키 값으로만 표현됨JPA 는 객체와 관계형 데이터베이스 사이의 불일치를 해결하기 위한 ORM 기술
JPA 는 아래를 자동으로 처리해 줌
엔티티를 저장(persist) 하면, JPA 가 엔티티를 관리하는 메모리 공간
쉽게 말해,
JPA = DB 와의 중간에서 엔티티를 관리하는 1차 캐시
--> 이건 엔티티 객체를 메모리에 저장해서 성능을 높이고, 일관성을 보장하는 장치
EntityManager.persist(member)
→ member 객체는 DB에 바로 저장 ❌
→ 영속성 컨텍스트(1차 캐시)에 저장됨
트랜잭션이 끝나고 커밋 시
→ JPA가 쿼리를 생성해서 DB에 반영
Member m1 = em.find(Member.class, 1L); // DB에서 가져옴 → 1차 캐시에 저장
Member m2 = em.find(Member.class, 1L); // 1차 캐시에서 가져옴 (쿼리 ❌)
Map<PK, Entity>
형태로 1차 캐시에 저장해둠SELECT
가 많이 나가는 걸 막을 수 있음(성능 향상)Member m1 = em.find(Member.class, 1L);
Member m2 = em.find(Member.class, 1L);
System.out.println(m1 == m2); // true
==
가능em.persist(member1); // INSERT ❌
em.persist(member2); // INSERT ❌
// DB에 아직 전송되지 않음
em.getTransaction().commit();
// 그때서야 INSERT member1, INSERT member2 실행
persist()
할 때 DB 에 바로 INSERT 쿼리를 날리지 않고Member member = em.find(Member.class, 1L);
member.setName("변경된 이름"); // setter 호출만 했을 뿐인데?
em.getTransaction().commit(); // update 쿼리 자동 생성됨
em.update()
같은 걸 호출할 필요 XJPA 가 트랜잭션 안에서 객체 상태를 감지하고, SQL 을 생성!
flush()
는 트랜잭션 커밋 전 DB 에 쿼리를 보내는 동작이고, 커밋 시 자동으로 실행됨