<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>ringDing.log</title>
        <link>https://velog.io/</link>
        <description>초짜 백엔드 개린이</description>
        <lastBuildDate>Mon, 28 Apr 2025 06:03:04 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>ringDing.log</title>
            <url>https://images.velog.io/images/dabeen-jung/profile/8fdd01c4-e571-4e7c-bb1f-7069966c6e88/KakaoTalk_20210531_004840169.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. ringDing.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/dabeen-jung" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[기획자 초보를 위한 목업]]></title>
            <link>https://velog.io/@dabeen-jung/%EA%B8%B0%ED%9A%8D%EC%9E%90-%EC%B4%88%EB%B3%B4%EB%A5%BC-%EC%9C%84%ED%95%9C-%EB%AA%A9%EC%97%85</link>
            <guid>https://velog.io/@dabeen-jung/%EA%B8%B0%ED%9A%8D%EC%9E%90-%EC%B4%88%EB%B3%B4%EB%A5%BC-%EC%9C%84%ED%95%9C-%EB%AA%A9%EC%97%85</guid>
            <pubDate>Mon, 28 Apr 2025 06:03:04 GMT</pubDate>
            <description><![CDATA[<p>매번 figma를 통해서만 와이어프레임을 그리던 나에게
이번 교육 수강을 들으며 아주 좋은 와이어프레임 &#39;목업 도구&#39;를 발견했다.</p>
<hr>
<br>


<h3 id="이곳에서-다운로드-받아야-합니다">이곳에서 다운로드 받아야 합니다!</h3>
<p><a href="https://www.powermockup.com/">PowerMockUp</a></p>
<hr>
<br/>



<h3 id="목업-다운-및-실행">목업 다운 및 실행</h3>
<ol>
<li>파워목업(PowerMockup) 설치파일을 더블 클릭해서 실행한다</li>
<li>Next(다음) 버튼을 선택한다.</li>
<li>이용약관을 확인하고, 동의하면 인스톨(Install)버튼을 누른다.</li>
<li>프로그램을 설치한 뒤 Rin PowerMockup 버튼을 선택해서 파워목업(PowerMockup)을 실행한다.
출처: <a href="https://miroiter.tistory.com/49">https://miroiter.tistory.com/49</a> [코딩하는 기획자 Daniel:티스토리]</li>
</ol>
<p><br><br></p>
<h3 id="다운로드-후-화면">다운로드 후 화면</h3>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/6e732a9e-6fd7-49d2-8807-e947059c187a/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/9e3c52ca-0e97-4254-9ec0-48f938a5116f/image.png" alt=""></p>
<p>라이센스가 없게 되면 이렇게 <strong>일부 기능만이 활성화</strong> 됩니다😂
라이센스를 원하신다면 ....</p>
<p><br><br></p>
<p><a href="https://miroiter.tistory.com/49">코딩하는 기획자 Daniel:티스토리</a>님의 블로그를 참고하여 &#39;파워목업&#39;의 사용 후기를 담은 블로그 글을 작성 및 업로드 후 , 이메일을 보내봅시다 😍</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SQL IFNULL]]></title>
            <link>https://velog.io/@dabeen-jung/SQL-IFNULL</link>
            <guid>https://velog.io/@dabeen-jung/SQL-IFNULL</guid>
            <pubDate>Sun, 16 Jun 2024 05:59:31 GMT</pubDate>
            <description><![CDATA[<h3 id="1-컬럼이-null인-경우-치환하여-반환하고-싶다--ifnull컬럼명--치환값">1. 컬럼이 Null인 경우 치환하여 반환하고 싶다? =&gt; IFNULL(컬럼명 , 치환값)</h3>
<p>ex) </p>
<pre><code>SELECT IFNULL(컬럼명, 0) FROM USER ;</code></pre><blockquote>
<p>컬럼이 NULL일 경우 0으로 치환하여 반환하겠다.</p>
</blockquote>
<p><br><br></p>
<h4 id="오늘-풀었던-문제에서도-이름이-null인-경우-치환을-하라고-했다">오늘 풀었던 문제에서도 이름이 Null인 경우 치환을 하라고 했다.</h4>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/59410">프로그래머스 - NULL처리하기</a></p>
<pre><code>SELECT ANIMAL_TYPE,
        IFNULL(NAME,&#39;No name&#39;) ,
        SEX_UPON_INTAKE
FROM ANIMAL_INS
ORDER BY ANIMAL_ID;</code></pre><p><br><br></p>
<h3 id="2-if">2. IF()</h3>
<h4 id="컬럼이-null일-경우-1을-null이-아닐때는-2를-return">컬럼이 NULL일 경우 1을, NULL이 아닐때는 2를 return</h4>
<pre><code>SELECT IF(컬럼명 IS NULL, &#39;1&#39;, &#39;2&#39;) FROM 테이블명</code></pre><br>
<br>

<h3 id="3-nullif--">3. NULLIF(?,  ?)</h3>
<h4 id="전자--후자-의-결과가-false면-전자의-값을-return-하고--true이면-null을-return-한다">(전자 == 후자) 의 결과가 false면 전자의 값을 return 하고,  true이면 NULL을 return 한다.</h4>
<pre><code>SELECT NULLIF(1, 1) ; 
--&gt; null 을 리턴한다
</code></pre><pre><code>SELECT NULLIF(1, 2) ;
--&gt; 1을 리턴한다.</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[백준-15486(DP)] 퇴사2]]></title>
            <link>https://velog.io/@dabeen-jung/%EB%B0%B1%EC%A4%80-15486DP-%ED%87%B4%EC%82%AC2</link>
            <guid>https://velog.io/@dabeen-jung/%EB%B0%B1%EC%A4%80-15486DP-%ED%87%B4%EC%82%AC2</guid>
            <pubDate>Sun, 24 Mar 2024 11:55:06 GMT</pubDate>
            <description><![CDATA[<p>이 글은 어떤 과정을 통해 해당 문제를 풀고 이해할 수 있었는지를 정리하기 위해 작성하였습니다!</p>
<h2 id="문제-링크">문제 링크</h2>
<p><a href="https://www.acmicpc.net/problem/15486">https://www.acmicpc.net/problem/15486</a></p>
<h3 id="문제">문제</h3>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/5595fae4-5b89-4d23-ab05-a2321a8ce73d/image.png" alt=""></p>
<ul>
<li>해당 문제는 dp를 통해서 풀어야 한다.
  =&gt; 완전 탐색으로 풀 경우 (1 ≤ N ≤ 1,500,000) 시간초과가 날 것임</li>
<li>N+1날 퇴사를 하기 때문에, <strong>N일까지 최대한의 금액을 벌어</strong> 일을 끝내야만 한다.<blockquote>
<p>🚨 단, N+1일 전에 일을 시작했어도 *<em>마무리가 N+1이후까지 진행되는 것이면, 수익으로 인정하지 X *</em></p>
</blockquote>
</li>
</ul>
<h4 id="💬-출력값--퇴사-일-전까지-최대한-수익을-벌었을-경우의-최댓값">💬 출력값 : 퇴사 일 전까지 최대한 수익을 벌었을 경우의 최댓값</h4>
<p><br><br></p>
<h2 id="2-접근-방식">2. 접근 방식</h2>
<p>N+1일에 퇴사를 함 -&gt; N일까지 일을 마무리 지어야 함</p>
<p>예시가 이렇게 된다고 했을 때, 7일에 끝을 내야 한단 것이다.
7
3 10
5 20
1 10
1 20
2 15
4 40
2 200</p>
<p>7일차의 상담은 7+2 = 9로 7을 초과 (x)
6일차의 상담은 6+4 = 10으로 초과 (x)
5일차의 상담은 5+2 = 7로 초과하지 않음 (⭕)
그렇게 되면 dp[5]에는 우리는 최댓값을 구해야 되기 때문에, 가장 큰 최댓값이 들어가야 한다.</p>
<p>p[5] + 5일까지 벌어들인 dp값, 혹은 지금까지의 값 중 최댓값 이들 중 더 큰 값이 기록되게 된다.</p>
<blockquote>
<p><code>dp[i] = max(p[i] + dp[t[i] + i], max값)</code></p>
</blockquote>
<p>5일차에 dp[5] = p[5] + dp[7]이 되는데, <strong>dp[7]은 아직 갱신된 적이 없어 값이 0이</strong> 된다.
=&gt; <strong>dp[5] = 15</strong>
다음으로 최댓값을 갱신하여 max_value = dp[5] = 15가 된다.
<br></p>
<p>4일차도 1일이 걸리므로 진행가능하다.
dp[4] = p[4] + dp[t[4] + 4] = p[4] + dp[5] = 20 + 15=35이다.</p>
<ul>
<li>max_value는 15에서 -&gt; 35으로 갱신</li>
</ul>
<br>

<p>3일차도 1일이 걸리므로 진행됨.
dp[3] = p[3] + dp[t[3] + 3] = p[3] + dp[4] = 10 + 35 = 45</p>
<ul>
<li>** max_value는 갱신 45**</li>
</ul>
<br>

<p>2일차는 5일이 진행된다. 가능하다. 2+5 = 7일차니까!
dp[2] = p[2] + dp[t[2] + 2] = p[2] + dp[7] = 20 + 0 = 20</p>
<ul>
<li>max_value = 45 이다. <strong>20은 45보다 작기 때문에 갱신될 수 없고,</strong>
이로인해 dp[2] = 45로, 최댓값으로 유지한다.</li>
</ul>
<br>

<p>1일차는 4일이 진행된다. 가능하다 -&gt; 1+4 = 5일차니까
dp[1] = p[1] + dp[t[1] + 1] = p[1] + dp[4] = 10 + 35 = 45</p>
<ul>
<li>max_value = 45 로 유지되며 이 값을 출력해내면 된다.</li>
</ul>
<br>


<h3 id="여기서-잠깐">여기서 잠깐</h3>
<h4 id="pi--dpti--i-에서-dpti--i는-뒤의-자리를-가리키는게-아닌가-🤔🤔">p[i] + dp[t[i] + i] 에서 dp[t[i] + i]는 뒤의 자리를 가리키는게 아닌가? 🤔🤔</h4>
<p>라고 생각할 수 있는 이들에게</p>
<p>우리는 역순으로 계산을 하고 있기 때문에 *<em>여기서의 기준으로 이전 값이란 우리의 뒤에 값들이란 것을 잊지말자!
*</em></p>
<br>

<p><a href="https://katfun.tistory.com/76">이 분의 설명으로 이해했습니다.</a></p>
<p><br><br></p>
<h3 id="2-1-시간초과가-난-코드-_해결함">2-1. 시간초과가 난 코드 (_해결함)</h3>
<p>제출했을 때는 <strong>N의 값</strong>을 신경쓰지 않아서 <del>&#39;퇴사&#39;와 같이 풀었더니 시간초과가 떴다</del>.😢</p>
<pre><code>&#39;&#39;&#39;
[DP] 퇴사2 (골 5)
조건 : n일까지만 근무
goal: 백준이가 얻을 수 있는 최대 수익을 구하라
&#39;&#39;&#39;
import sys
input = sys.stdin.readline

n = int(input())
t = []
p = []
dp = [0] * (n + 1)

for _ in range(n):
    ti, pi = map(int, input().rstrip().split())
    t.append(ti)
    p.append(pi)

#idx + t = 가능한 날의 idx
#idx 날 근무를 할지, pass 할지
&#39;&#39;&#39;
최대이익
t가 지나가
&#39;&#39;&#39;
for idx in range(n-1,-1,-1):
    #퇴사날을 넘긴다(진행할 수 x)
    if idx + t[idx] &gt; n:
        dp[idx] = dp[idx + 1] #(최댓값,0)을 그대로 저장

    else:
        #다른경우를 방문한 dp vs 그 직전 방문한 dp를 비교 후 -&gt; 최댓값을 삽입
        # 목표는 최댓값을 가지도록 해야함
        dp[idx] = max(p[idx] + dp[t[idx]+idx], dp[idx+1])

#최종적으로 최댓값을 출력할 수 밖에 없음
print(dp[0])</code></pre><br>

<h4 id="내-코드에서의-문제점은-이런게-있었다">내 코드에서의 문제점은 이런게 있었다.</h4>
<ol>
<li>N의 조건을 생각하지 않음</li>
<li>역순으로 풀다보니 불필요한 반복이 있을 수 있다.</li>
</ol>
<p>-&gt; 특정 조건에서 종료를 해도 좋을 것임.</p>
<blockquote>
<p>결과적으로 대량의 데이터를 최적화하기 위해 <strong>&#39;입력시간을 줄였다&#39;</strong>
<code>sys.stdin.readline</code> 을 이용하여 <strong>해결했다.</strong></p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/7a1d4094-4df0-47ca-8b73-48adabab78a8/image.png" alt=""></p>
<p>그러나 시간이 꽤나 걸린 것을 알 수 있었다..
좀 더 시간이 덜 걸리고 다른 방식으로 푸신 분들이 궁금했다.</p>
<p><br><br><br></p>
<h3 id="✨2-1-다른-코드">✨2-1. 다른 코드</h3>
<p>그래도 다른 방법을 더 확인하고 싶어 다른 분들의 코드를 참고했다.</p>
<p><a href="https://velog.io/@sunkyuj/python-%EB%B0%B1%EC%A4%80-15486-%ED%87%B4%EC%82%AC-2">장선규 님의 블로그</a></p>
<pre><code>import sys

input = sys.stdin.readline

n = int(input())
t, p = [0 for _ in range(n + 1)], [0 for _ in range(n + 1)]
for i in range(1, n + 1):
    t[i], p[i] = map(int, input().split())

dp = [0 for _ in range(n + 1)]

for i in range(1, n + 1):
    dp[i] = max(dp[i], dp[i - 1])  # 이전까지의 최댓값

    fin_date = i + t[i] - 1  # 당일 포함
     print(&quot;i값&quot;, i, &quot;findate = &quot;, fin_date)

    if fin_date &lt;= n:  # 최종일 안에 일이 끝나는 경우
        # i일부터는 일을 해야하므로 i일에 얻을 수 있는 최댓값이 아닌 i-1일까지 얻을 수 있는 최댓값을 구한다
        dp[fin_date] = max(dp[fin_date], dp[i - 1] + p[i])
print(max(dp))</code></pre><p>시간 복잡도가 비슷하단 것을 알 수 있었다. 이를 줄이기 위해서는 계산 부분에서 불필요한 계산을 줄일 수 있도록 수정하는 것이 가장 best인 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[백준 - 1629 곱셈 (feat. Python)]]></title>
            <link>https://velog.io/@dabeen-jung/%EB%B0%B1%EC%A4%80-1629-%EA%B3%B1%EC%85%88-feat.-Python</link>
            <guid>https://velog.io/@dabeen-jung/%EB%B0%B1%EC%A4%80-1629-%EA%B3%B1%EC%85%88-feat.-Python</guid>
            <pubDate>Sat, 03 Feb 2024 11:36:44 GMT</pubDate>
            <description><![CDATA[<h3 id="문제-출처">문제 출처</h3>
<p><a href="https://www.acmicpc.net/problem/1629">https://www.acmicpc.net/problem/1629</a></p>
<blockquote>
<p>우선 문제를 푸는데 시간초과가 나올 것 이라 생각했지만 도무지 수학적머리가 안 돌아가보니 이해에 꽤 많은 시간을 들였던 문제였다.(Feat 수능 수학 나형)</p>
</blockquote>
<p><br><br></p>
<p>문제를 푸는데 참고에 도움을 주신</p>
<h3 id="풀이-이해-및-참고">풀이 이해 및 참고</h3>
<p><a href="https://developer-next-to-you.tistory.com/35">여기서 코드를 전체적으로 참고</a></p>
<p><a href="https://nerogarret.tistory.com/55">거듭제곱에 대한 문제 이해를 여기서 했습니다</a></p>
<p><br><br></p>
<hr>
<h3 id="♻-이해한-문제-풀이-방식">♻ 이해한 문제 풀이 방식</h3>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/db2c21b6-accb-4812-a214-203792367773/image.png" alt=""></p>
<p>여기서 경우는 두가지가 나온다 2로 나누어 떨어질 때까지 우리는 계속 나눌 것인데
¹ 2로 끝까지 <strong>나누어 떨어지는 수</strong>가 있는 반면 위의 사진처럼 <strong>²거듭제곱으로 묶이지 않고 한 개가 남게 되는 경우</strong>이다.</p>
<br>
<br>


<h4 id="🚀코드를-참고하여-이해했다">🚀코드를 참고하여 이해했다.</h4>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/85470876-9642-4f2d-b578-73824d653af6/image.png" alt=""></p>
<p>참고한 풀이방식처럼 우리는 <strong>저 &#39;?&#39;를 재귀함수를 통해 계속 구해나간다.</strong>
=&gt; 2로 계속 나누며 거듭제곱으로 구할 것이다.</p>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/5810bf08-5c9e-4737-9359-b3e3f2be5b4e/image.png" alt=""></p>
<ul>
<li>그렇기 때문에** 홀수가 나오면 &#39;a&#39;를 따로 빼서 곱해줘**야 한다.<ul>
<li>저 형식으로 계속 구해나간다고 생각해주면 된다</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[백준 - 2468  | [dfs/bfs] | 안전영역 (feat. Python) ]]></title>
            <link>https://velog.io/@dabeen-jung/%EB%B0%B1%EC%A4%80-2468-dfsbfs-%EC%95%88%EC%A0%84%EC%98%81%EC%97%AD-feat.-Python</link>
            <guid>https://velog.io/@dabeen-jung/%EB%B0%B1%EC%A4%80-2468-dfsbfs-%EC%95%88%EC%A0%84%EC%98%81%EC%97%AD-feat.-Python</guid>
            <pubDate>Mon, 15 Jan 2024 07:39:54 GMT</pubDate>
            <description><![CDATA[<h2 id="출처">출처</h2>
<p><a href="https://www.acmicpc.net/problem/2468">2468 안전영역 문제</a></p>
<br>
<br>



<h3 id="목표-출력">목표 (출력)</h3>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/1e334859-58a2-49ee-a39b-cd70214ea6c3/image.png" alt=""></p>
<p>여기서 말하는 안전영역은 상하좌우 물에 잠기지 않은 인접영역 하나씩을 말한다.
비가 얼마나 올지 모르지만 아래의 그래프의 예시에서 비가 높이 별로 다양하게 왔을 경우를 상상해, <strong>안전영역의 갯수가 최대인 상황일 때 해당 갯수를 출력</strong>해라</p>
<br>






<h3 id="🛑예시-n-5인-지역-높이-정보">🛑예시) n= 5인 지역 높이 정보</h3>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/22009ad4-ee9a-4f12-affd-8e669c80d96e/image.png" alt=""></p>
<p>이 그래프를 <strong>높이가 4이하의</strong> 모든 지점들이 물에 잠겼다고 가정했을 경우 그래프는 이렇다.</p>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/34aa3e8d-a091-4426-b927-2739a58f08ac/image.png" alt=""></p>
<blockquote>
<p>가능한 안전영역(흰색)  = 5개</p>
</blockquote>
<p><br><br><br></p>
<hr>
<br>



<h3 id="⚡-문제에서-중요한-부분">⚡ 문제에서 중요한 부분</h3>
<ul>
<li>비가 얼마나 올지 모른다 -&gt; 비는 우선 현재 정해진 n의 높이까지가 최대 높이로 올 수 있는 것</li>
<li>비는 아무리 와도 최대 높이(n)까지 올 수 있다.
=&gt; 그렇다고 n만큼 오면 모두 잠기기 때문에 n-1까지만 계산</li>
<li>메모: &quot;<strong>아무 지역도 물에 잠기지 않을 수도 있다.&quot;</strong> 
=&gt; 우리는 <strong>비가 안 오는 0의 경우도 생각</strong>해야 한다.</li>
</ul>
<hr>
<br>


<h2 id="❌-어떻게-접근해야-풀렸을까">❌ 어떻게 접근해야 풀렸을까?</h2>
<h3 id="1-내가-접근한-방식과-실수">1. 내가 접근한 방식과 실수</h3>
<blockquote>
<p>bfs를 통해서 수중 높이가 t일 때마다 나올 수 있는 인접영역들의 갯수(안전영역)을 세서 일일히 MAX 값과 비교해주려고 함</p>
</blockquote>
<h4 id="이-때-발생한-문제">이 때 발생한 문제</h4>
<ol>
<li><strong><code>visited</code>로 방문리스트를 따로 생성하지 않았다.</strong><ul>
<li>그대신 graph에 일일히 0으로 방문처리를 하였다.</li>
<li><blockquote>
<p>이로써 t의 값이 올라갈 때마다 <strong>graph 리스트에  다시 처음 상태로 초기화 되어 있어야 했는데</strong> 그러지 못했다.</p>
</blockquote>
</li>
</ul>
</li>
</ol>
<p><br><br></p>
<h3 id="2-문제를-풀며-새로이-알게된-부분">2. 문제를 풀며 새로이 알게된 부분</h3>
<blockquote>
<p>하지만 이 부분은 visited 리스트를 생성 후 저 곳에서 초기화 하면 해결이 가능한 부분이였다.
<img src="https://velog.velcdn.com/images/dabeen-jung/post/b2e1f84f-1593-4ac3-aaec-4f3f881d17e7/image.png" alt=""></p>
</blockquote>
<ul>
<li>내 접근도 괜찮았지만 <strong>bfs 함수를 풀어왔던 방식을 좀 더 폯 넓게 생각</strong>하였다면 접근에 오래 걸리지 않았을 것 같다.</li>
</ul>
<p><br><br></p>
<hr>
<p><br><br></p>
<h2 id="🚩-접근해야-하는-방식">🚩 접근해야 하는 방식</h2>
<blockquote>
<p><strong>현재 물의 수심(t) 보다 높은</strong> 애들은 <strong>bfs()함수를 통해 안전 영역의 갯수를 counting</strong> 해줄 것</p>
</blockquote>
<ul>
<li>이제부터 우리는 현재 물의 수심보다 같거나 낮은 경우들은 </li>
<li><blockquote>
<p>방문할 필요가 없다</p>
</blockquote>
</li>
<li><blockquote>
<p>visited[] = 0으로 생각해준다</p>
</blockquote>
</li>
<li>현재 물의 수심보다 </li>
</ul>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/5466694b-c4a7-43d3-86ab-5d6a99261191/image.png" alt=""></p>
<p>이런 식으로 봐줘야 한다는 것이다.
(<del>검정은 따로 0으로 처리를 못해주었다.. 그림판으로 그리다보니</del>)</p>
<p><br><br></p>
<h3 id="🔋-해결한-코드">🔋 해결한 코드</h3>
<pre><code>#[dfs, bfs] 안전영역 (실1)
# 안전한 영역 구하기
# 안전영역: 지점들이 위, 아래, 오른쪽 혹은 왼쪽으로 인접한 영역

# BFS로 풀어야 함
# 가까운 영역을 전부 탐색해서 안전영역의 갯수를 세야함


from collections import deque
import sys
input = sys.stdin.readline


#3. bfs 함수 실행
def bfs(x,y, high):
    que = deque()
    que.append((x,y))
    visited[x][y] = 1 #방문

    while que:
        x,y = que.popleft()

        #상하좌우 방향으로 탐색
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]

            # 그래프를 영역 밖으로 벗어나지 않게
            if nx &lt;0 or ny &lt; 0 or ny&gt;=n or nx &gt;= n:
                continue

           # 현재 물의 수심과 비교, 방문 전적 x 면 =&gt; 동작
            if graph[nx][ny] &gt; high and visited[nx][ny] == 0:
                visited[nx][ny] = 1 #방문처리 함함
                que.append((nx,ny))



# 1. 입력값 받기
n = int(input())
graph = [list(map(int,input().split())) for _ in range(n)]
high = 0

for i in range(n):
    for j in range(n):
        if graph[i][j] &gt; high: #최대 높이값 저장
            high = graph[i][j]

dx = [-1, 1, 0, 0] #상하좌우
dy = [0, 0, -1, 1]


MAX = 0
# 2. 수심이 달라질 때마다 달라지는 안전영역 갯수 비교
for t in range(high):
    visited = [[0] * n  for _ in range(n)]
    cnt = 0 #안전 영역 갯수

    for i in range(n):
        for j in range(n):
            # 해당 칸을 방문한 전적 x, 해당 칸은 수심보다 높음 =&gt; bfs실행
            #bfs 실행으로 인접 영역들을 visited[] 체크해줌
            if graph[i][j] &gt; t and visited[i][j] == 0:
                bfs(i,j,t)
                cnt+=1
    # 4. 해당 수심의 안전영역과 &amp; 현재까지 가장 컸던 안전영역 갯수를 비교
    if MAX &lt; cnt:
        MAX = cnt

print(MAX)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[CS - OS] 메모리 관리 전략]]></title>
            <link>https://velog.io/@dabeen-jung/CS-OS-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B4%80%EB%A6%AC-%EC%A0%84%EB%9E%B5</link>
            <guid>https://velog.io/@dabeen-jung/CS-OS-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B4%80%EB%A6%AC-%EC%A0%84%EB%9E%B5</guid>
            <pubDate>Thu, 07 Dec 2023 17:23:13 GMT</pubDate>
            <description><![CDATA[<p><br><br></p>
<h1 id="1-메모리-관리-전략">1. 메모리 관리 전략</h1>
<h2 id="📕-메모리-관리-배경">📕 메모리 관리 배경</h2>
<blockquote>
<p><strong>각각의 프로세스는</strong>... <strong>독립된 메모리 공간을 갖고</strong>, 운영체제 혹은 <strong>다른</strong> 프로세스의 <strong>메모리 공간에 접근할 수 없는</strong> 제한이 걸려있다.**
*<em>단지, <span style='background-color:     #fff5b1'>운영체제만이 운영체제 메모리 영역과 사용자 메모리 영역의 접근에 제약이 ❌</span> *</em></p>
</blockquote>
<br>

<h4 id="◽-swapping">◽ Swapping</h4>
<p>다중 프로그래밍 환경에서 <strong>스케줄링 후</strong> <strong>CPU의 할당 시간이 끝난 &#39;프로세스&#39;의 메모리를 &#39;보조기억장치(ex 하드디스크)&#39;로 내보내고, &#39;다른 프로세스&#39;의 메모리를 불러</strong>들일 수 있다.</p>
<blockquote>
<ul>
<li>Swap - <strong>in</strong> : 주 기억장치(RAM)으로 <strong>불러들임</strong></li>
<li>Swap - <strong>out</strong> : 보조 기억장치(하드디스크)로 <strong>내보냄</strong>
=&gt; 디스크 전송시간이 많이 필요해서 <span style="color: red">현재는 <strong>메모리 공간 부족시 이용한다</strong></span></li>
</ul>
</blockquote>
<h4 id="◽-단편화">◽ 단편화</h4>
<p>프로세스들이 메모리에 적재되고 제거되는 일이 반복되다보면, <strong>프로세스들이 차지하는 메모리 틈 사이</strong>에 <strong>사용 하지 못할 만큼의 작은 자유공간들</strong>이 늘어나게 되는데, 이것이 단편화 이다.</p>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/143f2e89-158c-4df5-881f-966a7d12cc46/image.png" alt=""></p>
<blockquote>
<p>(단편화의 종류)</p>
</blockquote>
<ul>
<li><p><strong>외부 단편화</strong>: 메모리 공간 중 사용하지 못하게 되는 일부분.</p>
<ul>
<li><span style="color: red"><strong>다양한 크기의 메모리 블록들이 할당 및 해제</span>되며</strong> 그로 인해 <strong>메모리 공간 사이에 작은 조각들이 분산</strong></li>
<li>물리 메모리(RAM)에서 사이사이 남는 공간들을 <strong>모두 합치면 충분한 공간이 되는 부분들이 분산되어 있을때</strong> 발생한다고 볼 수 있다.</li>
</ul>
</li>
<li><p><strong>내부 단편화</strong>: 프로세스에 <span style="color: red">할당된 공간이  <strong>실제 필요한 공간보다 큰 경우</span> 발생</strong>.
-&gt; 이로 인해 <strong>메모리 공간에서 낭비되는 부분</strong>.
ex) 메모리 분할 자유 공간이 10,000B 있고 Process A 가 9,998B 사용하게되면 2B 라는 차이가 존재하고, 이 현상을 내부 단편화라 칭한다.</p>
</li>
</ul>
<br>
<br><br>


<h2 id="1-2-메모리-관리-기법">1-2. 메모리 관리 기법</h2>
<br>

<h3 id="1-연속-메모리-관리">1. 연속 메모리 관리</h3>
<ul>
<li><strong>고정 분할 기법</strong> : 주기억장치가 고정된 파티션으로 분할 (<strong>내부 단편화 발생</strong>)</li>
<li><strong>동적 분할 기법</strong> : 파티션들이 동적 생성되며 자신의 크기와 같은 파티션에 적재 (<strong>외부 단편화 발생</strong>)</li>
</ul>
<p><br><br></p>
<h3 id="2-불연속-메모리-관리">2. 불연속 메모리 관리</h3>
<p>프로세스가 &#39;연속 메모리 관리&#39; 때처럼 연속적인 블록으로 할당하지 않는다. 서로 다른 주소 공간에 할당되게하여 <strong>분산된 여러 작은 메모리 영역에 할당하는 메모리 관리 방법이다</strong></p>
<h4 id="1-페이징paging-방식">1. 페이징(Paging) 방식</h4>
<ul>
<li><p><span style='background-color:     #fff5b1'><strong>외부 단편화 &amp; 압축 작업을 해소</span></strong>하기 위해 만듦</p>
</li>
<li><blockquote>
<p>물리 메모리의 남는 &#39;프레임&#39;에 적절히 배치됨으로 &#39;외부 단편화&#39; 해결</p>
</blockquote>
</li>
<li><p>물리 메모리 : <strong>고정 크기(<code>Frame</code>)</strong>로 분리</p>
</li>
<li><p>논리 메모리[프로세스 점유] : <strong>고정크기 ( <code>Page</code>)</strong>로 분리</p>
<blockquote>
<p><strong>페이지들은</strong> <del>물리적인 메모리에 연속적</del>으로 할당되지 않고, <strong>여러 개의 <span style="color: red">물리적인 프레임(Frame)에 흩어져 저장</span></strong>됩니다. <strong>페이지 테이블을 통해</strong> 가상 주소와 물리 주소 간의 매핑을 관리합니다.</p>
</blockquote>
<ul>
<li><strong>(단점)</strong> : <strong>내부 단편화 문제</strong> 발생</li>
</ul>
</li>
</ul>
<p><br><br></p>
<h4 id="2-세그멘테이션segmentation-방식">2. 세그멘테이션(Segmentation) 방식</h4>
<ul>
<li><strong>논리∙물리 메모리</strong> : <span style="color: red">서로 다른 크기인 <strong>세그먼트(<code>Segment</code>)</strong> 단위</span>로 분리<ul>
<li><strong>세그먼트</strong>: 논리적인 단위</li>
</ul>
</li>
<li>세그먼트는 물리적인 메모리에 여러 개의 <strong>분산된 메모리 영역</strong>에 저장</li>
<li>페이징 방식처럼 세그멘테이션도 <strong>&#39;세그먼트 테이블&#39;을 통해</strong> 가상주소-물리주소 간의 매핑을 통해 관리한다. </li>
</ul>
<ul>
<li><strong>(단점)</strong> : <strong>외부 단편화 문제</strong> 발생<blockquote>
<p>이렇게 서로 다른 크기의 세그먼트들이 적재되고 제거되는 일이 반복되다 보면, 자유공간이 어쩔 수 없이 수많은 조각으로 나뉘어져 못 쓰게 될 수도 있다.</p>
</blockquote>
</li>
</ul>
<p><br><br></p>
<hr>
<p><br><br></p>
<blockquote>
<p>&#39;<strong>페이지의 부재 발생</strong>&#39; 이란 것은... </p>
</blockquote>
<ol>
<li>페이지 부재 발생 → 2. 새로운 페이지를 할당해야 함 → 3.현재 할당된 페이지 중 <strong>어떤 것 교체할 지</strong> 결정하는 방법
=&gt; 왜냐면 필요한 페이지를 적재해도 &#39;가상 메모리&#39;에 계속 쌓여있으니 안 쓰는 애들은 자리에서 제거를 해줘야 한다.<strong>(=&gt; 해당 공간을 현재 필요한 다른 페이지로 교체)</strong></li>
</ol>
<p><br><br><br><br><br></p>
<h1 id="가상-메모리-virtual-memory-system">가상 메모리 (Virtual Memory System)</h1>
<blockquote>
<p>다중 프로그래밍을 실현하기 위해서는 많은 프로세스들을 동시에 메모리에 올려두어야 한다. </p>
</blockquote>
<ul>
<li><strong>가상메모리</strong>는 <strong>프로세스 <span style="color: red">전체가 메모리 내에 올라오지 않더라도 실행이 가능</span>하도록 하는 기법</strong></li>
<li><strong>요구 페이징</strong>을 이용해 실행과정에서 필요할 때 페이지를 적재한다.</li>
<li><strong>프로그램이 물리 메모리보다 커도 된다는 주요 장점</strong>이 있다.<ul>
<li>프로세스를 실행할 때 <strong>필요한 일부만 메모리에 로드하고 나머지는 디스크에 두는 것</strong>
=&gt; 결과적으로 <strong>메모리에 작은 양의 주소 공간만 있으면</strong> 충분히 프로세스를 수행할 수 있고, 그에 따라 <span style="color: red"><strong>더 많은 프로그램을 동시에 실행</strong></span>할 수 있게 된다.
=&gt; <span style='background-color:     #fff5b1'><strong>응답시간은 유지되며 &#39;CPU 이용률&#39;/&#39;처리율&#39;은 상승</strong></span>한다
=&gt;** Swap에 필요한 입출력이 줄어든다**</li>
</ul>
</li>
</ul>
<br>

<h3 id="1-1-가상메모리의-단점">1-1. 가상메모리의 단점</h3>
<ul>
<li>&#39;요구 페이지 기법&#39;을 통해 필요한 페이지만 메모리에 적재하고 <strong>현재 사용하지 않더라도 정리를 안하고 그대로 둔다.</strong></li>
<li><blockquote>
<p>그래서 <span style="color: red"><strong>안쓰는 페이지(victim page)는 out</strong></span>, 현재 필요한 페이지는 in 시켜야 한다.</p>
</blockquote>
</li>
</ul>
<br>

<h4 id="구성">(구성)</h4>
<p>가상 메모리는 1. 실제 메모리(RAM)와 2. 보조 기억 장치의 Swap 영역으로 구성되며, <strong>OS는 메모리 관리자(MMU)를 통해 메모리 관리하며</strong> 프로세스는 사용하는 메모리가 실제 메모리인지 Swap의 영역인지는 알 수 없음.</p>
<p><br><br><br></p>
<h3 id="1-가상-메모리가-하는-일">1. 가상 메모리가 하는 일</h3>
<ul>
<li>실제의 <strong>물리 메모리 개념</strong>과 <strong>사용자의 논리 메모리 개념</strong>을 분리한 것으로 정리할 수 있다
  -&gt; 그래서 얼마든지 큰 &#39;가상 주소 공간&#39;을 (<del>작은 메모리를 가졌음에도 불구하고</del>) 제공이 가능했던 것이다.</li>
<li><span style='background-color:     #fff5b1'><strong>프로그램에 실제 메모리 주소가 아닌 가상 메모리 주소를 할당하는 방법</strong></span></li>
<li>물리 메모리에 의해 <strong>다른 프로세스들 간의 공유를 가능</strong>하게 한다.
  -&gt; 프로세스들이 메모리를 공유하게끔 해주며, 이 &#39;공유 메모리&#39;를 통해 프로세스들끼리 통신할 수 있다.(프로세스들은 인식하진 못하겠지만)<blockquote>
<p><strong>&lt;가상 주소 공간&gt;</strong></p>
</blockquote>
</li>
<li>현재 직접 필요치 않은 메모리 공간은 &#39;실제 물리 메모리&#39;에 올리지 않고, 프로세스가 요구하는 <strong>&#39;메모리 공간&#39;은 &#39;가상 메모리&#39;에 제공 **
=&gt; **물리 메모리 절약</strong></li>
</ul>
<br>






<p><br><br></p>
<hr>
<h2 id="2-페이징-교체-알고리즘">2. 페이징 교체 알고리즘</h2>
<h3 id="1-요구-페이징demand-paging">1. 요구 페이징(Demand Paging)</h3>
<p><strong>프로그램 실행 시작 시</strong>에 <strong>초기에 필요한 것들만 적재</strong>하는 전략을 요구 페이징이라고 한다.
=&gt; <strong>한 번도 접근하지 않은 페이지(가상 메모리 관리단위)는 물리 메모리에 적재될 일이 없다.</strong>
=&gt; 프로세스 동작에 필요한 페이지를 요청해야 하는데<span style="color: red"> <strong>&#39;페이지 부재(Page Fault)&#39;가 발생할 수 있다</span>.</strong></p>
<p><br><br></p>
<h3 id="2-페이지-교체">2. 페이지 교체</h3>
<p>요구 페이징 기법에서 초기 적재가 안된 페이징의 경우, 만일 프로세스 동작 중 물리 메모리에 해당 페이지가 안되서 &#39;페이지 부재&#39;가 발생할 수 있다.
이렇게 되면 원하는 페이지를 &#39;보조 저장장치&#39;에서 데려와야 하는데... 그렇다 해도 &#39;*<em>물리 메모리&#39;가 모두 사용 중이라면 &#39;페이지 교체&#39;를 *</em>시켜줘야 한다.</p>
<h4 id="페이지-교체의-기본흐름">&lt;페이지 교체의 기본흐름&gt;</h4>
<p>물리 메모리가 모두 사용중인 상황에서의 메모리 교체 흐름이다.</p>
<ol>
<li>디스크에서 필요한 페이지의 위치를 찾는다</li>
<li>빈 페이지 프레임을 찾는다.<ol>
<li>페이지 교체 알고리즘을 통해 <strong>희생될(victim) 페이지를 고른다.</strong></li>
<li><strong>희생될 페이지를 디스크에 기록</strong>하고, 관련 <strong>페이지 테이블을 수정</strong>한다.</li>
</ol>
</li>
<li>새롭게 비워진 페이지 테이블 내 프레임에 새 페이지를 읽어오고, 프레임 테이블을 수정한다.</li>
<li>사용자 프로세스 재시작</li>
</ol>
<p><br><br></p>
<h3 id="2-1-페이징-교체-알고리즘들">2-1. 페이징 교체 알고리즘들</h3>
<ul>
<li><p><strong>FIFO 페이지 교체</strong>
메모리가 할당된 순서대로 페이지를 교체</p>
<ul>
<li>장점 : 프로그램하기 쉽다.</li>
<li>단점<ul>
<li>처음부터 자주 사용되는 페이지를 교체하여 페이지 부재율을 높이는 부작용을 초래할 수 있다.</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>OPT 페이지 교체(최적 페이지 교체)</strong>
앞으로 <strong>가장 오랫동안 사용하지 않을 페이지 교체</strong> </p>
<ul>
<li>장점 : 알고리즘 중 가장 낮은 페이지 부재율을 보장</li>
<li>단점 : <strong>(실현 가능성 희박)</strong>-&gt; 어떻게 미래를 내다보겠는가</li>
</ul>
</li>
</ul>
<ul>
<li><strong>LRU 페이지 교체</strong>
가장 오랫동안 <del>사용하지 않은</del> 페이지를 교체<ul>
<li>FIFO 보단 우수, OPT 보단 아니다.
=&gt; 실제 사용할 수 있는 것들 중엔 best다</li>
</ul>
</li>
</ul>
<ul>
<li><strong>LFU 페이지 교체</strong>
<strong>사용 빈도가 가장 적은</strong> 페이지를 교체<ul>
<li>최적(OPT) 페이지 교체를 제대로 근사하지 못하기 때문에, 잘 쓰이지 않는다.</li>
</ul>
</li>
</ul>
<ul>
<li><strong>MFU 페이지 교체</strong>
<strong>참조 회수가 가장 작은 페이지</strong>를 교체<ul>
<li>최적(OPT) 페이지 교체를 제대로 근사하지 못하기 때문에, 잘 쓰이지 않는다.</li>
</ul>
</li>
</ul>
<br>


<h4 id="-페이지의-교체방식-2종류">+) 페이지의 교체방식 2종류</h4>
<ul>
<li>Global 교체
(메모리 상의 <strong>모든 프로세스 페이지에 대해</strong> 교체)</li>
<li>Local 교체
(메모리 상의 자기 프로세스 페이지에서만 교체)</li>
</ul>
<blockquote>
<p>실제 페이지를 교체할 때 알고리즘 선택 후 어떤 방식으로 할거냐 했을 때는 <strong>&#39;전체&#39;를 기준으로 교체하는게</strong> 더 좋다고 함.
-&gt; 각각 교체하면 다중 프로그래밍 시, 프로세스 별 각각 모두 교체를 해야하기에...</p>
</blockquote>
<h3 id="자바에서는">자바에서는...</h3>
<h4 id="swap-영역을-잡아주자-😮">Swap 영역을 잡아주자! 😮</h4>
<blockquote>
<p><strong>만약 Swap 영역을 잡아주지 않는다면 &#39;OOM&#39;이 발생할 수 있다.</strong>
-&gt; Swap은 실제 메모리가 아니다. 이 때문에 지연시간이 발생하여 <strong>가급적이면 Swap 메모리를 쓰지 않는게 좋으며 쓰더라도 양이 증가한다면 &#39;메모리 누수&#39;를 의심해볼만 하다.</strong></p>
</blockquote>
<br>

<hr>
<br>

<h2 id="3-캐시의-지역성">3. 캐시의 지역성</h2>
<h4 id="q-캐시는-무엇인가">Q. 캐시는 무엇인가?</h4>
<p><strong>자주</strong> 사용하는 데이터나 값을 <strong>미리 복사해 놓는 임시 장소</strong>를 가리킨다. 캐시는 저장 공간이 작고 비용이 비싼 대신 빠른 성능을 제공</p>
<h4 id="그러나">그러나...</h4>
<blockquote>
<p>원하는 데이터가 캐시에 존재하지 않을 경우 DBMS 또는 서버에 요청을 해야한다(Cache Miss).</p>
</blockquote>
<ul>
<li><strong>왜?</strong></li>
<li><em>캐시는 저장공간이 작기*</em> 때문에, 지속적으로 Cache Miss가 발생하는 데이터의 경우 캐시 전략에 따라서 저장중인 데이터를 변경해야 한다.</li>
</ul>
<p><br><br></p>
<h3 id="3-1-캐시-메모리">3-1. 캐시 메모리</h3>
<ul>
<li>주기억장치에 저장된 내용의 일부를 <strong>임시로 저장</strong>해두는 기억장치</li>
<li><span style='background-color: #fff5b1'><strong>CPU와 주기억장치의 속도 차이</strong>로 성능 저하를 방지하기 위한 범용 메모리이다.</span></li>
<li>CPU가 이미 본 것을 다시 재접근할 때, 메모리 참조나 인출과정에서 비용을 줄이기 위해 여기서 저장한 데이터를 활용한다.</li>
<li>DRAM보다 빠르다.</li>
</ul>
<br>




<h3 id="3-2-캐시의-지역성">3-2. 캐시의 지역성</h3>
<blockquote>
<p>이렇게 CPU의 데이터로 잘 활용되는데 더 잘 활용하려면 <strong>&#39;적중률(예측)&#39;을 높여야 한다.</strong>
-&gt; <strong>캐시에 많이 활용되는 쓸모 있는 정보가 들어 있을 수록</strong> 좋다.
=&gt; 데이터의 <strong>지역성의 원리를 잘 사용해야</strong> 한다.</p>
</blockquote>
<h4 id="📕-지역성">📕 지역성</h4>
<p>기억 장치 내의 정보를 균일하게 액세스 하는 것이 아니라 한 순간에 <strong>특정부분을 집중적으로 참조하는 특성</strong></p>
<br>

<h3 id="지역성의-종류">&lt;지역성의 종류&gt;</h3>
<p>¹시간 지역성과 ²공간 지역성으로 나뉜다</p>
<ul>
<li><strong>시간 지역성</strong>: 최근에 참조한 주소의 내용은 곧 다음에도 다시 참조하는 경향</li>
<li><strong>공간 지역성</strong>: 실제 프로그램이 참조된 주소와 인접한 주소의 내용을 다시 참조하는 경향</li>
</ul>
<p><br><br></p>
<h3 id="3-3-캐싱-라인caching-line">3-3. 캐싱 라인(Caching line)</h3>
<blockquote>
<p>캐시(cache)는 프로세서 가까이에 위치하면서 <strong>빈번하게 사용되는 데이터를 놔두는 장소</strong>이다. 빈번하게 사용되는 데이터들을 캐시에 저장했더라도, <strong>내가 필요한 데이터를 캐시에서 찾을 때 모든 데이터를 순회하는 것은 시간 낭비다.</strong>
=&gt; 즉, 캐시에 목적인 데이터가 저장되어 있다면, 바로 접근하여 출력할 수 있어야 캐시가 의미 있어진다는 것이다.</p>
</blockquote>
<ul>
<li>캐싱라인 : 이렇게 캐시에 데이터를 저장할 때부터, &#39;자료구조&#39;를 활용해 묶어서 저장하는 것을 뜻한다.</li>
</ul>
<p><br><br></p>
<h3 id="프로세스-관련-용어들-💬">프로세스 관련 용어들 💬</h3>
<ul>
<li><p>PCB: 프로세스 제어 블록, 프로세스에 대한 중요한 정보를 저장합니다.</p>
</li>
<li><p>PC: 프로그램 카운터, 프로세스 실행을 위한 다음 명령의 주소를 표시합니다.</p>
</li>
<li><p>캐시메모리: 자주 사용되는 데이터가 저장되는 공간으로 CPU의 레지스터와 메모리 사이에서 병목 현상을 완화하는 장치</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS - OS] 프로세스 동기화 - 뮤텍스,세마포어]]></title>
            <link>https://velog.io/@dabeen-jung/CS-OS-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EB%8F%99%EA%B8%B0%ED%99%94-%EB%AE%A4%ED%85%8D%EC%8A%A4%EC%84%B8%EB%A7%88%ED%8F%AC%EC%96%B4</link>
            <guid>https://velog.io/@dabeen-jung/CS-OS-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EB%8F%99%EA%B8%B0%ED%99%94-%EB%AE%A4%ED%85%8D%EC%8A%A4%EC%84%B8%EB%A7%88%ED%8F%AC%EC%96%B4</guid>
            <pubDate>Thu, 07 Dec 2023 10:42:38 GMT</pubDate>
            <description><![CDATA[<hr>
<p><br><br></p>
<h2 id="1-동기와-비동기">1. 동기와 비동기</h2>
<blockquote>
<p><strong>&lt; 쉬운예시 &gt;</strong>
할 일(task)가 : 빨래, 설거지, 청소 라고 할 경우
<strong>동기</strong> : 빨래 끝내고-&gt; 설거지 끝내고 -&gt; 청소를 한다.
<strong>비동기</strong> : 빨래 대행 업체, 설거지 <strong>대행 업체</strong>, 청소 대행 업체
=&gt; task가 언제 끝날지는 모르지만 완료되면 나한테 알려주니 <strong>난 다른 작업을 할 수 있다</strong></p>
</blockquote>
<h4 id="-동기의-정의">* 동기의 정의</h4>
<blockquote>
<ul>
<li>요청과 그에 따른 <del>결과가 동시에</del> 일어나는 것
=&gt; 이 말은 값이 <strong>반환 되기 전까지는 &#39;블로킹&#39;</strong> 되어 있다.</li>
</ul>
</blockquote>
<ul>
<li>즉 요청 후 <strong>결과가 와야만, ** <span style="color:red"> **그 다음 작업이 이루어지는 방식</strong></span></li>
</ul>
<p>🤦‍♀️어떠한 일을 처리하는 동안 <del>다른 일을 할 수 없다.</del>
<br></p>
<h4 id="비동기-정의">*비동기 정의</h4>
<blockquote>
<ul>
<li>요청과 그 결과가 <strong><del>동시에 일어나지 않는 것</del></strong>
=&gt; 얘는 &#39;<del>블로킹&#39; 되지 않고</del> 이벤트 큐에 넣거나, 백그라운드 스레드에게 해당 task 를 위임하고 바로 다음 코드를 실행하기 때문에 <strong>기대되는 값이 바로 반환되지 않는다.</strong></li>
</ul>
</blockquote>
<ul>
<li>요청 후 <strong>결과가 오는 동안</strong>, 그 다음 <strong>작업을</strong> 함</li>
</ul>
<p>👍 동기보다 복잡하지만, 일을 처리하면서도 다른 쪽에서도 일을 할 수 있어 <strong>효율적임.</strong></p>
<br>

<hr>
<br>

<h3 id="🚨-블로킹-논-블로킹">🚨 블로킹, 논 블로킹</h3>
<h4 id="정의-">정의 :</h4>
<p><strong>&#39;블로킹&#39;/&#39;논-블로킹&#39;은 동기/비동기와 <span style="color:red">관점이 다르고</strong>, <strong>제어권</strong>이 어디에 있느냐</span>에 대한 관점이다.</p>
<ul>
<li><p><strong>블로킹</strong>
호출된 함수가 자신의 작업을 <strong>모두 끝날 때 까지</strong> 제어권을 갖고 있어 호출한 함수가 <strong>대기하도록</strong> 함</p>
</li>
<li><p><strong>논-블로킹</strong>
호출된 함수가 <strong>바로 return 해서</strong> 호출한 함수에게 <strong>제어권을 넘겨주어 다른 일을 할 수 있게</strong> 함</p>
</li>
</ul>
<br>
<br>



<hr>
<br>
<br>


<h2 id="2프로세스-동기화">2.프로세스 동기화</h2>
<p>여러 프로세스가 <strong>공유하는 자원의 일관성을 유지</strong>하는 것.
=&gt; <strong>공유하는 자원에 <span style="color:red">하나의 프로세스만</span>이 이용하도록</strong> 제어</p>
<br>

<h3 id="2-1-경쟁-상태-race-condition">2-1. 경쟁 상태 (Race Condition)</h3>
<h4 id="-정의">* 정의</h4>
<pre><code>**공유 자원**에 대해 여러 프로세스 or 스레드가 **동시에 접근하려고**할 때, 결과값에 **영향을 줄 수 있는 상태**</code></pre><p>=&gt; <strong>동기화 메커니즘</strong>을 사용하여 <strong>공유 자원에 대한 접근을 조절할 수 있습니다.</strong></p>
<br>

<h3 id="2-1-1-경쟁-상태가-발생하는-경우">2-1-1. &#39;경쟁 상태&#39;가 발생하는 경우</h3>
<ol>
<li><strong>커널 작업 수행 중 &#39;인터럽트&#39;</strong>로 인해 동일한 자원을 조작한 경우<ul>
<li>문제: 인터럽트로 인해 현재 작업을 중단하고 인터럽트를 처리하는데 이 둘이 같은 데이터를 조작하는 경우</li>
<li>해결법
 커널모드에서 작업할 때, <strong>&#39;인터럽트&#39;를 disable</strong>에서 cpu 제어권을 뺏기지 말자</li>
</ul>
</li>
</ol>
<ol start="2">
<li><p>프로세스가 &#39;System Call&#39;을 하여 커널 모드로 진입하여 작업을 수행하는 도중 &#39;문맥 교환&#39;이 발생</p>
<ul>
<li><p><strong>문맥 교환</strong> : 현재 실행 중인 프로세스의 상태를 저장하고 다음 실행할 프로세스의 상태를 복원하는 작업</p>
<ul>
<li><p><strong>문제점</strong> :</p>
<blockquote>
<p>프로세스1이 커널모드에서 데이터를 조작하는 도중, 시간이 초과되어 CPU 제어권이 프로세스2로 넘어가 같은 데이터를 조작하는 경우 ( 프로세스2가 작업에 반영되지 않음 )</p>
</blockquote>
</li>
<li><p><strong>해결법</strong>
프로세스가 커널모드에서 작업을 하는 경우 <strong>시간이 초과되어도</strong> CPU 제어권이 다른 프로세스에게 <strong>넘어가지 않도록 함</strong></p>
</li>
</ul>
</li>
</ul>
</li>
</ol>
<ol start="3">
<li><strong>멀티 프로세서 환경</strong>에서 <strong>공유 메모리 내</strong>의 커널 데이터에 접근할 때<ul>
<li>문제점 : 멀티 프로세서 환경에서 <strong>2개의 CPU가 동시에</strong> 커널 내부의 <strong>공유 데이터에 접근</strong>하여 조작하는 경우</li>
<li><strong>해결법</strong> : 커널 내부에 있는 각 공유 데이터에 접근할 때마다, 그 <strong>데이터에 대한 lock/unlock을 하는 방법</strong></li>
</ul>
</li>
</ol>
<p><br><br></p>
<h3 id="2-2-임계영역">2-2. 임계영역</h3>
<h5 id="-정의-1">* 정의</h5>
<blockquote>
<p><strong>동일한 자원에 - 동시에 접근하는 작업</strong>(ex. 공유하는 변수 사용, 동일 파일 접근 및 수정 등)<strong>을 실행하는 <span style='background-color:#fff5b1'>코드 영역</span></strong>을 뜻함.</p>
</blockquote>
<ul>
<li>즉 동시에 접근하려고 하는 자원에서 문제가 발생하지 않게 <span style="color:red"><strong>독점을 보장해줘야 하는 영역</strong></span>
=&gt; <del>멀티 스레딩의 문제점 중 하나</del></li>
</ul>
<h4 id="💬-임계영역을-해결하기-위한-전제-조건">💬 &lt;임계영역을 해결하기 위한 전제 조건&gt;</h4>
<blockquote>
<p>우리의 목표 = 데이터가 한 번에 하나의 프로세스만 접근할 수 있게 하자</p>
</blockquote>
<ol>
<li><strong>상호배제</strong> 
 한 프로세스가 <strong>임계영역에 들어갔을 때 다른 프로세스는 <em>접근할 수 없게</em></strong> 함</li>
<li><strong>한정 대기</strong>
 특정 프로세스가 진입 요청 후, 받아들여질 때까지 다른 프로세스들이 이 <strong>임계영역에 진입하는 횟수는 제한이 있어야 함.</strong>
 =&gt; 아예 한 번도 안들어가는 경우는 x야함.</li>
<li><strong>진행</strong> 
 임계 구역에 들어간 프로세스가 없는 상태에서, 들어가려고 하는 프로세스가 여러 개 있다면 <strong>어느 것이 들어갈지를 적절히 결정해주어야</strong> 한다.</li>
</ol>
<br>

<h2 id="2-3-임계영역-해결방법">2-3. 임계영역 해결방법</h2>
<h3 id="1-mutex-뮤텍스">1. Mutex (뮤텍스)</h3>
<p>ex) 이해 꿀팁: 화장실 키를 들고 갔다로 이해하자
뮤텍스는 상태가 오직 <span style='background-color:#fff5b1'>획득(Lock) / 해제(Unlock)만 존재</span>한다</p>
<ul>
<li><p>(정의)</p>
<ul>
<li>임계 영역에 대한 접근을 제어하며 <strong>한 번에 하나의 스레드만이 접근 가능</strong>하다</li>
<li><strong>임계영역에 진입</strong>하는 프로세스는 <strong>&#39;Lock&#39;을 획득</strong> -&gt; 영역을 나올 때, <strong>&#39;Lock&#39;을 방출</strong></li>
<li><strong>실행시간이</strong> 서로 겹치지 않고 <strong>각각 단독으로 실행되게 하는 기술</strong></li>
</ul>
</li>
<li><p><strong>(한계)</strong> </p>
</li>
<li><p><em>다중처리기 환경*</em>에서는 시간적인 효율성 측면에서 적용이 어려움.</p>
</li>
</ul>
<p><br><br><br></p>
<h3 id="2-semaphores세마포어">2. Semaphores(세마포어)</h3>
<blockquote>
<p>ex) 이해 꿀팁 🤔:
세마포어는 화장실이 여러 개 있고, 화장실 입구에는 현재 빈 화장실의 개수를 알려주는 전광판이 있는 식당과 비슷하다.
<strong>모든 칸의 화장실이 사용중</strong>일 때 전광판의 숫자는 <strong>0</strong>이 되며, 손님들은 <strong>전광판 숫자가 1로 바뀔 때까지 대기</strong>해야한다.
<img src="https://velog.velcdn.com/images/dabeen-jung/post/89251979-9417-4720-a8fc-eba83eba7329/image.png" alt=""></p>
</blockquote>
<ul>
<li><p>(정의)</p>
<ul>
<li><strong>여러 개의 스레드 or 프로세스가 동시에 공유자원에 접근하되 <span style="color:red">이 공유자원의 갯수를 제한</strong></span>한다.</li>
<li>소프트웨어상에서 임계영역 문제를 해결하기 위한 <span style="color:red"><strong>동기화 도구로 2가지</strong></span>로 나뉘어진다.</li>
<li>0 이상의 정수 값 소지</li>
</ul>
</li>
<li><p><strong>(단점)</strong></p>
<ul>
<li><code>Busy Waiting(바쁜 대기)</code><blockquote>
<p><span style="color:red"><strong>&#39;스핀 락&#39;(세마포어 초기 버전)</strong></span>에서 <strong>&#39;임계영역&#39;에</strong> 진입해야하는 <strong>프로세스는 진입 코드를 계속 반복 실행</strong>해야 하며, <strong>CPU 시간을 낭비</strong>한다는 점.</p>
</blockquote>
</li>
</ul>
</li>
</ul>
<br>

