원래는 토비스프링 3.1에서도 말하지만 bean factory보다는 좀더 확장된 개념이 ApplicationContext이다라고 합니다
아무튼 어떤 기능에 대한 확장이니까 bean 객체들을 관리하는 IOC엔진이라고 생각하면 편합니다.
여기서 초보자 분들은
IOC는 역전 제어가 뭐지?라고 할수있습니다. 간단히 설명하면 IOC는 spring framework에 의존하는 방식이라 생각하면 좀 편합니다. 뭐 간단히 객체 생성같은거를 개발자가 아니라 framework가 대신해주는거죠! (말그대로 자동화!, 사람의 실수를 줄이는 거죠! 항상 개발자는 사람은 실수한다는 마음으로 개발해야 자동화를 하려고 노력하는것 같아요!)
.
이번엔 서블릿 컨테이너는 이전링크에서말했던 서블릿을 관리하는 컨테이너 겠죠
정의는 서블릿 컨테이너(Servlet Container)는 자바 웹 애플리케이션에서 중요한 역할을 하는 구성 요소입니다. 자바 서블릿을 실행하는 환경을 제공하며, 웹 서버와 함께 동작하여 HTTP 요청과 응답을 처리하는 역할입니다.
아래는 filter chain과 filter 인스턴스안에 DelegatingFilterProxy의 모습입니다.
DelegatingFilterProxy는 Bean Filter0 가 호출될때 ApplicationContext의 Bean Filter0에서 나타납니다. 아래 간단히 코드를 확인해보죠
여기서 스피링 빈에 등록된 필터는 lazily 하게 가져옵니다.(spring에서 lazy는 직접적 호출하기전까지는 생성및 초기화를 하지 않는다! 라고는걸로 있습니다. 즉 lazy 에 대한 개념을 알고가면 좋습니다.)
예를들어 DelegatingFilterProxy에서의 delegate 는 bean filter0의 instacne입니다.
여기서 delegate란?
일반적으로 객체가 특정 작업을 다른 객체에 위임하는 개념입니다. 즉 여기서 말하고자 하는것은 bean filter0가 DelegatingFilterProxy다 라고 생각하면 좋을듯합니다 ( 제가 틀렷다면 지적부탁드리겠습니다 제가 이해한건 이거입니다 )
여기서 2번 코드를 보면요
delegate.doFilter(request, response); //2
Spring bean에서 delgate 작업을 한다라고 합니다. 즉 DelegatingFilterProxy가 작동합니다
원문을 해석하면
마지막으로 DelegatingFilterProxy의 또 다른 장점은 Filter bean 인스턴스를 찾는 것을 지연시킬 수 있다는 것입니다. 이는 컨테이너가 시작되기 전에 Filter 인스턴스를 등록해야 하기 때문에 중요합니다. 그러나 Spring에서는 일반적으로 ContextLoaderListener를 사용하여 Spring Beans를 로드하는데, 이는 Filter 인스턴스가 등록되어야 할 시점 이후에야 완료됩니다.
말이 참 어렵죠.
먼저 ContextLoaderListener란?
주로 웹 기반의 Spring 애플리케이션에서 중요한 역할을 하며, 애플리케이션의 시작과 종료 시점에 각각 컨텍스트를 초기화하고 정리하는 역할을 합니다.( 즉 ApllicaitonContext를 초기화 및 종료 하는 역할 이라고 생각하면 편합니다. 일단 이것도 제가 생각한거라 틀릴수 잇습니다. 틀리면 지적부탁드립니다)
그렇다면
쉽게 설명하자면 spring에서 spring filter 인스턴스가 등록되어야 할 시점 이후에 ApplicationContext에서 spring beans을 불러오는겁니다. 근데 어째서 DelegatingFilterProxy는 필터 인스턴스를 늦게 로드 시킬까요?
(이유는 성능 최적화에 있다고하는데 . 당연한 얘기겟지만 모든 컴포너트를 즉시 로딩하면 상당한 양의 메모리를 차지하기 때문에 이런방식을 택한것같습니다. 이건 제추측입니다. 이것도 틀리면 지적부탁드립니다 보통 lazy한 경우가 다 성능 최적화여서 ㅠㅠ )
사실상 기존에 사용만 해봤지 실제 구조가 어떻게 굴러가는지에 대해서는 정확하게 공부하지 않았습니다.(반성중..사실 좀 바빳다는게 핑계... ㅎㅎ)
좋은 기회여서 일단 원서를 보면서 구조를 파악 해보려 합니다 ㅎㅎ
최대한 자세히 설명하거여서 쉬운 용어들 조차 설명을 할거라 내용이 조금 길어질수도 있습니다. 고수님들께서는 다른거 참조하셔도 됩니다. (저같은 초보를 위한 초보자들을 위해서... ㅎㅎ)
필터(filter)에 대해서
스프링 시큐리티의 서블릿 제공은 서블릿 필터에서 합니다!
여기서 서블릿이란? (모르는 분들을 위해서)
서블릿(Servlet)이란 동적 웹 페이지를 만들 때 사용되는 자바 기반의 웹 애플리케이션 프로그래밍 기술이다. 서블릿은 웹 요청과 응답의 흐름을 간단한 메서드 호출만으로 체계적으로 다룰 수 있게 해준다.(일단 spring mvc servlet에서는 DispatcherServlet 이어서 그건 아래에 설명하겠습니다.)
스프링 컨테이너는 스프링 프레임워크의 핵심 컴포넌트이다.
스프링 컨테이너는 자바 객체의 생명 주기를 관리하며, 생성된 자바 객체들에게 추가적인 기능을 제공한다.
스프링에서는 자바 객체를 빈(Bean)이라 한다.
즉, 스프링 컨테이너는 내부에 존재하는 빈의 생명주기를 관리(빈의 생성, 관리, 제거 등)하며, 생성된 빈에게 추가적인 기능을 제공하는 것이다.
스프링 컨테이너는 XML, 어노테이션 기반의 자바 설정 클래스로 만들 수 있다.
스프링 부트(Spring Boot)를 사용하기 이전에는 xml을 통해 직접적으로 설정해 주어야 했지만, 스프링 부트가 등장하면서 대부분 사용하지 않게 되었다.
출처: https://ittrue.tistory.com/220 [IT is True:티스토리]
블로그 글을 빌리자면 스프링 자바 객체를 자동적으로 생명주기를 관리해주는곳이 컨테이너입니다.
디스패처 서블릿의 dispatch는 "보내다"라는 뜻을 가지고 있습니다. 그리고 이러한 단어를 포함하는 디스패처 서블릿은 HTTP 프로토콜로 들어오는 모든 요청을 가장 먼저 받아 적합한 컨트롤러에 위임해주는 프론트 컨트롤러(Front Controller)라고 정의할 수 있습니다.
이것을 보다 자세히 설명하자면, 클라이언트로부터 어떠한 요청이 오면 Tomcat(톰캣)과 같은 서블릿 컨테이너가 요청을 받게 됩니다. 그리고 이 모든 요청을 프론트 컨트롤러인 디스패처 서블릿이 가장 먼저 받게 됩니다. 그러면 디스패처 서블릿은 공통적인 작업을 먼저 처리한 후에 해당 요청을 처리해야 하는 컨트롤러를 찾아서 작업을 위임합니다.
여기서 Front Controller(프론트 컨트롤러)라는 용어가 사용되는데, Front Controller는 주로 서블릿 컨테이너의 제일 앞에서 서버로 들어오는 클라이언트의 모든 요청을 받아서 처리해주는 컨트롤러로써, MVC 구조에서 함께 사용되는 디자인 패턴입니다.
출처: https://mangkyu.tistory.com/18 [MangKyu's Diary:티스토리]
말그대로 http 요청이 오면 가장 먼저 받는 위치에 존재하는 컨트롤러라고 생각하시면 편합니다.
당연히 아시겟지만 하나의 서블릿은 HttpServletRequest 및 HttpServletResponse를 처리할 수 있습니다.
하지만!! 하나 이상의 filter는 아래 다음과 같은 목적으로 이용할수 있습니다.
DownStream Filter 인스턴스 또는 서블릿이 호출되는 것을 방지합니다. 이 경우 필터는 일반적으로 HttpServletResponse를 작성합니다.
DownStream Filter 와 서블릿이 사용하는 HttpServletRequest나 HttpServletResponse를 수정합니다
DownStream Filter란?(저도 몰랐네요 ..)
말그대로 특정 필터 이후에 위치하는 필터들을DownStream Filter라고 합니다.
결국 여기서 말하자고 하는것은요.
원문을보면
The power of the Filter comes from the FilterChain that is passed into it.
저도 이해한느낌이 filter의 강력한 힘은 filterchain을 통함으로라는건데 filter의 강력한점이 filterchain덕분이다 라는뜻 같네요. (혹시나 저도 이부분좀 이해가 안가서 이런느낌인가 합니다.)
간단히 filter chain의 코드를 보겟습니다.
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
// do something before the rest of the application
chain.doFilter(request, response); // invoke the rest of the application
// do something after the rest of the application
}
오늘은 여기까지하고 내일은 DelegatingFilterProxy에 대해서 알아보겠습니다.
일단 이건 작성하려고 했는데 어쩌다보니 계속 뒤로 밀리게되어 이제 작성하게 되었습니다. 제가 초창기 신입일때 회사 홈페이지를 프론트쪽을 수정 후 재시작할일 있어서 재시작하였는데 사수도 없고 인수인계도 잘 되어 있지 않는 상태에서 자신감 넘치게재시작을 눌렀습니다. ㅎㅎ ㅠ
그때 당시에 문제가 발생한게 갑작스레 메일들이 나갔는데... ㅠ 당시 엄청 호되게 혼났엇습니다. 잘모르면 일단 확인을 철저히 하고 했어야했는데 뭐 핑계라면 인수인계 부족.... ㅎ 아무튼 확인 안한 제잘못이 큽니다.. 사실 post -fix 메일에 대한 존재 조차 몰랐기 때문에 무지로 인한 문제라고 생각했습니다. 만약에 제가 전체적으로 웹서비스에 대한 이해도가 높고 서버에 대한 이해도가 높았다면 다양한 시각으로 체크 후 재시작을 했을거라고 생각합니다.
링크의 말을 빌리면 sendmail 같은 SMTP(Simple Mail Transfer Protocl) 를 구현한 소프트웨어를 MTA(Mail Transfer Agent) 라고 부르며 MS의 아웃룩이나 모질라의 썬더버드, 콘솔에서 구동되는 mutt 등의 사용자 프로그램은 MUA(Mail User Agent) 라고 분류한다. sendmail 은 전통적으로 많이 사용되던 MTA 였고 RHEL 5 까지는 기본 메일 서버 데몬이었으나 RHEL 6 부터는 postfix 로 교체되었다. 물론 원하는 사용자는 sendmail 을 MTA 로 사용하는 것도 가능하다.
간이 전자 우편 전송 프로토콜(Simple Mail Transfer Protocol, SMTP)은 인터넷에서 이메일을 보내기 위해 이용되는 프로토콜이다. 사용하는 TCP 포트번호는 25번이다. 상대 서버를 지시하기 위해서 DNS의 MX레코드가 사용된다. RFC2821에 따라 규정되어 있다. 메일 서버간의 송수신뿐만 아니라, 메일 클라이언트에서 메일 서버로 메일을 보낼 때에도 사용되는 경우가 많다.
말그대로 메일끼리 서로 주고 받는거라고 생각하면 편합니다. smtp 사용법은 인터넷에 많으니 참고하시면 되고요. 사용할때 사전지식을 일단 잘 알고넘어가는게 더 중요해서
SMTP는 Simple Mail Transfer Protocol의 약자입니다. 인터넷을 통해 이메일 메시지를 보내고 받는 데 사용되는 통신 프로토콜입니다. 메일 서버 및 기타 메시지 전송 에이전트(MTA)는 SMTP를 사용하여 메일 메시지를 보내고, 받고, 중계합니다.
연관된 엔터티가 항상 함께 로딩되므로, 엔터티 사용 시 추가적인 쿼리 없이 바로 사용 가능.
단점:
항상 연관된 엔터티를 함께 불러오므로, 필요하지 않은 데이터까지 로드될 수 있다.
결과적으로 성능 문제가 발생할 수 있으며, 불필요한 네트워크 및 메모리 리소스가 사용될 수 있다.
2. FetchType.LAZY (지연 로딩)
장점:
실제로 연관된 엔터티에 접근할 때만 데이터베이스로부터 로딩한다. 따라서 필요한 경우에만 쿼리가 발생.
성능 최적화에 도움을 줄 수 있다. 불필요한 데이터를 로딩하지 않으므로 자원을 효율적으로 사용할 수 있다.
단점:
첫 접근 시 추가적인 쿼리가 실행됨. 즉, 처음 연관된 엔터티에 접근할 때마다 쿼리가 실행될 수 있다.
트랜잭션 밖에서 지연 로딩을 시도하면 LazyInitializationException이 발생한다.
대부분의 상황에서 모든 연관된 엔터티를 즉시 로딩하는 것은 비효율적입니다. 특히, 관계가 복잡한 큰 애플리케이션에서는 많은 데이터가 불필요하게 로딩될 수 있습니다. 그러나 상황에 따라 연관된 엔터티를 항상 함께 로드해야 하는 경우도 있습니다. 이런 경우에는 EAGER 전략을 사용하여 즉시 로딩을 할 수 있습니다.
Lazy Loading은 연관된 엔터티(Entity)를 즉시 불러오지 않고, 해당 엔터티에 실제로 접근될 때까지 로딩을 지연시키는 방법입니다. 예를 들어, 게시글(Notice)과 댓글(Comment)이 있고, 게시글에서 댓글을 Lazy Loading으로 설정했다고 가정해봅시다. 이 경우, 게시글을 불러올 때 연관된 댓글들은 즉시 로딩되지 않습니다. 댓글에 실제로 접근(예: notice.getComments())할 때 데이터베이스에서 댓글 정보를 불러오게 됩니다.