Spring
글
-
Spring 소스 파헤치기 5: @Autowired는 넣을 빈을 어떻게 고르나 — 의존성 주입 해석
@Autowired가 붙은 필드와 생성자에 Spring이 어떤 빈을 넣는지, 그 빈을 어떻게 찾고 여럿이면 어떻게 고르는지를 실제 소스에서 따라갑니다. 후보 찾기, @Primary·@Qualifier·이름 일치의 우선순위, List와 Map 주입, 생성자 선택 규칙, 그리고 없을 때의 처리를 예제를 돌려 확인합니다.
-
Spring 소스 파헤치기 6: 생명주기 콜백과 PostProcessor — 컨테이너에 끼어드는 자리
BeanFactoryPostProcessor, BeanPostProcessor와 그 하위 인터페이스들, Aware 계열, @PostConstruct·InitializingBean·init-method, @PreDestroy·DisposableBean·destroy-method, SmartInitializingSingleton, SmartLifecycle이 각각 언제, 어떤 순서로 불리는지 실제 소스와 실행 결과로 확인합니다. 끼어드는 자리가 왜 이렇게 여러 종류인지도 함께 봅니다.
-
Spring 소스 파헤치기 7: refresh() 12단계 — 컨테이너가 켜지는 순서
new AnnotationConfigApplicationContext(...) 한 줄 뒤에서 도는 refresh()를 열두 단계 하나씩 엽니다. ApplicationContext가 BeanFactory에 무엇을 더하는지, 왜 GenericApplicationContext와 AbstractRefreshableApplicationContext 두 갈래인지, 켜다가 실패하면 그리고 close()하면 무슨 일이 일어나는지를 실제 소스와 예제로 확인합니다.
-
Spring 소스 파헤치기 8: @Configuration과 @ComponentScan은 어떻게 설계도가 되나
설정 클래스(@Configuration)와 @Bean 메서드, @ComponentScan으로 찾은 @Component 클래스가 빈의 설계도(BeanDefinition)로 바뀌는 과정을 Spring을 처음 보는 사람 기준으로 따라갑니다. ConfigurationClassPostProcessor가 설계도를 읽어 설계도를 더하는 방법, 클래스를 로딩하지 않고 훑는 컴포넌트 스캔, 그리고 @Configuration 클래스가 CGLIB로 감싸져 @Bean 메서드를 두 번 불러도 같은 객체가 나오는 이유를 실제 소스와 예제로 확인합니다.
-
Spring 소스 파헤치기 9: @Conditional, @Profile, @Import — 조건에 따라 빈을 고르는 법
조건이 맞을 때만 빈을 등록하는 @Conditional과 @Profile, 다른 설정을 가져오는 @Import가 컨테이너 안에서 언제, 어떻게 평가되는지를 Spring을 처음 보는 사람 기준으로 따라갑니다. 조건이 세 번 평가되는 이유, @Import의 세 갈래, DeferredImportSelector가 "미루는" 이유, 순환 import를 잡는 ImportStack, 그리고 @EnableXxx가 전부 @Import의 응용인 까닭을 실제 소스와 예제로 확인합니다.
-
Spring 소스 파헤치기 10: AOP 프록시는 어떻게 만들어지나 — JDK 방식과 CGLIB 방식
ProxyFactory.getProxy() 한 줄이 JDK 동적 프록시와 CGLIB 프록시 가운데 무엇을 어떤 기준으로 고르고, 각각 어떻게 만들며, 프록시로 들어온 호출이 인터셉터 체인을 지나 대상 객체까지 어떻게 가는지 실제 소스에서 확인합니다. 자기 자신의 메서드를 안에서 부르면 어드바이스가 걸리지 않는 이유와 final 메서드의 함정도 예제로 봅니다.
-
Spring 소스 파헤치기 11: @Aspect는 어떻게 발견되고 어드바이스 체인은 어떻게 돌아가나
@EnableAspectJAutoProxy 한 줄이 컨테이너에 무엇을 등록하는지, @Aspect 클래스가 어떻게 어드바이저로 바뀌는지, 컨테이너는 어떤 빈을 프록시로 감쌀지 어떻게 정하는지, 그리고 프록시의 메서드를 부르면 @Around·@Before·@After·@AfterReturning·@AfterThrowing이 어떤 순서로 실행되는지를 실제 소스와 예제 출력으로 확인합니다.
-
Spring 소스 파헤치기 12: 이벤트, Environment, Resource — 컨테이너 주변의 세 추상화
ApplicationContext가 BeanFactory 위에 더하는 세 가지, 이벤트(보내고 받기)·Environment(설정값과 프로파일)·Resource(파일과 클래스패스 읽기)가 소스에서 어떻게 생겼고 refresh()의 어느 단계에 붙어 있는지, Spring을 처음 보는 사람 기준으로 따라갑니다. publishEvent 한 번의 여정, 시스템 프로퍼티가 설정 파일을 이기는 이유, classpath: 접두사가 클래스로 바뀌는 자리를 실제 소스와 예제로 확인합니다.
-
Spring 소스 파헤치기 13: ResolvableType과 MergedAnnotations — 타입과 어노테이션을 읽는 법
Spring이 List<String>의 String을 어떻게 알아내는지(ResolvableType), 어노테이션 위에 붙은 어노테이션과 @AliasFor를 어떻게 하나로 합쳐 읽는지(MergedAnnotations), 클래스를 로딩하지 않고 .class 파일에서 어떻게 읽는지(MetadataReader)를 Spring을 처음 보는 사람 기준으로 실제 소스와 예제로 확인합니다.
-
Spring 소스 파헤치기 14: 타입 변환과 BeanWrapper — 문자열이 객체의 속성이 되기까지
설정 파일의 문자열 "8080"이 빈의 int 필드에 들어가기까지 누가 무엇을 하는지 소스로 따라갑니다. PropertyEditor와 ConversionService가 왜 둘 다 있고 어느 쪽을 먼저 쓰는지, BeanWrapper가 "address.city" 같은 경로를 어떻게 따라 내려가는지, 컨테이너가 이 둘을 어디서 쓰는지를 Spring을 처음 보는 사람 기준으로 정리합니다.
-
Spring 소스 파헤치기 15: SpEL — 표현식은 어떻게 파싱되고 계산되나
"#{T(java.lang.Math).max(a, 3) + 1}" 같은 문자열이 토큰이 되고, 트리가 되고, 값이 되기까지를 소스로 따라갑니다. 연산자 우선순위가 파서 메서드의 호출 순서로 표현되는 방식, StandardEvaluationContext 와 SimpleEvaluationContext 가 둘인 이유, 식을 바이트코드로 바꾸는 컴파일 모드, 그리고 @Value("#{…}") 가 컨테이너 안에서 풀리는 길을 Spring을 처음 보는 사람 기준으로 정리합니다.
-
Spring 소스 파헤치기 16: 유틸리티와 AOT — 모두가 쓰는 도구 상자와 미리 계산해 두기
Spring의 모든 모듈이 가져다 쓰는 spring-core의 유틸리티(Assert, ClassUtils, ReflectionUtils, 맵 세 가지, OrderComparator)가 왜 따로 있고 어디서 쓰이며 어디가 함정인지, 그리고 Spring 6부터 들어온 AOT가 컨테이너를 빌드 시점에 "미리 계산"해 Java 소스와 RuntimeHints로 바꾸는 흐름을 실제 소스와 실행 예제로 확인합니다.
-
Spring 소스 파헤치기 17: @Transactional — 트랜잭션은 누가 열고 누가 닫나
메서드에 @Transactional 한 줄을 붙이면 누가 트랜잭션을 열고, 예외가 나면 누가 롤백하고, 정상이면 누가 커밋하는지 실제 소스로 따라갑니다. PlatformTransactionManager·TransactionDefinition·TransactionStatus 세 인터페이스, @EnableTransactionManagement가 등록하는 빈, TransactionInterceptor가 호출을 가로채는 순서, 전파 속성이 갈리는 자리, 커넥션이 ThreadLocal에 묶이는 이유, 그리고 체크 예외는 롤백되지 않는다·안쪽이 실패하면 바깥이 UnexpectedRollbackException을 받는다 같은 함정을 예제로 확인합니다.
-
Spring 소스 파헤치기 18: JdbcTemplate — 템플릿-콜백 패턴과 예외 변환
날 JDBC 코드가 매번 되풀이하는 일(커넥션 얻기, Statement 만들기, 예외 처리, 닫기)을 JdbcTemplate이 어떻게 한 곳에 모아 두고 내 코드에는 콜백만 남기는지 소스로 따라갑니다. 커넥션을 @Transactional 안에서 어떻게 같이 쓰는지, SQLException이 DuplicateKeyException 같은 Spring 예외로 바뀌는 길과 7.x의 기본 변환기가 무엇인지를 Spring을 처음 보는 사람 기준으로 정리합니다.
-
Spring 소스 파헤치기 19: ORM과 R2DBC 연동 — JPA 통합과 리액티브 트랜잭션
JPA의 EntityManagerFactory가 어떻게 빈이 되고, @PersistenceContext로 받은 EntityManager가 왜 여러 스레드가 함께 써도 안전한지, JpaTransactionManager 아래서 JdbcTemplate이 어떻게 같은 커넥션을 쓰는지, @Repository의 예외가 어디서 바뀌는지를 소스로 확인합니다. 이어서 스레드가 없는 리액티브 세계에서 R2DBC 트랜잭션이 Reactor Context에 실리는 방식을 봅니다.
-
Spring 소스 파헤치기 20: spring-web 기반 — HttpMessageConverter, WebApplicationContext, 필터
Spring MVC와 WebFlux가 함께 딛고 서는 spring-web 모듈을 처음 보는 사람 기준으로 읽습니다. HTTP 메시지를 객체로 다루는 인터페이스들, 본문을 Java 객체로 바꾸는 HttpMessageConverter와 그것을 고르는 규칙, 서블릿 컨테이너 안에서 Spring 컨테이너가 켜지는 자리(ContextLoaderListener), 그리고 한 요청에 한 번만 도는 필터가 어떻게 만들어져 있는지를 소스와 예제로 확인합니다.
-
Spring 소스 파헤치기 21: DispatcherServlet — 요청 하나가 응답이 되기까지
HTTP 요청 하나가 Spring MVC 안에서 응답이 되기까지를 DispatcherServlet의 소스로 따라갑니다. 서블릿이 켜질 때 자기 컨텍스트와 전략 객체를 마련하는 과정, 그리고 doDispatch가 핸들러를 찾아 부르고 인터셉터와 예외 처리를 끼워 넣는 순서를 Spring을 처음 보는 사람 기준으로 확인합니다.
-
Spring 소스 파헤치기 22: 핸들러 매핑과 어댑터 — @RequestMapping은 어떻게 찾고 어떻게 부르나
@GetMapping을 붙인 메서드가 언제 어디에 등록되는지, 요청이 오면 후보 가운데 어느 메서드가 뽑히는지, 뽑힌 메서드의 인자는 누가 채우고 반환값은 누가 응답으로 바꾸는지를 RequestMappingHandlerMapping과 RequestMappingHandlerAdapter의 소스로 따라갑니다. 매핑이 모호할 때 나는 두 가지 예외와, 직접 만든 인자 리졸버가 끼어드는 자리도 예제로 확인합니다.
-
Spring 소스 파헤치기 23: 예외 처리, 인터셉터, 뷰 — 요청 처리의 앞뒤와 끝
컨트롤러 메서드의 앞뒤에 끼어드는 HandlerInterceptor가 어떻게 줄을 서고 왜 preHandle을 통과한 것만 afterCompletion을 받는지, 컨트롤러가 던진 예외가 어떤 순서로 HandlerExceptionResolver를 거쳐 @ExceptionHandler 메서드에 닿는지, 그리고 뷰 이름 하나가 ViewResolver와 View를 거쳐 JSP로 forward되기까지를 실제 소스와 예제 출력으로 확인합니다.
-
Spring 소스 파헤치기 24: WebFlux — DispatcherHandler, 함수형 엔드포인트, WebClient
Spring WebFlux가 요청 하나를 응답으로 바꾸는 길을 소스로 따라갑니다. HttpHandler 아래에 WebFilter와 WebExceptionHandler가 엮이는 방법, DispatcherServlet의 리액티브 짝인 DispatcherHandler, 어노테이션 컨트롤러와 함수형 엔드포인트가 같은 길을 지나는 모습, 그리고 WebClient의 필터 사슬까지 봅니다.
-
Spring 소스 파헤치기 25: WebSocket과 메시징 — STOMP 메시지는 어떻게 흐르나
브라우저가 보낸 STOMP 메시지 하나가 @MessageMapping 메서드를 거쳐 구독자들에게 퍼지기까지를 소스로 따라갑니다. spring-messaging의 Message·채널·핸들러, spring-websocket의 핸드셰이크, 그리고 둘을 잇는 채널 세 개와 간단한 브로커를 WebSocket을 처음 보는 사람 기준으로 확인합니다.
-
Spring 소스 파헤치기 26: spring-test — SpringExtension, TestContext, MockMvc
테스트 클래스에 어노테이션 한 줄을 붙이면 컨테이너가 뜨고 빈이 주입되고 트랜잭션이 롤백됩니다. JUnit과 Spring이 만나는 SpringExtension, 같은 설정이면 컨텍스트를 한 번만 띄우는 컨텍스트 캐시와 그 열쇠, 테스트 트랜잭션, 서버 없이 진짜 DispatcherServlet을 돌리는 MockMvc를 실제 소스에서 확인합니다.
-
Spring 소스 파헤치기 27: 캐시, 스케줄링, 검증, 리질리언스 — 컨테이너 위에 얹힌 기능들
@Cacheable, @Scheduled, @Async, @Validated, @Retryable은 따로 만든 기능처럼 보이지만 속은 같은 틀을 되풀이합니다. 스위치 어노테이션이 무엇을 등록하고, 어느 후처리기가 빈을 감싸고, 어느 인터셉터가 호출을 가로채는지를 Spring을 처음 보는 사람 기준으로 소스에서 확인하고, 연재 전체를 정리합니다.
-
Spring 소스 파헤치기 1: AI와 함께 소스를 읽는 방법과 분석 지도
Spring이 무엇이고 어떻게 동작하며 어디에 쓰는지를 가장 작은 예제와 그림, 3분 실습으로 먼저 보고 시작하는, Spring 소스 읽기 시리즈의 첫 글입니다. 이어서 84만 줄짜리 소스를 작은 단위로 나눠 AI와 함께 읽는 방법, 똑같은 소스를 받는 법, 앞으로 읽을 순서를 정리합니다.
-
Spring 소스 파헤치기 2: 전체 지도 — 모듈과 패키지는 어떻게 나뉘어 있나
Spring Framework 저장소를 처음 열어 보는 사람을 위한 지도입니다. 모듈 22개가 각각 무슨 일을 하고 서로 어떻게 기대고 있는지, spring-core·spring-beans·spring-context·spring-aop 안에는 무엇이 있는지, 컨테이너가 켜질 때의 큰 흐름까지 실제 빌드 파일과 소스로 확인하며 따라갑니다.
-
Spring 소스 파헤치기 3: BeanFactory 계층 구조와 BeanDefinition
Spring이 객체를 만들기 전에 먼저 준비하는 설계도(BeanDefinition)와, 객체를 꺼내는 창구(BeanFactory)가 왜 여러 인터페이스로 나뉘어 있는지를 실제 소스 발췌와 그림으로 따라갑니다. Spring을 처음 보는 사람을 위한 글입니다.
-
Spring 소스 파헤치기 4: Bean은 어떻게 만들어지나 — 생성 흐름과 3단계 캐시
getBean()을 한 번 부르면 Spring 안에서 무슨 일이 일어나는지, Spring을 처음 보는 사람 기준으로 따라갑니다. 캐시 조회, 인스턴스화·의존성 주입·초기화 세 단계, 그리고 A와 B가 서로를 필요로 하는 순환 참조를 맵 세 개로 푸는 방법을 실제 소스에서 확인합니다.