<h3 id="2-1-세마포어의-2가지-연산pv연산">2-1. 세마포어의 2가지 연산(P,V연산)</h3>
<ul>
<li><strong>P (Proberen) 연산</strong>
  세마포어 값을 감소시킵니다. 만약 값이 <strong>0보다 작다면</strong> 프로세스 또는 스레드는 <strong>대기 상태로 전환</strong>됩니다.</li>
<li><strong>V (Verhogen) 연산</strong>
  세마포어 값을 증가시킵니다. *<em>대기 중인 프로세스 또는 스레드가 있다면 하나를 깨워 실행 가능 상태로 *</em>전환시킵니다.</li>
</ul>
<br>

<h4 id="◽📕-세마포어의-종류">◽📕 세마포어의 종류</h4>
<ol>
<li><p><strong>카운팅 세마포어</strong></p>
<ul>
<li>도메인이 <strong>0 이상인 임의의 정수값</strong>인 세마포어</li>
<li><span style="color:red"><strong>동시에 접근할 수 있는 프로세스 또는 스레드의 &#39;수&#39;를 제한</span></strong>하는 데 사용</li>
<li><strong>여러개의 자원을 가질 수 있으며</strong>, 제한된 자원을 가지고 액세스 작업할 때 사용</li>
</ul>
</li>
<li><p><strong>이진 세마포어</strong> (뮤텍스)</p>
<ul>
<li>** 0 or 1의 값만**을 가지는 세마포어</li>
<li><strong>임계영역 문제를 해결하는 데에 사용 **
  =&gt; **자원이 하나라 &#39;뮤텍스&#39;로 알려져있다.</strong></li>
