<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>매일 조금씩</title>
    <link>https://gimmesome.tistory.com/</link>
    <description>매일 조금씩</description>
    <language>ko</language>
    <pubDate>Wed, 5 Aug 2026 18:38:58 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>mezo</managingEditor>
    <image>
      <title>매일 조금씩</title>
      <url>https://tistory1.daumcdn.net/tistory/3220716/attach/5ba65ca1e24741f390afa67f2d48778f</url>
      <link>https://gimmesome.tistory.com</link>
    </image>
    <item>
      <title>트랜잭션 격리 수준 (feat. 비관적 락, 낙관적 락, MVCC)</title>
      <link>https://gimmesome.tistory.com/320</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;트랜잭션 격리 수준이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스에서 여러 트랜잭션이 동시에 실행될 때,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각의 트랜잭션이 다른 트랜잭션으로부터 얼마나 독립적으로 동작할 수 있는지를 정의하는 기준이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통해 &lt;b&gt;동시성 문제&lt;/b&gt;(Concurrency Issues)를 제어하고 데이터의 일관성을 유지한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;주요 동시성 문제&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Dirty Read (더티 리드)&lt;/b&gt;&lt;br /&gt;다른 트랜잭션이 아직 커밋하지 않은 데이터를 읽는 현상.&lt;br /&gt;&lt;u&gt;업데이트, 삭제&lt;/u&gt;에 대해 발생하고, 행 락으로 방지할 수 있다. Read Commited 이상에선 방지된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Non-Repeatable Read (반복 불가능한 읽기)&lt;/b&gt;&lt;br /&gt;한 트랜잭션 내에서 같은 데이터를 두 번 읽을 때 값이 다른 현상. (다른 트랜잭션이 데이터를 수정한 경우)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Phantom Read (팬텀 리드)&lt;/b&gt;&lt;br /&gt;한 트랜잭션이 동일한 쿼리를 두 번 실행할 때, &lt;br /&gt;다른 트랜잭션의 &lt;u&gt;삽입/삭제&lt;/u&gt;로 인해 데이터가 유령(Phantom)처럼 있었는데 없었어요 하며 &lt;br /&gt;조회 결과의 레코드 수나 내용이 달라지는 현상.&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;트랜잭션 격리 수준 종류 (MySQL 기준)&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Read Uncommitted (읽기 미완료 허용)&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;MVCC 사용 X&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커밋되지 않은 데이터를 읽을 수 있음.&lt;/li&gt;
