최근 제 주변 코딩 잘하는 사람이 면접을 보고 왔는데 질문이
SpringSecuritycontext 와 spring context 라이프사이클을 섞어서 설명하고 포크되는 순간과 어떻게 동작하는가
였습니다.
질문을 듣는 순간 머리가 멍 해졌고 생각해보지도 못한 질문이였습니다.
오늘은 그 라이프사이클을 파악하면서,
Spring Context, Application Context, SpringSecurityContext 에 대해 알아보도록 하겠습니다.
일단 저 문제에 대한 정답을 먼저 알려드리자면
Spring Application 이 시작될때 ApplicationContext가 초기화 되고 Application의 설정 정보와 빈 정보를 로드하고, 모든 빈을 생성 및 초기화 하는 단계입니다.
이 때 SpringSecurity 설정도 로드 됩니다.
이유를 보면
Spring Security는 Spring의 서브 프로젝트 로, 애플리케이션의 보안을 관리하기 위해 다양한 구성 요소와 필터를 제공합니다. Spring Security는 기본적으로 Spring의 DI 메커니즘과 ApplicationContext를 사용하여 보안 관련 빈들을 관리하고 초기화 합니다.
ApplicationContext가 초기화될 때, 애플리케이션의 모든 설정 파일 (예: @Configuration 클래스, XML 설정 파일 등)이 로드되고, 빈이 초기화됩니다. 이 과정에서 Spring Security의 설정도 함께 로드됩니다. 예를 들어, @EnableWebSecurity 애노테이션이 붙은 클래스나 XML 설정 파일에서 보안 설정을 정의합니다.
이제 하나하나 자세히 살펴보도록 하겠습니다.
1번 주제
Spring Context 와 Application Context 그리고 BeanFactory
스프링의 가장 큰 특징중 하나가 IoC 컨테이너를 통하여 객체의 생성과 관리를 해준다는게 있는데 Context가 이 Container의 일종이다.
Spring Contex 란 Spring 이 Bean을 다루기 좀 더 쉽도록 기능들이 추가된 공간이다.
- XML, Java Config 혹은 애노테이션을 통해 정의될 수 있다.
Bean은 모두 Context 안에서 이루어진다.
SpringContext는 일반적으로 빈의 생성, 구성 및 관리를 담당한다.
BeanFactory 란 빈을 생성하고 의존관계를 설정하는 기능을 담당하는 가장 기본적인 IoC 컨테이너이자 클래스를 말한다.
Application Context 는 SpringContext의 하위 인터페이스로, 더 구체적이고 확장적인 기능을 제공한다. ApplicationContext 에 등록된 Bean 객체의 경우 Context 가 초기화 될 적에 모두 생성되어 등록된 상태로 존재하고 그 이후부턴 생성하는 기능은 거의 하지 않는다.
IoC Container 에 Bean 객체를 등록할 적에는 POJO 와 메타정보를 합쳐 등록한다. 메타정보는 어노테이션, 클래스, XML 등 다양한 포맷으로 등록이 가능하다.
- 빈 팩토리 기능 : 빈의 생성 서정 및 관리 담당 → BeanFactory 인터페이스 상속 받은 기능
- BeanFactory의 경우, 오브젝트 생성과 오브젝트 사이의 런타임 관계를 설정하는 DI관점에서 지칭하는 용어이다.
- 메시지 소스 처리
- 이벤트 전파
- 부모-자식 관계의 컨텍스트 가질 수 있다.
- 장점
- 클라이언트는 구체적인 팩토리 클래스를 알 필요가 없다.
- 종합 IoC 서비스를 제공한다.
- 다양한 빈 검색 방법을 제공한다.
- 빈 목록을 관리하여,비늬이름 혹은 어노테이션 설정으로 빈을 찾을 수 있다.
BeanFactory와 ApplicationContext의 빈 생성 시기 차이점
BeanFactory는 Bean을 미리 생성하지 않는다. 그러면 언제 생성되는가? getBean을 사용해서 호출된 시점에 빈을 생성한다.
ApplicationContext는 App을 실행할 떼 Context초기화시점이 있는데 이 시점에 모든 Singleton 빈을 미리 다 생성하고, Application이 시작된 이후에는 빈이 이미 다 생성되어있기 때문에 빈을 지연없이 제공하고 받는다.
cf ) Context의 종류는 ApplicationContext, WebApplicationContext, ServletContext(Tomcat) 이 있다.
보통 Application Context가 Spring Context의 구현체라고 보면 된다.
Spring Container와 Spring Context는 같은 개념을 지칭한다고 볼 수 있고. 좀 더 정확히 말하자면, Spring Context는 Spring Container의 구체적인 구현체 중 하나이다.
예를들면 ServletContext 와 ApplicationContext가 공존하게 되면
위 Servlet Container는 서블릿들을 초기화할 때,
Spring Container는 각각의 서블릿이 제대로 동작하기 위해 필요한 의존성 주입(DI)을 제공한다.
두 컨테이너는 이렇게 밀접한 관계에 있기 때문에 Spring Container에 짚고 넘어갈 필요가 있다.
Spring Container의 역할은 빈(Bean) 객체들을 생성하고,
빈 객체들 간의 의존성을 관리하며 빈 객체들을 필요한 곳에서 주입(Injection)해주는 등의 역할을 맡는다.
빈 객체를 생성하고 생명주기를 관리할 때 스프링 컨테이너가 직접 컨트롤 하기 때문에
Inversion of Control (IoC) 방식이라고 불리며
객체 생성, 관리, 의존성 관련 코드들이 아닌, 서비스에 대한 코드에만 집중할 수 있는 장점이 있다.
때문에 Spring Container는 IoC Container라고도 불린다.
처리 하는 방식을 코드로 한 번 봐보겠다.
public class TobyspringApplication {
public static void main(String[] args) {
// 스프링 컨테이너 생성
GenericApplicationContext applicationContext = new GenericApplicationContext();
// 빈 등록
applicationContext.registerBean(HelloController.class);
// bean object 만들어서 가지고 있기.
// applicationContext가 빈오브젝트를 다 만들어준다. 초기화
applicationContext.refresh();
TomcatServletWebServerFactory serverFactory = new TomcatServletWebServerFactory();
// 톰캣 서블릿 컨테이너를 코드로 쉽게 사용할 수 있도록 한 도우미 클래스 , 추상화 시켜둠, 다른 서버들도 사용 할 수 있게
WebServer webServer = serverFactory.getWebServer(servletContext -> {
servletContext.addServlet("frontcontroller", new HttpServlet() {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//인증, 보안, 다국어, 공통기능 처리한다
//mapping을 frontcontroller 가 한다.
if(req.getRequestURI().equals("/hello") && req.getMethod().equals(HttpMethod.GET.name())){
// 요청
String name = req.getParameter("name");
HelloController helloController = applicationContext.getBean(HelloController.class);
// applicationContext한테 필요한 Object 의 reference를 주입 요청
String ret = helloController.hello(name);
// 응답
resp.setContentType(MediaType.TEXT_PLAIN_VALUE);
resp.getWriter().println(ret);
}else{
resp.setStatus(HttpStatus.NOT_FOUND.value());
}
}
}).addMapping("/*");
});
// tomcat 외의 다른 서블릿컨테이너를 지원 할 수 있고, 일관된 방식으로 실행하기위해서
// 추상화를 해놓았다
// ServletContainer 를 만드는 생성 함수이다.
webServer.start();
}
}
위 코드에서는 GenericApplicationContext를 사용하여 스프링 컨테이너를 생성하고,
applicationContext.registerBean을 사용하여 빈을 등록 applicationContext.refresh()를 호출하여 빈 오브젝트를 만들고,
TomcatServletWebServerFactory를 사용하여 WebServer를 만들고 시작한다. applicationContext.getBean을 사용하여 Controller의 빈을 가져와 처리한다.
이렇게 함으로써 코드의 의존성을 낮추고, 테스트 용이성을 높일 수 있다.
FrontController 랑 차이가 뭐야 ??
원래 이 전에는 FrontController 에서 바로 구현체인 Controller로 넘겨주는 형식으로 만들었다.
중요한 “SpringContainer” 가 할 수 있는 일들을 이후에 계속 적용 가능한 구조를 짜놨다.
SpringContainer 는 기본적으로 딱 한 번만 만든다.
새로운 오브젝트를 컨테이너가 만들어서 리턴하는게 아니라는 뜻이다. >> 처음에 만든 Object를 리턴 해준다.
SpringContainer 는 싱글톤 레지스트리 라고 한다.
싱글톤 패턴을 사용하지 않았는데도 마치 싱글톤 패턴을 사용한 것 처럼 하기 때문이다.
하지만 요즘은 저런 방법을 사용하지 않고 DispatcherServlet 을 사용한다. 여기에서는 다루지 않겠다.
간단하게 말하면 어떤Controller 가 어느 클래스로 만든 오브젝트의 메소드를 이용하는지 알 수가 없다.
왜냐하면 인터페이스만 이용하기 때문이다
여기서 연관관계를 만들어주는 과정을 Dependency Injection 이라고 부른다.
Dependency Injection 는 제 3의 존재가 필요하다.
앞에 frontcontroller 에서 해준걸 DispatcherServlet 에서 알아서 해준다.
applicationContext 을 통해 SpringContainer 와 의사소통한다
정리
- Spring Context는 Spring 프레임워크에서 애플리케이션의 설정과 빈을 관리하는 컨테이너의 개념
- ApplicationContext는 Spring Context의 구현체로서, 더 많은 기능을 제공하는 인터페이스.
- SpringContainer > BeanFactory > ApplicationContext
2번 주제
SpringSecuritycontext 와 SpringContext 의 관계
일단 이 관계를 알기 전에 두 개의 라이프 사이클에 대해 찾아보았다.
1. SpringBeanLifeStyle
-한글 버전
- Application Context 생성: Spring 애플리케이션 컨텍스트가 생성되고 초기화된다.
- Bean Initialization: 빈(Bean) 객체들이 생성되고 초기화된다. 이 단계에서는 빈 객체의 설정이나 초기화 작업이 수행된다.
- BeanNameAware & BeanFactoryAware 설정 특수 인터페이스인 BeanNameAware, BeanFactoryAware 를 구현한 클래스를 스캔하고 관련된 속성을 셋팅한다. 위의 두 인터페이스를 구현하면 Spring 컨테이너에 의해 관리되는 Bean 의 추가 정보나 기능에 접근 할 수 있다.
- Dependency Injection: Spring은 빈 객체들 간의 의존성을 주입한다. 즉, 필요한 의존 객체들을 빈에 주입된다.
- Custom Initialization: 사용자가 정의한 초기화 작업이 수행된다. 이는 InitializingBean 인터페이스를 구현하거나 @PostConstruct 어노테이션을 사용하여 정의할 수 있다.
- Application Running: 애플리케이션은 실행 상태로 들어가고, 서비스를 제공한다.
- Bean Destruction: 애플리케이션이 종료될 때 빈 객체들은 소멸된다. 이 단계에서는 빈 객체들이 사용한 자원을 해제하거나 정리하는 작업이 수행된다.
JSR-250은 자바플렛폼 공통 어노테이션이다. 기본 자바에서는 제공하지 않기 때문에 적용을 위해서는 라이브러리를 반드시 추가해야 한다.
JSR-250 어노테이션 종류는 @Resource, @PostConstruct, @PreDestroy가 있다.
빈이 생성되는 경우
- 먼저, 주석이 달린 메서드 @PostConstruct가 실행된다.
- 그런 다음, afterPropertiesSet()defined by InitializingBean가 실행된다.
- 셋째, 사용자 정의 구성이 init()실행된다.
마찬가지로, 빈 이 파괴되는 경우
- @PreDestroy실행되는 메서드
- destro아무거나y()그런 다음 DisposableBean의 메서드 가 실행된다.
- 마지막으로, 사용자 정의 구성된 destroy()메서드가 실행된다.
그 다음으로 Spring Security 라이프 사이클에 대해 봐보자
- Security Context: Spring Security에서 사용자의 보안 상태를 나타내는 객체이다. 인증된 사용자와 그들의 권한 정보를 포함한다.
- Authentication: 사용자의 인증 정보를 나타내는 객체이다. 주로 사용자의 신원(예: 사용자 이름, 비밀번호)과 그들의 권한 정보를 포함한다.
- Authentication Manager: Spring Security에서 인증을 관리하는 객체이다. 주어진 인증 요청에 대해 사용자를 인증하고 인증된 사용자의 Authentication 객체를 생성한다.
- Security Filter Chain Proxy: Spring Security에서 HTTP 요청을 처리하고 보안 필터 체인을 실행하는 객체이다. 보안 필터 체인에는 사용자의 인증, 권한 부여, 보안 검사 등의 작업을 수행하는 여러 보안 필터가 포함된다..
Spring application 이 시작될때 ApplicationContext가 초기화 되고 application의 설정 정보와 빈 정보를 로드하고, 모든 빈을 생성 및 초기화 하는 단계이다.
이 때 SpringSecurity 설정도 로드 된다.
결론 : Spring Context 초기화 시점에 같이 Spring Security Context가 초기화 된다
주제 1. 참고 문헌
https://mangkyu.tistory.com/210
https://devloper-dreaming.tistory.com/148
https://velog.io/@ch0jm/Spring-Context
https://velog.io/@choidongkuen/Spring-Application-Context-%EB%9E%80
https://beststar-1.tistory.com/39
https://mangkyu.tistory.com/18
주제 2. 참고
https://jstobigdata.com/spring/spring-bean-lifecycle-callbacks/
인프런 토비의 스프링
댓글