</ul>
</li>
</ol>
<br>




<br>

<h3 id="결론">(결론)</h3>
<ul>
<li><p><strong>&#39;뮤텍스&#39;는 상태가 0, 1 두 개 뿐인 &#39;이진 세마포어&#39;</strong> 이다.</p>
</li>
<li><p><strong>&#39;세마포어&#39;</strong>는 프로세스/스레드가 소유할 수 없는 반면, <strong>&#39;뮤텍스&#39;</strong>는 소유가 가능하며 프로세스/스레드가 이에 대한 책임을 진다. 
  =&gt; (Mutex 의 경우 상태가 두개 뿐인 lock 이므로 lock 을 ‘가질’ 수 있다.)</p>
</li>
<li><p><strong>&#39;뮤텍스&#39;</strong>는 동기화 대상이 오직 하나뿐일 때, <strong>&#39;세마포어&#39;</strong>는 동기화 대상이 하나 이상일 때 사용한다.</p>
</li>
<li><p><strong>사용 목적</strong></p>
<ul>
<li><strong>뮤텍스</strong>: 주로 <strong>임계 영역에 대한 접근을 제어</strong>하는 데 사용됩니다. 한 번에 하나의 스레드만이 임계 영역에 접근할 수 있도록 합니다.</li>
<li><strong>세마포어</strong>: <strong>주로 자원의 접근을 조율하고 동기화하는 데</strong> 사용됩니다. 여러 개의 스레드 또는 프로세스가 동시에 접근할 수 있는 자원의 개수를 제한하는 데 사용됩니다.</li>
</ul>
</li>
<li><p><strong>&#39;세마포어&#39;</strong>는 자원의 가용 개수를 제한하거나 동기화를 위해 카운팅이 필요한 경우</p>
</li>
<li><p>반면 <strong>&#39;뮤텍스&#39;</strong>는  임계 영역에 대한 동시 접근을 막아야 하는 경우에</p>
</li>
</ul>
<br>

<br>



<hr>
<br>

<br>


<h3 id="3-교착상태dead-lock">3. 교착상태(Dead lock)</h3>
<p>두 개 이상의 작업이 <strong>서로 상대방의 작업이 끝나기만을 기다리기</strong> 때문에 <strong>아무것도 완료되지 못하고 있는 상태</strong></p>
<blockquote>
<p>외나무 다리에 서있듯이 서로가 비켜주지 않는다.</p>
</blockquote>
<h3 id="🤦♂️교착상태를-발생시키는-조건모두-성립되어야-함">🤦‍♂️교착상태를 발생시키는 조건[모두 성립되어야 함]</h3>
<p><strong>1. 상호배제</strong> : 하나의 프로세스가 자원을 <strong>사용중일 때</strong> 다른 프로세스는 그를 <strong>사용할 수 없다.</strong>
<strong>2.점유 대기(Hold and Wait)</strong>  : <strong>1개 이상의 자원을 점유하고 있으면서</strong> 다른 프로세스가 <strong>사용중인 자원</strong>을 추가로 점유하기 위해 <strong>대기</strong>하는 프로세스가 존재한다.
<strong>3. 비선점</strong> : 다른 프로세스가 자원을 사용중인 경우 그 사용이 끝날 때 까지 <strong>강제로 뺏을 수 없다.</strong>
<strong>4. 순환 대기</strong> : 프로세스의 집합에서 <strong>순환형태로 자원을 대기</strong>하고 있어야 한다.</p>
<br>

<h3 id="👍교착상태의-예방과-회피회복-무시">👍교착상태의 예방과 회피,회복, 무시</h3>
<h4 id="예방">(예방)</h4>
<p><strong>조건 중 하나를 제거</strong>하면서 예방.</p>
<ul>
<li><strong>상호 배제 부정</strong> : 여러 프로세스가 공유 자원 사용</li>
<li><strong>점유 대기 부정</strong> : 프로세스 <strong>실행 전 모든 자원 할당</strong></li>
<li><strong>비선점 부정</strong> : 점유중인 자원을 다른 프로세스가 <strong>요구하는 경우 그를 반납</strong></li>
<li><strong>순환 대기 부정</strong> : 자원에 고유 번호를 할당한 후 순서대로 자원 요구<br>

</li>
</ul>
<h4 id="회피">(회피)</h4>
<ul>
<li><strong>은행원 알고리즘</strong></li>
</ul>
<blockquote>
<p>프로세스가 자원을 요구할 때 시스템은 자원을 할당한 후에도 안정 상태로 남아있게 되는지 <strong>미리 검사하여 교착 상태를 회피</strong>한다.</p>
</blockquote>
<h4 id="그-외에-회복과-무시">그 외에 회복과 무시...</h4>
<p>교착상태 발생시, 해결한다와 성능저하가 심할 경우 무시한다.</p>
<br>

<h3 id="2-기아상태">2. 기아상태</h3>
<p>특정 프로세스의 <strong>우선 순위가 낮아서</strong> 원하는 자원을 <strong>계속 할당받지 못하는 상태</strong>를 말함.</p>
<h4 id="해결-방법">(해결 방법)</h4>
<ol>
<li>프로세스 우선순위 수시 변경을 통해 각 프로세스 <strong>높은 우선순위를 가지도록 기회 부여</strong></li>
<li>오래 기다린 프로세스의 우선순위 높이기</li>
<li>요청 순서대로 처리하는 요청큐 사용</li>
</ol>
<br>