&lt;li&gt;가장 낮은 격리 수준, 높은 동시성 제공.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;문제점&lt;/b&gt;: Dirty Read, Non-Repeatable Read, Phantom Read 발생 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Read Committed (읽기 완료 허용) - &lt;span style=&quot;color: #006dd7;&quot;&gt;MVCC 적극 사용&lt;/span&gt;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커밋된 데이터만 읽을 수 있음.&lt;/li&gt;
&lt;li&gt;Dirty Read 방지.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;문제점&lt;/b&gt;: Non-Repeatable Read, Phantom Read 발생 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Repeatable Read (반복 가능한 읽기) - &lt;span style=&quot;color: #006dd7;&quot;&gt;MVCC 적극 사용&lt;/span&gt;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션 내에서 동일한 데이터를 반복적으로 읽을 때 항상 같은 결과를 보장.&lt;/li&gt;
&lt;li&gt;Dirty Read와 Non-Repeatable Read 방지.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;문제점&lt;/b&gt;: Phantom Read 발생 가능. &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;i&gt;(MySQL에선 발생 안함. 아래에서 설명)&lt;/i&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Serializable (직렬화 가능) &lt;b&gt;-&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;MVCC 부분 사용&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가장 높은 격리 수준.&lt;/li&gt;
&lt;li&gt;트랜잭션을 순차적으로 실행하는 것처럼 동작.&lt;/li&gt;
&lt;li&gt;Dirty Read, Non-Repeatable Read, Phantom Read 모두 방지.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단점&lt;/b&gt;: 성능 저하, 동시성 감소.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;격리 수준 선택 기준&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;동시성&lt;/b&gt;이 중요한 경우: 낮은 수준(Read Uncommitted, Read Committed).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 일관성&lt;/b&gt;이 중요한 경우: 높은 수준(Repeatable Read, Serializable).&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;트랜잭션 격리 수준 설정 (SQL 예시)&lt;/h3&gt;
&lt;pre id=&quot;code_1735541848215&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SET TRANSACTION ISOLATION LEVEL READ COMMITTED;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;DB별 기본 격리 수준&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;MySQL&lt;/b&gt;: Repeatable Read.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Oracle&lt;/b&gt;: Read Committed.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PostgreSQL&lt;/b&gt;: Read Committed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;트랜잭션 격리 수준은 총 4단계일까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;=&amp;gt; &lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;DB 마다 다르다&lt;/span&gt;&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에 설명한 격리 수준은 &lt;b&gt;MySQL&lt;/b&gt; 기준이고, 4단계이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Oracle&lt;/b&gt;, &lt;b&gt;Tibero&lt;/b&gt;는 &lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;총 3단계를 제공한다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;dirty read를 엄격히 금지하여 read uncommited는 아예 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;MySQL은 기본으로 Repeatable Read 인데, Phantom Read가 발생하지 않는다?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;=&amp;gt; 그렇다. &lt;b&gt;MySQL의 InnoDB 스토리지 엔진&lt;/b&gt;은 MVCC(Multi-Version Concurrency Control)를 사용하기 때문에, &lt;b&gt;Repeatable Read&lt;/b&gt; 격리 수준에서도 &lt;b&gt;Phantom Read&lt;/b&gt;가 발생하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;MySQL에서 Phantom Read 방지 메커니즘&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;MVCC&lt;br /&gt;MVCC란,&amp;nbsp; &lt;/b&gt;하나의 데이터를 여러 버전으로 관리하면서 트랜잭션마다 자기만의 스냅샷(버전)을 읽게 하는 방식.&lt;b&gt;&lt;br /&gt;&lt;/b&gt;MySQL의 InnoDB는 &lt;b&gt;MVCC&lt;/b&gt;를 통해 트랜잭션이 시작될 때 &lt;br /&gt;undo log 기반으로 해당 트랜잭션 ID가 볼수 있는 데이저 버전 목록을 기억하여 &lt;b&gt;스냅샷&lt;/b&gt;(Snapshot)을 생성하고, &lt;br /&gt;트랜잭션 동안 동일한 스냅샷을 참조한다. &lt;br /&gt;이를 통해 &lt;b&gt;반복 가능한 읽기(Repeatable Read)&lt;/b&gt;를 보장한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;READ COMMITTED 는 쿼리마다 새로운 스냅샷&lt;/li&gt;
&lt;li&gt;REAPEATABLE READ 는 트랜잭션 시작 시점 스냅샷 유지&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Next-Key Locking&lt;/b&gt;&lt;br /&gt;MySQL은 Repeatable Read에서 레코드 락(Record Lock)과 갭 락(Gap Lock)을 조합한 &lt;b&gt;Next-Key Locking&lt;/b&gt;을 사용.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;레코드 락&lt;/b&gt;: 특정 행(row)을 잠금.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;갭 락&lt;/b&gt;: 특정 행 주변의 인덱스 범위(gap)를 잠금.&lt;/li&gt;
&lt;/ul&gt;
이를 통해 삽입(INSERT)을 포함한 트랜잭션 간의 데이터 충돌을 방지하므로 ,&lt;br /&gt;&lt;b&gt;Phantom Read&lt;/b&gt; 문제 또한 발생하지 않도록 막을 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MySQL의 REPEATABLE READ는 &lt;b&gt;MVCC + Next-Key Locking(갭 락)&lt;/b&gt;&amp;nbsp;덕분에&lt;br /&gt;&lt;b&gt;phantom read 없이 높은 격리성을 제공&lt;/b&gt;하며,&lt;br /&gt;일부 상황에서는 &lt;b&gt;다른 DB의 SERIALIZABLE과 유사하게 동작&lt;/b&gt;한다고 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Next-Key Locking과 트랜잭션 ID(Transaction ID)의 쓰임과 관계는?&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Next-Key Locking : &lt;br /&gt;&lt;b&gt;Next-Key Locking&lt;/b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;은 &lt;/span&gt;&lt;b&gt;동시성 제어와 데이터 무결성 보장&lt;/b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;을 위해 MySQL InnoDB가 사용하는 잠금 메커니즘.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;목적&lt;/b&gt;: 트랜잭션 간 충돌을 방지하고 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;Phantom Read를 막기 위해&lt;/span&gt; 인덱스의 특정 범위와 해당 데이터를 잠금.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;작동 방식&lt;/b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;:&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;레코드 락 (Record Lock)&lt;/b&gt;: 행 자체에 락을 설정.(SELECT ... FOR UPDATE와 같은 쿼리에서 사용)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;갭 락 (Gap Lock)&lt;/b&gt;: 행 사이의 &quot;갭&quot;에 락을 설정. (id = 10, 20 이 있으면 10부터 20까지 갭에 락이 걸려서 id = 15를 insert 하려고 해도 안됨)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Next-Key Lock&lt;/b&gt;: 레코드 락 + 갭 락을 결합하여 사용.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;트랜잭션 ID (Transaction ID) :&lt;br /&gt;&lt;b&gt;트랜잭션 ID&lt;/b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;는 각 트랜잭션을 고유하게 식별하는 &lt;/span&gt;&lt;b&gt;ID&lt;/b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;로, InnoDB에서 MVCC를 구현하는 데 사용.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;목적&lt;/b&gt;: 트랜잭션 간 데이터의 &lt;b&gt;일관성&lt;/b&gt;을 보장하고, 어떤 트랜잭션이 어떤 데이터를 읽거나 변경했는지를 추적.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;작동 방식&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;트랜잭션이 시작될 때마다 고유한 트랜잭션 ID가 할당된다.&lt;/li&gt;
&lt;li&gt;MVCC는 이 트랜잭션 ID를 사용해 데이터의 &lt;b&gt;버전&lt;/b&gt;을 관리.&lt;/li&gt;
&lt;li&gt;특정 트랜잭션이 볼 수 있는 데이터의 범위를 결정.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;그럼 낙관적 락, 비관적 락은 왜 사용할까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션 격리 수준은 주로 &lt;b&gt;읽기 시점의 일관성&lt;/b&gt;을 보장하는 기능이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;읽기뿐 아니라 동시 수정에 대한 충돌 방지도 필요하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 두 트랜잭션이 동시에 같은 데이터를 읽고, 각자 수정한 뒤 커밋하려 하면 마지막에 덮어쓰기가 발생하여,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀더빨리 업데이트한 데이터가 유실될수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런&lt;b&gt; 쓰기 충돌&lt;/b&gt;은 트랜잭션 격리 수준만으로는 완벽히 제어할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SERIALIZABLE로 예방할 수 있지만, SERIALIZABLE은 동일한 데이터에 대해 읽고 쓰려는 트랜잭션이 동시에 존재하면 한쪽 트랜잭션을 롤백 처리해버려서 강제 실패시킨다. 그래서 성능 저하와 재시도하는 예외 처리를 개발자가 추가해야하기 때문에 이런 부담으로 실무에선 잘 쓰지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;549&quot; data-start=&quot;509&quot; data-ke-size=&quot;size23&quot;&gt;그래서 등장하는 것이 바로 &lt;b&gt;비관적 락과 낙관적 락&lt;/b&gt;이다.&lt;/h3&gt;
&lt;h4 data-end=&quot;582&quot; data-start=&quot;551&quot; data-ke-size=&quot;size20&quot;&gt;  비관적 락(Pessimistic Lock)&lt;/h4&gt;
&lt;blockquote data-end=&quot;630&quot; data-start=&quot;584&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p data-end=&quot;630&quot; data-start=&quot;586&quot; data-ke-size=&quot;size16&quot;&gt;&quot;다른 트랜잭션이 데이터를 건드릴 거라 생각하고 &lt;b&gt;선제적으로 락을 건다.&lt;/b&gt;&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;750&quot; data-start=&quot;632&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;663&quot; data-start=&quot;632&quot;&gt;대표 예: SELECT ... FOR UPDATE&lt;/li&gt;
&lt;li data-end=&quot;707&quot; data-start=&quot;664&quot;&gt;데이터 조회와 동시에 &lt;b&gt;행에 락을 걸어&lt;/b&gt;, 다른 트랜잭션의 접근을 차단&lt;/li&gt;
&lt;li data-end=&quot;750&quot; data-start=&quot;708&quot;&gt;&lt;b&gt;확실한 충돌 방지 가능&lt;/b&gt;, 하지만 락 경쟁 발생 시 성능 저하 우려&lt;/li&gt;
&lt;li data-end=&quot;750&quot; data-start=&quot;708&quot;&gt;@Lock으로 가능(PESSIMISTIC_READ - 공유락(읽기만 허용), PESSIMISTIC_WRITE - 배타 락(쓰기/읽기 모두 막음))&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;782&quot; data-start=&quot;752&quot; data-ke-size=&quot;size20&quot;&gt;  낙관적 락(Optimistic Lock)&lt;/h4&gt;
&lt;blockquote data-end=&quot;819&quot; data-start=&quot;784&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p data-end=&quot;819&quot; data-start=&quot;786&quot; data-ke-size=&quot;size16&quot;&gt;&quot;충돌이 드물 거라 믿고, &lt;b&gt;변경 시점에만 검증&lt;/b&gt;한다.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;940&quot; data-start=&quot;821&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;844&quot; data-start=&quot;821&quot;&gt;대표 예: JPA의 @Version&lt;/li&gt;
&lt;li data-end=&quot;900&quot; data-start=&quot;845&quot;&gt;데이터를 읽을 때는 자유롭게 읽고,&lt;br /&gt;저장 시점에 (업데이트하려는 대상 데이터와 업데이트용 엔티티의)&lt;b&gt;버전 번호를 비교해서 충돌을 감지&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;940&quot; data-start=&quot;901&quot;&gt;성능에 유리하지만, 충돌 발생 시 &lt;b&gt;예외 발생 후 재시도 필요&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;그럼 분산락은 왜 필요한가?&lt;/h3&gt;
&lt;p data-end=&quot;833&quot; data-start=&quot;788&quot; data-ke-size=&quot;size16&quot;&gt;비관적/낙관적 락은 충돌 시 대부분 &lt;b&gt;&amp;lsquo;폴링 기반 재시도&amp;rsquo;&lt;/b&gt;로 처리된다.&lt;/p&gt;
&lt;p data-end=&quot;833&quot; data-start=&quot;788&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #7e98b1;&quot;&gt;&lt;i&gt;(비관적 락은 DB가 직접 락을 걸고 기다리는 '진짜 대기' 구조이고, &lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #7e98b1;&quot;&gt;&lt;i&gt;낙관적 락과 SERIALIZABLE은 작업 시도 후 예외가 발생하면 개발자가 수동으로 재시도 로직을 구현하는 구조)&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;833&quot; data-start=&quot;788&quot; data-ke-size=&quot;size16&quot;&gt;이는 성공할 때까지 계속 시도하는 구조이기 때문에, 결과적으로 &lt;b&gt;CPU, 스레드, DB 부하 등 리소스 낭비&lt;/b&gt;가 발생한다.&lt;/p&gt;
&lt;p data-end=&quot;833&quot; data-start=&quot;788&quot; data-ke-size=&quot;size16&quot;&gt;특히 &lt;b&gt;MSA 구조에서는 요청량이 많고, 서비스 간 호출이 겹치기 때문에&lt;/b&gt;,&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;833&quot; data-start=&quot;788&quot; data-ke-size=&quot;size16&quot;&gt;재시도 로직이 &lt;b&gt;성능 저하&lt;/b&gt;는 물론, &lt;b&gt;장애를 연쇄적으로 전파시킬 위험&lt;/b&gt;도 크다.&lt;/p&gt;
&lt;p data-end=&quot;833&quot; data-start=&quot;788&quot; data-ke-size=&quot;size16&quot;&gt;또한, 여러 자원에 동시에 락을 거는 상황에서는 서로 교차 락을 걸다가 데드락(Deadlock)이 발생할 가능성도 존재한다.&lt;br /&gt;데드락은 트랜잭션이 &lt;b&gt;영원히 대기 상태에 빠지는 치명적인 문제&lt;/b&gt;로, 폴링 방식의 재시도 구조에서는 감지와 해소가 어렵다.&lt;/p&gt;
&lt;p data-end=&quot;633&quot; data-start=&quot;556&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;633&quot; data-start=&quot;556&quot; data-ke-size=&quot;size16&quot;&gt;✅ 이러한 문제를 해결하기 위해&lt;br /&gt;전역에서 락을 일관되게 관리할 수 있는 '분산 락(Distributed Lock)'이 필요하다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;901&quot; data-start=&quot;635&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;716&quot; data-start=&quot;635&quot;&gt;&lt;b&gt;Redis나 ZooKeeper 기반 분산 락&lt;/b&gt;은&lt;br /&gt;여러 서버나 인스턴스가 &lt;b&gt;동일한 자원을 동시에 조작하지 못하게 막아주고&lt;/b&gt;,&lt;/li&gt;
&lt;li data-end=&quot;799&quot; data-start=&quot;717&quot;&gt;TTL(Time to Live)과 &lt;b&gt;try-lock 구조&lt;/b&gt;를 통해&lt;br /&gt;락이 오래 유지되어 생기는 &lt;b&gt;데드락도 예방&lt;/b&gt;할 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;901&quot; data-start=&quot;800&quot;&gt;또한, &lt;b&gt;락 획득 순서를 강제하거나&lt;/b&gt;&lt;br /&gt;재시도 횟수와 대기 시간(Backoff)을 조절함으로써&lt;br /&gt;분산 환경에서도 &lt;b&gt;안정적인 자원 접근 제어가 가능&lt;/b&gt;하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>mezo</author>
      <guid isPermaLink="true">https://gimmesome.tistory.com/320</guid>
      <comments>https://gimmesome.tistory.com/320#entry320comment</comments>
      <pubDate>Mon, 30 Dec 2024 20:51:08 +0900</pubDate>
    </item>
    <item>
      <title>Leet code (Easy): 1768. Merge Strings Alternately - Java</title>
      <link>https://gimmesome.tistory.com/319</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-11-19 오후 8.58.04.png&quot; data-origin-width=&quot;2100&quot; data-origin-height=&quot;1070&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FINrc/btsKOKkDw96/FP4uxK5kTSLRjSxDIKvyAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FINrc/btsKOKkDw96/FP4uxK5kTSLRjSxDIKvyAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FINrc/btsKOKkDw96/FP4uxK5kTSLRjSxDIKvyAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFINrc%2FbtsKOKkDw96%2FFP4uxK5kTSLRjSxDIKvyAk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2100&quot; height=&quot;1070&quot; data-filename=&quot;스크린샷 2024-11-19 오후 8.58.04.png&quot; data-origin-width=&quot;2100&quot; data-origin-height=&quot;1070&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-11-19 오후 8.58.22.png&quot; data-origin-width=&quot;2056&quot; data-origin-height=&quot;726&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5cEab/btsKQfp8ZN4/bR2M1Kbgdyke7prY8ZFkc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5cEab/btsKQfp8ZN4/bR2M1Kbgdyke7prY8ZFkc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5cEab/btsKQfp8ZN4/bR2M1Kbgdyke7prY8ZFkc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5cEab%2FbtsKQfp8ZN4%2FbR2M1Kbgdyke7prY8ZFkc0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2056&quot; height=&quot;726&quot; data-filename=&quot;스크린샷 2024-11-19 오후 8.58.22.png&quot; data-origin-width=&quot;2056&quot; data-origin-height=&quot;726&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1732017537527&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
    public String mergeAlternately(String word1, String word2) {
        StringBuilder merged = new StringBuilder();
        int maxLength = Math.max(word1.length(), word2.length());

        for(int i = 0; i &amp;lt; maxLength; i++){
            if(i &amp;lt; word1.length()){
                merged.append(word1.charAt(i));
            }
            if(i &amp;lt; word2.length()){
                merged.append(word2.charAt(i));
            }
        }

        return merged.toString();
        
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/String</category>
      <author>mezo</author>
      <guid isPermaLink="true">https://gimmesome.tistory.com/319</guid>
      <comments>https://gimmesome.tistory.com/319#entry319comment</comments>
      <pubDate>Tue, 19 Nov 2024 21:00:23 +0900</pubDate>
    </item>
    <item>
      <title>[IoC 컨테이너와 빈] 6. Environment 2부. 프로퍼티</title>
      <link>https://gimmesome.tistory.com/318</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[전체 목차]&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;IoC 컨테이너와 빈
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스프링 IoC 컨테이너와 빈&lt;/li&gt;
&lt;li&gt;ApplicationContext와 다양한 빈 설정 방법&lt;/li&gt;
&lt;li&gt;@Autowired&lt;/li&gt;
&lt;li&gt;@Component와 컴포넌트 스캔&lt;/li&gt;
&lt;li&gt;빈의 스코프&lt;/li&gt;
&lt;li&gt;Environment - 프로파일&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;Environment - 프로퍼티&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#no1&quot;&gt;프로퍼티&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#no2&quot;&gt;프로퍼티에는 우선순위가 있다&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#no3&quot;&gt;@PropertySource&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#no4&quot;&gt;스프링 부트 외부 설정 참고&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Resource / Validation&lt;/li&gt;
&lt;li&gt;데이터 바인딩&lt;/li&gt;
&lt;li&gt;SpEL&lt;/li&gt;
&lt;li&gt;스프링 AOP&lt;/li&gt;
&lt;li&gt;Null-Safety&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no1&quot; data-ke-size=&quot;size26&quot;&gt;1. 프로퍼티&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다양한 방법으로 정의할 수 있는 설정값&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Environment&lt;/code&gt;의 역할은 프로퍼티 소스 설정 및 프로퍼티 값 가져오기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 애플리케이션 JVM 옵션으로 &lt;code&gt;Active profiles&lt;/code&gt; 값을 설정해 두고.. (여기선 test로 설정)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1634&quot; data-origin-height=&quot;1398&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKh8WV/btsKMd1j9h9/jsIxCnab3gRQIHhuLRU50K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKh8WV/btsKMd1j9h9/jsIxCnab3gRQIHhuLRU50K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKh8WV/btsKMd1j9h9/jsIxCnab3gRQIHhuLRU50K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKh8WV%2FbtsKMd1j9h9%2FjsIxCnab3gRQIHhuLRU50K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1634&quot; height=&quot;1398&quot; data-origin-width=&quot;1634&quot; data-origin-height=&quot;1398&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래처럼 &lt;code&gt;env.getProperty(&quot;spring.profiles.active&quot;)&lt;/code&gt; 로 가져와서 로그를 찍으면..!&lt;/p&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;package com.test.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Objects;

@Component
public class AppRunner implements ApplicationRunner {

    @Autowired
    ApplicationContext ctx;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        Environment env = ctx.getEnvironment();
        System.out.println(Arrays.toString(Objects.requireNonNull(env.getProperty(&quot;spring.profiles.active&quot;)).split(&quot;,&quot;)));
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1488&quot; data-origin-height=&quot;672&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bly5Hw/btsKLyyanu4/84L6uoFkpNNs7bzTeYljgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bly5Hw/btsKLyyanu4/84L6uoFkpNNs7bzTeYljgK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bly5Hw/btsKLyyanu4/84L6uoFkpNNs7bzTeYljgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbly5Hw%2FbtsKLyyanu4%2F84L6uoFkpNNs7bzTeYljgK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1488&quot; height=&quot;672&quot; data-origin-width=&quot;1488&quot; data-origin-height=&quot;672&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위처럼 내가 설정해둔 값인 &quot;test&quot; 가 찍힌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no2&quot; data-ke-size=&quot;size26&quot;&gt;2. 프로퍼티에는 우선 순위가 있다.&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;StandardServletEnvironment의 우선순위
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ServletConfig 매개변수&lt;/li&gt;
&lt;li&gt;ServletContext 매개변수&lt;/li&gt;
&lt;li&gt;JNDI (java:comp/env/)&lt;/li&gt;
&lt;li&gt;JVM 시스템 프로퍼티 (-Dkey=&amp;rdquo;value&amp;rdquo;)&lt;/li&gt;
&lt;li&gt;JVM 시스템 환경 변수 (운영 체제 환경 변수)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no3&quot; data-ke-size=&quot;size26&quot;&gt;3. @PropertySource&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Environment를 통해 프로퍼티 추가하는 방법&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 효율적으로 properties를 설정하고 싶다! 하면 properties 파일을 하나 만들어서 (여기선 app.properties)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 어노테이션을 추가하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1056&quot; data-origin-height=&quot;362&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/onkhC/btsKL9dL214/6zKq53nbKqhHTIdxEzkeV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/onkhC/btsKL9dL214/6zKq53nbKqhHTIdxEzkeV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/onkhC/btsKL9dL214/6zKq53nbKqhHTIdxEzkeV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FonkhC%2FbtsKL9dL214%2F6zKq53nbKqhHTIdxEzkeV1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1056&quot; height=&quot;362&quot; data-origin-width=&quot;1056&quot; data-origin-height=&quot;362&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 아래와 같이 제대로 가져와서 출력도 되는걸 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2722&quot; data-origin-height=&quot;1644&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NJzZH/btsKL9kxSul/qF6bdVu5baRkaznZlkO6Ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NJzZH/btsKL9kxSul/qF6bdVu5baRkaznZlkO6Ck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NJzZH/btsKL9kxSul/qF6bdVu5baRkaznZlkO6Ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNJzZH%2FbtsKL9kxSul%2FqF6bdVu5baRkaznZlkO6Ck%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2722&quot; height=&quot;1644&quot; data-origin-width=&quot;2722&quot; data-origin-height=&quot;1644&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no4&quot; data-ke-size=&quot;size26&quot;&gt;4. 스프링 부트의 외부 설정 참고&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본 프로퍼티 소스 지원 (application.properties)&lt;/li&gt;
&lt;li&gt;프로파일까지 고려한 계층형 프로퍼티 우선 순위 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계층형이라 JVM옵션으로 준 프로퍼티와 프로퍼티 파일을 하나 만들어서 적용한 프로퍼티 둘 중 하나만 찍힐텐데..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과연 어떤게 더 우선순위가 높을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JVM 옵션이 더 우선순위가 높다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;※ 요약&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;- &lt;b&gt;Profile :&lt;/b&gt; 환경에 맞춰 사용할 수 있는 하나의 큰 설정 파일 그룹.&lt;br /&gt;- &lt;b&gt;Property :&lt;/b&gt; Profile 파일 안에 들어 있는 구체적인 설정 값.&lt;br /&gt;- &lt;b&gt;@Value:&lt;/b&gt; 코드 내에서 프로퍼티 값을 가져와서 사용할 수 있도록 해주는 어노테이션.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring Framework/스프링 프레임워크 핵심 기술</category>
      <author>mezo</author>
      <guid isPermaLink="true">https://gimmesome.tistory.com/318</guid>
      <comments>https://gimmesome.tistory.com/318#entry318comment</comments>
      <pubDate>Sun, 17 Nov 2024 19:15:06 +0900</pubDate>
    </item>
    <item>
      <title>[IoC 컨테이너와 빈] 6. Environment 1부. 프로파일</title>
      <link>https://gimmesome.tistory.com/317</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[전체 목차]&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;IoC 컨테이너와 빈
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스프링 IoC 컨테이너와 빈&lt;/li&gt;
&lt;li&gt;ApplicationContext와 다양한 빈 설정 방법&lt;/li&gt;
&lt;li&gt;@Autowired&lt;/li&gt;
&lt;li&gt;@Component와 컴포넌트 스캔&lt;/li&gt;
&lt;li&gt;빈의 스코프&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;Environment - 프로파일&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#no1&quot;&gt;ApplicationContext extends EnvironmentCapable&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#no2&quot;&gt;프로파일&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#no3&quot;&gt;프로파일 유즈케이스&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#no4&quot;&gt;프로파일 정의하기&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#no5&quot;&gt;프로파일 설정하기&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#no6&quot;&gt;프로파일 표현식&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Resource / Validation&lt;/li&gt;
&lt;li&gt;데이터 바인딩&lt;/li&gt;
&lt;li&gt;SpEL&lt;/li&gt;
&lt;li&gt;스프링 AOP&lt;/li&gt;
&lt;li&gt;Null-Safety&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;ApplicationContext&lt;/code&gt; 는 실제로 아주 많은 인터페이스들을 상속 받고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;EnvironmentCapable&lt;/code&gt;, &lt;code&gt;ListableBeanFactory&lt;/code&gt;, &lt;code&gt;HierarchicalBeanFactory&lt;/code&gt; ... 등&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 중 하나 &lt;code&gt;EnvironmentCapable&lt;/code&gt;의 기능들에 대해 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no1&quot; data-ke-size=&quot;size26&quot;&gt;1. ApplicationContext extends EnvironmentCapable&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;getEnvironment()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 &lt;code&gt;EnvironmentCapable&lt;/code&gt;이 제공하는 여러가지의 기능 중 하나인 프로파일에 대해서 알아볼 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no2&quot; data-ke-size=&quot;size26&quot;&gt;2. 프로파일&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빈들의 그룹&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Environment&lt;/code&gt; 의 역할은 프로파일 확인 및 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로파일은 빈들의 묶음이다. Maven에도 프로파일이 있고, Spring에도 프로파일이 있는데 어떠한 환경이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 어떤 환경에선 어떤 빈들을 쓰겠다는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no3&quot; data-ke-size=&quot;size26&quot;&gt;3. 프로파일 유즈케이스&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테스트 환경에서는 A라는 빈을 사용하고, 배포 환경에서는 B라는 빈을 쓰고 싶다.&lt;/li&gt;
&lt;li&gt;이 빈은 모니터링 용도니까 테스트&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각의 환경에 따라 다른 빈들을 써야 되는 경우 또는 특정 환경에서만 어떤 빈을 등록해야하는 경우 등이 요구사항을 충족시키기 위해 프로파일이 추가됨. 이는 spring의 &lt;code&gt;Environment&lt;/code&gt;를 통해서 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;ApplicationContext&lt;/code&gt;가 &lt;code&gt;EnvironmentCapable&lt;/code&gt;를 상속받기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우린 &lt;code&gt;ApplicationContext&lt;/code&gt;의 &lt;code&gt;getEnvironment()&lt;/code&gt;를 호출해서 &lt;code&gt;Environment&lt;/code&gt;를 가져올 수 있다.&lt;/p&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;package com.test.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
public class AppRunner implements ApplicationRunner {

    @Autowired
    ApplicationContext ctx;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        Environment env = ctx.getEnvironment();
        System.out.println(Arrays.toString(env.getActiveProfiles()));
        System.out.println(Arrays.toString(env.getDefaultProfiles()));
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no4&quot; data-ke-size=&quot;size26&quot;&gt;4. 프로파일 정의하기&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1) 클래스에 정의&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@Configuration @Profile(&quot;test&quot;)&lt;/li&gt;
&lt;li&gt;@Component @Profile(&quot;test&quot;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 &lt;code&gt;@Profile(&quot;test&quot;)&lt;/code&gt;로 설정을 하면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;test라는 프로파일로 애플리케이션을 실행하지 않으면 아래 빈 설정 파일이 적용되지않는다.&lt;/p&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;package com.test.demo;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
@Profile(&quot;test&quot;)
public class TestConfiguration {
    @Bean
    public BookRepository bookRepository(){
        return new TestBookRepository();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2) 메소드에 정의&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@Bean @Profile(&quot;test)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빈에다가 일일이 다 붙여줘야해서 불편할거다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no5&quot; data-ke-size=&quot;size26&quot;&gt;5. 프로파일 설정하기&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Active Profiles: &lt;b&gt;&quot;test&quot;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;VM options: &lt;b&gt;-Dspring.profiles.active=&quot;test,A,B,...&quot;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;@ActiveProfiles (테스트용)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1628&quot; data-origin-height=&quot;1428&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b813nm/btsKLq7Yu5Q/miM0YPD4WeJmbBSBpkI3x0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b813nm/btsKLq7Yu5Q/miM0YPD4WeJmbBSBpkI3x0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b813nm/btsKLq7Yu5Q/miM0YPD4WeJmbBSBpkI3x0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb813nm%2FbtsKLq7Yu5Q%2FmiM0YPD4WeJmbBSBpkI3x0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1628&quot; height=&quot;1428&quot; data-origin-width=&quot;1628&quot; data-origin-height=&quot;1428&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no6&quot; data-ke-size=&quot;size26&quot;&gt;6. 프로파일 표현식&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;! (not)&lt;/li&gt;
&lt;li&gt;&amp;amp; (and)&lt;/li&gt;
&lt;li&gt;| (or)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring Framework/스프링 프레임워크 핵심 기술</category>
      <author>mezo</author>
      <guid isPermaLink="true">https://gimmesome.tistory.com/317</guid>
      <comments>https://gimmesome.tistory.com/317#entry317comment</comments>
      <pubDate>Sun, 17 Nov 2024 18:42:28 +0900</pubDate>
    </item>
    <item>
      <title>Entity가 생성되지 않아서 data.sql 실행에 실패하는 에러 (feat. Spring boot의 DB 초기화)</title>
      <link>https://gimmesome.tistory.com/316</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;spring.jpa.hibernate.ddl-auto와 data.sql 실행 순서 !!&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;spring.jpa.hibernate.ddl-auto 옵션은 JPA가 엔티티를 기반으로 데이터베이스 테이블을 자동 생성하게 한다.&lt;/li&gt;
&lt;li&gt;그러나 Spring Boot 2.5 이후, data.sql 파일이 실행되는 순서가 달라지면서 &lt;b&gt;JPA의 테이블 생성 작업이 완료되기 전에 data.sql이 실행될 수 있는 문제&lt;/b&gt;가 발생했다고 한다..&lt;/li&gt;
&lt;li&gt;해결을 위해 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;spring.jpa.defer-datasource-initialization=true&lt;/span&gt;&lt;/b&gt;를 application.yml에 추가 설정하여 &lt;b&gt;JPA가 엔티티를 기반으로 테이블을 생성한 후에 data.sql이 실행되도록 보장&lt;/b&gt;했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring Framework</category>
      <author>mezo</author>
      <guid isPermaLink="true">https://gimmesome.tistory.com/316</guid>
      <comments>https://gimmesome.tistory.com/316#entry316comment</comments>
      <pubDate>Fri, 8 Nov 2024 17:18:37 +0900</pubDate>
    </item>
    <item>
      <title>[IoC 컨테이너와 빈] 5. 빈의 스코프</title>
      <link>https://gimmesome.tistory.com/315</link>
      <description>&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;[전체 목차]&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;IoC 컨테이너와 빈
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;스프링 IoC 컨테이너와 빈&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;ApplicationContext와 다양한 빈 설정 방법&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;@Autowired&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;@Component와 컴포넌트 스캔&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;빈의 스코프&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#no1&quot;&gt;스코프&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#no2&quot;&gt;프로토타입 빈이 싱글톤 빈을 참조하면?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#no3&quot;&gt;싱글톤 빈이 프로토타입 빈을 참조하면?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#no4&quot;&gt;싱글톤 객체 사용시 주의할 점&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;Resource / Validation&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;데이터 바인딩&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;SpEL&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;스프링 AOP&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;Null-Safety&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no1&quot; data-ke-size=&quot;size26&quot;&gt;1. 스코프&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 지금까지 등록한 모든 빈들은 사실상 스코프라는게 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 중에서도 싱글톤 스코프의 빈들만 사용해왔다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐면 아무런 설정도 하지 않으면 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;Spring에서 기본 설정이 싱글톤 스코프&lt;/span&gt;이기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1) 싱글톤&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;싱글톤 스코프란?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;=&amp;gt; &lt;b&gt;애플리케이션 전반&lt;/b&gt;에서 해당 빈의 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;인스턴스가 오직 한개&lt;/span&gt;뿐인게 싱글톤 스코프다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거의 대부분의 경우에 싱글톤 스코프를 쓸거다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2) 프로토타입&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Request&lt;/li&gt;
&lt;li&gt;Session&lt;/li&gt;
&lt;li&gt;Websocket&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로토타입이라는 스코프는 매번 새로운 인스턴스를 만들어서 써야하는 거다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런 스코프의 경우엔 아래 예시처럼 &lt;code&gt;@Scope&lt;/code&gt;를 사용해서 직접 원하는 스코프를 써주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Enum이라도 추가해주면 좋은데.. 그게 없어서 스트링을 직접 쳐야함.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;532&quot; data-origin-height=&quot;112&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bW0WUE/btsKzGhKsq4/8N95R56MvgmnDFHrG1YcBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bW0WUE/btsKzGhKsq4/8N95R56MvgmnDFHrG1YcBK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bW0WUE/btsKzGhKsq4/8N95R56MvgmnDFHrG1YcBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbW0WUE%2FbtsKzGhKsq4%2F8N95R56MvgmnDFHrG1YcBK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;532&quot; height=&quot;112&quot; data-origin-width=&quot;532&quot; data-origin-height=&quot;112&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러면 프로토타입 빈이기 때문에 해당 빈을 받아 올때마다 새로운 인스턴스가 생성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를들어,&lt;/p&gt;
&lt;pre id=&quot;code_1730898354454&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;applicationContext.getBean(RoomService.class);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 할때마다 새로운 인스턴스를 생성해서 가져온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no2&quot; data-ke-size=&quot;size26&quot;&gt;2. 프로토타입 빈이 싱글톤 빈을 참조하면?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로토타입의 빈이 싱글톤 스코프의 빈을 참조해서(주입받아서) 쓰면 아무 문제가 없다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로토타입 빈은 계속 바뀌지만, 내부의 싱글톤 스코프의 빈은 계속 재활용 되어 하나여서 두개 다 의도된대로 동작하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no3&quot; data-ke-size=&quot;size26&quot;&gt;3. 싱글톤 빈이 프로토타입 빈을 참조하면?&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1) 프로토타입 빈이 업데이트가 안되네?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 반대로, 싱글톤 스코프의 빈이 프로토타입의 빈을 참조해서 쓰면 문제가 생긴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면, 싱글톤 스코프는 변하지 않기때문에 주입받을 때의 그 빈을 계속 가져다가 쓴다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 아래처럼,&lt;/p&gt;
&lt;pre id=&quot;code_1730898607971&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;applicationContext.getBean(Single.class).getProto();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 방식으로 Proto 빈을 가져오면 의도한 것은 매번 다른 빈을 가져오는 거지만, 매번 같은 빈을 가져오게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2) 업데이트 하려면?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 1.12em; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;2-1) scoped-proxy&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 해결하는 방법 중, 이해해보려하면 어렵지만 적용하기에 가장 쉬운 방법은,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;proxy&lt;/span&gt;모드를 설정해주는 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-11-06 오후 10.13.47.png&quot; data-origin-width=&quot;1328&quot; data-origin-height=&quot;74&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p9jv0/btsKyZvDaDp/YDHqtwkdRK1XTrSb65STI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p9jv0/btsKyZvDaDp/YDHqtwkdRK1XTrSb65STI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p9jv0/btsKyZvDaDp/YDHqtwkdRK1XTrSb65STI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp9jv0%2FbtsKyZvDaDp%2FYDHqtwkdRK1XTrSb65STI1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1328&quot; height=&quot;74&quot; data-filename=&quot;스크린샷 2024-11-06 오후 10.13.47.png&quot; data-origin-width=&quot;1328&quot; data-origin-height=&quot;74&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시는 해당 클래스가 인터페이스가 아닌 클래스라서 프록시 모드는 &lt;code&gt;TARGET_CLASS&lt;/code&gt;로 설정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 &lt;code&gt;TARGET_CLASS&lt;/code&gt;를 사용하면 &lt;span style=&quot;background-color: #9feec3;&quot;&gt;CGlib를 사용한 다이나믹 프록시&lt;/span&gt;가 적용이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이게 무슨말이냐 하면..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로토 타입으로 정의한 해당 클래스 빈을 프록시 기반으로 감싸서,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 빈들이 해당 빈을 가져다 쓸 때, 프록시로 감싸진 빈을 가져다 쓰라는 말이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐면, 다른 빈들이 이 프로토타입 스코프의 빈을 직접 참조하면 안되기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 프록시를 거쳐서 참조하도록 해야한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 직접 참조하면 안되냐? 직접 쓰면 바꿔줄 여지가 없기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 자바 기반의 &lt;span style=&quot;background-color: #9feec3;&quot;&gt;JDK 안에 있는 다이나믹 프록시는 인터페이스의 프록시 밖에&lt;/span&gt; 못 만든다..ㅜㅜ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 기존 프로토타입의 클래스를 상속받은 클래스로 프록시를 만들어주는 CGlib 라는 3rd party의 라이브러리가 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 &lt;span style=&quot;background-color: #9feec3;&quot;&gt;CGlib는 클래스도 프록시를 만들 수 있게&lt;/span&gt; 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 위 예시 코드에 추가된 &lt;code&gt;proxyMode = ScopedProxyMode.TARGET_CLASS&lt;/code&gt; 옵션은 어떤 모드로 만들건지,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, CGlib 기반의 클래스를 상속받은 (클래스 기반의) 프록시를 만들도록 언급해 준 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-11-06 오후 10.50.50.png&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;362&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cREuK7/btsKzcBJpZh/sNssFxCchTzdHzk5QLRDIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cREuK7/btsKzcBJpZh/sNssFxCchTzdHzk5QLRDIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cREuK7/btsKzcBJpZh/sNssFxCchTzdHzk5QLRDIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcREuK7%2FbtsKzcBJpZh%2FsNssFxCchTzdHzk5QLRDIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;580&quot; height=&quot;326&quot; data-filename=&quot;스크린샷 2024-11-06 오후 10.50.50.png&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;362&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약, 프로토타입의 클래스가 인터페이스였다면 &lt;code&gt;TARGET_CLASS&lt;/code&gt;가 아닌 &lt;code&gt;INTERFACE&lt;/code&gt;도 쓸수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 JDK에 있는 인터페이스 기반의 프록시를 만들어서 썼을 거다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프록시 인스턴스가 빈으로 등록이 되고, 프록시 빈이 존재하는 기존 빈은 주입될 때 프록시 빈으로 주입이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 프록시에 대해선 AOPA 에서 더 자세하게 다루게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2-2) Object-Provider&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 프록시가 성능에 영향을 줄거같아서 꺼려진다 하면 다른 방법도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로토 타입 빈을 주입받는 클래스에서 다음과 같이 &lt;code&gt;ObjectProvider&lt;/code&gt;로 감싸도록 코드를 변경해주면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1730900240871&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Component
public class Single {

    @Autowired
    private ObjectProvider&amp;lt;Proto&amp;gt; proto;

    public Proto getProto() {
            return proto.getIfAvailable();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 &lt;code&gt;ObjectProvider&lt;/code&gt;는 Spring에서 제공하는 거고, 코드 자체에 Spring코드가 들어가버려서 &lt;u&gt;딱히 추천하진 않는다.&lt;/u&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 위의 프록시를 사용한 방법처럼 빈을 생성할때만 Spring 관련된 스코프 프로필을 쓰는게 낫다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 해서 코드는 완전 POJO스럽게 유지하는게 낫다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분의 상황에선 싱글톤만 써서 걱정안해도 되지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;롱런 하는(싱글톤) 빈이 짧은 생명주기를 가지는 빈들을 주입 받을 때, 위 방법들로 해결하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no4&quot; data-ke-size=&quot;size26&quot;&gt;4. 싱글톤 객체 사용 시 주의할 점&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;프로퍼티가 공유 (멀티스레드 환경에서 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;Thread-safe 보장 x&lt;/span&gt;)&lt;/li&gt;
&lt;li&gt;ApplicationContext 초기 구동 시 인스턴스 생성 (초기 구동시 시간이 더 소요될수 있음)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring Framework/스프링 프레임워크 핵심 기술</category>
      <author>mezo</author>
      <guid isPermaLink="true">https://gimmesome.tistory.com/315</guid>
      <comments>https://gimmesome.tistory.com/315#entry315comment</comments>
      <pubDate>Wed, 6 Nov 2024 23:07:48 +0900</pubDate>
    </item>
    <item>
      <title>Leet code (Medium): 98. Validate Binary Search Tree (재귀) - Java</title>
      <link>https://gimmesome.tistory.com/314</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-11-06 오후 5.21.01.png&quot; data-origin-width=&quot;1452&quot; data-origin-height=&quot;1118&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEnejS/btsKzyDWFUu/79IDxKkBAUpFMdhAR6PxC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEnejS/btsKzyDWFUu/79IDxKkBAUpFMdhAR6PxC1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEnejS/btsKzyDWFUu/79IDxKkBAUpFMdhAR6PxC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEnejS%2FbtsKzyDWFUu%2F79IDxKkBAUpFMdhAR6PxC1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1452&quot; height=&quot;1118&quot; data-filename=&quot;스크린샷 2024-11-06 오후 5.21.01.png&quot; data-origin-width=&quot;1452&quot; data-origin-height=&quot;1118&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-11-06 오후 5.21.33.png&quot; data-origin-width=&quot;1486&quot; data-origin-height=&quot;1264&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mQrLf/btsKyIU8cMF/5Nl4zjLHXibdc0OscsWaQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mQrLf/btsKyIU8cMF/5Nl4zjLHXibdc0OscsWaQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mQrLf/btsKyIU8cMF/5Nl4zjLHXibdc0OscsWaQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmQrLf%2FbtsKyIU8cMF%2F5Nl4zjLHXibdc0OscsWaQ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1486&quot; height=&quot;1264&quot; data-filename=&quot;스크린샷 2024-11-06 오후 5.21.33.png&quot; data-origin-width=&quot;1486&quot; data-origin-height=&quot;1264&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이진트리 법칙을 만족하는지 여부를 판단하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장먼저 경우의 수에 따른 작은 부분에 대한 문제를 생각했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;한 단계의 트리만 생각했을 때,&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;left는 root보다 작아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;right는 root보다 커야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, &lt;u&gt;한단계 위의 root 까지도 생각&lt;/u&gt;해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;root가 &lt;b&gt;left&lt;/b&gt; 였다면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;left 는 root 보다 작아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;right는 root보다 크고 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;root의 root&lt;/b&gt;보단 작아야한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;root 가 &lt;b&gt;right&lt;/b&gt; 였다면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;left는 root보다 작고, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;root의 root&lt;/b&gt;보단 커야한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;right는 root보다 커야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 기반으로 재귀식을 짜면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;boolean 메서드명(노드, 왼쪽 제한 값, 오른쪽 제한 값) &lt;/code&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 재귀로 코드를 작성하면 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1730881847137&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isValidBST(TreeNode root) {
        return isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE);
    }

    // 재귀를 반복하면서 자연히 min, max 값이 적절히 바뀜.
    // left는 부모보다 작아야하고, 부모가 right였다면 그 윗부모 보단 커야함
    // right는 부모보다 커야하고, 부모가 left였다면 그 윗부모 보단 작아야함
    // 위 두가지에 대응 가능한 재귀 함수임.
    private boolean isValidBST(TreeNode node, long min, long max){
        // 만약 null 이면 무조건 검사할 필요도 없으니 true 리턴 
        if(node == null){
            return true;
        }
        
        if(node.val &amp;lt;= min || node.val &amp;gt;= max){
            return false;
        }

        return isValidBST(node.left, min, node.val) &amp;amp;&amp;amp; isValidBST(node.right, node.val, max);
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘/Tree</category>
      <author>mezo</author>
      <guid isPermaLink="true">https://gimmesome.tistory.com/314</guid>
      <comments>https://gimmesome.tistory.com/314#entry314comment</comments>
      <pubDate>Wed, 6 Nov 2024 17:49:00 +0900</pubDate>
    </item>
    <item>
      <title>[IoC 컨테이너와 빈] 4. @Component 와 컴포넌트 스캔</title>
      <link>https://gimmesome.tistory.com/313</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[전체 목차]&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;IoC 컨테이너와 빈
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스프링 IoC 컨테이너와 빈&lt;/li&gt;
&lt;li&gt;ApplicationContext와 다양한 빈 설정 방법&lt;/li&gt;
&lt;li&gt;@Autowired&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;@Component와 컴포넌트 스캔&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#no1&quot;&gt;컴포넌트 스캔 주요 기능&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#no2&quot;&gt;@Component&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#no3&quot;&gt;동작 원리&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#no4&quot;&gt;function을 사용한 빈 등록&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Resource / Validation&lt;/li&gt;
&lt;li&gt;데이터 바인딩&lt;/li&gt;
&lt;li&gt;SpEL&lt;/li&gt;
&lt;li&gt;스프링 AOP&lt;/li&gt;
&lt;li&gt;Null-Safety&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 id=&quot;no1&quot; data-ke-size=&quot;size26&quot;&gt;1. 컴포넌트 스캔 주요 기능&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;@ComponentScan&lt;/code&gt; 은 spring 3.1부터 도입이 되었고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 중요한 속성이 &lt;code&gt;basePackage()&lt;/code&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 &lt;code&gt;basePackage()&lt;/code&gt;는 문자열을 받기 때문에 타입 세이프하지 않아서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입 세이프 한 방법으로 설정할 수 있는 &lt;code&gt;basePackageClasses()&lt;/code&gt;라는 속성이 또 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-11-04 오후 1.38.36.png&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;418&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MI3N6/btsKuw8BS3M/MVwzB6xhavvfYhhyNfYHF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MI3N6/btsKuw8BS3M/MVwzB6xhavvfYhhyNfYHF1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MI3N6/btsKuw8BS3M/MVwzB6xhavvfYhhyNfYHF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMI3N6%2FbtsKuw8BS3M%2FMVwzB6xhavvfYhhyNfYHF1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;962&quot; height=&quot;418&quot; data-filename=&quot;스크린샷 2024-11-04 오후 1.38.36.png&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;418&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 속성은 베이스가 되는 패키지를 말하는데 이는 &lt;code&gt;@ComponentScan&lt;/code&gt;가 붙여진 클래스가 포함된 패키지가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1) 스캔 위치 설정&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 Spring boot를 쓰면 애플리케이션 클래스에 &lt;code&gt;@SpringBootApplication&lt;/code&gt; 어노테이션을 쓰는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 어노테이션을 타고 들어가면 SpringBootApplication 인터페이스가 아래 사진처럼&amp;nbsp;&lt;code&gt;@ComponentScan&lt;/code&gt;을 붙이고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 우리가 &lt;code&gt;@ComponentScan&lt;/code&gt;를 직접 볼일은 드물다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-11-04 오후 1.35.06.png&quot; data-origin-width=&quot;1198&quot; data-origin-height=&quot;610&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/I8svy/btsKvMoX2xb/cMv6ErMxX4FdaH24o1u9Z1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/I8svy/btsKvMoX2xb/cMv6ErMxX4FdaH24o1u9Z1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/I8svy/btsKvMoX2xb/cMv6ErMxX4FdaH24o1u9Z1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FI8svy%2FbtsKvMoX2xb%2FcMv6ErMxX4FdaH24o1u9Z1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1198&quot; height=&quot;610&quot; data-filename=&quot;스크린샷 2024-11-04 오후 1.35.06.png&quot; data-origin-width=&quot;1198&quot; data-origin-height=&quot;610&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그게 아니더라도 &lt;code&gt;@ComponentScan&lt;/code&gt;을 붙이고 있는 클래스가 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;스캔 시작 지점&lt;/span&gt;이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;그 클래스를 포함하는 패키지 안의 것도 전부 스캔의 대상&lt;/b&gt;&lt;/span&gt;이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;패키지 밖은 컴포넌트 스캔이 안된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 스캔의 범위를 지정하는 중요한 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 스프링을 쓰다가 빈 주입이 잘안된다~~ 하면!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트 스캔의 범위를 잘 따져봐야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2) 필터: 어떤 어노테이션을 스캔 할지 또는 하지 않을지&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트 스캔의 또다른 특징중 하나가 필터다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트 스캔을 한다고 해서 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;모든 어노테이션을 빈으로 등록해주는건 아니다&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-11-04 오후 1.47.10.png&quot; data-origin-width=&quot;1084&quot; data-origin-height=&quot;442&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2eAki/btsKvnJTxmg/SGMtKlRrjBV1wki5rpVJbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2eAki/btsKvnJTxmg/SGMtKlRrjBV1wki5rpVJbk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2eAki/btsKvnJTxmg/SGMtKlRrjBV1wki5rpVJbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2eAki%2FbtsKvnJTxmg%2FSGMtKlRrjBV1wki5rpVJbk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1084&quot; height=&quot;442&quot; data-filename=&quot;스크린샷 2024-11-04 오후 1.47.10.png&quot; data-origin-width=&quot;1084&quot; data-origin-height=&quot;442&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러가지 필터 중, 위에선 &lt;code&gt;ExcludeFilters&lt;/code&gt;로 &lt;code&gt;TypeExcludeFilter&lt;/code&gt;와 &lt;code&gt;AutoConfigurationExcludeFilter&lt;/code&gt; 이 두개의 필터로 빈 생성을 거르고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;TypeExcludeFilter&lt;/code&gt;는 주로 Spring boot에서 테스트 컨텍스트에서 &lt;b&gt;테스트에 필요하지 않은 특정 타입의 빈을 제외&lt;/b&gt;할 때 사용되고, &lt;code&gt;AutoConfigurationExcludeFilter&lt;/code&gt;은 Spring boot가 제공해주는 AutoConfiguration 관련 필터이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;TypeExcludeFilter&lt;/code&gt;는 &lt;b&gt;테스트나 특정 조건에서 불필요한 특정 타입의 빈을 제외&lt;/b&gt;하여, 로드되지 않도록 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;AutoConfigurationExcludeFilter&lt;/code&gt;는 &lt;b&gt;자동 구성 클래스들이 스캔되지 않도록 필터링&lt;/b&gt;하여, 필요한 클래스만 빈으로 등록될 수 있도록 제한한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-11-04 오후 1.51.56.png&quot; data-origin-width=&quot;742&quot; data-origin-height=&quot;170&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XpTEJ/btsKvHH9jss/qxIjqz3ZNrXyL84mSpNEW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XpTEJ/btsKvHH9jss/qxIjqz3ZNrXyL84mSpNEW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XpTEJ/btsKvHH9jss/qxIjqz3ZNrXyL84mSpNEW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXpTEJ%2FbtsKvHH9jss%2FqxIjqz3ZNrXyL84mSpNEW1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;742&quot; height=&quot;170&quot; data-filename=&quot;스크린샷 2024-11-04 오후 1.51.56.png&quot; data-origin-width=&quot;742&quot; data-origin-height=&quot;170&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 사진처럼 &lt;code&gt;@Configuration&lt;/code&gt;이라는 어노테이션도 사실 &lt;code&gt;@Component&lt;/code&gt;이기 때문에 빈으로 등록을 해주는데..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;code&gt;@ComponentScan&lt;/code&gt;은 &lt;code&gt;@SpringBootApplication&lt;/code&gt; 에 붙어있고, Spring boot 에서 제공하는 AutoConfiguration 관련 빈을 등록해줄 필요가 없어서 저렇게 옵션으로 제외 해주고 있는 것으로 보인다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 id=&quot;no2&quot; data-ke-size=&quot;size26&quot;&gt;2. @Component&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스캔 위치와 범위, 그리고 필터링을 통해 정해진 스캔 범주 안의 클래스들 중, &lt;code&gt;@Component&lt;/code&gt; 가 붙은 애들만 빈으로 등록이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 &lt;code&gt;@Component&lt;/code&gt; 어노테이션을 들고 있는 &lt;b&gt;&lt;code&gt;@Controller&lt;/code&gt;, &lt;code&gt;@Service&lt;/code&gt;, &lt;code&gt;@Repository&lt;/code&gt;, &lt;code&gt;@Configuration&lt;/code&gt;&lt;/b&gt;같은 어노테이션이 붙은 클래스들은 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;모두 빈으로 등록&lt;/span&gt;이 된다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 id=&quot;no3&quot; data-ke-size=&quot;size26&quot;&gt;3. 동작 원리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빈 등록은 &lt;code&gt;BeanPostProcessor&lt;/code&gt;(의존성 주입 관련 인터페이스)가 아닌 &lt;code&gt;BeanFactoryPostProcessor&lt;/code&gt;를 구현한&lt;code&gt;ConfigurationClassPostProcessor&lt;/code&gt;와 연결이 되어있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;BeanFactoryPostProcessor&lt;/code&gt;는 &lt;code&gt;BeanPostProcessor&lt;/code&gt;와 비슷하지만 좀 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;BeanFactoryPostProcessor&lt;/code&gt;는 다른 모든 빈들을 만들기 이전에 적용을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 다른 빈들(우리가 &lt;code&gt;@Bean&lt;/code&gt;이나 function 등을 써서 직접 등록하는 빈들)을 다 등록하기 전에 컴포넌트 스캔을 해서 &lt;code&gt;BeanFactoryPostProcessor&lt;/code&gt;의 구현체들이 &lt;code&gt;@Component&lt;/code&gt;(&lt;code&gt;@Service&lt;/code&gt;, &lt;code&gt;@Repository&lt;/code&gt; 등)인 클래스들을 빈으로 등록 해준다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 id=&quot;no4&quot; data-ke-size=&quot;size26&quot;&gt;4. function을 사용한 빈 등록&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;ApplicationContext&lt;/code&gt;이 싱글톤 스코프인 빈들은 초기에 다 생성을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 등록해야하는 빈이 많은 경우엔 초기 구동시간이 오래 걸릴 수가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 이건 초기 구동 할때만 오래 걸리는거라 크게 문제가 되지 않는다고 본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 초기 구동시간에 예민한 사람이라면 ㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래처럼 function을 사용해서 빈을 등록할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;public static void main(String[] args) {
        new SpringApplicationBuilder()
            .sources(Demospring51Application.class)
            .initializers((ApplicationContextInitializer&amp;lt;GenericApplicationContext&amp;gt;)
                applicationContext -&amp;gt; {
                applicationContext.registerBean(MyBean.class);
            })
            .run(args);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 function으로 빈을 등록하는 방법은 Reflection이나 CG Library, Proxy 같은 성능에 영향을 주는 기법을 사용하지 않기 때문에,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션 구동타임이 빨라지는 성능 상의 이점이 조금이나마 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 빈이 많아서 초기 구동시간이 오래걸리는게 거슬리면 이방법을 쓰면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나, &lt;u&gt;이 방법이 componentScan을 대신하는 건 아니다. 난사하지 마라!!!&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;@Bean&lt;/code&gt;을 써서 직접 빈을 등록할때 이 방법을 쓰는건 괜찮을 것도 같다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;gt;&amp;gt; 기존 빈 생성엔 Reflection, CG Libray(CGLIB), Proxy를 사용하나?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다. 일반적으로 Spring에서는 &lt;code&gt;@Component&lt;/code&gt;, &lt;code&gt;@Service&lt;/code&gt;, &lt;code&gt;@Repository&lt;/code&gt;, &lt;code&gt;@Configuration&lt;/code&gt; 등의 어노테이션이 붙은 클래스들을 스캔하고 빈으로 등록하기 위해 &lt;b&gt;Reflection&lt;/b&gt;을 사용해 클래스 정보를 읽어오고, 의존성을 주입하기 위한 &lt;b&gt;Proxy 객체&lt;/b&gt;를 생성하는 경우가 많다. Proxy 객체는 &lt;code&gt;@Lazy&lt;/code&gt;와 같은 지연 초기화나 &lt;code&gt;@Transactional&lt;/code&gt; 등의 AOP 관련 어노테이션이 붙은 객체를 말한다. &lt;b&gt;CGLIB&lt;/b&gt;은 Spring AOP에서 &lt;b&gt;트랜잭션 기능은 Proxy를 통해 추가되는데&lt;/b&gt; 이때, 인터페이스가 구현되어있지 않으면 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Proxy 대상 객체에 인터페이스가 있을 땐 JDK 동적 Proxy를 사용하고, 없을 땐 CGLIB Proxy를 사용하여 필요한 기능을 적용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;gt;&amp;gt; 어노테이션을 구현한 클래스들은 왜 class도 아닌 interface도 아닌, &lt;code&gt;@interface&lt;/code&gt;로 되어 있을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;@interface&lt;/code&gt;는 &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;어노테이션을 정의하기 위한 Java 문법&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring은 &lt;code&gt;@interface&lt;/code&gt;로 정의된 어노테이션을 통해 메타데이터를 읽고, 특정 로직이나 설정을 적용하는 데 활용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring Framework/스프링 프레임워크 핵심 기술</category>
      <author>mezo</author>
      <guid isPermaLink="true">https://gimmesome.tistory.com/313</guid>
      <comments>https://gimmesome.tistory.com/313#entry313comment</comments>
      <pubDate>Mon, 4 Nov 2024 23:23:59 +0900</pubDate>
    </item>
    <item>
      <title>[IoC 컨테이너와 빈] 3. @Autowired</title>
      <link>https://gimmesome.tistory.com/312</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[전체 목차]&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;IoC 컨테이너와 빈
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스프링 IoC 컨테이너와 빈&lt;/li&gt;
&lt;li&gt;ApplicationContext와 다양한 빈 설정 방법&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;@Autowired&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#no1&quot;&gt;@Autowired&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#no2&quot;&gt;사용할 수 있는 위치&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#no3&quot;&gt;주입할 빈에 따른 경우의 수&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#no4&quot;&gt;같은 타입의 빈이 여러개 일 때&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#no5&quot;&gt;동작 원리&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Resource / Validation&lt;/li&gt;
&lt;li&gt;데이터 바인딩&lt;/li&gt;
&lt;li&gt;SpEL&lt;/li&gt;
&lt;li&gt;스프링 AOP&lt;/li&gt;
&lt;li&gt;Null-Safety&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no1&quot; data-ke-size=&quot;size26&quot;&gt;1. @Autowired&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: 필요한 의존 객체의 &quot;타입&quot;에 해당하는 빈을 찾아 주입한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본값은 true (못 찾으면 애플리케이션 구동 실패)&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 id=&quot;no2&quot; data-ke-size=&quot;size26&quot;&gt;2. 사용할 수 있는 위치&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1) 생성자 (스프링 4.3부터는 @Autowired 생략 가능)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;@Service&lt;/code&gt; 클래스의 생성자에 &lt;code&gt;@Autowired&lt;/code&gt;를 안붙여도 Spring 4.3 부터는 의존성 주입을 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;@Repository&lt;/code&gt; 가 붙어야할 리파지터리 클래스에는 &lt;code&gt;@Component&lt;/code&gt;가 아닌 &lt;code&gt;@Repository&lt;/code&gt;를 붙여주는 것이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래야 &lt;code&gt;@Repository&lt;/code&gt;가 붙은 모든 빈의 특정 기능을 실행시킬 수도 있고, AOP 에서 사용하기 더 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;gt;&amp;gt; @Repository 가 @Component 보다 AOP 에서 사용하기 더 좋은 이유는?&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;@Repository&lt;/code&gt; 어노테이션이 붙은 클래스는 Spring AOP의 예외 변환 기능을 통해 데이터베이스 예외를 DataAccessException으로 일관되게 변환할 수 있기 때문이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;AOP가 데이터 접근 계층에서 발생하는 예외를 변환해주기 때문에, 다른 계층에서 예외를 쉽게 처리할 수 있다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;이는 예외가 데이터 접근 계층의 세부 구현에 종속되지 않고, 일관된 방식으로 처리되도록 도와준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-11-04 오후 8.48.26.png&quot; data-origin-width=&quot;532&quot; data-origin-height=&quot;144&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQXJhO/btsKvaLtsks/eNGr3XO39kDgVvjCeR8JyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQXJhO/btsKvaLtsks/eNGr3XO39kDgVvjCeR8JyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQXJhO/btsKvaLtsks/eNGr3XO39kDgVvjCeR8JyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQXJhO%2FbtsKvaLtsks%2FeNGr3XO39kDgVvjCeR8JyK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;532&quot; height=&quot;144&quot; data-filename=&quot;스크린샷 2024-11-04 오후 8.48.26.png&quot; data-origin-width=&quot;532&quot; data-origin-height=&quot;144&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론, 위 사진의 코드처럼&lt;code&gt;@Repository&lt;/code&gt;는 &lt;code&gt;@Component&lt;/code&gt;가 붙은 인터페이스라서, &lt;code&gt;@Component&lt;/code&gt; 와 같은 기능을 하는 하위 클래스 느낌이지만, &lt;code&gt;@Repository&lt;/code&gt;에 특화된 데이터베이스 예외 기능 같은 걸 이용하기 위해서 &lt;code&gt;@Repository&lt;/code&gt; 처럼 구체화된 걸 쓰는게 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2) 세터, 필드&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의존성 주입은&amp;nbsp;&lt;b&gt;생성자&lt;/b&gt; 말고, &lt;b&gt;세터&lt;/b&gt;와 &lt;b&gt;필드&lt;/b&gt;에서도 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필드로 넣어둔 다른 빈을 해당 필드를 set하는 메서드에 &lt;code&gt;@Autowired&lt;/code&gt;를 달면 의존성 주입이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필드의 경우 필드 위에 달면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3) 정리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 Spring에서 의존성 주입은 생성자, 필드, 세터에&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt; &lt;code&gt;@Autowired&lt;/code&gt;&lt;/span&gt;&lt;/span&gt;를 붙이면 할수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나, &lt;b&gt;Spring에서 가장 권장하는 방법&lt;/b&gt;은 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;생성자&lt;/span&gt;를 사용한 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면 생성자를 사용하는 방법이 ~&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;final 필드를 사용할 수 있어, 의존성 주입 후 &lt;b&gt;해당 필드를 변경할 수 없어 안정성이 높고&lt;/b&gt;,&lt;/li&gt;
&lt;li&gt;생성자로 의존성을 전달 받아서, 테스트 시에 &lt;b&gt;쉽게 mock 객체나 테스트용 객체를 주입&lt;/b&gt;할 수 있으며,&lt;/li&gt;
&lt;li&gt;생성자를 통해 의존성을 주입하므로, &lt;b&gt;코드만 보고도 해당 클래스가 어떤 의존성을 갖는지&lt;/b&gt; 생성자만 보면 명확히 알수있고,&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Spring에 가장 덜 의존적&lt;/b&gt;이기 때문이다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4번의 Spring에 의존적이라는 말은 ~&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;@Autowired&lt;/code&gt;는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;스프링에서 제공하는 의존성 주입용 어노테이션&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, Spring의 경우 &lt;code&gt;@Autowired&lt;/code&gt;를 사용한 의존성 주입을 제공하기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;필드&lt;/b&gt;와&lt;b&gt; 세터&lt;/b&gt;를 통한 의존성 주입처럼 &lt;code&gt;@Autowired&lt;/code&gt;를 써야만 의존성 주입이 된다면, Spring에 의존하는 것이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나, &lt;b&gt;생성자를 이용하는 방법&lt;/b&gt;은 프레임워크(Spring) 없이 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;Java&lt;/b&gt;만으로 의존성을 주입할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 Java의 기본적인 객체 생성 방식이므로, 의존성 주입의 원형이기도 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;Spring IoC 컨테이너&lt;/b&gt;는 이런 생성자를 통한 주입을 자동화&lt;/span&gt;하여 객체 생성과 의존성 관리를 더 편하게 해주는 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, Spring4.3에서 부턴 생성자가 하나일때,&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;code&gt;@Autowired&lt;/code&gt;를 생략&lt;/span&gt;할 수 있기 때문에 더욱 편리해졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자 방법의 유일한 단점인 코드의 길이가 길다는 것 또한, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;Lombok&lt;/span&gt;를 사용하여 커버 가능해졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;@RequiredArgsConstructor&lt;/code&gt; or &lt;code&gt;@AllArgsConstructor&lt;/code&gt;를 쓰면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;@RequiredArgsConstructor&lt;/code&gt;의 경우, 필드에 final 키워드를 쓰거나, &lt;code&gt;@NonNull&lt;/code&gt;를 붙이면 적용 되고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;@AllArgsConstructor&lt;/code&gt;의 경우, 모든 필드에 적용 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no3&quot; data-ke-size=&quot;size26&quot;&gt;3. 주입할 빈에 따른 경우의 수&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;해당 타입의 빈이 없는 경우 (required = false 하면 에러 안남)&lt;/li&gt;
&lt;li&gt;해당 타입의 빈이 한개인 경우&lt;/li&gt;
&lt;li&gt;해당 타입의 빈이 여러개인 경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빈 이름으로 시도, ('@Primary', '@Qualifier', '빈 클래스 이름 직접 언급' 등의 방법 사용)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;같은 이름의 빈 찾으면 해당 빈 사용&lt;/li&gt;
&lt;li&gt;같은 이름의 빈 못 찾으면 실패&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;gt;&amp;gt;&lt;/b&gt; 생성자를 사용해서 의존성 주입을 할땐 주입할 빈이 없으면 현재 빈을 생성하는 것에도 에러가 나겠지만..&lt;b&gt;세터를 사용하면 현재 빈을 생성하는거 자체엔 에러가 안나야하는 것 아닌가??&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아니다. &lt;code&gt;@Autowired&lt;/code&gt;라는 어노테이션이 있다면 해당 빈을 생성할 때, 이 &lt;b&gt;어노테이션이 붙은 걸로 의존성 주입을 하려고 시도&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, &lt;code&gt;@Autowired&lt;/code&gt; 때문에 의존성 주입할 빈이 없으면 현재 빈생성도 실패한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 해당 의존성이 없어도 되면 &lt;code&gt;@Autowired&lt;/code&gt; 옵션으로 &lt;b&gt;required=false&lt;/b&gt;를 주면된다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 id=&quot;no4&quot; data-ke-size=&quot;size26&quot;&gt;4. 같은 타입의 빈이 여러개 일때 (인터페이스 구현체 클래스들)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1) &lt;code&gt;@Primary&lt;/code&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터페이스 그 자체를 &lt;code&gt;@Autowired&lt;/code&gt;로 의존성을 주입 하는건 불가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 하나의 &lt;b&gt;인터페이스&lt;/b&gt;에서 여러개의 구현체 빈들이 있다면, 어떤 빈이 우선적으로 다른 빈에 주입이 되게 할지,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구현체 중 하나의 어노테이션 '옆에' &lt;code&gt;@Primary&lt;/code&gt;를 붙여줘야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) &lt;code&gt;@Repository&lt;/code&gt; &lt;code&gt;@Primary&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2024-11-04 오후 8.53.06.png&quot; data-origin-width=&quot;546&quot; data-origin-height=&quot;214&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/deme2w/btsKvp9xLDX/UugjdrJaznkSkkX0FKn3a0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/deme2w/btsKvp9xLDX/UugjdrJaznkSkkX0FKn3a0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/deme2w/btsKvp9xLDX/UugjdrJaznkSkkX0FKn3a0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdeme2w%2FbtsKvp9xLDX%2FUugjdrJaznkSkkX0FKn3a0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;546&quot; height=&quot;214&quot; data-filename=&quot;edited_스크린샷 2024-11-04 오후 8.53.06.png&quot; data-origin-width=&quot;546&quot; data-origin-height=&quot;214&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2) &lt;code&gt;@Qualifier(&quot;&quot;)&lt;/code&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹은, 의존성 주입시,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;@Autowired&lt;/code&gt; 옆에 &lt;code&gt;@Qualifier(&quot;주입할 구현체의 소문자 시작 카멜케이스 이름&quot;)&lt;/code&gt; 를 붙이면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 &lt;code&gt;@Primary&lt;/code&gt; 가 좀더 타입 세이프해서 더 추천한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;gt;&amp;gt; 왜 &lt;code&gt;@Primary&lt;/code&gt;가 더 타입 세이프할까?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;@Primary&lt;/code&gt;는 &lt;b&gt;타입 일치&lt;/b&gt;만으로 빈을 선택하므로, 컴파일 시점에 타입 오류를 쉽게 발견할 수 있지만, &lt;code&gt;@Qualifier&lt;/code&gt;는 &lt;b&gt;문자열로 빈 이름을 개발자가 직접 지정&lt;/b&gt;하기 때문에 문자열 오타나 잘못된 빈 이름 지정 시 런타임 오류가 발생할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;3) 구현체 이름을 직접 언급&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잘 추천하진 않는 방법인데..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러개의 빈 중 하나의 빈 클래스 이름을 넣어서 주입 받을 수도 있다. 아래와 같이..&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;@Autowired
BookRepository myBookRepository;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;code&gt;@Primary&lt;/code&gt; 를 가장 추천한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4) 여러개를 모두 주입 받아야하는 경우엔?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;@Autowired&lt;/code&gt; 붙이는 필드에 &lt;b&gt;&lt;code&gt;List&lt;/code&gt;&lt;/b&gt; 타입으로 선언하면 된다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 id=&quot;no5&quot; data-ke-size=&quot;size26&quot;&gt;5. 동작 원리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;@Autowired&lt;/code&gt;의 동작 원리를 알려면 이 어노테이션을 감지하고, 의존성 주입을 수행하는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt; Spring 의 인터페이스(BeanPostProcessor)&lt;/u&gt;와&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;그걸 실제로 실행하는 구현체 빈(AutowiredAnnotaionBeanPostProcessor)&lt;/u&gt;을 알아야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1)&amp;nbsp; BeanPostProcessor 인터페이스&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빈의 인스턴스를 만든 다음에, 빈의 initialization 라는 라이프사이클이 있는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 라이프사이클 이전 또는 이후에 부가적인 작업을 할수 있는 라이프 사이클이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그게 바로 &lt;code&gt;BeanPostProcessor&lt;/code&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 &lt;code&gt;BeanFactory&lt;/code&gt; 인터페이스와는 별개다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘 다 Spring의 IoC 컨테이너가 제공하는 기능의 일부인데.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;BeanPostProcessor&lt;/code&gt;는 &lt;code&gt;BeanFactory&lt;/code&gt;와는 직접적인 상속 관계가 없으며, &lt;code&gt;BeanFactory&lt;/code&gt;가 관리하는 빈의 라이프사이클에 참여하는 독립적인 역할을 가집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2) &lt;code&gt;BeanPostProcessor&lt;/code&gt; 인터페이스 사용법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빈 생성 이후에 뭘 실행 시키려면,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빈 클래스 안에 실행시킬 메서드에 @PostConstruct를 붙이거나,&lt;/li&gt;
&lt;li&gt;해당 클래스를 implements InitializingBean 하게 하고, afterProperiesSet 메서드를 클래스 안에 @Override 하면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring boot runner는 애플리케이션 구동 후에 실행이 돼서 주입된 빈을 출력하면 마지막에 찍히는데,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;@PostConstruct&lt;/code&gt; 는 다음 spring 애플리케이션 구동 단계 중에서 ..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;11. postProcessorBeforeInitialization methods of BeanPostProcessors&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;12. &lt;b&gt;InitializingBean's afterPropertiesSet&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;13. a custom init-method definition&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;14. postProcessorAfterInitialization methods of BeanPostProcessors&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;12번 단계에서 일을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;11번에서 &lt;code&gt;@Autowired&lt;/code&gt;로 빈 주입을 다 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;12번에선 빈 주입이 다 됐다고 생각하고, 초기화 단계에서 수행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;13번과정은 초기화과정에서 커스텀된게 있다면 실행하는데, 12번이랑 비슷하지만 12번이 먼저 동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 말해주는 라이프사이클 정도만 알아도 크게 지장없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;BeanPostProcessor&lt;/b&gt;,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;AutowiredAnnotaionBeanPostProcessor&lt;/b&gt; extends BeanPostProcessor&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 두 인터페이스가 핵심.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;3)&amp;nbsp; 정리하자면,,,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빈 라이프 사이클에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;code&gt;BeanPostProcessor&lt;/code&gt;&lt;/b&gt;라는 게 있구나!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 그 구현체 중 하나인&lt;br /&gt;&lt;b&gt;&lt;code&gt;AutowiredAnnotaionBeanPostProcessor&lt;/code&gt;&lt;/b&gt;가 동작을 하는구나!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4) 이 구현체가 어떻게 동작을 하느냐! 동작 순서를 보자!&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;ApplicationContext&lt;/b&gt;가 &lt;b&gt;BeanFactory&lt;/b&gt; 역할을 수행하며, 모든 빈을 생성하고 관리하는 &lt;b&gt;IoC 컨테이너&lt;/b&gt; 역할을 하는데.&lt;/li&gt;
&lt;li&gt;빈을 생성할 때마다 내부에 등록된 &lt;b&gt;BeanPostProcessor&lt;/b&gt; 빈들을 찾는다.&lt;/li&gt;
&lt;li&gt;그중에 하나로 &lt;b&gt;@Autowired&lt;/b&gt; 와 같은 어노테이션을 처리하는&amp;nbsp;&lt;b&gt;AutowiredAnnotaionBeanPostProcessor&lt;/b&gt;라는 빈 후처리기&lt;br /&gt;또한 &lt;b&gt;빈&lt;/b&gt;으로 포함 되어있다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ApplicationContext&lt;/b&gt;는 이렇게 초기화 과정에 &lt;b&gt;AutowiredAnnotationBeanPostProcessor&lt;/b&gt;를 개입시켜 구동시킨다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;AutowiredAnnotationBeanPostProcessor&lt;/b&gt;는 모든 빈에 등록된 &lt;b&gt;@Autowired&lt;/b&gt;를 감지하여 의존성을 주입한다.&lt;/li&gt;
&lt;li&gt;그리고 다른 일반적인 빈들한테 이걸 적용하는 거다.&lt;/li&gt;
&lt;li&gt;예를 들어, UserService 빈의 필드에 &lt;b&gt;@Autowired&lt;/b&gt; 가 붙어 있으면, &lt;b&gt;AutowiredAnnotationBeanPostProcessor&lt;/b&gt; 는 같은 타입의 빈을 찾아 UserService 빈에 주입한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니까 기본적으로 &lt;b&gt;&lt;code&gt;AutowiredAnnotaionBeanPostProcessor&lt;/code&gt;&lt;/b&gt; 얘도 빈으로 등록이 되어있다는 것!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;5) claud.ai가 그려준 Spring Framework의 핵심 아키텍처&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림 그리는건 chatGPT 보다 훨~~~씬 나은거 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;점선은 의존성 주입을 표한한 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-11-04 오전 10.10.48.png&quot; data-origin-width=&quot;1162&quot; data-origin-height=&quot;1256&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzzAAA/btsKubQZ3dC/8Drs9lLBXRM6ASl5kDLmq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzzAAA/btsKubQZ3dC/8Drs9lLBXRM6ASl5kDLmq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzzAAA/btsKubQZ3dC/8Drs9lLBXRM6ASl5kDLmq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzzAAA%2FbtsKubQZ3dC%2F8Drs9lLBXRM6ASl5kDLmq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1162&quot; height=&quot;1256&quot; data-filename=&quot;스크린샷 2024-11-04 오전 10.10.48.png&quot; data-origin-width=&quot;1162&quot; data-origin-height=&quot;1256&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Configuration 메타데이터&lt;/b&gt;: 빈 설정 정보를 제공 (어노테이션, XML, 자바 설정).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ApplicationContext&lt;/b&gt;: Configuration 메타데이터를 읽고, 빈을 생성하고 등록.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;AutowiredAnnotationBeanPostProcessor&lt;/b&gt;: 빈 초기화 단계에서 @Autowired를 처리하여 의존성을 주입.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;빈 생명주기 관리&lt;/b&gt;: ApplicationContext가 빈의 생명주기를 관리하고, 초기화와 종료 작업을 수행.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;gt;&amp;gt; 테스트 중에 spring boot runner를 썼던 이유는?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;@SpringBootApplication&lt;/code&gt; 을 쓰다보니 의존성 주입 된 빈 출력하려면 빈등록 과정에서 빼와서 찍었는데 그걸 저 어노테이션이 다 해줘서 spring boot runner 써서 구동 이후에 &lt;code&gt;ApplicationContext&lt;/code&gt; 에서 빈을 꺼내와서 찍도록 했음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;ApplicationContext&lt;/code&gt;도 Spring 애플리케이션에서 빈으로 등록된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 &lt;code&gt;ApplicationContext&lt;/code&gt;는 자체적으로 빈을 관리하고 제공하는 컨테이너이지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 자체도 하나의 빈(BeanFactory 의 하위 클래스)으로 등록되어 다른 빈들이 필요할 때 주입받아 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;gt;&amp;gt; 모든 빈들은 &lt;code&gt;@Autowired&lt;/code&gt;로 다 꺼내와서 의존성 주입을 받을 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring Framework/스프링 프레임워크 핵심 기술</category>
      <author>mezo</author>
      <guid isPermaLink="true">https://gimmesome.tistory.com/312</guid>
      <comments>https://gimmesome.tistory.com/312#entry312comment</comments>
      <pubDate>Sun, 3 Nov 2024 18:53:22 +0900</pubDate>
    </item>
    <item>
      <title>[IoC 컨테이너와 빈] 2. ApplicationContext와 다양한 빈 설정 방법</title>
      <link>https://gimmesome.tistory.com/311</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;
&lt;div style=&quot;background-color: #ffffff;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;[전체 목차]&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;&lt;span&gt;IoC&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;컨테이너와 빈&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span&gt;스프링 IoC 컨테이너와 빈&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;ApplicationContext와 다양한 빈 설정 방법&lt;/span&gt;&amp;nbsp;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li style=&quot;list-style-type: circle;&quot;&gt;&lt;span&gt;&lt;a href=&quot;#no1&quot;&gt;스프링 IoC 컨테이너의 역할&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: circle;&quot;&gt;&lt;span&gt;&lt;a href=&quot;#no2&quot;&gt;ApplicationContext&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: circle;&quot;&gt;&lt;span&gt;&lt;a href=&quot;#no3&quot;&gt;빈 설정&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: circle;&quot;&gt;&lt;span&gt;&lt;a href=&quot;#no4&quot;&gt;컴포넌트 스캔&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: circle;&quot;&gt;&lt;span&gt;&lt;a href=&quot;#no5&quot;&gt;빈 설정 방법의 변천사&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;&lt;span&gt;Resource /&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Validation&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;&lt;span&gt;데이터 바인딩&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;&lt;span&gt;SpEL&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;&lt;span&gt;스프링&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;AOP&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;&lt;span&gt;Null-Safety&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;spring-boot-stater-web 의존성만 넣어 두면 우리가 애플리케이션을 만드는데 필요한 의존성들이 대부분 들어온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;spring core, spring context, spring beans 이렇게 세개가 주요한 의존성들...&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h2 id=&quot;no1&quot; data-ke-size=&quot;size26&quot;&gt;1. 스프링 IoC 컨테이너의 역할&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빈 인스턴스 생성&lt;/li&gt;
&lt;li&gt;의존 관계 설정&lt;/li&gt;
&lt;li&gt;빈 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h2 id=&quot;no2&quot; data-ke-size=&quot;size26&quot;&gt;2. ApplicationContext&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;: BeanFactory의 확장판.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;빈 관리 외에도 애플리케이션 이벤트, 국제화, 환경 설정, 애플리케이션 생명주기 관리 등 고급 기능을 지원&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ClassPathXmlApplicationContext (XML)&lt;/li&gt;
&lt;li&gt;AnnotaionConfigApplicationContext (Java)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no3&quot; data-ke-size=&quot;size26&quot;&gt;3. 빈 설정&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빈 명세서: 빈에 대한 정의를 담고있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이름&lt;/li&gt;
&lt;li&gt;클래스&lt;/li&gt;
&lt;li&gt;스코프&lt;/li&gt;
&lt;li&gt;생성자 아규먼트 (constructor)&lt;/li&gt;
&lt;li&gt;프로퍼트 (setter)&lt;/li&gt;
&lt;li&gt;..&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no4&quot; data-ke-size=&quot;size26&quot;&gt;4. 컴포넌트 스캔&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;설정 방법
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;XML 설정에서는 context:component-scan&lt;/li&gt;
&lt;li&gt;자바 설정에서 @ComponentScan&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;특정 패키지 이하의 모든 클래스 중에 @Component 어노테이션을 사용한 클래스를 빈으로 자동으로 등록해 줌.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no5&quot; data-ke-size=&quot;size26&quot;&gt;5. 빈 설정 방법의 변천사&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) application.xml에 &amp;lt;bean ~ /&amp;gt; 추가하는 방식&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 application.xml에 빈을 하나하나 으로 적어주고 했다.&lt;/p&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;ApplicationContext context = ClassPathXmlApplicationContext(application.xml)&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) application.xml에 &amp;lt;context:component-scan ~/&amp;gt; 쓰고,&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;@Component&lt;/code&gt; 등 빈 어노테이션 쓰는 방식&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거기서 의존성도 적어주고 하는게 귀찮다~ 해서 나온게&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;application.xml에 &lt;a href=&quot;context:component-scan~~/&quot;&gt;context:component-scan~~/&lt;/a&gt; 을 쓰고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;@Component&lt;/code&gt;확장 받은 &lt;code&gt;@Service&lt;/code&gt;, &lt;code&gt;@Repository&lt;/code&gt; 등을 쓰는 거다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 이 어노테이션을 쓰면 의존성 주입은 @Autowired같은 어노테이션으로 해줘야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;xml에 bean을 하나하나 명시하지 않아도 component-scan만 써두면 그걸 사용해서 어노테이션들을 스캔해서 빈으로 등록하는 식으로 허용하는게 Java Spring 2.5부터 가능했던 기능이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3) Java 빈 설정 파일 쓰는 방식 (&lt;code&gt;@Configuration&lt;/code&gt;, &lt;code&gt;@Bean&lt;/code&gt;, &lt;code&gt;@Autowired&lt;/code&gt;)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 여기서 xml말고 java로 빈 설정 파일을 만들수 없을까? 해서 나온게 java 설정파일인 &lt;code&gt;@Configuration&lt;/code&gt; 어노테이션이 붙은 자바 파일이다. 이안에서 &lt;code&gt;@Bean&lt;/code&gt;을 붙여가며 등록이 가능하다.&lt;/p&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;ApplicationContext context = AnnotationConfigApplicationContext(ApplicationConfig.class)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;@Configuration&lt;/code&gt; 클래스 내에서 &lt;code&gt;@Bean&lt;/code&gt; 으로 클래스를 빈으로 등록할때 그 코드 안에서 의존성 주입을 해주지 않아도,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 클래스 안에서 &lt;code&gt;@Autowired&lt;/code&gt;를 써도 의존성 주입이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4) Java 빈 설정 파일에 &lt;code&gt;@Bean&lt;/code&gt; 말고 &lt;code&gt;@ComponentScan&lt;/code&gt; 어노테이션 쓰는 방식&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;@Bean&lt;/code&gt; 으로 하나하나 해주는게 귀찮다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;@Configuration&lt;/code&gt; 에 또 붙여주는 &lt;code&gt;@ComponentScan&lt;/code&gt;이 추가됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5) &lt;code&gt;@SpringBootApplication&lt;/code&gt; 쓰는 방식&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 모든건 Spring 에 대한 얘기고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring boot에선 이걸 편리하게 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그게 &lt;code&gt;@SpringBootApplication&lt;/code&gt; 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;@SpringBootApplication&lt;/code&gt; 만 애플리케이션 클래스 위에 붙어있다면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우린 이 모든 작업(ApplicationContext 를 사용한 모든 빈설정 관련 코드)을 안 해놔도 다 포함된 격이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring Framework/스프링 프레임워크 핵심 기술</category>
      <author>mezo</author>
      <guid isPermaLink="true">https://gimmesome.tistory.com/311</guid>
      <comments>https://gimmesome.tistory.com/311#entry311comment</comments>
      <pubDate>Sun, 3 Nov 2024 18:40:04 +0900</pubDate>
    </item>
  </channel>
</rss>