<br>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS - OS] 스케줄링]]></title>
            <link>https://velog.io/@dabeen-jung/CS-OS-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%A7%81</link>
            <guid>https://velog.io/@dabeen-jung/CS-OS-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%A7%81</guid>
            <pubDate>Tue, 05 Dec 2023 15:20:40 GMT</pubDate>
            <description><![CDATA[<p><br><br></p>
<h2 id="1-스케줄러">1. 스케줄러</h2>
<h3 id="스케줄링">스케줄링</h3>
<p> 운영체제에서 여러 프로세스들 사이에 <strong>CPU 사용의 우선순위를 부여</strong>하고, <strong>어떤 프로세스에게 CPU를 할당할 것인지를 결정</strong>하는 작업
=&gt; 즉, *<em>CPU를 잘 사용하기 위해 *</em>&#39;프로세스&#39;들을 어떻게 배정할 것인지를 결정하는 작업이다</p>
<blockquote>
<p><strong>&lt; *<em>프로세스를 *</em>스케줄링 하기 위한 Queue 종류</strong>&gt;</p>
</blockquote>
<ul>
<li>Job Queue : 현재 시스템 내에 있는 모든 프로세스의 집합</li>
<li>Ready Queue : 현재 메모리 내에 있으면서 CPU 를 잡아서 실행되기를 기다리는 프로세스의 집합</li>
<li>Device Queue : Device I/O 작업을 대기하고 있는 프로세스의 집합</li>
</ul>
<br>

<h3 id="스케줄링의-목표">스케줄링의 목표</h3>
<h4 id="cpu를-잘-사용하려면-프로세스를-어떤-식의-규칙으로-배정해야-할까🤔">CPU를 잘 사용하려면 프로세스를 어떤 식의 규칙으로 배정해야 할까?🤔</h4>
<h4 id="조건--오버헤드-↓--사용률-↑--기아-현상-↓">조건 : 오버헤드 ↓ / 사용률 ↑ / 기아 현상 ↓</h4>
<h4 id="목표">목표</h4>
<ol>
<li>Batch System: 가능하면 <strong>많은 일</strong>을 수행. 시간(time) 보단 처리량(throughout)이 중요</li>
<li>Interactive System: <strong>빠른 응답 시간</strong>. 적은 대기 시간.</li>
<li>Real-time System: <strong>기한</strong>(deadline) 맞추기.</li>
</ol>
<br>

<h3 id="1-1-스케줄러">1-1. 스케줄러</h3>
<p> 스케줄링을 수행해주는 컴포넌트를 <strong>&#39;스케줄러&#39;</strong>라고 한다.</p>
<blockquote>
<p>프로세스에게<strong><span style="color:red"> 공정한 CPU 접근 기회</strong></span>를 제공하며, 시스템의 전반적인 <strong>성능과 효율성을 향상</strong></p>
</blockquote>
<br>

<h3 id="1-1-1-프로세스-상태">1-1-1. 프로세스 상태</h3>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/bbe0213f-f187-47e2-a95e-c815a702916e/image.png" alt=""></p>
<h4 id="⭐-프로세스의-상태-전이">⭐ 프로세스의 상태 전이</h4>
<blockquote>
<ul>
<li><strong>승인 (Admitted)</strong> 
프로세스 생성이 가능하여 승인됨.</li>
</ul>
</blockquote>
<ul>
<li><strong>스케줄러 디스패치 (Scheduler Dispatch)</strong> 
준비 상태에 있는 프로세스 중 하나를 선택하여 실행시키는 것.</li>
<li>*<em>인터럽트 (Interrupt) *</em>
예외, 입출력, 이벤트 등이 발생하여 현재 실행 중인 프로세스를 준비 상태로 바꾸고, 해당 작업을 먼저 처리하는 것.</li>
<li><strong>입출력 또는 이벤트 대기 (I/O or Event wait)</strong> 
실행 중인 프로세스가 입출력이나 이벤트를 처리해야 하는 경우, 입출력/이벤트가 모두 끝날 때까지 대기 상태로 만드는 것.</li>
<li><strong>입출력 또는 이벤트 완료 (I/O or Event Completion)</strong>
입출력/이벤트가 끝난 프로세스를 준비 상태로 전환하여 스케줄러에 의해 선택될 수 있도록 만드는 것</li>
</ul>
<br>


<h3 id="1-1-2-스케줄러-종류">1-1-2. 스케줄러 종류</h3>
<h4 id="◽-장기-스케줄러">◽ 장기 스케줄러</h4>
<p><strong>어떤 프로세스를 메모리를 할당해 Ready Queue로 적재할지 결정하는 역할</strong>을 합니다. 이를 통해 동시에 실행될 프로세스의 수를 제어합니다. </p>
<blockquote>
<ul>
<li><strong>메모리와 - 디스크 사이</strong>의 스케줄링 담당</li>
</ul>
</blockquote>
<ul>
<li>프로세스의 상태 (new -&gt; ready(in memory))</li>
</ul>
<br>

<h4 id="◽-단기-스케줄러">◽ 단기 스케줄러</h4>
<p><strong>CPU가 할당될 프로세스를 선택</strong>합니다. 이는 매우 빠른 주기로 실행되며, <span style="color:red"><strong>컨텍스트 스위칭을 수행</strong></span>합니다.</p>
<blockquote>
<ul>
<li><strong>Ready Queue</strong> 에 존재하는 <strong>프로세스 중<span style="color:red"> 어떤 프로세스를 running 시킬지</strong> </span>결정.</li>
</ul>
</blockquote>
<ul>
<li><strong>CPU - 메모리 사이</strong>의 스케줄링 담당</li>
<li>ready -&gt; running -&gt; waiting -&gt; ready</li>
</ul>
<br>

<h4 id="◽-중기-스케줄러">◽ 중기 스케줄러</h4>
<p>현재 실행 중인 프로세스를 <strong>일시 중단</strong>(swap out)하고 메모리를 확보하기 위해 <strong>프로세스를 통째로 메모리에서 디스크로 쫓아냄</strong></p>
<blockquote>
<ul>
<li>ready -&gt; stopped</li>
</ul>
</blockquote>
<br>


<p><br><br><br>
<br><br><br></p>
<hr>
<br>

<h3 id="2-선점--비선점-스케줄링">2. 선점 / 비선점 스케줄링</h3>
<h4 id="-선점">* 선점</h4>
<p>현재 CPU를 <strong>사용하고 있는 프로세스를 중단</strong>시키고, <strong>다른 프로세스에게 CPU를 할당</strong>할 수 있는 스케줄링 방식</p>
<blockquote>
<p>(<strong>장점</strong>) 작업을 빠르게 처리
(<strong>단점</strong>) <strong>&#39;컨텍스트 스위칭 오버헤드&#39;</strong> 발생이 생길 수 있다.</p>
</blockquote>
<h4 id="-비선점">* 비선점</h4>
<p> 한 번 CPU를 할당받은 프로세스가 <strong>자발적으로 CPU를 반납하거나 작업을 완료할 때까지</strong> <span style="color:red"><strong>CPU를 계속 사용</strong></span>하는 스케줄링 방식</p>
<blockquote>
<p>(<strong>장점</strong>) 강제로 프로세스를 중단하지 않아-&gt; &#39;컨텍스트 스위칭 오버헤드&#39;가 적다
(<strong>단점</strong>) <strong>&#39;기아 상태&#39;</strong> 발생 위험이 있다.
-&gt;(오랫동안 cpu에 점유하는 작업에 의해서)</p>
</blockquote>
<p><br><br></p>
<hr>
<br>

<h3 id="3-cpu-스케줄링의-종류">3. CPU 스케줄링의 종류</h3>
<h4 id="🚦-비선점-스케줄링">🚦 비선점 스케줄링</h4>
<ul>
<li><p><strong>FCFS (First Come First Served)</strong>
큐에 <strong>도착한 순서대로</strong> CPU 할당
실행 시간이 짧은 게 뒤로 가면 평균 대기 시간이 길어짐</p>
<ul>
<li><strong>( 문제점 ) : &#39;콘보이 효과(Convoy effect)&#39;</strong></li>
<li><blockquote>
<p>작은 작업이 큰 작업 뒤에 대기=&gt; 평균 대기시간 증가</p>
</blockquote>
</li>
</ul>
</li>
<li><p><strong>SJF (Shortest Job First)</strong></p>
<ul>
<li><strong>수행시간(Cpu burst time)이 가장 짧다</strong>고 판단되는 작업을 먼저 수행</li>
<li>짧은 작업에 유리<ul>
<li><strong>( 문제점 ) : &#39;기아 현상&#39;</strong></li>
</ul>
</li>
</ul>
</li>
<li><p><strong>HRN (Hightest Response-ratio Next)</strong>
우선순위를 계산하여 점유 불평등을 보완한 방법<strong>(SJF의 단점 보완)</strong>
우선순위 = (대기시간 + 실행시간) / (실행시간)</p>
</li>
</ul>
<p><br><br></p>
<h4 id="🚦-선점-스케줄링">🚦 선점 스케줄링</h4>
<ul>
<li><strong>우선순위 스케줄링</strong><ul>
<li>정적/동적으로 <strong>우선순위를 부여</strong>하여 우선순위가 높은 순서대로 처리</li>
<li><strong>(문제점)</strong> 
 <strong>무한정 기다리는 &#39;기아현상</strong>&#39; 이 생길 수 있음</li>
<li><strong>(해결법)</strong> : Aging 방법</li>
<li><blockquote>
<p>너무 <del><em>오래 기다리면 우선순위를 올려줌</em></del></p>
</blockquote>
</li>
</ul>
</li>
</ul>
<ul>
<li><p><strong>Round Robin (현대적인 스케줄링)</strong></p>
<ul>
<li>FCFS에 의해** 각 프로세스에게 일정 시간을 할당하고, 그 시간이 지나면 다음 프로세스**에게 CPU를 넘김</li>
<li><strong>(단점)</strong>
if 할당 시간이 크면? FCFS와 같게 되고,</li>
<li><em>if 작으면*</em>, 문맥 교환 (Context Switching) 잦아져서 <strong>&#39;오버헤드&#39; 증가</strong>
=&gt; 동등한 기회를 주어, 실시간 시스템 등에서 이용</li>
</ul>
</li>
<li><p><strong>SRTF</strong></p>
<ul>
<li><strong>새로운 프로세스가 도착할 때마다 새로운 스케줄링</strong>이 이루어진다.<ul>
<li><strong>(문제점)</strong> : ** &#39;기아현상**&#39;</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>다단계 큐(Multilevel Queue)</strong></p>
<ul>
<li>여러 개의 큐를 사용하여 <strong>각 큐마다 다른 스케줄링 알고리즘</strong>을 적용</li>
<li><blockquote>
<p>그 안에서 <del>우선순위를 부여</del>하여 높은 우선순위의 큐에 있는 프로세스를 먼저 처리* <strong>다단계 큐</strong></p>
</blockquote>
</li>
<li>여러 개의 큐를 사용하여 <strong>각 큐마다 다른 스케줄링 알고리즘</strong>을 적용</li>
<li><blockquote>
<p>그 안에서 <del>우선순위를 부여</del>하여 높은 우선순위의 큐에 있는 프로세스를 먼저 처리</p>
</blockquote>
</li>
</ul>
</li>
<li><p><strong>다단계 피드백 큐(Multilevel Feedback Queue)</strong></p>
<ul>
<li><span style="color:red">다단계 큐에서</span> 자신의 <strong>&#39;실행 최소 단위시간(Time Quantum)&#39;을 다 채운 프로세스는 밑으로</strong> 내려가고,
자신의 Time Quantum을** 다 채우지 못한 프로세스는 원래 큐 그대로**
-&gt; Time Quantum을 다 채운 프로세스는 CPU burst 프로세스로 판단하기 때문</li>
<li><strong>짧은 작업에 유리</strong>, 입출력 위주(Interrupt가 잦은) 작업에 우선권을 줌</li>
<li><span style="color:red"><strong>처리 시간이 짧은 프로세스를 먼저 처리</strong></span>하기 때문에 작업이 완료될 때까지 걸리는 평균 시간을 줄여준다</li>
</ul>
</li>
</ul>
<p><br><br></p>
<hr>
<h3 id="참고">참고</h3>
<p><a href="https://velog.io/@sangjin98/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-%EB%8F%99%EA%B8%B0%EC%99%80-%EB%B9%84%EB%8F%99%EA%B8%B0-%EB%B0%8F-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EB%8F%99%EA%B8%B0%ED%99%94">sangjin98님의 글을 참고하였습니다.</a></p>
<p><a href="https://velog.io/@hidaehyunlee/Philosophers-%EC%98%88%EC%8B%9C%EC%98%88%EC%A0%9C%EB%A1%9C-%EB%B3%B4%EB%8A%94-%EB%AE%A4%ED%85%8D%EC%8A%A4%EC%99%80-%EC%84%B8%EB%A7%88%ED%8F%AC%EC%96%B4%EC%9D%98-%EC%B0%A8%EC%9D%B4">이대현 님의 글을 참고하였습니다.</a></p>
<p><a href="https://velog.io/@underlier12/OS-24-%EA%B5%90%EC%B0%A9%EC%83%81%ED%83%9C%EC%99%80-%EA%B8%B0%EC%95%84%EC%83%81%ED%83%9C">underlier12 님의 글을 참고하였습니다.</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS - OS] 프로세스와 스레드 (+ PCB, 컨텍스트 스위칭)]]></title>
            <link>https://velog.io/@dabeen-jung/CS-New</link>
            <guid>https://velog.io/@dabeen-jung/CS-New</guid>
            <pubDate>Tue, 05 Dec 2023 09:49:36 GMT</pubDate>
            <description><![CDATA[<ul>
<li>들어가기 앞서 OS란...<blockquote>
<p>하드웨어를 관리하고, 컴퓨터 시스템의 자원들을 효율적으로 관리하며, <strong>응용 프로그램과 하드웨어 간의 인터페이스</strong>로써 다른 응용 프로그램이 유용한 작업을 할 수 있도록 환경을 제공해준다.
즉, 운영 체제는 사용자가 컴퓨터를 편리하고 효과적으로 사용할 수 있도록 환경을 제공하는 시스템 소프트웨어라고 할 수 있다.</p>
</blockquote>
</li>
</ul>
<h2 id="0-운영체제">0. 운영체제</h2>
<h3 id="-운영체제의-역할-">[ 운영체제의 역할 ]</h3>
<h3 id="1-프로세스-관리">1. 프로세스 관리</h3>
<p> 운영체제에서 작동하는 <strong>응용 프로그램을 관리</strong>하는 기능이다.
  프로세서(CPU) 관리하는 것이라고 볼 수도 있다. <strong>현재 CPU를 점유해야 할 프로세스를 결정</strong>하고, <strong>실제로 CPU를 프로세스에 할당하</strong>며, <strong>이 프로세스 간 공유 자원 접근과 통신 등을 관리</strong></p>
<blockquote>
<ul>
<li>프로세스, 스레드</li>
</ul>
</blockquote>
<ul>
<li>스케줄링</li>
<li>동기화</li>
<li>IPC 통신</li>
</ul>
<br>

<h3 id="2-저장장치-관리">2. 저장장치 관리</h3>
<p>1차 저장장치에 해당하는 <strong>메인 메모리</strong>와 2차 저장장치에 해당하는 <strong>하드디스크, NAND 등</strong>을 관리하는 기능</p>
<ul>
<li>1차 저장장치(Main Memory)<ul>
<li>프로세스에 할당하는 메모리 영역의 할당과 해제</li>
<li>각 메모리 영역 간의 침범 방지</li>
<li>메인 메모리의 효율적 활용을 위한 가상 메모리 기능</li>
</ul>
</li>
<li>2차 저장장치(HDD, NAND Flash Memory 등)<ul>
<li>파일 형식의 데이터 저장</li>
<li>이런 파일 데이터 관리를 위한 파일 시스템을 OS에서 관리</li>
<li>FAT, NTFS, EXT2, JFS, XFS 등 많은 파일 시스템들이 개발되어 사용 중</li>
</ul>
</li>
</ul>
<blockquote>
<ul>
<li>메모리 관리</li>
</ul>
</blockquote>
<ul>
<li>가상 메모리</li>
<li>파일 시스템</li>
</ul>
<br>


<h3 id="3-네트워킹">3. 네트워킹</h3>
<p> TCP/IP 기반의 <strong>인터넷에 연결</strong>하거나, 응용 프로그램이 네트워크를 <strong>사용하려면 운영체제에서 네트워크 프로토콜을 지원</strong>해야 한다.
<strong>운영체제는 사용자와 컴퓨터 하드웨어 사이에 위치</strong>해서, 하드웨어를 운영 및 관리하고 명령어를 제어하여 응용 프로그램 및 하드웨어를 소프트웨어적으로 제어 및 관리</p>
<blockquote>
<ul>
<li>TCP/IP</li>
</ul>
</blockquote>
<ul>
<li>기타 프로토콜</li>
</ul>
<br>


<h3 id="4-사용자-관리">4. 사용자 관리</h3>
<p>운영체제는 <strong>각 계정을 관리할 수 있는 기능</strong>이 필요하다. 사용자 별로 프라이버시와 보안을 위해 개인 파일에 대해선 다른 사용자가 접근할 수 없도록 해야 한다. 이 밖에도 <strong>파일이나 시스템 자원에 접근 권한을 지정</strong>할 수 있도록 지원하는 것이 사용자 관리 기능</p>
<blockquote>
<ul>
<li>계정 관리</li>
</ul>
</blockquote>
<ul>
<li>접근권한 관리</li>
</ul>
<br>

<h3 id="5-디바이스-드라이버">5. 디바이스 드라이버</h3>
<p>운영체제는 시스템의 자원, 하드웨어를 관리한다. 시스템에는 여러 하드웨어가 붙어있는데, 이들을 운영체제에서 인식하고 관리하게 만들어 응용 프로그램이 하드웨어를 사용할 수 있게 만들어야 한다.</p>
<p>따라서, <strong>운영체제 안에 하드웨어를 추상화 해주는 계층이 필요</strong>하다. 이 계층이 바로 <strong>디바이스 드라이버</strong>라고 불린다. 하드웨어의 종류가 많은 만큼, 운영체제 내부의 디바이스 드라이버도 많이 존재한다.
이러한 수많은 <strong>디바이스 드라이버들을 관리하는 기능</strong> 또한 운영체제가 맡고 있다.</p>
<blockquote>
<ul>
<li>순차접근 장치</li>
</ul>
</blockquote>
<ul>
<li>임의접근 장치</li>
<li>네트워크 장치</li>
</ul>
<br>

<hr>
<p><br><br></p>
<h2 id="1-프로세스와-스레드">1. 프로세스와 스레드</h2>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/06a3cfad-1922-4d14-bf21-6051f8ef2024/image.png" alt=""></p>
<h4 id="단어-정의">단어 정의</h4>
<ul>
<li><strong>프로세스</strong> : </li>
</ul>
<ol>
<li>메모리에 적재되어 <strong>실행 중인 프로그램</strong>(작업)</li>
<li>운영체제로부터 주소 공간, 파일, 메모리 등을 할당받으며 이것들을 총칭한다.</li>
<li>프로세스는  <strong>별도의 주소공간을 독립적으로 할당받는다.</strong></li>
<li><strong>프로세스마다 <span style="color:red"> 기본적으로 1개의 스레드가 같이 생성</span>된다. (메인 스레드 포함)</strong><blockquote>
<p>&lt;구성&gt; </p>
<ul>
<li>code</li>
<li>Data : 전역변수, 정적변수, 배열 등</li>
<li>Heap : 동적 할당 시 사용</li>
<li>Stack : 지역변수, 매개변수, 리턴 값 (임시 메모리 영역)</li>
</ul>
</blockquote>
</li>
</ol>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/b2de39b3-0609-49e9-adf7-3f6f448e3606/image.png" alt=""></p>
<h4 id="q-왜-스택과-데이터를-구성에서-나누는-것인가">Q. 왜 스택과 데이터를 구성에서 나누는 것인가?</h4>
<p><strong>Stack은 LIFO의 특성</strong>을 가졌다. 전역변수나, 스택 구조의 특성 등의 활용성을 생각했다. 그렇기에 <strong><em>공통</em> 으로 사용되는 &#39;전역변수&#39;</strong>를 따로 데이터에 지정해주면 <strong>메모리를 아낄 수 있따.</strong></p>
<br>

<h4 id="1-2-프로세스와-스레드-차이점">1-2. 프로세스와 스레드 차이점</h4>
<blockquote>
<p><strong>프로레스</strong>는 자신만의 <strong>고유 공간</strong>과, 자원 할당을 받아 사용 
 <strong>스레드</strong>는 다른 스레드와 공간, 자원을 <strong>공유</strong>하여 사용
=&gt; <span style="color:red">그래서 <strong>스레드</strong>는 좀 더 효율적으로 통신할 수 있음 </span></p>
</blockquote>
<br>

<ul>
<li><strong>스레드</strong> :</li>
</ul>
<ol>
<li>** <span style="color:red">프로세스 안</span>에서 실행되는** 하나 하나의 흐름들의 단위</li>
<li>스레드는 <strong>Stack만 따로 할당</strong>받으며 <strong>다른 운영체제 자원들은 서로 공유</strong>하여 이용</li>
</ol>
<blockquote>
<p>Q.  스레드마다 Stack을 독립적으로 할당하는 까닭</p>
<ul>
<li>&#39;스택&#39;은 함수 호출 시 전달되는 인자, 되돌아갈 주소값 및 함수 내에서 선언하는 변수 등을 저장하기 위해 사용되는 메모리 공간이다.
(결론) 스택 메모리 공간이 독립적이라는 것은 독립적인 함수 호출이 가능하다는 것.
즉, 하나의 스레드에서 호출한 함수의 <strong>지역 변수와 매개 변수 등</strong>의 정보가 <strong>다른 스레드에서 호출한 함수와 관련된 정보와 혼동되어서는 안되기 때문</strong>이다.</li>
</ul>
</blockquote>
<p><br><br></p>
<hr>
<h3 id="1-2-💡-멀티-프로세스">1-2. 💡 멀티 프로세스</h3>
<h4 id="-정의-">( 정의 )</h4>
<p> <strong>하나의 프로그램을 여러개의 프로세스로 구성</strong>하여 <span style="color: red">각 프로세스가 <strong>병렬적</strong>으로 작업을 수행</span></p>
<blockquote>
<ul>
<li><strong>장점</strong>
안전성 (메모리 침범을 OS 내에서 해결)</li>
</ul>
</blockquote>
<ul>
<li><strong>단점</strong>
독립적인 메모리 영역을 가져, <span style="color: red">작업량이 많아질 수록 &#39;<strong>오버헤드</strong>&#39; 발생, <strong>&#39;컨텍스트 스위칭&#39;</strong>으로 <strong>성능저하</strong></span></li>
</ul>
<p><br><br><br></p>
<h3 id="1-3-💡-멀티-스레딩멀티-스레드">1-3. 💡 <strong>멀티 스레딩(멀티 스레드)</strong></h3>
<h4 id="정의--하나의-응용-프로그램에서-여러-스레드를-구성하여-각-스레드가-하나의-작업을-처리하는-것">(정의) : 하나의 응용 프로그램에서 <strong>여러 스레드를 구성하여 각 스레드가 하나의 작업을 처리</strong>하는 것</h4>
<ul>
<li>여러 개의 스레드들이 &#39;공유 메모리&#39;를 통해 다수의 작업들을 동시에 처리하게 해줌</li>
<li>각각의 스레드는 독립적인 작업을 위하여 <strong>&#39;스택&#39;과 &#39;PC 레지스터 값&#39;을 각각 가지고 있음</strong><blockquote>
<p><strong>PC 값은 스레드가 어디까지 수행했는지를 기억</strong>해주는 것
=&gt; 스레드는 CPU에 할당받았다 스케줄러에 의해 다시 선점되기 때문</p>
</blockquote>
</li>
</ul>
<br>

<h4 id="💪장점">💪(장점)</h4>
<ol>
<li><p><strong>메모리 공간과 시스템 자원 소모가 줆</strong></p>
</li>
<li><p>프로세스 간 통신 방법에 비해 <strong>간단</strong></p>
</li>
</ol>
<p>-&gt; 별도의 자원을 이용하지 않고, 전역 변수의 공간 또는 동적으로 할당된 공간인 <strong>Heap 영역을 이용하여 데이터를 주고 받음(스레드 간 통신)</strong></p>
<ol start="3">
<li><strong>&#39;스레드의 컨텍스트 스위치&#39;는</strong> &#39;프로세스 컨텍스트 스위치&#39;와 달리 <strong>캐시 메모리를 비울 필요가 없기 때문에 더 빠르다</strong></li>
</ol>
<p>=&gt; 그래서 여러 프로세스를 통해 작업하지 않고 <strong>&#39;하나의 프로세스에서 스레드를 여러개로 나눠 수행&#39;</strong></p>
<br>

<h4 id="😢단점">😢(단점)</h4>
<ul>
<li><p>공유 메모리로 인해 <strong>&#39;동시 접근&#39;</strong>으로 인한 문제</p>
<blockquote>
<p>멀티 프로세스의 프로세스 사이엔 공유자원을 동시에 접근하는 일이 없었다.
그러나 멀테 스레드에서는...</p>
</blockquote>
<ul>
<li>하나의 스레드가 공유 데이터 값을 변경하는 시점에 다른 스레드가 그 값을 읽으려고 접근할 경우 발생하는 문제</li>
</ul>
</li>
<li><blockquote>
<p><span style="background-color:     #fff5b1"><strong>&#39;동기화 작업(synchronization)&#39;</span> 필요</strong></p>
<br>
</blockquote>
</li>
</ul>
<h4 id="📕-해결법-span-stylebackground-color-----f5f0ff동기화-작업의--여러가지-방법span">📕 (해결법) <span style="background-color:     #f5f0ff">동기화 작업의  여러가지 방법</span></h4>
<blockquote>
</blockquote>
<ul>
<li><strong>뮤텍스</strong></li>
<li><strong>세마포어</strong><blockquote>
<p>뒤의 블로그에서 더 구체적으로 다룰 예정</p>
</blockquote>
</li>
</ul>
<br>

<h3 id="1-4-멀티-스레드-vs-멀티-프로세스">1-4. 멀티 스레드 vs 멀티 프로세스</h3>
<h4 id="차이점">(차이점)</h4>
<ul>
<li><p><strong>멀티 스레드</strong>는 보다 ¹<strong>적은 메모리 공간</strong>을 차지하고 ²<strong>문맥 전환이 빠르다</strong>는 장점이 있지만,
  <span style="color: red">&lt; <strong>문제점</strong>&gt;</span></p>
<pre><code>  1. 오류로 인해 하나의 스레드가 종료되면 전체 스레드가 종료될 수 있다는 점
  2. **동기화 문제**</code></pre></li>
<li><p><strong>멀티 프로세스</strong>는  나의 프로세스가 죽더라도 다른 프로세스에는 영향을 끼치지 않고 정상적으로 수행된다는 장점이 있다
<span style="color: red">&lt; <strong>문제점</strong> &gt; </span></p>
<pre><code>  1. 멀티 스레드보다 **많은 메모리 공간과 CPU 시간을 차지**한다</code></pre></li>
</ul>
<h4 id="공통점--둘-다-동시에-여러-작업을-수행한다는-점">(공통점) : 둘 다 동시에 여러 작업을 수행한다는 점</h4>
<blockquote>
<p>즉 적용하는 시스템에 따라 동작방식을 선택하자.</p>
</blockquote>
<br>
<br><br><br>

<hr>
<p><br><br><br></p>
<h2 id="2-인터럽트">2. 인터럽트</h2>
<h4 id="◽-정의">◽ (정의)</h4>
<p>프로그램을 실행하는 도중에 <del>예기치 않은 상황이 발생</del>할 경우 <strong>현재 실행 중인 작업을 즉시 중단</strong>하고, <span style="color:red"><strong>발생된 상황에 대한 &#39;우선 처리&#39;가 필요함</span>을 &#39;CPU&#39;에게 알리는 것</strong></p>
<h4 id="종류">(종류)</h4>
<ul>
<li><p>** 외부 인터럽트**
  입출력 장치, 타이밍 장치, 전원 등 외부적인 요인으로 발생
  ex) 전원 이상, 기계 착오, 외부 신호, 입출력</p>
</li>
<li><p><strong>내부 인터럽트</strong>
잘못된 명령이나 데이터를 사용할 때 발생
  ex)  오버플로우, Exception</p>
</li>
<li><p><strong>소프트웨어 인터럽트</strong></p>
</li>
</ul>
<br>

<h3 id="2-1-인터럽트-발생-처리-과정">2-1. 인터럽트 발생 처리 과정</h3>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/2ab88fcc-b63c-4974-b687-255d257377e0/image.png" alt=""></p>
<blockquote>
<p>인터럽트가 없었다면 <strong>&#39;폴링&#39;</strong>을 썼어야 하는데
    특정 어떤 일을 할 시기에 대해 알 수 없어서 계속 체크를 해야 하는 방식을 말한다.
    =&gt; 원래 하던 일에 집중할 수 없다.</p>
</blockquote>
<br>

<h3 id="2-1-2-컨트롤러가-우선순위를-판별하는-방법">2-1-2. 컨트롤러가 우선순위를 판별하는 방법</h3>
<ul>
<li><p><strong>폴링 방식</strong>
사용자가 명령어를 사용해 입력 핀의 <strong>값을 계속 읽어</strong> 변화를 알아내는 방식
 =&gt; <strong>텍스트</strong> (하드웨어에 비해 속도 느림)</p>
</li>
<li><p><strong>인터럽트 방식</strong>
MCU 자체가 하드웨적으로 변화를 체크하여 변화 시에만 일정한 동작을 하는 방식</p>
</li>
</ul>
<blockquote>
<p>즉, <strong>&#39;인터럽트&#39;</strong>는 <span style="color:red"><strong>발생 시기를 예측하기 힘든 경우</strong></span>에 컨트롤러가 가장 <strong>빠르게 대응할 수 있는 방법</strong>
    =&gt; <span style="background-color:     #fff5b1"><strong>실시간 대응</strong></span>이 필요할 때는 필수적인 기능이다</p>
</blockquote>
<br>

<hr>
<br>


<h2 id="3-컨텍스트-스위칭--pcb">3. 컨텍스트 스위칭 &amp; PCB</h2>
<br>


<h3 id="3-1--컨텍스트-스위칭context-switching">3-1.  컨텍스트 스위칭(Context Switching)</h3>
<h4 id="◽-정의-부제-cpu는-쉴-수-없다">◽ (정의) 부제: cpu는 쉴 수 없다...</h4>
<p><strong>프로세스들의</strong> 상태 전이를 통해 <strong>현재 <span style="color:red">실행 중인 프로세스(또는 스레드)를 중지</strong>하고</span>, <strong>다음에 실행할 프로세스를 선택해서 &#39;CPU의 제어권&#39;을 넘겨주는 과정</strong></p>
<p>=&gt; 즉, 수행 중인 프로세스를 변경할 때, <span style="background-color:     #fff5b1"><strong>CPU의 레지스터 정보가 변경</strong></span>되는 것</p>
<blockquote>
<p>그래서 실시간으로 동시에 돌아가는 듯 보이지만 빠르게 교체해가면 cpu 상에서 돌아가고 있어서 그렇게 보이는 것이다.</p>
</blockquote>
<br>

<p>◽  ( <strong>문제점</strong> )
    각 <strong>독립된 메모리 영역을 할당받아 사용</strong>되므로, <strong>캐시 메모리 초기화</strong>와 같은 무거운 작업이 진행되었을 때 <span style="background-color:     #fff5b1"><strong>오버헤드</span>가 발생할 문제가 존재</strong></p>
<ul>
<li>📕** 해결법** :
  여러가지 <span style="background-color:     #fff5b1"><strong>스케줄링 알고리즘</strong></span>이 존재</li>
</ul>
<p>💡) <strong>&#39;스레드의 컨텍스트 스위치&#39;</strong>는 프로세스의 컨텍스트 스위칭과 다르게 &#39;<strong>캐시메모리&#39;를 비울 필요가 없어서 빠르다</strong></span></p>
<p><br><br></p>
<h3 id="3-2-pcb란-process-context-block">3-2. PCB란? (Process Context Block)</h3>
<blockquote>
</blockquote>
<p>** A. 컨텍스트 스위칭 때 이전 작업에 대한 내용을 기억하기 위해서</span> 무언가 필요하지 않을까...?🤷‍♂️🤷‍♂️💦**</p>
<p><img src="blob:https://velog.io/14baefce-df7f-4687-9e40-d631442d6c93" alt="업로드중.."></p>
<h4 id="정의">(정의)</h4>
<ul>
<li>운영체제가 컨텍스트 스위칭을 하기 위해서 프로세스의 정보를 저장해 놓는 곳</li>
<li>앞으로 다시 수행할 <strong>대기 중인 프로세스에 관한 저장 값을 PCB에 저장해두는 것</strong>
<span style="background-color:     #fff5b1"><strong>즉, 프로세스의 상태정보(메타 데이터)를 PCB에 저장하는 구조체</span>이다.</strong></li>
<li><strong>&#39;Linked List&#39; 방식</strong>으로 관리</li>
</ul>
<blockquote>
<ul>
<li><strong>PCB에 저장되는 정보 (메타데이터)</strong></li>
</ul>
</blockquote>
<ul>
<li>프로세스 식별자(Process ID, PID) : 프로세스 식별번호</li>
<li>프로세스 상태 : new, ready, running, waiting, terminated 등의 상태를 저장
프로그램 카운터 : 프로세스가 다음에 실행할 명령어의 주소</li>
<li>CPU 레지스터</li>
<li>CPU 스케쥴링 정보 : 프로세스의 우선순위, 스케줄 큐에 대한 포인터 등</li>
<li>메모리 관리 정보 : 페이지 테이블 또는 세그먼트 테이블 등과 같은 정보를 포함</li>
<li>입출력 상태 정보 : 프로세스에 할당된 입출력 장치들과 열린 파일 목록</li>
<li>어카운팅 정보 : 사용된 CPU 시간, 시간제한, 계정번호 등</li>
</ul>
<p><br><br></p>
<h3 id="3-3-컨텍스트-스위칭-순서">3-3. 컨텍스트 스위칭 순서</h3>
<p>컨텍스트 스위칭은 크게 다음과 같은 두 동작으로 구분할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/98303139-b231-4021-bc39-f84c37fec05c/image.png" alt=""></p>
<ol>
<li>실행 <strong>중지할 프로세스 정보</strong>를 해당 프로세스의 <strong>PCB에 업데이트</strong>하여 메인 메모리에 저장</li>
<li><strong>컨텍스트 스위칭</strong> </li>
<li><strong>다음 실행할 프로세스 정보를</strong> 메인 메모리에 있는 해당 PCB 정보를 CPU에 넣고 실행</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[cs - spring] Spring에서 cors를 해결하는 방법]]></title>
            <link>https://velog.io/@dabeen-jung/cs-spring-Spring%EC%97%90%EC%84%9C-cors%EB%A5%BC-%ED%95%B4%EA%B2%B0%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@dabeen-jung/cs-spring-Spring%EC%97%90%EC%84%9C-cors%EB%A5%BC-%ED%95%B4%EA%B2%B0%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Tue, 02 May 2023 10:02:32 GMT</pubDate>
            <description><![CDATA[<p><br><br></p>
<h2 id="cors란">CORS란?</h2>
<h4 id="◽-의미">◽ 의미</h4>
<p>CORS는 Cross-Origin Resource Sharing 의 줄임말로, 교차 출처 리소스 공유를 의미하며, 교차 출차는 ‘다른 출처’라고 생각하면 이해하기 쉽다. 
=&gt; 즉, 다른 출처 간의 자원을 공유하는 정책을 말한다.</p>
<p>이해가 잘 안가니 좀 더 살펴보자</p>
<br>

<h4 id="출처라는-것은">출처라는 것은</h4>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/d53fcf99-8abb-4a35-95c3-44e9fbce2cb9/image.png" alt=""></p>
<p>이런 식으로 url은 구성되어 있는데 
이 url의 구성요소 중 <strong>출처(Origin)는 Protocol과 Host, 그리고 :80 , :443 같은 포트 번호까지 모두 합친 것</strong>을 의미한다.</p>
<h4 id="cors는-출처가-다르기-때문에-발생한다">CORS는 출처가 다르기 때문에 발생한다.</h4>
<blockquote>
<ul>
<li>즉, SOP를 준수해야 한다.</li>
<li><blockquote>
<p>그대로 <strong>같은 출처만 허용한다</strong>는 정책을 의미한다.</p>
</blockquote>
</li>
</ul>
</blockquote>
<ul>
<li>과거에는 보안을 위해 엄격하게 같은 출처만 통신하도록 허용하였으나, <strong>최근</strong>에는 다른 출처에 있는 리소스를 가져와서 사용하는 일이 아주 흔하므로 SOP의 예외 조항인 CORS 정책을 두게 되었다.</li>
</ul>
<br>


<hr>
<h3 id="cors-해결-방법">CORS 해결 방법</h3>
<p>프론트엔드(ex. React)와 백엔드(ex. Spring)로 나누어 개발할 경우 CORS 이슈는 아주 흔하게 발생한다.** Spring을 사용하여 CORS 이슈를 해결하는 방법은 크게 3가지가 있다.**</p>
<br>

<h4 id="🚨-cors가-발생하였다">🚨 CORS가 발생하였다.</h4>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/e6b79e0a-7295-4875-b96f-cd8dadf9e9ac/image.png" alt=""></p>
<br>


<h3 id="1-crossorigin-사용">1. CrossOrigin 사용</h3>
<ul>
<li>CORS 정책을 설정해 줄 대상에 @CrossOrigin 어노테이션을 활용</li>
</ul>
<pre><code>@CrossOrigin(originPatterns = &quot;http://localhost:8080&quot;)
@RestController
public class LoginController {

    @GetMapping(&quot;/login&quot;)
    public String login() {
        return &quot;로그인 성공! ID: jayon, PW: 1234&quot;;
    }
}</code></pre><blockquote>
<p>위 쪽에 해당 어노테이션을 붙이고, <code>originPatters</code> 속성을 통해 <strong>요청을 허용할 출처</strong>를 적어준다.</p>
</blockquote>
<ul>
<li>그러나... 설정해야할 대상이 많아지면 코드가 점점 늘어나기에 간단하지만 비추..</li>
</ul>
<br>

<br>

<h3 id="2-webmvcconfigurer-설정">2. WebMvcConfigurer 설정</h3>
<pre><code>@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping(&quot;/**&quot;)
                .allowedOrigins(&quot;http://localhost:8080&quot;)
                .allowedMethods(HttpMethod.GET.name());
    }
}</code></pre><ul>
<li><code>WebMvcConfigurer</code>를 상속한 클래스를 만들고, <strong><code>addCorsMappings()</code> 를 재정의하면 된다.</strong><ul>
<li><code>addMapping()</code> 메소드를 통해 CORS 정책을 적용할 &#39;URL 패턴&#39;을 설정하고, <code>allowedOrigins()</code> 메소드를 통해 허용할 출처를 적어준다.</li>
</ul>
</li>
<li><blockquote>
<p>이 외에 allowedMethods() 메소드를 통해 GET, POST와 같은 HTTP 메소드의 종류도 제한할 수 있다. (구체적으로 가능)</p>
</blockquote>
</li>
</ul>
<p><br><br></p>
<h3 id="3-프록시-서버를-사용하자">3. 프록시 서버를 사용하자</h3>
<ul>
<li>400, 500번대와 같은 상태 코드를 반환하지 않고 200번 코드를 반환한다.</li>
</ul>
<pre><code>@Controller
public class UserController {

    @GetMapping(&quot;/api/view&quot;)
    public String view() {
        return &quot;/cors&quot;;
    }

    @GetMapping(&quot;/api/proxy&quot;)
    @ResponseBody
    public String proxyView() {
        String url = &quot;http://localhost:1000/login&quot;;

        RestTemplate restTemplate = new RestTemplate();
        return restTemplate.getForObject(url, String.class);
    }
}</code></pre><ul>
<li>CORS 이슈는 브라우저 단에서 서버의 Access-Control-Allow-Origin 값을 보고 방금 보낸 요청의 출처가 허용되는지 판단하고, 허용되지 않으면 발생한다고 이야기하였다.
=&gt; 즉, <strong>요청을 보내는 쪽에서 프록시 서버를 만들어 간접적으로 전달</strong>하면 응답을 받을 수 있다.</li>
</ul>
<p>그리고 이것을 &#39;localhost:8080/api/proxy&#39; 로 요청을 보내면 정상적으로 CORS 오류가 해결된 것을 확인할 수 있다.</p>
<h4 id="q-왜-된-것일까">Q. 왜 된 것일까?</h4>
<blockquote>
<p>A. 
RestTemplate를 통해 <strong>서버와 서버 간 통신을 하였으므로</strong> 
-&gt; 이를통해 CORS 이슈 없이 응답 데이터를 얻어올 수 있고, 브라우저 입장에서는 <strong>요청을 보낸 출처와 응답을 받은 출처가 같으므로</strong> 응답 데이터를 정상적으로 렌더링 할 수 있었다.</p>
</blockquote>
<p><br><br><br></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[cs - Java] Facade 패턴 (퍼사드 패턴)]]></title>
            <link>https://velog.io/@dabeen-jung/cs-Java-Facade-%ED%8C%A8%ED%84%B4-%ED%8D%BC%EC%82%AC%EB%93%9C-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@dabeen-jung/cs-Java-Facade-%ED%8C%A8%ED%84%B4-%ED%8D%BC%EC%82%AC%EB%93%9C-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Tue, 02 May 2023 08:45:24 GMT</pubDate>
            <description><![CDATA[<br>


<p><a href="https://dev-aiden.com/design%20pattern/Facade-Pattern/">이 글을 통해 작성하였습니다.</a></p>
<p><br><br><br></p>
<h2 id="facade-패턴">Facade 패턴?</h2>
<ul>
<li>디자인 패턴 중 목적의 <strong>&#39;구조패턴&#39;</strong>에 속한다.</li>
</ul>
<h4 id="◽-의미">◽ 의미</h4>
<ul>
<li>퍼사드 패턴(Facade Pattern)은 구조 패턴의 한 종류로, 서브시스템들의 공통적인 기능을 정의하는 단순화된 상위 수준의 인터페이스를 정의하는 패턴이다. </li>
</ul>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/bd34414f-97ad-40c7-aaab-a5f19c6a63fe/image.png" alt=""></p>
<ul>
<li><p>Facade : 사용자의** 요청을 서브시스템 객체에 전달<strong>하는 단순하고 **일관된 통합 인터페이스</strong></p>
</li>
<li><p>Subsystem Classes :** Facade에 대한 정보를 가지지 않고**, 서브시스템의 기능을 구현하는 클래스</p>
</li>
</ul>
<br>


<h4 id="-💡-구조패턴">+) 💡 구조패턴?</h4>
<blockquote>
<p>구조 패턴이란 <strong>작은 클래스들의 상속과 합성을 통해 더 큰 클래스를 생성</strong>하는 방법을 제공하는 패턴으로, <strong>독립적으로 개발한 클래스들을 마치 하나인 것처럼</strong> 사용할 수 있다.
ex) 어댑터 패턴, 가교 패턴, Composite 패턴, Decorator 패턴, Proxy 패턴 등</p>
</blockquote>
<br>


<h3 id="예제-코드">예제 코드</h3>
<h4 id="◽-상황">◽ 상황</h4>
<p>아침에 일어나서 사무실에 출근하기까지를 여러 과정으로 나눠볼 수 있다.
예를들어 씻고, 아침을 먹고, 대중교통을 타서 출근을 하는데, Facade Pattern을 이용하여 <strong>각각의 동작들을 서브클래스로 구현</strong>하고, <strong>서브클래스들의 공통 기능을 정의하는 &#39;상위 수준의 인터페이스&#39;를 정의</strong>할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/83a8e187-aa4d-434e-8cff-967a28de6371/image.png" alt=""></p>
<br>

<h4 id="-facade-정의">* Facade 정의</h4>
<pre><code>public class GoOffice {

    public void goToWork() {
        Wash wash = new Wash();
        Breakfast breakfast = new Breakfast();
        Move move = new Move();

        wash.brushTeeth();
        wash.shower();
        breakfast.eat();
        breakfast.water();
        move.bus();
    }
}</code></pre><br>

<h3 id="subsystem-classes">Subsystem Classes</h3>
<h4 id="wash-breakfast-move-등으로-3가지-서브시스템-클래스를-만들어주자">Wash, Breakfast, Move 등으로 3가지 서브시스템 클래스를 만들어주자.</h4>
<pre><code>//Wash.class
public class Wash {

    public void brushTeeth() {
        System.out.println(&quot;Brush my teeth&quot;);
    }

    public void shower() {
        System.out.println(&quot;Take a shower&quot;);
    }
}

//Breakfast.class
public class Breakfast {

    public void eat() {
        System.out.println(&quot;Have breakfast&quot;);
    }

    public void water() {
        System.out.println(&quot;Drink water&quot;);
    }
}



//Move.class
public class Move {

    public void bus() {
        System.out.println(&quot;Take the bus&quot;);
    }
}

</code></pre><p>이제 이것들을 테스트해보자</p>
<pre><code>
public class Client {

    public static void main(String[] args) {
        GoOffice goOffice = new GoOffice();
        goOffice.goToWork();
    }
}</code></pre><p><img src="https://velog.velcdn.com/images/dabeen-jung/post/de15c5d8-cdb8-46dd-b74f-83d34f303a48/image.png" alt=""></p>
<blockquote>
<p>이로써 작은 클래스들(서브시스템 클래스들)의 상속과 합성을 통해 더 큰 클래스를 생성한 것을 확인할 수 있었다.</p>
</blockquote>
<br>

<h3 id="특징">특징</h3>
<ul>
<li><p>낮은 결합도
  -&gt; <strong>클라이언트가 서브시스템의 코드를 모르더라도</strong> Facade 클래스를 통해 사용 가능</p>
</li>
<li><p>서브 클래스 직접 접근이 가능하다
  -&gt; Facade 클래스를 <strong>통해</strong> 서브클래스를 <strong>사용할지, 서브클래스를 직접 사용할지</strong> <em>선택 가능</em></p>
</li>
</ul>
<p><br><br></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[cs - Java ] Factory method 패턴 ]]></title>
            <link>https://velog.io/@dabeen-jung/cs-Java-Factory-method-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@dabeen-jung/cs-Java-Factory-method-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Tue, 02 May 2023 08:16:44 GMT</pubDate>
            <description><![CDATA[<br>


<p><a href="https://velog.io/@jamieshin/%ED%8C%A9%ED%86%A0%EB%A6%AC-%EB%A9%94%EC%86%8C%EB%93%9C-%ED%8C%A8%ED%84%B4Factory-Method-Pattern">이 글을 통해 작성하였습니다.</a></p>
<ul>
<li>GoF의 디자인 패턴(개정판) / 에릭 감마, 리처드 헬름, 랄프 존슨, 존 블라시디스 공저 / 김정아 역</li>
</ul>
<h2 id="팩토리-메소드-패턴">팩토리 메소드 패턴?</h2>
<ul>
<li>디자인 패턴 중 목적의 <strong>&#39;생성패턴&#39;</strong>에 속한다.</li>
</ul>
<h4 id="◽-의미">◽ 의미</h4>
<blockquote>
<ul>
<li>객체를 생성하기 위해 인터페이스를 만듭니다. <span style="color: red">어떤 클래스의 <strong>인스턴스를 만들지를 서브클래스에서 결정하도록</strong></span> 합니다.</li>
</ul>
</blockquote>
<ul>
<li><strong>팩토리 메소드를 이용하면 인스턴스를 만드는 일을 서브클래스로 미룰 수 있습니다.</strong></li>
<li>생성할 객체의 클래스를 국한하지 않고 객체를 생성</li>
</ul>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/43bd94bd-4fb7-47df-a737-e1196e43e4e3/image.png" alt=""></p>
<br>


<h3 id="어떤-상황에서-주로-쓸까">어떤 상황에서 주로 쓸까?</h3>
<ul>
<li>어떤 클래스가 <strong>자신이 생성해야 하는 객체의 클래스를 예측할 수 없을 때</strong></li>
<li>생성할 객체를 기술하는 책임을 자신의 서브클래스가 지정했으면 할 때</li>
<li>객체 생성의 책임을 몇 개의 보조 서브클래스 가운데 하나에게 위임하고, 어떤 서브클래스가 위임자인지에 대한 정보를 국소화시키고 싶을 때</li>
</ul>
<br>

<h3 id="예제">예제</h3>
<h4 id="다음은-피자를-주문하는-예제입니다">다음은 피자를 주문하는 예제입니다.</h4>
<p>1) 먼저 Creator 클래스인 <code>PizzaStore</code>를 만든다.
2) 이 클래스는 <strong><code>createPizza</code>라는 팩토리 메소드를 실행</strong>해서 pizza를 생성한다.</p>
<pre><code>public abstract class PizzaStore {
    public Pizza orderPizza(String type) {
        Pizza pizza = createPizza(type);

        pizza.prepare();
        pizza.bake();
        pizza.box();

        return pizza;
    }

    abstract Pizza createPizza(String type);
}</code></pre><br>

<ol start="3">
<li>PizzaStore 클래스를 확장해 각 지점을 만들고 지점마다 피자를 만드는 것을 책임지도록 <strong><code>createPizza 팩토리 메소드</code>를 오버라이딩</strong>한다.</li>
</ol>
<pre><code>//NYPizzaStore.class
public class NYPizzaStore extends PizzaStore {
    @Override
    Pizza createPizza(String item) {
        if (&quot;cheese&quot;.equals(item)) {
            return new NYStyleCheesePizza();
        } else if (&quot;veggie&quot;.equals(item)) {
            return new NYStyleVeggiePizza();
        } else if (&quot;clam&quot;.equals(item)) {
            return new NYStyleClamPizza();
        } else {
            return null;
        }
    }
}


//ChicagoPizzaStore.class
public class ChicagoPizzaStore extends PizzaStore {
    @Override
    Pizza createPizza(String item) {
        if (&quot;cheese&quot;.equals(item)) {
            return new ChicagoStyleCheesePizza();
        } else if (&quot;veggie&quot;.equals(item)) {
            return new ChicagoStyleVeggiePizza();
        } else if (&quot;clam&quot;.equals(item)) {
            return new ChicagoStyleClamPizza();
        } else {
            return null;
        }
    }
}


</code></pre><br>

<ol start="4">
<li>Product 클래스인 Pizza 를 만들고 <strong>이 클래스를 확장해 구상 클래스를 만들어보자</strong>.</li>
</ol>
<pre><code>public abstract class Pizza {
    String name;
    String dough;
    String sauce;

    void prepare() {
        System.out.println(&quot;preparing~~ &quot; + name);
    }

    void bake() {
        System.out.println(&quot;baking~~&quot;);
    }

    void box() {
        System.out.println(&quot;boxing~~&quot;);
    }

    public String getName() {
        return name;
    }
}</code></pre><br>


<ol start="5">
<li><code>Product 클래스</code>인 <strong><code>Pizza</code>를 확장</strong>하여 3가지의 시카고 스타일 피자를 만들었다.</li>
</ol>
<pre><code>
//1. 치즈피자
public class ChicagoStyleCheesePizza extends Pizza {
    public ChicagoStyleCheesePizza() {
        name = &quot;ChicagoStyleCheesePizza&quot;;
    }
}

//2. clam 피자
public class ChicagoStyleClamPizza extends Pizza {
    public ChicagoStyleClamPizza() {
        name = &quot;ChicagoStyleClamPizza&quot;;
    }
}


//3. Veggie피자
public class ChicagoStyleVeggiePizza extends Pizza {
    public ChicagoStyleVeggiePizza() {
        name = &quot;ChicagoStyleVeggiePizza&quot;;
    }
}

</code></pre><br>

<ol start="6">
<li>main 메소드에서 예제를 실행해보자.</li>
</ol>
<pre><code>PizzaStore nyStore = new NYPizzaStore();
PizzaStore chicagoStore = new ChicagoPizzaStore();

Pizza nyCheesePizza = nyStore.orderPizza(&quot;cheese&quot;);
Pizza nyClamPizza = nyStore.orderPizza(&quot;clam&quot;);

Pizza chicagoCheesePizza = chicagoStore.orderPizza(&quot;cheese&quot;);
Pizza chicagoClamPizza = chicagoStore.orderPizza(&quot;clam&quot;);</code></pre><ul>
<li>결과</li>
</ul>
<pre><code>preparing~~ NYStyleCheesePizza
baking~~
boxing~~
preparing~~ NYStyleClamPizza
baking~~
boxing~~
preparing~~ ChicagoStyleCheesePizza
baking~~
boxing~~
preparing~~ ChicagoStyleClamPizza
baking~~
boxing~~</code></pre><blockquote>
<p>지점과 주어진 타입(cheeze, clam)에 따라서 다른 피자를 만드는 것을 확인할 수 있다.</p>
</blockquote>
<p><br><br></p>
<h3 id="장점과-단점">장점과 단점</h3>
<h4 id="장점">장점</h4>
<ul>
<li>팩토리 메서드 패턴은 응용프로그램에 국한된 클래스가 코드에 종속되지 않도록 해준다</li>
<li>응용프로그램은 Product 클래스에 정의된 인터페이스와만 동작하도록 코드가 만들어지기 때문에, 사용자가 정의한 어떤 ConcreteProduct 클래스가 와도 동작할 수 있다.</li>
<li>SRP
  -&gt; 객체는 단 하나의 책임만 가져야 한다는 원칙</li>
<li>OCP
  -&gt; 개방 폐쇄 원칙
  =&gt; &quot;기능을 변경하거나 확장할 수 있으면서 그 기능을 사용하는 코드는 수정하지 않는다.&quot;</li>
</ul>
<h4 id="단점">단점</h4>
<ul>
<li>패턴 구현에 의한 코드가 복잡해질 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[cs - Java] Builder 패턴]]></title>
            <link>https://velog.io/@dabeen-jung/cs-Java-Builder-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@dabeen-jung/cs-Java-Builder-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Tue, 02 May 2023 07:31:05 GMT</pubDate>
            <description><![CDATA[<br>


<p><a href="https://velog.io/@midas/Builder-%ED%8C%A8%ED%84%B4-%ED%95%84%EC%9A%94%EC%84%B1%EA%B3%BC-%EC%82%AC%EC%9A%A9%EB%B2%95">이 글을 통해 작성하였습니다.</a></p>
<h2 id="빌더-패턴">빌더 패턴?</h2>
<h4 id="◽-의미">◽ 의미</h4>
<blockquote>
<p>복잡한 Object들을 단계별로 구축할 수 있는 <strong>생성 디자인 패턴</strong></p>
</blockquote>
<ul>
<li>이를 이용하면 동일한 구성코드를 사용해 <strong>다양한 타입과 표현을 제공</strong>한다.
=&gt; 즉 생성자를 가독성 있게 만들어주는 도구라고 생각하자.</li>
</ul>
<br>

<h4 id="그렇다면-보통-다들-생성자-말고-setter를-쓰면-어떤가">그렇다면 보통 다들 생성자 말고 Setter를 쓰면 어떤가?</h4>
<p>라는 생각을 할 수도 있을텐데 Setter를 쓰면 가독성은 좋지만 다른 문제가 생긴다.</p>
<h3 id="q-setter를-지양하는-이유">Q. Setter를 지양하는 이유?</h3>
<h3 id="1-의도-파악이-어렵다">1. 의도 파악이 어렵다.</h3>
<p>객체의 값을 바꾼다는 것은 보통 비즈니스 로직을 위해서 바꾸지만 Setter를 이용하는 경우에선 무슨 의도를 가지고 하였는지 알 수 없다.</p>
<h4 id="-이-의도를-명확히-할-수-있는-함수를-만들자">=&gt; 이 의도를 명확히 할 수 있는 함수를 만들자</h4>
<br>


<h3 id="2-객체의-일관성을-유지하기-어렵다">2. 객체의 일관성을 유지하기 어렵다.</h3>
<p><strong>Setter</strong>를 쓰게 된다면, 객체 하나를 만들기 위해서 함수를 여러개 호출해야되고,
<strong>객체가 완전히 생성되기 전까지는 일관성이 무너진 상태에</strong> 놓이게 된다.</p>
<ul>
<li>Setter는 <strong>public으로 변경이 용이</strong>하다
  -&gt; 즉 어디서든 변경이 이루어질 수 있는 위험이 생긴다.
  -&gt; 객체의 일관성을 유지하기 어렵다.😥
  -&gt; final 키워드로 제한을 주면 되는거 아닌가? A. 굳이 그렇게 할거면 생성자에서 값을 설정하고 Setter를 만들 필요가 있을까?</li>
</ul>
<br>

<h3 id="결론은">결론은</h3>
<p>이런 이유 때문에 빌더 패턴이 필요하고 권장하고 있다.</p>
<p>⚡️ 이펙티브 자바 책에서도 아래와 같이 이야기 한다.</p>
<blockquote>
<p><strong>생성자나 정적 팩터리가 처리해야 할 매개변수가 많다면 빌더 패턴을 선택하는 게 더 낫다</strong></p>
</blockquote>
<p><br><br></p>
<h3 id="2-빌더-패턴-사용-방법">2. 빌더 패턴 사용 방법</h3>
<p>기본적으로 <code>@Builder</code> 어노테이션을 사용하면 간단히 사용할 수 있다.</p>
<br>

<ul>
<li>클래스 전체에서 적용</li>
</ul>
<pre><code>@Getter @Builder // ✨ 클래스 전체 필드를 빌더로 사용 가능!
public class UserLombok {

  private Long id;
  private String email;
  private String password;
  private String name;
}

// 사용예제
public User join(String email, String password, String name) {
  UserLombok build = UserLombok.builder()
            .email(email)
            .password(password)
            .name(name)
            .build();
  ...
}</code></pre><br>

<ul>
<li>특정 생성자에서 적용</li>
</ul>
<pre><code>@Getter
public class UserLombok {

  private Long id;
  private String email;
  private String password;
  private String name;

  @Builder // ✨ 빌더는 email, password만 사용 가능
  public UserLombok(String email, String password) {
    this.email = email;
    this.password = password;
  }

  public UserLombok(Long id, String email, String password, String name) {
    this.id = id;
    this.email = email;
    this.password = password;
    this.name = name;
  }
}

// 사용예제 - email, password만 가능!
public User join(String email, String password, String name) {
  UserLombok build = UserLombok.builder()
            .email(email)
            .password(password)
            .build();
  ...
}</code></pre><p><br><br></p>
<p><br><br></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[cs - spring] Spring에서의 POJO란]]></title>
            <link>https://velog.io/@dabeen-jung/cs-spring-Spring%EC%97%90%EC%84%9C%EC%9D%98-POJO%EB%9E%80</link>
            <guid>https://velog.io/@dabeen-jung/cs-spring-Spring%EC%97%90%EC%84%9C%EC%9D%98-POJO%EB%9E%80</guid>
            <pubDate>Tue, 02 May 2023 06:32:28 GMT</pubDate>
            <description><![CDATA[<h4 id="q">Q.</h4>
<p> POJO란 무엇인가요? <strong>Spring Framework에서 POJO는 무엇</strong>이 될 수 있을까요?</p>
<br>

<p><a href="https://dev-coco.tistory.com/82">이 글을 참고하여 작성하였습니다.</a></p>
<p><a href="https://velog.io/@backtony/Spring-AOP-%EC%B4%9D%EC%A0%95%EB%A6%AC">이 글을 참고하여 작성하였습니다.</a></p>
<h4 id="a">A.</h4>
<p>진정한 POJO란 토비의 스프링에서는 진정한 POJO를 아래와 같이 정의했다고 합니다.
그럼 특정 기술규약과 환경에 종속되지 않으면 모두 POJO라고 말할 수 있는가?
많은 개발자가 크게 오해하는 것 중의 하나가 바로 이것이다. . .(중략). .</p>
<p>&quot; <strong>진정한 POJO란 ¹객체지향적인 원리에 충실하면서, ²환경과 기술에 종속되지 않고
필요에 따라 ³재활용될 수 있는 방식으로 설계된 오브젝트를 말한다.</strong> &quot;</p>
<br>

<p>POJO란 개념에 대해서 먼저 말해보자</p>
<h3 id="1-pojoplain-old-java-object가-탄생하게-된-이유">1. POJO(Plain Old Java Object)가 탄생하게 된 이유</h3>
<p>위키백과에서는 이를 이렇게 정의한다.</p>
<blockquote>
<p>Plain Old Java Object, 간단히 POJO는 말 그대로 해석을 하면 <strong>오래된 방식의 간단한 자바 오브젝트</strong>라는 말로서 Java EE 등의 중량 프레임워크들을 사용하게 되면서 <strong>해당 프레임워크에 종속된 &quot;무거운&quot; 객체를 만들게 된 것에 반발해서 사용되게 된 용어</strong>이다.</p>
</blockquote>
<p>이렇게 된 자바 코드는 과연 가독성이 좋을까? 
당연히 아니다. <strong>가독성이 떨어지고 유지보수성도 좋지 않고 물론 확장성 또한 떨어진다.</strong></p>
<p>그래서 POJO라는 개념이 생겼다고 한다.</p>
<pre><code>public class MyPojo {
    private String name;
    private int age;
    
    public String getName() {
        return name;
    }
    public String getAge() {
        return age;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(int age) {
        this.age = age;
    }
}</code></pre><ul>
<li>위와 같이 가장 기본적인 형태의 Java 객체를 POJO라 한다.</li>
</ul>
<h4 id="이게-무슨-말일까-🤔">이게 무슨 말일까?? 🤔</h4>
<p>EJB 등에서 사용되는 Java Bean이 아닌 Getter, Setter로 구성된 가장 기본이 되는 순수한 형태의 기본 클래스를 POJO라고 한다. </p>
<h4 id="그러나-여기서도-문제가-있었다">그러나 여기서도 문제가 있었다.</h4>
<p>스프링이 등장하기 이전에는 EJB가 자바 엔터프라이즈 애플리케이션 개발 시장을 독점하고 있었다. 하지만 EJB에는 치명적인 단점이 있었으니....</p>
<blockquote>
<p>&quot; EJB(Enterprise Java Beans)란 자바 개발에 있어 <strong>로우개발에 신경을 안쓰고 어플리케이션을 쉽게 만들어 준 기술이다. 그러나 EJB는 객체지향성을 감소시키는 단점을 가지고 있었다.</strong>&quot;</p>
</blockquote>
<p>즉, import 선언문부터 implenets, 인스턴스 변수까지 코드가 EJB에 완전히 종속되는 것을 볼 수 있었다.</p>
<br>

<p>EJB를 사용과 규모가 큰 프로그램이 많아지면서 특정 기술과 환경에 종속되어 자바 코드는 가독성도 유지보수성도 떨어졌고, 특정 기술의 클래스를 상속받거나 혹은 직접 의존을 하게 되면서 객체지향성을 잃어갔다. 
그래서 순수한 객체지향성이 짙었던 이전으로 돌아가자는 취지로 POJO를 개발하게 되었다.</p>
<p><br><br></p>
<h3 id="2-pojo-프레임워크">2. POJO 프레임워크</h3>
<blockquote>
<p>POJO 프레임워크 =  POJO를 사용하는 장점 + EJB에서 제공하는 엔터프라이즈 서비스와 기술
ex) 하이버네이트, 스프링</p>
</blockquote>
<br>

<h3 id="2-1-하이버네이트">2-1. 하이버네이트?</h3>
<ul>
<li><strong>Persistence 기술과 오브젝트-관계형 DB 매핑을 순수한 POJO를 이용해 사용할 수 있게</strong> 하는 POJO 기반의 Persistence 프레임워크.
  -&gt; JDBC API를 직접 사용해 개발하는 것 못지않은 <strong>성능</strong>과 <strong>복잡한 퍼시스턴스 로직을 개발 가능하게</strong> 해주었다</li>
<li>하이버네이트가 사용하는 POJO 엔티티들은 <strong>객체지향적인 다양한 설계와 구현이 가능</strong>하다</li>
</ul>
<br>

<h4 id="q-특정-기술에-종속적인-것은-pojo가-아니지-않나요">Q. 특정 기술에 종속적인 것은 POJO가 아니지 않나요?</h4>
<p>A. 스프링에서 하이버이트를 사용하지 않나? 
라고 생각할텐데 어떻게 새로운 엔터프라이즈 기수를 도입하면서도 POJO를 이용한 것일까??</p>
<blockquote>
<p>바로 스프링에서 ORM이라는 기술을 사용하기 위해 <strong>JPA라는 표준 인터페이스를 정했기 때문</strong>이다.</p>
</blockquote>
<ul>
<li>그래서 ORM 프레임워크들은 이 JPA라는 표준 인터페이스 아래에서 안전적으로 구현되어 돌아가고 있다!
=&gt; 이런 방법을 <strong>스프링의 PSA라고 한다.</strong></li>
</ul>
<br>

<h3 id="2-2-스프링">2-2. 스프링</h3>
<ul>
<li>엔터프라이즈 서비스를 POJO 기반으로 만든 비즈니스 오브젝트에서 사용할 수 있게 한다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/bf3e2269-7ba7-4e8b-84bd-76bc56109cf9/image.png" alt=""></p>
<ul>
<li>IoC 컨테이너를 제공하여 인스턴스들의 라이프 사이클을 관리</li>
<li>특정 인터페이스를 구현하거나 상속할 필요가 없고 <strong>라이브러리를 지원</strong>하기에 용이 및 객체 또한 가벼운 것이 특징</li>
<li>스프링의 주요 기술인 Ioc/DI, AOP, PSA는 애플리케이션을 POJO로 개발할 수 있게 해주는 가능하게 한다.</li>
</ul>
<h4 id="aop">AOP??</h4>
<blockquote>
<p>AOP(Aspect-Oriented Programming)는 <strong>핵심 로직과 부가 기능을 분리</strong>하여 애플리케이션 전체에 걸쳐 사용되는 <strong>부가 기능을 모듈화하여 재사용할 수 있도록 지원</strong>하는 것 </p>
</blockquote>
<ul>
<li>AOP는 <strong>공통된 기능을 재사용하는 기법</strong> 입니다.
  -&gt; 기존의 OOP에서는 공통된 기능들을 재사용하기 위해 상속이나 위임을 썼다 😥
ex) 모니터링 및 로깅, 동기화, 오류 검사 및 처리, 성능 최적화(캐싱) 등</li>
</ul>
<p><br><br></p>
<hr>
<h3 id="3-pojo-프로그래밍의-가치">3. POJO 프로그래밍의 가치</h3>
<h4 id="pojo-기반의-코드인지를-확인하는-두-가지-기준">POJO 기반의 코드인지를 확인하는 두 가지 기준</h4>
<h4 id="1-객체지향적으로-설계-되었는가">1. 객체지향적으로 설계 되었는가?</h4>
<ul>
<li>반복적인 템플릿 코드와 테스트하기 힘든 구조인가
  -&gt; 확장 및 재활용의 어려움이 남아있다면 EJB의 문제점을 여전히 안고 있는 것</li>
</ul>
<h4 id="2-테스트가-용이한가">2. 테스트가 용이한가?</h4>
<ul>
<li>자동화된 테스트 코드 작성이 편리해야 한다.
  -&gt; 코드 작성이 편리하면 좀 더 꼼꼼하게 만들게 되고, 코드 검증과 품질 향상에 좋다.</li>
</ul>
<p><br><br><br></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[cs - spring] 1개의 Controller가 어떻게 Thread들의 요청을 수행하는건가?]]></title>
            <link>https://velog.io/@dabeen-jung/cs-spring</link>
            <guid>https://velog.io/@dabeen-jung/cs-spring</guid>
            <pubDate>Tue, 02 May 2023 04:49:18 GMT</pubDate>
            <description><![CDATA[<h4 id="q">Q.</h4>
<p>Spring Web MVC에서 <strong>요청 마다 Thread가 생성되어 Controller를 통해 요청을 수행</strong>할텐데, <strong><em>어떻게 1개의 Controller만 생성</em></strong> 될 수 있을까요?</p>
<br>

<p><a href="https://velog.io/@ejung803/Spring-Web-MVC%EC%97%90%EC%84%9C-%EC%9A%94%EC%B2%AD-%EB%A7%88%EB%8B%A4-Thread%EA%B0%80-%EC%83%9D%EC%84%B1%EB%90%98%EC%96%B4-Controller%EB%A5%BC-%ED%86%B5%ED%95%B4-%EC%9A%94%EC%B2%AD%EC%9D%84-%EC%88%98%ED%96%89%ED%95%A0%ED%85%90%EB%8D%B0-%EC%96%B4%EB%96%BB%EA%B2%8C-1%EA%B0%9C%EC%9D%98-Controller%EB%A7%8C-%EC%83%9D%EC%84%B1%EB%90%A0-%EC%88%98-%EC%9E%88%EC%9D%84%EA%B9%8C%EC%9A%94">이 글을 참고하여 작성하였습니다.</a></p>
<h4 id="a">A.</h4>
<p><strong>생성한 Controller 클래스에 대한 정보가</strong> JVM 메모리 영역 중** Method Area(메서드 영역)에 올라가기 때문**입니다.</p>
<p>Controller <em>객체는 Heap(힙)에 생성</em> 되지만, 해당 클래스의 정보(메소드 처리 로직, 명령들)는 Method Area(메서드 영역)에 생성 됩니다.</p>
<p>따라서 <strong>결국 모든 Thread가 객체의 메서드를 공유할 수 있기 때문</strong>에 Controller는 1개만 생성됩니다.</p>
<br>

<h3 id="그렇다면-controller-1개로-여러가지의-요청을-어떻게-다-처리한다는건가">그렇다면 Controller 1개로 여러가지의 요청을 어떻게 다 처리한다는건가?</h3>
<p>그렇게 되면 의문이 생길 수 있다. 애초에 요청별로 Thread가 따로 생성된다고 했는데 그렇다면 이에 따라서 ServletContext를 가진다는 것이다.
어떻게 Controller가 1개만 생성되는 것이고 어떻게 처리를 한다는 것일까? 🤔</p>
<br>

<h4 id="1-싱글톤">1. 싱글톤</h4>
<p>이 Thread들은 실상 싱글톤으로 생성된 Bean들을 참고하여 일을 한다.
    -&gt; 즉 이 <strong>Bean들은 기본적으로 Singleton으로 생성 및 관리</strong>된다.</p>
<ul>
<li>이 Thread들은 1개의 Singleton Controller 객체를 공유한다.
=&gt;** 최종적으로 공유를 통해 1개의 Controller만 사용하는 것이다.**</li>
<li>곧 이 하나의 Singleton Controller가 힘겹게 <del>들어오는 수많은 요청들을 처리하는 것이 아닌</del>, <strong>각각의 Thread가 singleton으로 생성된 1개의 Controller를 참고하여 실행한다고 보면</strong> 되는 것 </li>
</ul>
<br>

<h4 id="2-controller가-저장되는-곳">2. Controller가 저장되는 곳</h4>
<ul>
<li>Controller 객체는 Heap에 생성된다.</li>
<li><blockquote>
<p>그러나 해당 class에 대한 정보는 Heap이 아닌 <strong>Method Area(메서드 영역)에 저장</strong>된다.</p>
</blockquote>
</li>
<li>메소드 영역으로 모든 Thread가 접근이 가능하다.
  -&gt; 이로인해 객체의 Binary Code정보를 공유할 수 있다. 
  =&gt; <span style='background-color:#fff5b1'>Controller를 Thread들이 참고할 수 있다 </span></li>
</ul>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/69f8ac7a-4cfb-4a86-9bc1-70537b832450/image.png" alt=""></p>
<br>

<h4 id="3-동기화를-하지-않아도-된다">3. 동기화를 하지 않아도 된다.</h4>
<p>공유되는 정보를 이용하고자 Controller 객체를 사용하는 Thread나 Controller 객체 자체를 동기화를 굳이할 필요가 없다.</p>
<ul>
<li>원래 동기화를 해주는 이유는 프로세스(Thread)들간 알고있는 정보(상태)를 일치하기 위해서인데, <strong>Controller가 내부적으로 상태를 갖는 것이 없으니</strong>, 그냥 메소드 호출만 하면 된다.
  → 공유하는 데이터
  =&gt; 즉, <strong>클래스변수, 전역변수를 컨트롤러에서 사용하지 않기 때문에 상태를 갖는 것이 ❌</strong>
  =&gt; 굳이 동기화가 필요 없네? A. 처리 로직만 공유되어 사용한다.</li>
</ul>
<p><strong>결론은 Thread는 Controller 객체의 메소드를 공유하고, 제각각 호출</strong>하기만 하면 되기 때문에 굳이 동기화가 필요가 없다.</p>
<br>



<h3 id="결론">결론</h3>
<p>그렇기 때문에 1개의 Controller를 이용해서 요청 마다 Thread가 생성되어 해당 요청들을 수행할 수 있었다.</p>
<p>💡 이럴 수 있었던 이유들은 ¹<strong>싱글톤</strong>으로 Bean들이 관리되었고, ² Bean이 상태정보를 가지지 않았기 때문에 Thread들 간에 동기화가 필요없었던 것이였다.</p>
<h4 id="만약-bean이-상태정보를-가졌다면">만약 Bean이 상태정보를 가졌다면?</h4>
<p>그렇다면 Thread간의 동기화를 통해 상태정보 업데이트가 필요했을 것이다. 그리고 이로인해 오버헤드가 발생했을 것이다.
=&gt; 결론적으로 Controller 객체 1개만을 이용해 컨테이너에서 단순히 꺼내쓰던 장점이 사라졌을 것이다.</p>
<p><br><br><br></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[cs - Spring] Spring시작 로딩 시점에 로직 실행 하는 방법]]></title>
            <link>https://velog.io/@dabeen-jung/cs-Spring-Spring%EC%8B%9C%EC%9E%91-%EB%A1%9C%EB%94%A9-%EC%8B%9C%EC%A0%90%EC%97%90-%EB%A1%9C%EC%A7%81-%EC%8B%A4%ED%96%89-%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@dabeen-jung/cs-Spring-Spring%EC%8B%9C%EC%9E%91-%EB%A1%9C%EB%94%A9-%EC%8B%9C%EC%A0%90%EC%97%90-%EB%A1%9C%EC%A7%81-%EC%8B%A4%ED%96%89-%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Tue, 02 May 2023 00:37:18 GMT</pubDate>
            <description><![CDATA[<h2 id="spring시작-로딩-시점에-로직-실행-하는-방법">Spring시작 로딩 시점에 로직 실행 하는 방법</h2>
<p><a href="https://recordsoflife.tistory.com/252">출처</a>
<a href="https://sgc109.github.io/2020/07/09/spring-running-startup-logic/">출처2</a>에서 관련하여 글을 작성하였습니다.</p>
<p><br><br></p>
<h3 id="들어가기-전">들어가기 전...</h3>
<p><strong>Spring 애플리케이션 시작 중 / 후에 로직을 실행하는 것</strong>은 일반적인 시나리오이지만 <strong>여러 문제를 일으키는 시나리오</strong>다.</p>
<p>IoC의 이점을 얻으려면 당연히 컨테이너로가는 애플리케이션의 흐름에 대한 부분적인 제어를 포기해야한다. 이것이 바로 인스턴스화, 시작시 로직 설정 등에 특별한 주의가 필요한 이유이다.</p>
<p>빈의 생성자에 로직을 포함 시키거나 객체의 인스턴스화 후에 메서드를 호출 할 수는 없다. 우리는 그 과정에서 통제권을 가지고 있지 않다.</p>
<pre><code>@Component
public class InvalidInitExampleBean {

    @Autowired
    private Environment env;

    public InvalidInitExampleBean() {
        env.getActiveProfiles();
    }
}</code></pre><blockquote>
<p>생성자가 호출될 때 Spring Bean은 완전히 초기화 되지 않았으며 이로 인해 NullPointerException의 문제가 필드를 초기화 하는 이 과정에서 발생하게 됩니다.</p>
</blockquote>
<p>스프링에서는 이러한 상황을 해결하면서 동시에 Spring 시작 로딩 때 로직 실행 하는 방법에 아래와 같은 방법들을 제공합니다.</p>
<p><br><br></p>
<hr>
<br>


<h3 id="2-1-postconstruct-어노테이션">2-1. @PostConstruct 어노테이션</h3>
<p>Javax의 <code>@PostConstruct</code> 어노테이션은 특정 클래스의 메소드에 붙여서 <strong>해당 클래스의 객체 내 모든 의존성(Bean) 들이 초기화 직후 한 번 실행되어야하는 메소드</strong>에 어노테이션을 작성하는 데 사용할 수 있다 . </p>
<h4 id="주입-할-것이-없더라도-어노테이션이-달린-메서드는-spring에-의해-항상-실행된다는-점을-명심하자">주입 할 것이 없더라도 어노테이션이 달린 메서드는 Spring에 의해 항상 실행된다는 점을 명심하자.</h4>
<pre><code>@Component
public class PostConstructExampleBean {

    private static final Logger LOG 
      = Logger.getLogger(PostConstructExampleBean.class);

    @Autowired
    private Environment environment;

    @PostConstruct
    public void init() {
        LOG.info(Arrays.asList(environment.getDefaultProfiles()));
    }
}</code></pre><blockquote>
<ul>
<li><code>NullPointerException</code>을 발생 시키지 않고 <code>@PostConstruct</code> 어노테이션이 달린 메서드 에서 호출 되었음을 알 수 있다 .</li>
</ul>
</blockquote>
<ul>
<li><code>init()</code> 메소드는 클래스 내 의존성인 <strong>environment 가 초기화 된 직후</strong>에 호출되기 때문에 동작이 정상적으로 이뤄진다.</li>
</ul>
<p><br><br></p>
<h3 id="2-2-initializingbean-인터페이스">2-2. InitializingBean 인터페이스</h3>
<p>이 방식은 어노테이션을 붙이는 대신 <code>InitializingBean 인터페이스</code>와 <code>afterPropertiesSet()</code> 메소드를 구현한다는 것 말곤
앞서 설명한 <strong><code>@PostConstruct</code> 방식과 유사하게 동작</strong>한다.</p>
<pre><code>@Component
public class InitializingBeanExampleBean implements InitializingBean {

    private static final Logger LOG 
      = Logger.getLogger(InitializingBeanExampleBean.class);

    @Autowired
    private Environment environment;

    @Override
    public void afterPropertiesSet() throws Exception {
        LOG.info(Arrays.asList(environment.getDefaultProfiles()));
    }
}</code></pre><br>

<h3 id="2-3-applicationlistener">2-3. ApplicationListener</h3>
<p>이 접근법은 로직을 실행하는 데 사용할 수 있어 
앞서 설명한 방식처럼 특정 Bean에 초점을 맞추지 않고  Spring 컨텍스트가 초기화가 완료된 후, <strong>즉 모든 Bean 의 초기화가 완료된 후에 실행되도록 하는 방식이다</strong></p>
<p><code>ApplicationListener 인터페이스</code>를 구현하는 Bean 을 정의하고 <code>onApplicationEvent()</code> 메소드를 Override 하여, 그 안에 원하는 로직을 작성하면 된다.</p>
<pre><code>@Component
public class StartupApplicationListenerExample implements 
  ApplicationListener&lt;ContextRefreshedEvent&gt; {

    private static final Logger LOG 
      = Logger.getLogger(StartupApplicationListenerExample.class);

    public static int counter;

    @Override public void onApplicationEvent(ContextRefreshedEvent event) {
        LOG.info(&quot;Increment counter&quot;);
        counter++;
    }
}</code></pre><br>

<h3 id="2-4-bean-의-initmethod-속성">2-4. @Bean 의 initMethod 속성</h3>
<p><code>@Bean</code> 어노테이션의 <code>initMethod</code> 속성으로 <strong>이 Bean 의 초기화가 완료(의존성이 모두 주입)된 뒤에 실행 되어야 할 Bean 내 메소드의 이름을 지정할 수가 있다.</strong>
예를 들어 다음과 같은 Bean 이 있다고 가정하자.</p>
<pre><code>public class InitMethodExampleBean {

    private static final Logger LOG = Logger.getLogger(InitMethodExampleBean.class);

    @Autowired
    private Environment environment;

    public void init() {
        LOG.info(Arrays.asList(environment.getDefaultProfiles()));
    }
}</code></pre><p>이 때, @Bean 메소드에 initMethod 속성으로 &#39;InitMethodExampleBean&#39; <strong>Bean 내의 메소드인 <code>init()</code> 의 이름을 설정해준다.</strong></p>
<pre><code>@Bean(initMethod=&quot;init&quot;)
public InitMethodExampleBean exBean() {
    return new InitMethodExampleBean();
}</code></pre><p><br><br></p>
<h3 id="2-5-spring-boot-의-commandlinerunner">2-5. Spring Boot 의 CommandLineRunner</h3>
<p>스프링 부트는 <code>run()</code> 이라는 콜백 메소드를 가진 <strong><code>CommandLineRunner</code> 라는 인터페이스를 제공</strong>한다.</p>
<p><code>run()</code> 메소드는 Spring application context 의 초기화가 완료된(모든 Bean 이 초기화된) <strong>후에 실행</strong>되므로 <strong>이 안에 원하는 로직을 작성</strong>하면 된다.</p>
<pre><code>@Component
public class CommandLineAppStartupRunner implements CommandLineRunner {
    private static final Logger LOG =
      LoggerFactory.getLogger(CommandLineAppStartupRunner.class);

    public static int counter;

    @Override
    public void run(String...args) throws Exception {
        LOG.info(&quot;Increment counter&quot;);
        counter++;
    }
}</code></pre><blockquote>
<p>참고로 CommandLineRunner Bean 은 같은 <strong>애플리케이션 컨텍스트 내에 여러개를 정의할 수 있으며</strong>,
Ordered 인터페이스, 혹은 <code>@Order</code> 어노테이션으로 <em>실행 순서를 정해줄 수도 있다</em>.</p>
</blockquote>
<br>


<ul>
<li><p><code>@Component</code> 가 아니라 다음과 같이 <code>@Configuration</code> 과 <code>@Bean</code> 을 사용한 방식으로도 정의할 수 있다.</p>
<pre><code>@SpringBootApplication
public class Application {

  public static void main(String[] args) {
      SpringApplication.run(Application.class, args);
  }

  @Bean
  public CommandLineRunner run(UserRepository userRepository) throws Exception {
      return (String[] args) -&gt; {
          User user1 = new User(&quot;John&quot;, &quot;john@domain.com&quot;);
          User user2 = new User(&quot;Julie&quot;, &quot;julie@domain.com&quot;);
          userRepository.save(user1);
          userRepository.save(user2);
          userRepository.findAll().forEach(user -&gt; System.out.println(user));
      };
  }
}</code></pre></li>
</ul>
<br>


<h3 id="2-6-spring-boot-의-applicationrunner">2-6. Spring Boot 의 ApplicationRunner</h3>
<p>스프링 부트는 앞서 언급한 CommandLineRunner 인터페이스 외에 ApplicationRunner 인터페이스도 제공한다.
동일하게 <code>run()</code> 이라는 콜백 메소드를 가지고 있어 <strong>이 안에 원하는 로직을 작성</strong>하면 된다.</p>
<p>+) 참고로 <code>run()</code> 메소드로 들어오는 문자열들은 커맨드 라인으로 앱을 실행할 때 들어온 명령행 인자들이다.</p>
<pre><code>@Component
public class AppStartupRunner implements ApplicationRunner {
    private static final Logger LOG =
      LoggerFactory.getLogger(AppStartupRunner.class);

    public static int counter;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        LOG.info(&quot;Application started with option names : {}&quot;, 
          args.getOptionNames());
        LOG.info(&quot;Increment counter&quot;);
        counter++;
    }
}</code></pre><h4 id="commandlinerunner-와-차이">CommandLineRunner 와 차이?</h4>
<blockquote>
<p>run() 메소드의 인자가 String 가 아니라 ApplicationArguments 인데
<strong>ApplicationArguments 인터페이스는</strong> 보통의 <strong>커맨드라인 인자 뿐만 아니라</strong>,
옵션 읽어 들일 수 있는 getOptionNames(), getOptionValues() 등의 메소드도 가지고 있다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[cs - Spring] 서블릿 Filter와 Spring Interceptor 차이, 예외처리]]></title>
            <link>https://velog.io/@dabeen-jung/cs-Spring-%EC%84%9C%EB%B8%94%EB%A6%BF-Filter%EC%99%80-Spring-Interceptor-%EC%B0%A8%EC%9D%B4-%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%AC</link>
            <guid>https://velog.io/@dabeen-jung/cs-Spring-%EC%84%9C%EB%B8%94%EB%A6%BF-Filter%EC%99%80-Spring-Interceptor-%EC%B0%A8%EC%9D%B4-%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%AC</guid>
            <pubDate>Fri, 28 Apr 2023 02:51:57 GMT</pubDate>
            <description><![CDATA[<p>이전에 서블릿 필터와  스프링 인터셉터에의 차이에 대해 따로 정리는 여기에 있다!
<br><br></p>
<p>질문에 대비해 차이 및 추가적으로 요약 정리를 더 해보자면</p>
<p><br><br><br></p>
<h2 id="서블릿-필터와-스프링-인터셉터">서블릿 필터와 스프링 인터셉터</h2>
<p><a href="https://velog.io/@dabeen-jung/%EC%8A%A4%ED%94%84%EB%A7%81-MVC-2%ED%8E%B8-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EC%B2%98%EB%A6%AC2-%ED%95%84%ED%84%B0-%EC%9D%B8%ED%84%B0%EC%85%89%ED%84%B0">스프링 MVC 2편 - 로그인 처리2 - 필터, 인터셉터</a>에서 관련하여 글을 작성하였습니다.</p>
<p><br><br></p>
<h3 id="📕-필터filter와-인터셉터interceptor-차이-정리">📕 필터(Filter)와 인터셉터(Interceptor) 차이 정리</h3>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/3fd79474-048b-4c96-a991-5a95767b4730/image.png" alt=""></p>
<h4 id="1-관리되는-컨테이너">1. 관리되는 컨테이너</h4>
<p>필터와 인터셉터는 관리되는 영역이 다르다. <strong>필터</strong>는 스프링 이전의 <strong>서블릿 영역에서 관리</strong>되지만, <strong>인터셉터</strong>는 <strong>스프링 영역에서 관리</strong>되는 영역이기 때문에
=&gt;** 필터는 스프링이 처리해주는 내용들을 적용 받을 수 없다. **
=&gt; 🚨 이로 인한 차이로 발생하는 대표적인 예시가 <span style='background-color:#fff5b1'><strong>필터는 스프링에 의한 <del>예외처리가 되지 않는다</del></strong></span>는 것이다.</p>
<br>

<blockquote>
<p>+)  참고로 일부 포스팅 또는 자료에서 필터(Filter)가 스프링 빈으로 등록되지 못하며, 빈을 주입 받을 수도 없다고 하는데, 이는 잘못된 설명이다.
=&gt; 이는 매우 옛날의 이야기이며🤔 , <strong>필터는 현재 스프링 빈으로 등록이 가능하며, 다른 곳에 주입되거나 다른 빈을 주입받을 수도 있다.</strong> </p>
</blockquote>
<p><br><br></p>
<h4 id="2-스프링의-예외-처리-여부">2. 스프링의 예외 처리 여부</h4>
<p>스프링을 사용한다면 <code>ControllerAdvice</code>와 <code>ExceptionHandler</code>를 이용한 예외처리 기능을 주로 사용한다.</p>
<p>그래서 예외처리에 관한 예시로 만약 원하는 멤버를 찾지 못하여 로직에서 &#39;MemberNotFoundException&#39;을 던졌다면 404 Status로 응답을 반환하길 원할 것이다.</p>
<p><a href="https://mangkyu.tistory.com/173">망나니 개발자님 코드 인용</a></p>
<pre><code>@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(MemberNotFoundException.class)
    public ResponseEntity&lt;Object&gt; handleMyException(MemberNotFoundException e) {
        return ResponseEntity.notFound()
            .build();
    }

    ...
}</code></pre><ul>
<li><p>이처럼 예외처리기를 구현하여 <strong>예외가 서블릿까지 전달되지 않고 처리되어야 할 것이다.</strong></p>
</li>
<li><blockquote>
<p>그러나 <strong>&#39;필터&#39;는</strong> 스프링 <strong>앞의 서블릿 영역에서 관리되기 때문에 스프링의 지원을 <del>받을 수 없다.</del></strong></p>
</blockquote>
</li>
<li><p>그래서 만약 필터에서  MemberNotFoundException이 던져졌다면, <strong>에러가 처리되지 않고 서블릿(여기서 말하는 필터 다음 과정인 서블릿은 Dispatcher Servlet을 뜻함)까지 전달된다</strong>. 서블릿은 예외가 핸들링 되기를 기대했지만, 예외가 그대로 올라와서 예상치 못한 Exception을 만난 상황이다. 
=&gt; 따라서 내부에 문제가 있다고 판단하여 500 Status로 응답을 반환한다.
=&gt; 이를 해결하려면 <strong>필터에서 다음과 같이 응답(Response) 객체에 예외 처리가 필요하다.</strong></p>
</li>
</ul>
<pre><code>public class MyFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse servletResponse = (HttpServletResponse) response;
        servletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
        servletResponse.getWriter().print(&quot;Member Not Found&quot;);
    }
}</code></pre><p><br><br></p>
<h4 id="3-requestresponse-객체-조작-가능-여부">3. Request/Response 객체 조작 가능 여부</h4>
<ul>
<li><strong>필터는 Request와 Response를 조작할 수 있지만 인터셉터는 조작할 수 없다.</strong></li>
<li>) 여기서 조작한다는 것은 내부 상태를 변경한다는 것이 아니라 <strong>다른 객체로 바꿔진다</strong>는 의미이다.</li>
</ul>
<p>필터는 위에도 나오다시피 Filter Chaining(다음 필터 호출) 이라는 기능이 있다. 그리고 이때 Request/Respsonse 객체를 넘겨줄 수 있다.(물론 NPE가 나겠지만서도)</p>
<p>ex) <strong>필터에서는</strong> 이런 식으로 넣어줄 수 있다는 것이다.</p>
<pre><code>public MyFilter implements Filter {

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
        // 개발자가 다른 request와 response를 넣어줄 수 있음
        chain.doFilter(new MockHttpServletRequest(), new MockHttpServletResponse());       
    }

}</code></pre><br>


<ul>
<li>반면에 <strong>인터셉터는 처리 과정이 필터와 다르다</strong>. <strong>Dispatcher Servlet이 여러 인터셉터 목록을 가지고 있고, for문으로 순차적으로 실행</strong>시킨다. 그리고 <strong>true를 반환하면 다음 인터셉터가 실행되거나 컨트롤러로 요청이 전달</strong>되며, false가 반환되면 요청이 중단된다. 
=&gt; 그래서... 우리가 다른 Request/Response 객체를 넘겨줄 수 없다.<h4 id="그리고-이러한-부분이-필터와-확실히-다른-점이다-👍">그리고 이러한 부분이 필터와 확실히 다른 점이다. 👍</h4>
</li>
</ul>
<p><br><br></p>
<h3 id="3-필터와-인터셉터의-용도-및-예시">3. 필터와 인터셉터의 용도 및 예시</h3>
<hr>
<h3 id="스프링에서의-servlet-filter와-spring-interceptor를-통한-예외처리-및-오류페이지에-관하여">스프링에서의 Servlet Filter와 Spring Interceptor를 통한 예외처리 및 오류페이지에 관하여</h3>
<p><a href="https://velog.io/@dabeen-jung/%EC%8A%A4%ED%94%84%EB%A7%81-MVC-2%ED%8E%B8-%EC%98%88%EC%99%B8-%EC%B2%98%EB%A6%AC%EC%99%80-%EC%98%A4%EB%A5%98-%ED%8E%98%EC%9D%B4%EC%A7%80#%EC%84%9C%EB%B8%94%EB%A6%BF-%EC%98%88%EC%99%B8-%EC%B2%98%EB%A6%AC---%ED%95%84%ED%84%B0%EC%99%80-%EC%9D%B8%ED%84%B0%EC%85%89%ED%84%B0">스프링 MVC 2편 - 예외 처리와 오류 페이지
</a>에 관하여</p>
<h4 id="q-filter는-servlet의-스펙이고-interceptor는-spring-mvc의-스펙입니다-spring-application에서-filter와-interceptor를-통해-예외를-처리할-경우-어떻게-해야-할까요">Q. Filter는 Servlet의 스펙이고, Interceptor는 Spring MVC의 스펙입니다. Spring Application에서 Filter와 Interceptor를 통해 &#39;예외&#39;를 처리할 경우 어떻게 해야 할까요?</h4>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/f9f75139-9108-4825-ba7b-3c51001d5e3f/image.png" alt=""></p>
<p><br> <strong>&#39;필터&#39;는 WAS(웹컨테이너)에 의해 관리가 되는 영역이고,  &#39;인터셉터&#39;는 <code>DispatcherServlet</code>(스프링의 프론트컨트롤러) 이후 영역이므로 스프링에 의해 관리되는 영역</strong>이다.</p>
<ul>
<li><p>공통점
<strong>컨트롤러 진입전 실행로직을 작성할 수 있다</strong>는 것.</p>
</li>
<li><p>차이점</p>
</li>
<li><p><em>&#39;필터&#39;는...*</em> 스프링이 관리하지 않으므로, <strong>Spring Context를 <del>사용할 수 없다</del>는 것.</strong></p>
</li>
</ul>
<p><br><br></p>
<h4 id="1-인터셉터">1) 인터셉터</h4>
<p> <code>@ControllerAdvice</code> 로 스프링의 도움을 받아 객체지향적으로 예외처리를 할 수 있다.</p>
<h4 id="2-필터">2) 필터</h4>
<p>¹직접 <code>response</code>에 접근하여 예외처리를 하거나, 톰캣의 경우 <error-page>를 선언하여 처리하거나, ²인터셉터까지 계속 통과시켜 <strong>인터셉터에게 예외처리를 미뤄버려야</strong> 한다.</p>
<p>만약 인터셉터에게 미루지 않고 에러가 발생한 필터에서 <code>doFilter()</code>를 호출하여 다음필터로 전파하지 않고 바로 return 으로 클라이언트로 <code>response</code> 를 보내게 되면...
  =&gt; 프론트 컨트롤러인 <strong><code>&#39;DispatcherServlet&#39;</code>에 서블릿 자체가 도달하지 않으므로 <del>스프링에서는 알 방법이 없다</del>...</strong>😥</p>
<p>그러므로   </p>
<h4 id="a-답은">A. 답은</h4>
<p>필터는 <strong>DispatcherServlet 외부에 존재하기 때문에</strong> 예외가 발생했을 때 <strong>ErrorController에서 처리</strong>해야 합니다.</p>
<p>인터셉터는 <strong>DispatcherServlet 내부에 존재</strong>하기 때문에 <strong>@ControllerAdvice를 적용해서 처리할 수</strong> 있습니다.</p>
<h3 id="이-곳의-에러처리-방식이-좋은-정보가-되었다-참고하면-좋을-것-같다">이 곳의 에러처리 방식이 좋은 정보가 되었다. 참고하면 좋을 것 같다.</h3>
<p><a href="https://incheol-jung.gitbook.io/docs/q-and-a/spring/controlleradvice-exceptionhandler">이 곳</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[cs - Spring] Dispatcher Servlet 원리]]></title>
            <link>https://velog.io/@dabeen-jung/cs-Spring-Dispatcher-Servlet-%EC%9B%90%EB%A6%AC</link>
            <guid>https://velog.io/@dabeen-jung/cs-Spring-Dispatcher-Servlet-%EC%9B%90%EB%A6%AC</guid>
            <pubDate>Thu, 27 Apr 2023 14:02:19 GMT</pubDate>
            <description><![CDATA[<p><br><br></p>
<br>



<h2 id="스프링-mvc-전체-구조">스프링 MVC 전체 구조</h2>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/991ed592-9d66-4d44-9901-ada0d9a756a9/image.png" alt=""></p>
<p>오늘 우리는 이 중에서 Dispatcher Servlet에 대해서 좀 더 배워보자.</p>
<h2 id="dispatcher-servlet">Dispatcher Servlet</h2>
<br>


<h3 id="1-개념">1. 개념</h3>
<h4 id="◽-dispatcher-servlet디스패처-서블릿-이란">◽ Dispatcher-Servlet(디스패처 서블릿) 이란?</h4>
<p>디스패처 서블릿의 dispatch는 &quot;보내다&quot;라는 뜻을 가진다. 곧 디스패처 서블릿은 <strong>HTTP 프로토콜로 들어오는 모든 요청을 가장 먼저 받아 적합한 컨트롤러에 위임해주는 프론트 컨트롤러</strong>(Front Controller)라고 정의한다.</p>
<br>

<p>더 자세히 풀면...🤔</p>
<br>

<p> <strong>클라이언트로부터 어떠한 요청이 오면</strong>...
 ex)Tomcat(톰캣)과 같은 <strong>&#39;서블릿 컨테이너&#39;가 요청을 받는다.</strong>
그리고  이 <strong>모든 요청</strong>을 프론트 컨트롤러인 <strong>&#39;디스패처 서블릿&#39;이 가장 먼저 받게</strong> 된다.
그리고 이  <strong>&#39;디스패처 서블릿&#39;</strong>은 <span style="color: red">공통적인 작업을 먼저 처리</span>를 한 후,  <span style='background-color:#fff5b1'> *<em>_ 해당 요청을 처리해야 하는 &#39;컨트롤러&#39;를 찾아서 작업을 위임_ *</em></span>한다.</p>
<p><br><br></p>
<h4 id="-front-controller-프론트-컨트롤러">+) Front Controller (프론트 컨트롤러)???</h4>
<blockquote>
<p>주로 <strong><em>&#39;서블릿 컨테이너&#39;</em> 의 제일 앞에서</strong> 서버로 들어오는 <strong>클라이언트의 모든 요청을 받아서 처리해주는 컨트롤러</strong>로써, MVC 구조에서 함께 사용되는 <strong>디자인 패턴</strong>이다.</p>
</blockquote>
<p><br><br></p>
<h3 id="2-disptcher-servlet디스패처-서블릿의-장점">2. Disptcher-Servlet(디스패처 서블릿)의 장점</h3>
<p>과거에는 모든 서블릿을 URL 매핑을 위해 web.xml에 <del>모두 등록해주어야 했다</del>.. 🤔</p>
<p><strong>그.러.나 &#39;디스패쳐 서블릿&#39;이 해당 어플리케이션으로 들어오는 모든 요청을 핸들링해주고 공통 작업을 처리하면서</strong> 상당히 편리하게 이용할 수 있게 되었다✌✌</p>
<blockquote>
<p>즉, 우리는 <strong>컨트롤러를 구현해두기만 하면 디스패처 서블릿가 알아서 적합한 컨트롤러로 위임을 해주는 구조가 되었다.</strong></p>
</blockquote>
<br>

<h4 id="물론-장점만-있지는-않다">물론 장점만 있지는 않다.</h4>
<h3 id="2-dispatcher-servlet의-단점도-있었다">2. Dispatcher-Servlet의 단점도 있었다.</h3>
<h4 id="◽-문제상황">◽ 문제상황</h4>
<p>모든 요청을 처리하다보니 이미지나 HTML/CSS/JavaScript 등과 <strong>같은 정적 파일에 대한 요청마저 모두 가로채버려서</strong>
-&gt; <strong>정적자원을 불러오지 못하는 상황이 발생되었었다.</strong></p>
<p><br><br></p>
<p>그로인해 개발자들은 2가지 방법을 고안했는데...</p>
<p><strong>1. 정적 자원 요청과 애플리케이션 요청을 분리</strong></p>
<ul>
<li>첫번째 방법은 클라이언트의 요청을 2가지로 분리해서 구분하는 것
  -&gt; but,  코드가 지저분 함, 요청에 따라서 url로 구분을 지어줘야 하므로 직관적 설계를 벗어남</li>
</ul>
<br>

<p><strong>2. 애플리케이션 요청을 탐색하고 없으면 정적 자원 요청으로 처리</strong> [현재]</p>
<ul>
<li>Dispatcher Servlet이 <strong>요청을 처리할 컨트롤러를 먼저 찾는다.</strong> 이때 컨트롤러를 <strong>찾지 못한 경우 2차적으로 설정된 자원경로를 탐색</strong>해 자원 탐색을 한다.
=&gt; 리소스 관리를 효율적으로 할 수 있다.
=&gt; 확장이 용이하다.</li>
</ul>
<br>


<hr>
<p><br><br><br><br></p>
<h2 id="3-dispatcher-servlet디스패처-서블릿의-동작-과정">3. Dispatcher-Servlet(디스패처 서블릿)의 동작 과정</h2>
<p>우리는 앞에서 정의하고 기능을 자세히 들여다 보면서 알게 되었다 싶이 이 곳에서의 주 일은 </p>
<ul>
<li>디스패처 서블릿은 <strong>적합한 컨트롤러와 메소드를 찾아 요청을 위임</strong> 해주는 것이다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/5919bd2a-d5f4-45a7-826f-8c7738c84d2b/image.png" alt=""></p>
<h4 id="◽-dispatcher-servlet의-동작과정">◽ Dispatcher Servlet의 동작과정</h4>
<ol>
<li>클라이언트의 요청을 디스패처 서블릿이 받음</li>
<li>요청 정보를 통해 요청을 위임할 컨트롤러를 찾음</li>
<li>요청을 컨트롤러로 위임할 핸들러 어댑터를 찾아서 전달함</li>
<li>핸들러 어댑터가 컨트롤러로 요청을 위임함</li>
<li>비지니스 로직을 처리함</li>
<li>컨트롤러가 반환값을 반환함</li>
<li>핸들러 어댑터가 반환값을 처리함</li>
<li>서버의 응답을 클라이언트로 반환함</li>
</ol>
<blockquote>
<p>🌈 디스패처 서블릿을 통해서 요청을 처리할 컨트롤러를 찾아서 위임하고, 그 결과를 받아오는 것을 하는구나!!🙌</p>
</blockquote>
<p><br><br></p>
<h3 id="3-1-클라이언트의-요청을-디스패처-서블릿이-받음">3-1. 클라이언트의 요청을 디스패처 서블릿이 받음</h3>
<p>디스패처 서블릿은 가장 먼저 요청을 받는 프론트 컨트롤러입니다.</p>
<ul>
<li>서블릿 컨텍스트(Web Context)에서 필터들을 지나 <strong>&#39;스프링 컨텍스트&#39;에서 <code>Dispatcher Servlet</code>
이 가장 먼저 요청을 받게 된다</strong></li>
</ul>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/f96da695-09a3-4a00-8e1e-ac6c188f07f3/image.png" alt=""></p>
<p><br><br></p>
<h3 id="3-2-요청-정보를-통해-요청을-위임할-컨트롤러를-찾음">3-2. 요청 정보를 통해 요청을 위임할 컨트롤러를 찾음</h3>
<ul>
<li>&#39;디스패처 서블릿&#39;은 요청 정보를 바탕으로, <strong>요청을 처리할 컨트롤러를 찾고 해당 메소드를 호출</strong>해야 한다. </li>
<li>요청을 처리할 컨트롤러는 주로 <code>HandlerMapping</code>의 구현체 중 하나인 <strong><code>RequestMappingHandlerMapping</code>가 찾아준다.</strong></li>
</ul>
<p>이때 <strong>요청을 처리할 대상</strong>은 컨트롤러가 아닌 <strong>컨트롤러를 가지고 있는 <code>HandlerMethod 객체</code></strong>이다.
    -&gt; <code>HandlerMethod</code>를 갖는 이유는 컨트롤러와 컨트롤러의 메소드 등을 포함해 부가적인 정보들이 더욱 필요하기 때문</p>
<p>그리고 이렇게 찾아온 <strong><code>HandlerMethod</code>를 <code>HandlerMethodExecutionChain</code>으로 감싸서 반환</strong>한다.
    -&gt; why? 컨트롤러로 요청을 넘겨주기 전에 처리해야 하는** 인터셉터 등을 포함하기 위해**</p>
<p><br><br></p>
<h3 id="3-3-요청을-컨트롤러로-위임할-핸들러-어댑터를-찾아서-전달">3-3. 요청을 컨트롤러로 위임할 &#39;핸들러 어댑터&#39;를 찾아서 전달</h3>
<blockquote>
<p>사실 요청을 직접 위임하진 않고 중간 다리인 <strong>&#39;핸들러 어댑터(HandlerAdapter)&#39;를 통해 <em>어댑터 패턴</em> 을 적용하여 컨트롤러로 위임</strong>하는 것이다.</p>
</blockquote>
<ul>
<li>왜 어댑터 패턴?
개발자로 인해 다양하게 작성되는 컨트롤러에 대응하고자 어댑터 패턴을 적용해 <strong>컨트롤러의 구현 방식에 규제 받지 않고</strong> 요청을 위임하고자 함. </li>
</ul>
<p><br><br></p>
<h3 id="3-4-핸들러-어댑터가-컨트롤러로-요청을-위임함">3-4. 핸들러 어댑터가 컨트롤러로 요청을 위임함</h3>
<blockquote>
<ul>
<li>&#39;핸들러 어댑터&#39;가 컨트롤러로 요청을 넘기기 <strong>전</strong>에 <em><strong>&#39;공통적인 전처리 과정&#39; 이 필요</strong></em> 하다.</li>
</ul>
</blockquote>
<p>어떻게 보면 핸들러 어댑터라는 집사를 부르는거 같기도 하다. 직접 일은 하지 않고 남을 시켜서 부른다니🤔</p>
<p>요청에 매칭되는 인터셉터들도 실행을 시키고, <code>@RequestParam</code>, <code>@RequestBody</code> 등으로 파라미터를 준비하는 <code>ArgumentResolver</code>도 실행하는 등의 다양한 공통 작업들이 수행된다.
    -&gt; <strong>이러한 전처리 작업들이 완료되면 파라미터 값들과 함께 컨트롤러로 요청을 위임</strong>한다.</p>
<br>


<h3 id="3-5-비지니스-로직을-처리함">3-5. 비지니스 로직을 처리함</h3>
<br>



<h3 id="3-6-컨트롤러가-반환값을-반환함">3-6. 컨트롤러가 반환값을 반환함</h3>
<ul>
<li>비지니스 로직이 처리된 후에는 <strong>컨트롤러가 반환값을 반환</strong>한다.<blockquote>
<p>응답 데이터를 사용하는 경우에는 주로 <code>ResponseEntity</code>를 반환하게 되고, 응답 페이지를 보여주는 경우라면 String으로 View의 이름을 반환할 수도 있다.</p>
</blockquote>
</li>
</ul>
<br>


<h3 id="3-7-핸들러-어댑터가-반환값을-처리함">3-7. 핸들러 어댑터가 반환값을 처리함</h3>
<ul>
<li>&#39;핸들러 어댑터&#39;는 컨트롤러로부터 받은 <strong>반환값을 응답 처리기인 <code>ReturnValueHandler</code>가 후처리한 후</strong>에 다시 <code>&#39;Dispatcher Servlet&#39;</code>으로 돌려준다.</li>
</ul>
<ul>
<li><p>ex 1 ) 만약 컨트롤러가 <code>ResponseEntity</code>를 반환하면 <code>HttpEntityMethodProcessor</code>가 <strong>&#39;MessageConverter&#39;를 사용해 응답 객체를 직렬화하고 응답 상태(HttpStatus)를 설정</strong>한다. </p>
</li>
<li><p>ex 2) 만약 컨트롤러가 View 이름을 반환하면 View를 반환하기 위한 준비 작업을 처리</p>
</li>
</ul>
<br>

<h3 id="3-8-서버의-응답을-클라이언트로-반환함">3-8. 서버의 응답을 클라이언트로 반환함</h3>
<ul>
<li><code>&#39;Dispatcher Servlet&#39;</code>을 통해 반환되는 응답은 다시 필터들을 거쳐 클라이언트에게 반환된다.</li>
</ul>
<blockquote>
<p>이때 ex 1) 응답이 <strong>데이터</strong>라면?
=&gt; 그대로 반환
ex 2 ) 응답이 <strong>화면</strong>이라면 View의 이름에 맞는 View를 찾아서 반환해주는 <strong>ViewResolver가 적절한 화면을 내려줍니다.</strong></p>
</blockquote>
<p><br><br><br></p>
<h3 id="출처">출처</h3>
<p><a href="https://mangkyu.tistory.com/18">망나니 개발자</a>님의 글을 읽고 작성하였습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[cs] - DI]]></title>
            <link>https://velog.io/@dabeen-jung/cs-DI</link>
            <guid>https://velog.io/@dabeen-jung/cs-DI</guid>
            <pubDate>Mon, 24 Apr 2023 04:41:18 GMT</pubDate>
            <description><![CDATA[<br>

<p><br><br><br></p>
<h2 id="1-다양한-의존관계-주입-방법">1. 다양한 의존관계 주입 방법</h2>
<h3 id="didependency-injection란">DI(Dependency Injection)란?</h3>
<h4 id="◽-정의">◽ 정의</h4>
<p><strong>DI란 의존성 주입</strong>이라 부르며, 객체를 직접 생성하는 게 아닌 <strong>외부(IOC 컨테이너)에서 생성한 후 주입시켜주는 방식</strong>이다.</p>
<p>의존성 주입 방식으로는 3가지 방법이 존재</p>
<ul>
<li>생성자 주입</li>
<li>수정자 주입(setter 주입)</li>
<li>필드 주입</li>
<li>일반 메서드 주입</li>
</ul>
<h4 id="🎉-생성자-주입">🎉 생성자 주입</h4>
<ul>
<li>우리가 주로 진행한 방식임</li>
<li>생성자 호출시점에 딱 1번만 호출되는 것이 보장</li>
<li>불변, 필수 의존관계에 사용 (null 이나 비워두어선 안됨)</li>
<li>생성자가 1개 밖에 없다면 @Autowired 생략해도 자동 주입이 가능.</li>
</ul>
<pre><code>@Component
public class OrderServiceImpl implements OrderService {
    private final MemberRepository memberRepository;
     private final DiscountPolicy discountPolicy;

    @Autowired
     public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy 
discountPolicy) {
         this.memberRepository = memberRepository;
         this.discountPolicy = discountPolicy;
     }
}</code></pre><br>

<h4 id="🎉-수정자-주입setter주입">🎉 수정자 주입(setter주입)</h4>
<ul>
<li>선택, 변경 가능성이 있는 의존관계에 사용</li>
<li>@Autowired의 기본동작은 주입 대상이 없다면 오류가 발생 -&gt; @Autowired(required = false) 지정해주면 해결</li>
</ul>
<pre><code>@Component
public class OrderServiceImpl implements OrderService {
     private MemberRepository memberRepository;
     private DiscountPolicy discountPolicy;

    @Autowired
     public void setMemberRepository(MemberRepository memberRepository) {
         this.memberRepository = memberRepository;
     }
     @Autowired
     public void setDiscountPolicy(DiscountPolicy discountPolicy) {
         this.discountPolicy = discountPolicy;
     }
}
</code></pre><h4 id="🎉-필드-주입">🎉 필드 주입</h4>
<ul>
<li>코드는 간결, but  외부에서 변경이 불가능 =&gt; DI 프레임워크가 없으면 아무것도 할 수 없음.</li>
<li>사용하지 말길...(굳이 쓴다면 테스트 코드)</li>
</ul>
<pre><code>@Autowired
private MemberRepository memberRepository;

@Autowired
private DiscountPolicy discountPolicy;
</code></pre><h4 id="🎉-일반-메서드-주입-잘-사용-x">🎉 일반 메서드 주입 (잘 사용 x)</h4>
<pre><code>@Autowired
public void init(MemberRepository memberRepository, DiscountPolicy 
discountPolicy) {
    this.memberRepository = memberRepository;
     this.discountPolicy = discountPolicy;
 }</code></pre><br>
<br>

<h3 id="-옵션처리">+) 옵션처리</h3>
<p>: 주입할 스프링 빈 없이도 동작해야 할 때가 있다. 그리고, @Autowired의 <strong>required=true</strong>라면 <strong>자동주입 대상이 없을 시 오류</strong>가 발생해버린다...</p>
<h4 id="자동-주입-대상을-옵션으로-처리하는-방법">자동 주입 대상을 옵션으로 처리하는 방법</h4>
<blockquote>
<ul>
<li>@Autowired(required = false) </li>
<li><blockquote>
<p>수정자 메서드 자체가 호출 x  , 주입할 대상이 없어도 동작 가능.</p>
</blockquote>
</li>
<li>매개변수에 @Nullable</li>
<li><blockquote>
<p>호출은 되지만 자동 주입 대상이 없으면 null이 입력</p>
</blockquote>
</li>
<li>Optional&lt;&gt; </li>
<li><blockquote>
<p>자동 주입 대상이 없다면, Optional.empty 이 호출된다.</p>
</blockquote>
</li>
</ul>
</blockquote>
<hr>
<h2 id="2-생성자-주입을-추천">2. 생성자 주입을 추천</h2>
<h4 id="-의존성과-설정값을-생성자-인자로-주입해야-하는-이유에-대해-설명해주세요">+) 의존성과 설정값을 생성자 인자로 주입해야 하는 이유에 대해 설명해주세요.</h4>
<h3 id="왜-추천할까">왜 추천할까?</h3>
<h4 id="1-불변">1. 불변</h4>
<blockquote>
<ul>
<li>생성자 주입은 객체 생성 때 단 1번만 호출된다.
=&gt;즉, 종료 시점까지 의존관계가 변경되지 않으며 다시 호출될 일이 없다.</li>
</ul>
</blockquote>
<h4 id="2-final">2. final</h4>
<blockquote>
<ul>
<li>오로지 생성자 주입만 사용 가능하며 값이 설정되지 않는 부분을 알려준다.
=&gt; 컴파일 시점에 오류를 막을 수 있다.</li>
</ul>
</blockquote>
<h4 id="3-누락">3. 누락</h4>
<ul>
<li>데이터를 누락 했을 때 컴파일 오류를 발생시킨다</li>
<li>IDE를 통해 어떤 값을 필수로 주입해야 하는지 알려준다.</li>
</ul>
<p><br><br></p>
<h3 id="di의-장점">DI의 장점</h3>
<ul>
<li>의존성이 줄어든다. (변경에 덜 취약해진다.)</li>
<li>모의 객체를 주입할 수 있기 때문에 단위 테스트가 쉬워진다.</li>
<li>가독성이 높아진다.</li>
<li>재사용성이 높아진다.</li>
</ul>
<p><br><br><br></p>
<h3 id="출처">출처</h3>
<p><a href="https://velog.io/@ohzzi/Spring-DIIoC-IoC-DI-%EA%B7%B8%EA%B2%8C-%EB%AD%94%EB%8D%B0">ohzzi</a>님의 글을 참고하여 작성하였습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[cs] - Spring Bean, Spring Bean 생성 과정]]></title>
            <link>https://velog.io/@dabeen-jung/cs-Spring-Bean-Spring-Bean-%EC%83%9D%EC%84%B1-%EA%B3%BC%EC%A0%95</link>
            <guid>https://velog.io/@dabeen-jung/cs-Spring-Bean-Spring-Bean-%EC%83%9D%EC%84%B1-%EA%B3%BC%EC%A0%95</guid>
            <pubDate>Sun, 23 Apr 2023 16:13:24 GMT</pubDate>
            <description><![CDATA[<p><br><br>
<br></p>
<h2 id="1-spring-bean이란">1. Spring Bean이란?</h2>
<ul>
<li>스프링 <strong>Ioc 컨테이너가 관리하는 자바 객체</strong>를 뜻하며 <strong>필요할 때마다 IoC 컨테이너에서 가져와서 사용</strong>한다.</li>
<li>IoC 컨테이너에 의해 생명주기가 관리되는 객체를 의미한다.</li>
<li>사용할 때는 ¹<strong>어노테이션</strong>인 <code>@Bean</code>을 사용하거나 ² <strong>xml 설정을 통해 일반 객체를 Bean으로 등록</strong>이 가능하다.</li>
</ul>
<h3 id="iocinversion-of-control란">IoC(Inversion of Control)란?</h3>
<p>IoC란 영어 그대로 <strong>제어의 역전</strong>이라 부른다.
제어의 역전이란 메서드나 객체의 호출 작업을 <strong>개발자가 아닌 스프링에게 제어권을 넘기는 것</strong>을 말한다. 
이전까지는 개발자가 객체의 생성을 관리하며 제어했지만, 스프링을 사용하게 되면 <strong>스프링 컨테이너에게 제어권을 넘겨 스프링 컨테이너가 흐름을 제어</strong>하게 된다.</p>
<br>


<h4 id="ioc-분류">IoC 분류</h4>
<ul>
<li><p>DL</p>
<ul>
<li>저장소에 저장되어 있는 Bean에 접근하기 위해 컨테이너가 제공하는 API를 이용하여 Bean을 Lockup하는 것</li>
</ul>
</li>
<li><p>DI </p>
<ul>
<li>각 클래스간의 의존관계를 빈 설정(Bean Definition) 정보를 바탕으로 컨테이너가 자동으로 연결해주는 것</li>
</ul>
</li>
</ul>
<blockquote>
<p>DL 사용시 컨테이너 종속이 증가하기 때문에 <strong>주로 DI를 사용한다.</strong></p>
</blockquote>
<br>


<h4 id="이해가-안가서-다른-블로그의-글을-인용하였습니다">&lt; 이해가 안가서 다른 블로그의 글을 인용하였습니다. &gt;</h4>
<p>프레임워크를 적용하지 않은, 우리가 <strong>그동안 작성해왔던 일반적인 프로그램</strong>을 생각해보자. 객체의 생명주기(객체의 생성, 초기화, 소멸, 메서드 호출 등)를 <strong>클라이언트 구현 객체가 직접 관리</strong>한다. 또한 다른 사람이 작성한 외부 코드(라이브러리)를 호출하더라도 해당 코드의 호출 시점 역시 직접 관리한다. 하지만 <strong>이러한 생명주기를 직접 관리하지 않는 경우라면?</strong>🤔
<br>
<strong>스프링과 같은 프레임워크</strong>를 사용할 때를 생각해보자. Controller, Service 같은 객체들의 동작을 <strong>우리가 직접 구현하기는 하지만, 해당 객체들이 어느 시점에 호출될 지는 신경쓰지 않는다🤷‍♀️</strong>. 단지 프레임워크가 요구하는대로 객체를 생성하면, 프레임워크가 해당 객체들을 가져다가 생성하고, 메서드를 호출하고, 소멸시킨다. <strong>프로그램의 제어권이 역전된 것</strong>이다.
<br>
때문에 프레임워크와 라이브러리는 어떤 차이가 있는지에 대해 IoC를 통해 설명이 가능하다. 라이브러리를 사용하는 어플리케이션은 어플리케이션의 제어 흐름을 라이브러리에 내주지 않는다. <strong>단지 필요한 시점에 라이브러리에 작성된 객체를 적재적소에 가져다 쓸 뿐</strong>이다. 하지만 프레임워크를 사용한 어플리케이션의 경우, 어플리케이션 코드에 <strong>작성한 객체들을 프레임워크가 필요한 시점에 가져다가 프로그램을 구동하기 때문에 프로그램의 제어권이 프레임워크로 역전된다.</strong></p>
<p><br><br></p>
<h4 id="ioc-덕에-우리는-이런-점을-얻을-수-있었다">IoC 덕에 우리는 이런 점을 얻을 수 있었다.</h4>
<ol>
<li>프로그램의 진행 흐름과 구체적인 구현을 분리시킬 수 있다.</li>
<li>개발자는 <strong>비즈니스 로직에 집중할 수 있다.</strong></li>
<li><strong>구현체 사이의 변경이 용이</strong>하다.</li>
<li>객체 간 <strong>의존성이 낮아진다.</strong></li>
</ol>
<p><br><br></p>
<h3 id="ioc-컨테이너란spring-container--">IOC 컨테이너란(Spring Container) .. ?</h3>
<ul>
<li>제어의 역전의 약어로 &quot;<strong>객체의 생성 및 생명주기에 대한 모든 객체에 대한 제어권이 바뀌었다</strong>는 것을 의미&quot;</li>
</ul>
<blockquote>
<p>spring 컨테이너가 ioc 컨테이너의 역할을 하는거지 둘이 완전히 같은게 아님
-&gt; di컨테이너라고도 한다.
=&gt; 그 반대는 적용되지 않는다. 포함하지 않는다.
ioc 컨테이너의 역할을 하려고 하는게 스프링에서는 &#39;스프링컨테이너&#39;가 그 역할을 하는 것</p>
</blockquote>
<br>

<h4 id="🎉-컨테이너의-사용-역할">🎉 컨테이너의 사용 역할</h4>
<p><strong>1) DI(Dependency Injection, 의존성 주입)</strong>
개발자가 객체를 new해서 생성하지않고, <strong>Ioc컨테이너에 존재하는 Bean 객체를 주입해준다.</strong> 해당 기능을 사용하면 싱글톤, 개발자의 편의, 성능 이슈 등등을 해결해준다.</p>
<p><strong>2) 객체의 Scope</strong>
Ioc 컨테이너에 객체의 제어권을 넘겨주면, Ioc 컨테이너가 <strong>해당 객체의 Scope를 관리</strong>해준다.</p>
<p><strong>3) 라이프 사이클 인터페이스 지원</strong>
완벽히 구현되지 않은 클래스를 단위 테스트할 때, 테스팅을 도와준다</p>
<br>


<h3 id="🌹-ioc-컨테이너의-di를-통한-중재-🌹">🌹 IoC 컨테이너의 DI를 통한 중재 🌹</h3>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/ce3840af-ca7d-44c1-a23a-c0c2435b0805/image.png" alt=""></p>
<ol>
<li>Container가 로드되면, <strong>Bean에 해당하는 객체들을 scan 하여, 해당 Bean들을 생성</strong>하려고 한다.</li>
</ol>
<p>-&gt; 이 과정에서 <strong>의존성 주입</strong>이 이루어진다.
=&gt; <strong>만약 순환 참조가 있다면 예외가 발생</strong>하여 <del>Application은 종료</del>된다.</p>
<ol start="2">
<li><p>이제 <strong>Bean들이 생성되려고 하는데</strong>, 사용자가 지정한 init method가 존재한다면, 객체가 생성되고 init이 실행되게 된다.</p>
</li>
<li><p>그 뒤에 사용자가 지정한 utility method(afterPropertiesSet)과 같은 메서드가 존재한다면, 해당 메서드가 실행되게 된다.(콜백 함수)</p>
</li>
<li><p>프로그램이 종료되기 전에 이제 <strong>Container도 같이 종료</strong>되려고 하는데, 이 과정에서 destory 메서드가 존재한다면, 실행하고 정상적으로 종료</p>
</li>
</ol>
<p><br><br></p>
<h3 id="🚨-주의점-di--ioc-는-아니다">🚨 주의점... DI == IOC 는 아니다!!</h3>
<blockquote>
<ul>
<li><strong>절대 IoC == DI가 아니다! (DI ⊂ IoC 라면 몰라도)</strong> DI 없이도 IoC를 만족하는 프로그램을 만들 수 있다.</li>
</ul>
</blockquote>
<ul>
<li><strong>IoC는 프로그램 제어권을 역전</strong>시키는 개념이고, <strong>DI는 해당 개념을 구현하기 위해 사용하는 디자인 패턴 중 하나</strong>로, 이름 그대로 객체의 의존관계를 외부에서 주입시키는 패턴을 말한다.</li>
</ul>
<p><br><br></p>
<hr>
<p><br><br></p>
<h2 id="2-spring-bean-등록-방법">2. Spring Bean 등록 방법</h2>
<p>웹 프로그래밍은 멀티유저에 대한 <strong>동시성 제어가 중요하며 이를 위해 스프링 컨테이너에서는 싱글톤 패턴으로 관리</strong>한다.</p>
<p>크게 두 가지 방법이 있는데,</p>
<h3 id="1-컴포넌트-스캔">(1) 컴포넌트 스캔</h3>
<p>스프링에서 제공하는 @Component 어노테이션으로 클래스를 명시하여 <strong>컨테이너가 생성될 때 컴포넌트 스캔을 통해 자동으로 빈에 등록</strong>할 수 있다.</p>
<ul>
<li><code>@Component</code><ul>
<li><code>@Controller</code></li>
<li><code>@Service</code></li>
<li><code>@Repository</code></li>
</ul>
</li>
</ul>
<blockquote>
<p>위 3가지 어노테이션들은 *<em>@Component로 구성되어 있어서 컴포넌트 스캔에 이용할 수 있다. *</em></p>
</blockquote>
<ul>
<li>(결론): 연관된 어노테이션들을 이용하여 <strong>클래스를 명시해주면</strong> 스프링 컨테이너는 컴포넌트 스캔을 통해 <strong>자동으로 해당 클래스의 객체를 빈(Bean)으로 관리</strong>한다.</li>
</ul>
<br>


<h3 id="2-직접-스프링-빈-등록">(2) 직접 스프링 빈 등록</h3>
<p><img src="https://velog.velcdn.com/images/dabeen-jung/post/36ca6c62-95e7-4c1b-b56b-bbf5795a21c7/image.png" alt=""></p>
<p>Configuration을 위한 클래스를 하나 만든 후(ex SpringConfig,,,), <code>@Configuration</code>으로 명시를 하면 된다. 그리고 <strong>빈으로 등록할 클래스를 <code>@Bean 메소드</code>로 생성하여 객체를 리턴</strong>하면 된다.</p>
<p>이렇게 쓰게되면 만일 인터페이스로 구현된 Repository 클래스가 다른 클래스로 변경된다고 했을 경우, 간단히 *<em>해당 Config파일에서 찾아 리턴 클래스 객체만을 수정해주면 된다. *</em></p>
<p><br><br><br></p>
<br>

<h2 id="3-spring-bean의-scope">3. Spring Bean의 Scope</h2>
<h4 id="◽-정의">◽ 정의</h4>
<p>Bean Scope는 기본적으로 <strong>빈이 존재하는 범위</strong>를 뜻한다.</p>
<ul>
<li>Bean의 객체는 <strong>기본적으로 singleton의 범위를 가지며</strong> singleton는 스프링 컨테이너의 시작과 <strong>종료까지 단 하나의 객체만을 사용</strong>하는 방식이다.</li>
<li>request, session, global session의 scope는 일반 spring 어플리케이션이 아니라 Spring MVC Web Application에서만 사용된다.</li>
</ul>
<br>

<h4 id="◾-scope-종류-및-설명">◾ Scope 종류 및 설명</h4>
<table>
<thead>
<tr>
<th align="center">Scope</th>
<th align="center">설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">singleton</td>
<td align="center">하나의 Bean 정의에 대해 <strong>Spring IoC Container에서 단 하나의 객체만 존재</strong>한다.</td>
</tr>
<tr>
<td align="center">prototype</td>
<td align="center">하나의 Bean 정의에 대해 다수의 객체가 존재할 수 있다.</td>
</tr>
<tr>
<td align="center">request</td>
<td align="center">&lt;웹스코프..&gt; 하나의 Bean 정의에 대해 하나의 HTTP request의 생명주기 안에 단 하나의 객체만 존재한다. 각각의 HTTP request는 자신만의 객체를 가지며 Web-aware Spring ApplicationContext 안에서만 유효한 특징이 있다.</td>
</tr>
<tr>
<td align="center">session</td>
<td align="center">하나의 Bean 정의에 대해 하나의 HTTP Session의 생명주기 안에서 단 하나의 객체만 존재한다.  Web-aware Spring ApplicationContext 안에서만 유효한 특징이 있다.</td>
</tr>
<tr>
<td align="center">global session</td>
<td align="center">하나의 Bean 정의에 대해 하나의 global HTTP Session의 생명주기 안에서 단 하나의 객체만 존재한다. 일반적으로는 portlet context안에서만 유효하며,  Web-aware Spring ApplicationContext 안에서만 유효한 특징이 있다.</td>
</tr>
</tbody></table>
<ul>
<li>Bean의 객체 범위를 <strong>prototype</strong>으로 설정하면 <strong>객체를 매번 새롭게 생성한다</strong>는 특징이 있다.</li>
<li><blockquote>
<p>** prototype으로 설정<strong>하면 **<code>@Scope 어노테이션</code>을 <code>@Bean 어노테이션</code>과 함께 사용해야 한다.</strong></p>
</blockquote>
</li>
</ul>
<p><br><br><br><br></p>
<p>그 중에 몇 개의 예시를 들면...</p>
<h3 id="1-singlenton">1. Singlenton</h3>
<blockquote>
<p>singleton bean은 <strong>Spring 컨테이너 안에서 딱 한 번 생성되며, 컨테이너가 사라질 때는 bean고 같이 사라진다.</strong></p>
</blockquote>
<ul>
<li><strong>생성된 하나의 인스턴스는 single bean cache에 저장</strong>되며 해당 bean에 대한 요청과 참조가 있을 때마다 캐시된 객체를 반환한다.</li>
<li><strong>기본적</strong>으로 모든 bean은 scope이 명시적이지 않으면 <strong>singleton scope을 가진다.</strong></li>
</ul>
<pre><code>// xml 설정
&lt;bean id=&quot;...&quot; class=&quot;...&quot; scope=&quot;singleton&quot;&gt;&lt;/bean&gt;

// annotaion 설정 (대상 클래스에 적용)
@Scope(&quot;singleton&quot;)</code></pre><br>

<h3 id="2-prototype">2. Prototype</h3>
<ul>
<li>prototype bean은 <strong>모든 요청에서 새로운 객체로 생성</strong>하는 것이며, 의존성 관계의 bean이 주입될 때마다 새로운 객체가 생성되어 주입된다.</li>
<li><strong>GC에 의해 bean이 자동으로 제거</strong>된다.</li>
</ul>
<pre><code>// xml 설정
&lt;bean id=&quot;...&quot; class=&quot;...&quot; scope=&quot;prototype&quot;&gt;&lt;/bean&gt;

// annotaion 설정 (대상 클래스에 적용)
@Scope(&quot;prototype&quot;)</code></pre><p><br><br></p>
<h3 id="spring-bean-생명주기life-cycle">Spring Bean 생명주기(Life Cycle)</h3>
<h4 id="feat-마지막">Feat (마지막</h4>
<blockquote>
<p><strong>1. 스프링 IoC 컨테이너 생성 → 2. 스프링 빈 생성 → 3. 의존관계 주입 → 4. 초기화 콜백 메소드 호출 → 5. 사용 → 6. 소멸 전 콜백 메소드 호출 → 7. 스프링 종료</strong> 과정의 생명 주기를 가지고 있다.</p>
</blockquote>
<ul>
<li>Bean은 스프링 컨테이너에 의해 <strong>생명주기를 관리한다.</strong> </li>
</ul>
<p>스프링은 &quot;의존관계 주입이 완료되면&quot;... <strong>스프링 빈에게 콜백 메소드를 통해 초기화 시점을 알려주며</strong>,
스프링 컨테이너가 <strong>종료되기 직전에도 소멸 콜백 메소드를 통해 소멸 시점을 알려준다</strong>.</p>
<br>

<h3 id="bean-생명주기-콜백-3가지-방법">Bean 생명주기 콜백 3가지 방법</h3>
<ol>
<li>인터페이스( InitializingBean, DisposableBean )</li>
<li>설정 정보에 초기화 메소드, 종료 메소드 지정</li>
<li>@PostConstruct, @PreDestroy 어노테이션 지원</li>
</ol>
<br>

<h4 id="1-인터페이스-initializingbean-disposablebean-">1. 인터페이스( InitializingBean, DisposableBean )</h4>
<pre><code>public class ExampleBean implements InitializingBean, DisposableBean {

    @Override
    public void afterPropertiesSet() throws Exception {
        // 초기화 콜백 (의존관계 주입이 끝나면 호출)
    }

    @Override
    public void destroy() throws Exception {
        // 소멸 전 콜백 (Bean 종료 전 메모리 반납, 연결 종료와 같은 과정)
    }
}</code></pre><ul>
<li><strong>빈 객체의 클래스가</strong> <code>InitializingBean Interface</code> 또는 <code>DisposableBean</code>을 구현하고 있으며 해당 인터페이스에서 <strong>정의된 메소드를 호출해 빈 객체의 초기화 또는 종료를 수행</strong>한다.</li>
</ul>
<h4 id="단점">(단점)</h4>
<ol>
<li>해당 코드가 인터페이스에 의존한다.</li>
<li>초기화, 소멸 메소드를 오버라이드 하기 때문에 메소드명을 변경할 수 없다.</li>
<li>코드를 커스터마이징 할 수 없는 외부 라이브러리에 적용 불가능하다.</li>
</ol>
<blockquote>
<p><del>** 현재는 거의 쓰지 않음**</del>( 초창기 방법임)</p>
</blockquote>
<br>


<h4 id="2-설정-정보에서-초기화-메소드-종료-메소드-지정">2. 설정 정보에서 초기화 메소드, 종료 메소드 지정</h4>
<pre><code>public class ExampleBean {

    public void initialize() throws Exception {
        // 초기화 콜백 (의존관계 주입이 끝나면 호출)
    }

    public void close() throws Exception {
        // 소멸 전 콜백 (메모리 반납, 연결 종료와 같은 과정)
    }
}

@Configuration
class LifeCycleConfig {

    @Bean(initMethod = &quot;initialize&quot;, destroyMethod = &quot;close&quot;)
    public ExampleBean exampleBean() {
        // 생략
    }
}</code></pre><h4 id="장점">장점</h4>
<ol>
<li>메소드명을 자유롭게 부여 가능하다.</li>
<li><strong>스프링 코드에 의존하지 않는다.</strong></li>
<li>설정 정보를 사용하기 때문에 코드를 커스터마이징 할 수 없는 외부라이브러리에서도 적용 가능하다.</li>
</ol>
<h4 id="단점-1">단점</h4>
<ul>
<li>Bean 지정시 <code>initMethod</code>와 <code>destoryMethod</code>를 <strong>직접 지정해야 하기에 번거롭다.</strong></li>
</ul>
<br>


<h4 id="-참고">+) 참고</h4>
<blockquote>
<ul>
<li><code>@Bean</code>의 <strong><code>destoryMethod</code>는 기본값이 inferred(추론)</strong>으로 등록 </li>
</ul>
</blockquote>
<ul>
<li>즉, <code>close</code>, <code>shutdown</code>이라는 이름의 메소드가 &#39;종료 메소드이군~!&#39;이라고 추론하고 🤔 <strong>자동으로 호출</strong>해준다.👍
=&gt; 즉, <strong>종료 메소드를 따로 부여하지 않더라도 잘 작동</strong>한다.</li>
</ul>
<p><br><br></p>
<h4 id="3-어노테이션을-이용한-빈-초기화-방법에는-postconstruct와-빈-소멸에서는-predestory를-사용한다">3. 어노테이션을 이용한 <strong>빈 초기화</strong> 방법에는 <strong>@PostConstruct</strong>와 <strong>빈 소멸</strong>에서는 <strong>@PreDestory를 사용</strong>한다.</h4>
<pre><code>import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class ExampleBean {

    @PostConstruct
    public void initialize() throws Exception {
        // 초기화 콜백 (의존관계 주입이 끝나면 호출)
    }

    @PreDestroy
    public void close() throws Exception {
        // 소멸 전 콜백 (메모리 반납, 연결 종료와 같은 과정)
    }
}</code></pre><h4 id="장점-1">장점</h4>
<ul>
<li>최신 스프링에서 가장 권장하는 방법이다.</li>
</ul>
<ol>
<li>어노테이션 하나만 붙이면 되므로 매우 편리하다.</li>
<li>패키지가 <code>javax.annotation.xxx</code> 이다. 
 -&gt; 자바 표준이다. <strong>따라서 스프링이 아닌 다른 컨테이너에서도 동작한다.</strong></li>
<li>컴포넌트 스캔과 잘 어울린다.<br>

</li>
</ol>
<h4 id="단점-2">단점</h4>
<ul>
<li>커스터마이징이 불가능한 <strong>외부 라이브러리에서 적용이 불가능</strong>하다.<blockquote>
<p>외부 라이브러리에서 초기화, 종료를 해야 할 경우 <strong>두 번째 방법 즉, <code>@Bean</code>의 <code>initMethod</code>와 <code>destoryMethod</code> 속성을 사용하자.</strong></p>
</blockquote>
</li>
</ul>
<br>
<br>



<hr>
<h3 id="bean과-component-차이점">@Bean과 @Component 차이점</h3>
<blockquote>
<p>&quot;둘다 빈으로 등록되게 하고 관리되게 해주는 것이라던데,,, 빈을 생성하는데 @Bean과 @Component 어노테이션 둘의 차이 점은 무엇일까?&quot; 🤔</p>
</blockquote>
<h4 id="1-왜why-사용하는가">1. 왜(why) 사용하는가?</h4>
<p>A. <strong>특정 객체를 의존하는 다른 객체들에게 의존성을 주입하기 위해서</strong>입니다. </p>
<p>이를 위해서 Spring IoC 컨테이너에서 관리할 수 있도록, 즉 ApplicationContext가 관리하는 bean으로 등록하기 위해서 이런 어노테이션을 붙이는 것이고, 해당 어노테이션이 붙은 객체들을 의존하는 다른 객체들이 컨테이너가 빈으로 등록하여 관리하는 의존성을  @Autowired를 선언함으로써 주입받을 수 있습니다.</p>
<br>

<h4 id="2-bean과-component-사용하는-방법-how">2. @Bean과 @Component 사용하는 방법 (How)</h4>
<ul>
<li><code>@Bean</code>은 <ul>
<li><code>@Configuration</code>이나 <code>@Component</code> 어노테이션이 붙은 클래스 내에 메서드 레벨에서 사용</li>
</ul>
</li>
<li><code>@Component</code>는<ul>
<li>클래스 레벨에서 사용</li>
</ul>
</li>
</ul>
<br>

<h4 id="결론적으로-차이점은">결론적으로 차이점은</h4>
<p><code>@Bean</code>은 <strong>개발자가 <del>직접 작성하지 않은</del> 서드파티 라이브러리의 설정과 같은 의존성</strong>을 주입받기 위해서 사용하기에 적절하고,(@Configuration이 붙은 설정 파일에 주로 선언함) 
<code>@Component</code>는 <strong>개발자가 직.접. 작성한 코드에 있는 의존성을 주입받기 위해</strong>서 사용하기에 적절</p>
<p><br><br></p>
<hr>
<h3 id="면접-때-나올-수-있는-질문">면접 때 나올 수 있는 질문</h3>
<ul>
<li>싱글톤 레지스트리를 통해서 싱글톤 객체를 생성만 해주는거지 동기화 같은것은 개발자가 해줘야 함 =&gt; 싱글톤 빈은 thread-safe하지 않다.</li>
</ul>
<ul>
<li><p>컴포넌트 스캔은 스프링 스캔을 어디서부터 시작하는지 </p>
</li>
<li></li>
</ul>
<p><br><br></p>
<h3 id="출처">출처</h3>
<p><a href="https://developer-ellen.tistory.com/198">developer-ellen</a>님의 글을 바탕으로 작성하였습니다.</p>
<p><a href="https://dev-coco.tistory.com/80">dev-coco</a>님의 이 글을 바탕으로 작성하였습니다.
<a href="https://dev-coco.tistory.com/170">dev-coco</a>님의 이 글을 바탕으로 작성하였습니다.</p>
]]></description>
        </item>
    </channel>
</rss>