<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>태마의 테마</title>
    <link>https://te-ma.tistory.com/</link>
    <description>협업 제안 / 개발 의뢰 / 상담(취준생) / 프리랜서 작업 요청 / 인터뷰 요청 등
문의는 아래 카카오톡 링크로 편하게 연락주세요  
https://open.kakao.com/o/sRFE4unh</description>
    <language>ko</language>
    <pubDate>Thu, 2 Jul 2026 14:57:34 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>TEMA_</managingEditor>
    <image>
      <title>태마의 테마</title>
      <url>https://tistory1.daumcdn.net/tistory/2931179/attach/d641919dc2d04c108f81e37f621e63a2</url>
      <link>https://te-ma.tistory.com</link>
    </image>
    <item>
      <title>Spring 기초 &amp;lt;40. 실전 프로젝트에서 Spring Boot 적용 Best Practices&amp;gt;</title>
      <link>https://te-ma.tistory.com/345</link>
      <description>&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p style=&quot;clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 18pt;&quot;&gt;스프링 Spring&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;40. 실전&amp;nbsp;프로젝트에서&amp;nbsp;Spring&amp;nbsp;Boot&amp;nbsp;적용&amp;nbsp;Best&amp;nbsp;Practices&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요! 태마입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;Spring&lt;/span&gt;&amp;nbsp;기초 강좌입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;강좌의 경우&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 주제 간단 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 상세 주제 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;으로 이루어져 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;스프링 Spring&lt;/span&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;9T7tobH9QpueIjclQy6EdlBbd-CXNprDfNLQIyq8u3rqv9dxYbI6efgHXsf5tAUqbO6EkpjDUJaKVnsdlOzGKQu5wWBsoPuOIl0k18Nx1z_Tzw6o_3sbYUo6Lvgl51DWkE6n7GGfU32K4G0bpZnHSA.svg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;78&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/I3uf9/btsMQgOPrjr/7XjhOPIvzOUvKAvo6DGd81/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/I3uf9/btsMQgOPrjr/7XjhOPIvzOUvKAvo6DGd81/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/I3uf9/btsMQgOPrjr/7XjhOPIvzOUvKAvo6DGd81/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FI3uf9%2FbtsMQgOPrjr%2F7XjhOPIvzOUvKAvo6DGd81%2Ftfile.dat&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;300&quot; height=&quot;78&quot; data-filename=&quot;9T7tobH9QpueIjclQy6EdlBbd-CXNprDfNLQIyq8u3rqv9dxYbI6efgHXsf5tAUqbO6EkpjDUJaKVnsdlOzGKQu5wWBsoPuOIl0k18Nx1z_Tzw6o_3sbYUo6Lvgl51DWkE6n7GGfU32K4G0bpZnHSA.svg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;78&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;포스팅 시작하겠습니다 :)&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;xyz&quot;&gt;&lt;!-- 티스토리 본문에 애드센스 광고를 삽입 합니다. --&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9977447109791049&quot;&gt;&lt;/script&gt;
&lt;!-- 336X280 Size mid 1 --&gt; &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-slot=&quot;3927916504&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;
&lt;script&gt;document.getElementById('abc').appendChild(document.getElementById('xyz'));&lt;/script&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 주제 간단 정리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot; data-start=&quot;1567&quot; data-end=&quot;1717&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;250&quot; data-start=&quot;220&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 성능 최적화가 필요한 주요 문제&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;355&quot; data-start=&quot;251&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;대규모 프로젝트에서는 예상치 못한 성능 이슈가 발생할 수 있음&lt;/b&gt;&lt;br /&gt;✔ &lt;b&gt;가장 많이 발생하는 문제는 &quot;DB 성능 저하, GC 문제, API 응답 지연, I/O 부하&quot; 등&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;391&quot; data-start=&quot;357&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;실제 프로젝트에서 발생한 주요 성능 이슈 사례&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;성능 이슈원인해결 방법
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;795&quot; data-start=&quot;393&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;795&quot; data-start=&quot;447&quot;&gt;
&lt;tr data-end=&quot;524&quot; data-start=&quot;447&quot;&gt;
&lt;td&gt;&lt;b&gt;API 응답 속도 지연&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;과도한 DB 조회, 비효율적인 쿼리&lt;/td&gt;
&lt;td&gt;캐싱 적용 (Redis), JPA Fetch Join 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;593&quot; data-start=&quot;525&quot;&gt;
&lt;td&gt;&lt;b&gt;DB 부하 증가&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;N+1 문제, Connection Pool 부족&lt;/td&gt;
&lt;td&gt;인덱스 최적화, HikariCP 튜닝&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;646&quot; data-start=&quot;594&quot;&gt;
&lt;td&gt;&lt;b&gt;GC 문제 발생&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;메모리 누수, 객체 과다 생성&lt;/td&gt;
&lt;td&gt;JVM &amp;amp; GC 튜닝 적용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;727&quot; data-start=&quot;647&quot;&gt;
&lt;td&gt;&lt;b&gt;트래픽 폭증 시 서버 다운&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Auto Scaling 미적용, 부하 분산 부족&lt;/td&gt;
&lt;td&gt;로드 밸런싱 적용 (Nginx, AWS ALB)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;795&quot; data-start=&quot;728&quot;&gt;
&lt;td&gt;&lt;b&gt;로그로 인해 성능 저하&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;실시간 로그 I/O 부하 발생&lt;/td&gt;
&lt;td&gt;비동기 로그 처리 (Logback Async)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;849&quot; data-start=&quot;797&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;성능 최적화가 필요한 문제를 사전에 발견하고, 적절한 해결 방법을 적용해야 함&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;854&quot; data-start=&quot;851&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;889&quot; data-start=&quot;856&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 실전 프로젝트 성능 최적화 접근 방식&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;936&quot; data-start=&quot;890&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;성능 최적화는 문제를 정확히 분석한 후, 단계적으로 해결해야 효과적임&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;975&quot; data-start=&quot;938&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Spring Boot 성능 최적화 5단계 접근 방식&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1258&quot; data-start=&quot;977&quot; data-ke-size=&quot;size16&quot;&gt;1️⃣ &lt;b&gt;문제 발견&lt;/b&gt;: APM (Application Performance Monitoring) 도구를 활용하여 성능 이슈를 감지&lt;br /&gt;2️⃣ &lt;b&gt;원인 분석&lt;/b&gt;: JVM, DB, API 성능을 분석하여 병목 구간을 파악&lt;br /&gt;3️⃣ &lt;b&gt;성능 개선 적용&lt;/b&gt;: 캐싱, GC 튜닝, DB 쿼리 최적화 등의 해결 방법 적용&lt;br /&gt;4️⃣ &lt;b&gt;테스트 및 검증&lt;/b&gt;: JMeter, Gatling을 활용한 부하 테스트 수행&lt;br /&gt;5️⃣ &lt;b&gt;지속적인 모니터링&lt;/b&gt;: Prometheus + Grafana로 실시간 모니터링&lt;/p&gt;
&lt;p data-end=&quot;1301&quot; data-start=&quot;1260&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;이제 실제 프로젝트에서 적용한 성능 최적화 사례를 살펴보자&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;1306&quot; data-start=&quot;1303&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;1464&quot; data-start=&quot;1308&quot; data-ke-size=&quot;size16&quot;&gt;✅ 여기까지 성능 최적화가 필요한 주요 문제 사례와 해결 접근 방식을 배웠습니다!&lt;br /&gt;  &lt;b&gt;&quot;그렇다면, 실전에서 적용한 Spring Boot 성능 최적화 사례는?&quot;&lt;/b&gt;&lt;br /&gt;✅ 2부에서 &lt;b&gt;실제 프로젝트에서 성능 최적화를 어떻게 적용했는지 상세한 사례 분석&lt;/b&gt;을 배워봅시다!&lt;/p&gt;
&lt;p data-end=&quot;2387&quot; data-start=&quot;2218&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 상세 주제 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;1551&quot; data-start=&quot;1511&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. API 응답 속도 최적화 (Redis 캐싱 적용)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1627&quot; data-start=&quot;1552&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;과도한 DB 조회로 인한 응답 속도 지연 문제 해결&lt;/b&gt;&lt;br /&gt;✔ &lt;b&gt;자주 조회되는 데이터를 Redis에 캐싱하여 성능 개선&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1671&quot; data-start=&quot;1629&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;1️⃣ Redis 캐싱 적용 (@Cacheable 활용)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742386121330&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Cacheable(value = &quot;productCache&quot;, key = &quot;#productId&quot;)
public Product getProduct(Long productId) {
    return productRepository.findById(productId)
           .orElseThrow(() -&amp;gt; new RuntimeException(&quot;Product not found&quot;));
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1960&quot; data-start=&quot;1908&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;자주 조회되는 데이터를 캐싱하여 &quot;DB 부하를 줄이고 API 응답 속도를 개선&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2006&quot; data-start=&quot;1962&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;2️⃣ 캐싱 만료 정책 설정 (application.yml)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742386127210&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  cache:
    type: redis
  redis:
    time-to-live: 60000  # 캐싱 만료 시간 (60초)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2147&quot; data-start=&quot;2103&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;TTL(Time-To-Live) 설정을 통해 데이터 최신성을 유지&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2187&quot; data-start=&quot;2149&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;캐싱을 활용하면 &quot;조회 성능을 3배 이상 향상 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;2192&quot; data-start=&quot;2189&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2232&quot; data-start=&quot;2194&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. DB 성능 최적화 (JPA N+1 문제 해결)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;2315&quot; data-start=&quot;2233&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;JPA를 사용할 때 N+1 문제로 인해 과도한 DB 조회가 발생할 수 있음&lt;/b&gt;&lt;br /&gt;✔ &lt;b&gt;Fetch Join을 활용하여 성능을 최적화&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2350&quot; data-start=&quot;2317&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;1️⃣ 문제 발생 예시 (N+1 문제 존재)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742386141246&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public List&amp;lt;Order&amp;gt; findAllOrders() {
    return orderRepository.findAll(); // 주문 조회 시 고객 정보까지 로딩됨
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2512&quot; data-start=&quot;2463&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;이 코드 실행 시, 주문 개수만큼 추가 쿼리가 실행됨 (N+1 문제 발생)&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2548&quot; data-start=&quot;2514&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;2️⃣ Fetch Join을 활용한 해결 방법&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742386146847&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Query(&quot;SELECT o FROM Order o JOIN FETCH o.customer&quot;)
List&amp;lt;Order&amp;gt; findAllOrdersWithCustomer();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2711&quot; data-start=&quot;2656&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Fetch Join을 활용하면 &quot;한 번의 쿼리로 데이터를 조회하여 성능을 개선 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2758&quot; data-start=&quot;2713&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;JPA 최적화를 하면 &quot;DB 조회 속도를 50% 이상 개선 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;2763&quot; data-start=&quot;2760&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2802&quot; data-start=&quot;2765&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. JVM &amp;amp; GC 튜닝 적용 (메모리 최적화)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;2894&quot; data-start=&quot;2803&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;서버의 메모리 사용량이 많아지고, GC 동작으로 인해 애플리케이션 성능 저하 발생&lt;/b&gt;&lt;br /&gt;✔ &lt;b&gt;JVM Heap 크기 조정 및 GC 정책 최적화 적용&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2921&quot; data-start=&quot;2896&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;1️⃣ JVM 옵션 튜닝 적용&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742386151788&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-Xms1024m -Xmx2048m -XX:NewRatio=2 -XX:SurvivorRatio=8
-XX:+UseG1GC -XX:MaxGCPauseMillis=200&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3059&quot; data-start=&quot;3027&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;G1GC를 활용하여 GC 지연 시간을 최소화&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3093&quot; data-start=&quot;3061&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;2️⃣ GC 로그 분석 및 모니터링 활성화&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742386156736&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/var/log/gc.log&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3215&quot; data-start=&quot;3173&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;GC 로그를 통해 &quot;메모리 사용량을 모니터링하여 최적화 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3273&quot; data-start=&quot;3217&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;JVM 튜닝을 적용하면 &quot;메모리 누수를 방지하고, 서버 성능을 안정적으로 유지 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;3278&quot; data-start=&quot;3275&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;3329&quot; data-start=&quot;3280&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 트래픽 폭증 대응 (Auto Scaling + 로드 밸런싱 적용)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;3420&quot; data-start=&quot;3330&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;트래픽이 급격하게 증가하는 경우 서버 다운 발생 가능&lt;/b&gt;&lt;br /&gt;✔ &lt;b&gt;Auto Scaling과 Load Balancer를 활용하여 트래픽을 분산 처리&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3464&quot; data-start=&quot;3422&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;1️⃣ Nginx + Spring Boot 로드 밸런싱 적용&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742386162406&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;upstream backend {
    server app1.example.com;
    server app2.example.com;
}

server {
    listen 80;
    location / {
        proxy_pass http://backend;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3693&quot; data-start=&quot;3642&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Nginx를 활용하여 여러 개의 Spring Boot 서버로 요청을 분산 처리&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3727&quot; data-start=&quot;3695&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;2️⃣ AWS Auto Scaling 적용&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742386167867&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;aws:
  auto-scaling:
    min-instances: 2
    max-instances: 10&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3845&quot; data-start=&quot;3804&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;트래픽 증가 시 자동으로 서버 인스턴스를 확장하여 대응 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3899&quot; data-start=&quot;3847&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;트래픽 분산을 적용하면 &quot;서버 과부하를 방지하고, 서비스 안정성을 보장 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;3904&quot; data-start=&quot;3901&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;4078&quot; data-start=&quot;3906&quot; data-ke-size=&quot;size16&quot;&gt;✅ 여기까지 실전 프로젝트에서 Spring Boot 성능 최적화를 적용한 사례를 배웠습니다!&lt;br /&gt;  &lt;b&gt;&quot;그렇다면, 실전 프로젝트에서 Spring Boot를 활용한 베스트 프랙티스는?&quot;&lt;/b&gt;&lt;br /&gt;✅ 다음 회차에서 &lt;b&gt;실전 프로젝트에서 Spring Boot 적용 Best Practices&lt;/b&gt;를 배워봅시다!&lt;/p&gt;
&lt;p data-end=&quot;4078&quot; data-start=&quot;3906&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;xyz&quot;&gt;&lt;!-- 티스토리 본문에 애드센스 광고를 삽입 합니다. --&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9977447109791049&quot;&gt;&lt;/script&gt;
&lt;!-- 336X280 Size mid 2 --&gt; &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-slot=&quot;8340259647&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot; data-start=&quot;4132&quot; data-end=&quot;4304&quot;&gt;
&lt;script&gt;document.getElementById('abc').appendChild(document.getElementById('xyz'));&lt;/script&gt;
&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-end=&quot;5867&quot; data-start=&quot;5724&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>IT Developer/Spring</category>
      <author>TEMA_</author>
      <guid isPermaLink="true">https://te-ma.tistory.com/345</guid>
      <comments>https://te-ma.tistory.com/345#entry345comment</comments>
      <pubDate>Fri, 25 Apr 2025 13:09:44 +0900</pubDate>
    </item>
    <item>
      <title>Spring 기초 &amp;lt;39. Spring Boot에서 서버 성능 튜닝 및 최적화 방법&amp;gt;</title>
      <link>https://te-ma.tistory.com/344</link>
      <description>&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p style=&quot;clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 18pt;&quot;&gt;스프링 Spring&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;39. Spring&amp;nbsp;Boot에서&amp;nbsp;서버&amp;nbsp;성능&amp;nbsp;튜닝&amp;nbsp;및&amp;nbsp;최적화&amp;nbsp;방법&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요! 태마입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;Spring&lt;/span&gt;&amp;nbsp;기초 강좌입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;강좌의 경우&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 주제 간단 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 상세 주제 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;으로 이루어져 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;스프링 Spring&lt;/span&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;9T7tobH9QpueIjclQy6EdlBbd-CXNprDfNLQIyq8u3rqv9dxYbI6efgHXsf5tAUqbO6EkpjDUJaKVnsdlOzGKQu5wWBsoPuOIl0k18Nx1z_Tzw6o_3sbYUo6Lvgl51DWkE6n7GGfU32K4G0bpZnHSA.svg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;78&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSNKQl/btsMPOL5Z3H/FKUWKf5TcfE6k4m81IlSG1/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSNKQl/btsMPOL5Z3H/FKUWKf5TcfE6k4m81IlSG1/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSNKQl/btsMPOL5Z3H/FKUWKf5TcfE6k4m81IlSG1/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSNKQl%2FbtsMPOL5Z3H%2FFKUWKf5TcfE6k4m81IlSG1%2Ftfile.dat&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;300&quot; height=&quot;78&quot; data-filename=&quot;9T7tobH9QpueIjclQy6EdlBbd-CXNprDfNLQIyq8u3rqv9dxYbI6efgHXsf5tAUqbO6EkpjDUJaKVnsdlOzGKQu5wWBsoPuOIl0k18Nx1z_Tzw6o_3sbYUo6Lvgl51DWkE6n7GGfU32K4G0bpZnHSA.svg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;78&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;포스팅 시작하겠습니다 :)&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;xyz&quot;&gt;&lt;!-- 티스토리 본문에 애드센스 광고를 삽입 합니다. --&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9977447109791049&quot;&gt;&lt;/script&gt;
&lt;!-- 336X280 Size mid 1 --&gt; &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-slot=&quot;3927916504&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;
&lt;script&gt;document.getElementById('abc').appendChild(document.getElementById('xyz'));&lt;/script&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 주제 간단 정리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot; data-start=&quot;1567&quot; data-end=&quot;1717&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;264&quot; data-start=&quot;223&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. Spring Boot 서버 성능 튜닝이 필요한 이유&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;390&quot; data-start=&quot;265&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Spring Boot는 간편한 설정과 강력한 기능을 제공하지만, 기본 설정만으로는 성능 최적화가 부족할 수 있음&lt;/b&gt;&lt;br /&gt;✔ &lt;b&gt;특히, 대량 트래픽 처리나 복잡한 비즈니스 로직을 포함하는 경우 성능 튜닝이 필수적&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;431&quot; data-start=&quot;392&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Spring Boot에서 성능 튜닝이 필요한 주요 원인&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;원인설명
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;695&quot; data-start=&quot;433&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;695&quot; data-start=&quot;461&quot;&gt;
&lt;tr data-end=&quot;499&quot; data-start=&quot;461&quot;&gt;
&lt;td&gt;&lt;b&gt;메모리 부족&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;불필요한 객체 생성, GC 최적화 부족&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;551&quot; data-start=&quot;500&quot;&gt;
&lt;td&gt;&lt;b&gt;DB 부하&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;N+1 문제, 인덱스 미적용, Connection Pool 부족&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;597&quot; data-start=&quot;552&quot;&gt;
&lt;td&gt;&lt;b&gt;I/O 블로킹&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;동기적 API 호출, 파일 처리 및 네트워크 지연&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;641&quot; data-start=&quot;598&quot;&gt;
&lt;td&gt;&lt;b&gt;GC 튜닝 부족&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;적절한 GC 정책 미적용으로 인한 성능 저하&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;695&quot; data-start=&quot;642&quot;&gt;
&lt;td&gt;&lt;b&gt;불필요한 Spring Bean&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;과도한 Bean 등록으로 인한 애플리케이션 부하&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;746&quot; data-start=&quot;697&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;성능 튜닝을 하면 &quot;트래픽 증가에도 안정적으로 서비스를 운영할 수 있음&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;751&quot; data-start=&quot;748&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;793&quot; data-start=&quot;753&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. Spring Boot 애플리케이션 성능 측정 방법&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;846&quot; data-start=&quot;794&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Spring Boot 애플리케이션의 성능을 최적화하려면 먼저 성능을 측정해야 함&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;882&quot; data-start=&quot;848&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Spring Boot 성능 측정 도구 및 기법&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;도구/기법설명
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1169&quot; data-start=&quot;884&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;1169&quot; data-start=&quot;920&quot;&gt;
&lt;tr data-end=&quot;988&quot; data-start=&quot;920&quot;&gt;
&lt;td&gt;&lt;b&gt;Spring Actuator&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;/actuator/metrics API를 통해 애플리케이션 성능 모니터링&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1037&quot; data-start=&quot;989&quot;&gt;
&lt;td&gt;&lt;b&gt;JProfiler, YourKit&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;실시간 CPU, 메모리 사용량 분석&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1088&quot; data-start=&quot;1038&quot;&gt;
&lt;td&gt;&lt;b&gt;Prometheus + Grafana&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;애플리케이션 및 서버 성능 모니터링&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1129&quot; data-start=&quot;1089&quot;&gt;
&lt;td&gt;&lt;b&gt;JMeter, Gatling&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;부하 테스트 및 성능 측정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1169&quot; data-start=&quot;1130&quot;&gt;
&lt;td&gt;&lt;b&gt;OpenTelemetry&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;분산 트레이싱 및 성능 분석&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1234&quot; data-start=&quot;1171&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Spring Boot Actuator를 활용하면 &quot;애플리케이션의 성능을 실시간으로 모니터링 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;1239&quot; data-start=&quot;1236&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;1396&quot; data-start=&quot;1241&quot; data-ke-size=&quot;size16&quot;&gt;✅ 여기까지 Spring Boot 성능 튜닝이 필요한 이유와 기본 개념을 배웠습니다!&lt;br /&gt;  &lt;b&gt;&quot;그렇다면, Spring Boot에서 성능을 최적화하는 실전 방법은?&quot;&lt;/b&gt;&lt;br /&gt;✅ 2부에서 &lt;b&gt;Spring Boot의 주요 성능 튜닝 기법과 실전 최적화 방법&lt;/b&gt;을 배워봅시다!&lt;/p&gt;
&lt;p data-end=&quot;1396&quot; data-start=&quot;1241&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 상세 주제 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;1487&quot; data-start=&quot;1453&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. JVM &amp;amp; GC 튜닝 (메모리 최적화)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1548&quot; data-start=&quot;1488&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;JVM 옵션 및 GC 설정을 최적화하여 메모리 사용량을 줄이고, 애플리케이션 성능을 개선 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1585&quot; data-start=&quot;1550&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;1️⃣ JVM 옵션 튜닝 (메모리 설정 최적화)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385896098&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-Xms512m -Xmx1024m -XX:NewRatio=2 -XX:SurvivorRatio=8
-XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+HeapDumpOnOutOfMemoryError&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1866&quot; data-start=&quot;1722&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Heap 크기 조정 (-Xms, -Xmx)&lt;/b&gt;: 적절한 메모리 크기를 설정하여 OutOfMemory 오류 방지&lt;br /&gt;✔ &lt;b&gt;G1GC 사용 (-XX:+UseG1GC)&lt;/b&gt;: 최신 Garbage Collector(GC)로 멀티스레드 환경 최적화&lt;/p&gt;
&lt;p data-end=&quot;1910&quot; data-start=&quot;1868&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;2️⃣ GC 로그 모니터링 설정 (문제 발생 시 분석 용이)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385901963&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/var/log/gc.log&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2034&quot; data-start=&quot;1990&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;GC 로그를 활성화하여 &quot;메모리 누수 및 성능 문제를 추적 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;2039&quot; data-start=&quot;2036&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2067&quot; data-start=&quot;2041&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 데이터베이스 성능 최적화&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;2130&quot; data-start=&quot;2068&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Spring Boot 애플리케이션에서 가장 중요한 성능 최적화 요소 중 하나는 데이터베이스 최적화&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2170&quot; data-start=&quot;2132&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;1️⃣ 데이터베이스 Connection Pool 튜닝&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385982957&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  datasource:
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5
      idle-timeout: 30000
      max-lifetime: 1800000&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2379&quot; data-start=&quot;2321&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;HikariCP를 사용하여 Connection Pool을 적절히 설정하여 DB 연결 최적화&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2423&quot; data-start=&quot;2381&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;2️⃣ JPA N+1 문제 해결 (Fetch Join 활용)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385990977&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Query(&quot;SELECT o FROM Order o JOIN FETCH o.customer WHERE o.id = :id&quot;)
Order findOrderWithCustomer(@Param(&quot;id&quot;) Long id);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2598&quot; data-start=&quot;2558&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;JPA JOIN FETCH를 활용하여 N+1 문제 해결&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2630&quot; data-start=&quot;2600&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;3️⃣ 인덱스 튜닝 (조회 성능 개선)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385999707&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE INDEX idx_user_email ON users(email);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2728&quot; data-start=&quot;2687&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;자주 조회하는 컬럼에 인덱스를 설정하여 DB 조회 속도 개선&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2781&quot; data-start=&quot;2730&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;데이터베이스 튜닝을 하면 &quot;DB 부하를 최소화하고, 성능을 크게 향상 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;2786&quot; data-start=&quot;2783&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2820&quot; data-start=&quot;2788&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 캐싱 전략 적용 (Redis 활용)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;2872&quot; data-start=&quot;2821&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;자주 조회되는 데이터를 캐싱하여 DB 부하를 줄이고, API 응답 속도를 개선&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2903&quot; data-start=&quot;2874&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;1️⃣ Redis를 활용한 캐싱 적용&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742386004994&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  cache:
    type: redis
  redis:
    host: localhost
    port: 6379&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3040&quot; data-start=&quot;2993&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Redis 캐싱을 활용하여 &quot;자주 사용하는 데이터를 빠르게 조회 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3088&quot; data-start=&quot;3042&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;2️⃣ Spring Cache 활용 (@Cacheable 적용)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742386011568&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Cacheable(value = &quot;userCache&quot;, key = &quot;#id&quot;)
public User getUserById(Long id) {
    return userRepository.findById(id).orElseThrow();
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3275&quot; data-start=&quot;3237&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;캐시 적용 시 DB 조회 없이 빠르게 데이터 반환 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3319&quot; data-start=&quot;3277&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;캐싱을 활용하면 &quot;API 응답 속도를 획기적으로 개선 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;3324&quot; data-start=&quot;3321&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;3371&quot; data-start=&quot;3326&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 비동기 처리 및 WebFlux 활용 (I/O 성능 최적화)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;3440&quot; data-start=&quot;3372&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;CPU 연산이 아닌 외부 API 호출, DB 조회 등의 I/O 작업은 비동기로 처리하여 성능을 높일 수 있음&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3475&quot; data-start=&quot;3442&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;1️⃣ @Async를 활용한 비동기 처리&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742386016783&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Async
public CompletableFuture&amp;lt;String&amp;gt; asyncMethod() {
    return CompletableFuture.completedFuture(&quot;Hello Async!&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3648&quot; data-start=&quot;3608&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;비동기 작업을 수행하여 메인 스레드의 부담을 줄일 수 있음&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3698&quot; data-start=&quot;3650&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;2️⃣ WebClient를 활용한 비동기 API 호출 (논블로킹 방식)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742386022258&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public Mono&amp;lt;String&amp;gt; fetchData() {
    return webClient.get().uri(&quot;/data&quot;)
           .retrieve()
           .bodyToMono(String.class);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3903&quot; data-start=&quot;3848&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;WebClient를 활용하면 &quot;블로킹 없는 API 호출이 가능하여 성능 최적화 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;3908&quot; data-start=&quot;3905&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;4056&quot; data-start=&quot;3910&quot; data-ke-size=&quot;size16&quot;&gt;✅ 여기까지 Spring Boot 애플리케이션의 주요 성능 튜닝 기법을 배웠습니다!&lt;br /&gt;  &lt;b&gt;&quot;그렇다면, 실전 프로젝트에서 성능 최적화 사례는?&quot;&lt;/b&gt;&lt;br /&gt;✅ 다음 회차에서 &lt;b&gt;실전 프로젝트에서 Spring Boot 성능 최적화 사례 분석&lt;/b&gt;을 배워봅시다!&lt;/p&gt;
&lt;p data-end=&quot;4056&quot; data-start=&quot;3910&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;xyz&quot;&gt;&lt;!-- 티스토리 본문에 애드센스 광고를 삽입 합니다. --&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9977447109791049&quot;&gt;&lt;/script&gt;
&lt;!-- 336X280 Size mid 2 --&gt; &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-slot=&quot;8340259647&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4056&quot; data-start=&quot;3910&quot; data-ke-size=&quot;size16&quot;&gt;
&lt;script&gt;document.getElementById('abc').appendChild(document.getElementById('xyz'));&lt;/script&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot; data-start=&quot;4132&quot; data-end=&quot;4304&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-end=&quot;5867&quot; data-start=&quot;5724&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>IT Developer/Spring</category>
      <author>TEMA_</author>
      <guid isPermaLink="true">https://te-ma.tistory.com/344</guid>
      <comments>https://te-ma.tistory.com/344#entry344comment</comments>
      <pubDate>Thu, 24 Apr 2025 13:17:30 +0900</pubDate>
    </item>
    <item>
      <title>Spring 기초 &amp;lt;38. Spring Boot에서 CQRS 패턴 적용 및 활용법&amp;gt;</title>
      <link>https://te-ma.tistory.com/343</link>
      <description>&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p style=&quot;clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 18pt;&quot;&gt;스프링 Spring&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;38. Spring&amp;nbsp;Boot에서&amp;nbsp;CQRS&amp;nbsp;패턴&amp;nbsp;적용&amp;nbsp;및&amp;nbsp;활용법&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요! 태마입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;Spring&lt;/span&gt;&amp;nbsp;기초 강좌입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;강좌의 경우&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 주제 간단 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 상세 주제 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;으로 이루어져 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;스프링 Spring&lt;/span&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;9T7tobH9QpueIjclQy6EdlBbd-CXNprDfNLQIyq8u3rqv9dxYbI6efgHXsf5tAUqbO6EkpjDUJaKVnsdlOzGKQu5wWBsoPuOIl0k18Nx1z_Tzw6o_3sbYUo6Lvgl51DWkE6n7GGfU32K4G0bpZnHSA.svg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;78&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pJ59E/btsMPrX2b4Y/5BdFMQt76yAEkwvHF2B3O0/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pJ59E/btsMPrX2b4Y/5BdFMQt76yAEkwvHF2B3O0/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pJ59E/btsMPrX2b4Y/5BdFMQt76yAEkwvHF2B3O0/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpJ59E%2FbtsMPrX2b4Y%2F5BdFMQt76yAEkwvHF2B3O0%2Ftfile.dat&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;300&quot; height=&quot;78&quot; data-filename=&quot;9T7tobH9QpueIjclQy6EdlBbd-CXNprDfNLQIyq8u3rqv9dxYbI6efgHXsf5tAUqbO6EkpjDUJaKVnsdlOzGKQu5wWBsoPuOIl0k18Nx1z_Tzw6o_3sbYUo6Lvgl51DWkE6n7GGfU32K4G0bpZnHSA.svg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;78&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;포스팅 시작하겠습니다 :)&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;xyz&quot;&gt;&lt;!-- 티스토리 본문에 애드센스 광고를 삽입 합니다. --&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9977447109791049&quot;&gt;&lt;/script&gt;
&lt;!-- 336X280 Size mid 1 --&gt; &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-slot=&quot;3927916504&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;
&lt;script&gt;document.getElementById('abc').appendChild(document.getElementById('xyz'));&lt;/script&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 주제 간단 정리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot; data-start=&quot;1567&quot; data-end=&quot;1717&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;307&quot; data-start=&quot;242&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. CQRS(Command Query Responsibility Segregation) 패턴이란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;462&quot; data-start=&quot;308&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;CQRS(Command Query Responsibility Segregation)는 명령(Command)과 조회(Query)를 분리하는 소프트웨어 아키텍처 패턴&lt;/b&gt;&lt;br /&gt;✔ &lt;b&gt;데이터 변경(Write)과 조회(Read)를 독립적으로 처리하여 성능과 확장성을 개선&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;487&quot; data-start=&quot;464&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;CQRS 패턴의 핵심 개념&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;개념설명
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;731&quot; data-start=&quot;489&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;731&quot; data-start=&quot;517&quot;&gt;
&lt;tr data-end=&quot;585&quot; data-start=&quot;517&quot;&gt;
&lt;td&gt;&lt;b&gt;Command(명령)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;데이터를 변경하는 작업 (예: INSERT, UPDATE, DELETE)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;632&quot; data-start=&quot;586&quot;&gt;
&lt;td&gt;&lt;b&gt;Query(조회)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;데이터를 조회하는 작업 (예: SELECT)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;676&quot; data-start=&quot;633&quot;&gt;
&lt;td&gt;&lt;b&gt;책임 분리&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Command와 Query를 분리하여 최적화 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;731&quot; data-start=&quot;677&quot;&gt;
&lt;td&gt;&lt;b&gt;이벤트 소싱과 결합 가능&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;데이터 변경을 이벤트 형태로 저장하여 변경 이력을 추적&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;782&quot; data-start=&quot;733&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;CQRS 패턴을 활용하면 &quot;데이터 변경과 조회 성능을 각각 최적화 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;787&quot; data-start=&quot;784&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;818&quot; data-start=&quot;789&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. CQRS 패턴을 적용하는 이유&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;900&quot; data-start=&quot;819&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;기존의 전통적인 CRUD 방식에서는 하나의 서비스가 모든 작업을 처리하지만, CQRS 패턴은 이를 분리하여 더 효율적으로 운영 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;928&quot; data-start=&quot;902&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;CQRS 패턴 적용의 주요 장점&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;장점설명
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1183&quot; data-start=&quot;930&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;1183&quot; data-start=&quot;958&quot;&gt;
&lt;tr data-end=&quot;1003&quot; data-start=&quot;958&quot;&gt;
&lt;td&gt;&lt;b&gt;읽기/쓰기 성능 최적화&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;조회 요청과 변경 요청을 독립적으로 처리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1066&quot; data-start=&quot;1004&quot;&gt;
&lt;td&gt;&lt;b&gt;확장성(Scalability) 증가&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;조회(Read)와 변경(Write) 로직을 별도 확장 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1126&quot; data-start=&quot;1067&quot;&gt;
&lt;td&gt;&lt;b&gt;데이터 정합성 유지&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;이벤트 소싱(Event Sourcing)과 결합하여 변경 이력을 관리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1183&quot; data-start=&quot;1127&quot;&gt;
&lt;td&gt;&lt;b&gt;복잡한 비즈니스 로직 적용 가능&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Command와 Query 로직을 개별적으로 최적화&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1235&quot; data-start=&quot;1185&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;CQRS 패턴을 활용하면 &quot;대규모 시스템에서 확장성과 성능을 극대화 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;1240&quot; data-start=&quot;1237&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;1381&quot; data-start=&quot;1242&quot; data-ke-size=&quot;size16&quot;&gt;✅ 여기까지 CQRS 패턴의 개념과 필요성을 배웠습니다!&lt;br /&gt;  &lt;b&gt;&quot;그렇다면, Spring Boot에서 CQRS 패턴을 어떻게 적용할까?&quot;&lt;/b&gt;&lt;br /&gt;✅ 2부에서 &lt;b&gt;Spring Boot에서 CQRS 패턴을 실제로 적용하는 방법&lt;/b&gt;을 배워봅시다!&lt;/p&gt;
&lt;p data-end=&quot;2387&quot; data-start=&quot;2218&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 상세 주제 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;1465&quot; data-start=&quot;1432&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. CQRS 패턴을 적용한 프로젝트 구조&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1525&quot; data-start=&quot;1466&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;CQRS 패턴을 적용할 때, Command와 Query를 별도의 계층으로 분리하는 것이 핵심&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1563&quot; data-start=&quot;1527&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Spring Boot CQRS 프로젝트 구조 예시&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385756433&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cqrs-example/
 ├── domain/
 │   ├── entity/        # JPA 엔티티(Entity)
 │   ├── repository/    # Command용 Repository (데이터 저장)
 │   ├── projection/    # Query용 Projection (데이터 조회)
 │
 ├── command/
 │   ├── controller/    # Command API (POST, PUT, DELETE)
 │   ├── service/       # Command Service
 │   ├── handler/       # Command Handler (CQRS 적용)
 │
 ├── query/
 │   ├── controller/    # Query API (GET)
 │   ├── service/       # Query Service
 │   ├── repository/    # Query Repository (별도 DB 또는 캐싱 활용)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2122&quot; data-start=&quot;2075&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Command와 Query의 데이터를 별도로 관리하여 성능 최적화 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2176&quot; data-start=&quot;2124&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;CQRS 패턴을 활용하면 &quot;데이터 변경과 조회를 분리하여 효율적인 운영 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;2181&quot; data-start=&quot;2178&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2213&quot; data-start=&quot;2183&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. Command(쓰기) 계층 구현&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;2279&quot; data-start=&quot;2214&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Command 계층에서는 데이터 변경을 담당하며, Command Handler를 통해 명령을 처리함&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2323&quot; data-start=&quot;2281&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;1️⃣ 엔티티(Entity) 정의 (Order.java)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385764520&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String product;
    private int quantity;
    
    public Order(String product, int quantity) {
        this.product = product;
        this.quantity = quantity;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2790&quot; data-start=&quot;2746&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;JPA를 활용하여 주문(Order) 데이터를 저장하는 엔티티 생성&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2852&quot; data-start=&quot;2792&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;2️⃣ Command Handler 구현 (OrderCommandHandler.java)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385770690&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class OrderCommandHandler {

    private final OrderRepository orderRepository;

    public OrderCommandHandler(OrderRepository orderRepository) {
        this.orderRepository = orderRepository;
    }

    @Transactional
    public Order createOrder(String product, int quantity) {
        Order order = new Order(product, quantity);
        return orderRepository.save(order);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3426&quot; data-start=&quot;3380&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Command Handler는 데이터를 변경하는 비즈니스 로직을 담당&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3492&quot; data-start=&quot;3428&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;3️⃣ Command API 컨트롤러 구현 (OrderCommandController.java)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385776419&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping(&quot;/orders&quot;)
public class OrderCommandController {

    private final OrderCommandHandler orderCommandHandler;

    public OrderCommandController(OrderCommandHandler orderCommandHandler) {
        this.orderCommandHandler = orderCommandHandler;
    }

    @PostMapping
    public Order createOrder(@RequestParam String product, @RequestParam int quantity) {
        return orderCommandHandler.createOrder(product, quantity);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4058&quot; data-start=&quot;4019&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;POST 요청을 통해 새로운 주문을 생성하는 API 구현&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;4110&quot; data-start=&quot;4060&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Command 계층을 활용하면 &quot;데이터 변경 작업을 독립적으로 관리 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;4115&quot; data-start=&quot;4112&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;4145&quot; data-start=&quot;4117&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. Query(읽기) 계층 구현&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;4210&quot; data-start=&quot;4146&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Query 계층에서는 데이터 조회를 담당하며, 별도의 Query Projection을 사용할 수 있음&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;4268&quot; data-start=&quot;4212&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;1️⃣ Projection(조회 전용 DTO) 정의 (OrderView.java)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385788765&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public record OrderView(Long id, String product, int quantity) { }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4397&quot; data-start=&quot;4348&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;JPA Entity가 아닌 별도의 DTO를 활용하여 조회 성능 최적화 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;4461&quot; data-start=&quot;4399&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;2️⃣ Query Repository 구현 (OrderQueryRepository.java)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385796457&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;

public interface OrderQueryRepository extends JpaRepository&amp;lt;Order, Long&amp;gt; {
    List&amp;lt;OrderView&amp;gt; findAllProjectedBy();
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4708&quot; data-start=&quot;4679&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;프로젝션을 활용하여 조회 성능을 최적화&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;4770&quot; data-start=&quot;4710&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;3️⃣ Query API 컨트롤러 구현 (OrderQueryController.java)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385803109&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping(&quot;/orders&quot;)
public class OrderQueryController {

    private final OrderQueryRepository orderQueryRepository;

    public OrderQueryController(OrderQueryRepository orderQueryRepository) {
        this.orderQueryRepository = orderQueryRepository;
    }

    @GetMapping
    public List&amp;lt;OrderView&amp;gt; getOrders() {
        return orderQueryRepository.findAllProjectedBy();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5291&quot; data-start=&quot;5265&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;조회 요청을 처리하는 API 구현&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;5352&quot; data-start=&quot;5293&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Query 계층을 활용하면 &quot;조회 전용 데이터베이스나 캐시를 활용하여 성능을 최적화 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;5357&quot; data-start=&quot;5354&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;5516&quot; data-start=&quot;5359&quot; data-ke-size=&quot;size16&quot;&gt;✅ 여기까지 Spring Boot에서 CQRS 패턴을 적용하는 방법을 배웠습니다!&lt;br /&gt;  &lt;b&gt;&quot;그렇다면, Spring Boot에서 서버 성능을 튜닝하고 최적화하는 방법은?&quot;&lt;/b&gt;&lt;br /&gt;✅ 다음 회차에서 &lt;b&gt;Spring Boot에서 서버 성능 튜닝 및 최적화 방법&lt;/b&gt;을 배워봅시다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot; data-start=&quot;4132&quot; data-end=&quot;4304&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;xyz&quot;&gt;&lt;!-- 티스토리 본문에 애드센스 광고를 삽입 합니다. --&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9977447109791049&quot;&gt;&lt;/script&gt;
&lt;!-- 336X280 Size mid 2 --&gt; &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-slot=&quot;8340259647&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot; data-start=&quot;4132&quot; data-end=&quot;4304&quot;&gt;
&lt;script&gt;document.getElementById('abc').appendChild(document.getElementById('xyz'));&lt;/script&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-end=&quot;5867&quot; data-start=&quot;5724&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>IT Developer/Spring</category>
      <author>TEMA_</author>
      <guid isPermaLink="true">https://te-ma.tistory.com/343</guid>
      <comments>https://te-ma.tistory.com/343#entry343comment</comments>
      <pubDate>Wed, 23 Apr 2025 13:32:35 +0900</pubDate>
    </item>
    <item>
      <title>Spring 기초 &amp;lt;37. Spring Boot에서 멀티 모듈(Multi-Module) 프로젝트 설계&amp;gt;</title>
      <link>https://te-ma.tistory.com/342</link>
      <description>&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p style=&quot;clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 18pt;&quot;&gt;스프링 Spring&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;37. Spring&amp;nbsp;Boot에서&amp;nbsp;멀티&amp;nbsp;모듈(Multi-Module)&amp;nbsp;프로젝트&amp;nbsp;설계&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요! 태마입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;Spring&lt;/span&gt;&amp;nbsp;기초 강좌입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;강좌의 경우&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 주제 간단 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 상세 주제 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;으로 이루어져 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;스프링 Spring&lt;/span&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;9T7tobH9QpueIjclQy6EdlBbd-CXNprDfNLQIyq8u3rqv9dxYbI6efgHXsf5tAUqbO6EkpjDUJaKVnsdlOzGKQu5wWBsoPuOIl0k18Nx1z_Tzw6o_3sbYUo6Lvgl51DWkE6n7GGfU32K4G0bpZnHSA.svg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;78&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIaDVy/btsMP6ZYApE/2WY61pxNyxZUTDzdLWBK81/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIaDVy/btsMP6ZYApE/2WY61pxNyxZUTDzdLWBK81/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIaDVy/btsMP6ZYApE/2WY61pxNyxZUTDzdLWBK81/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIaDVy%2FbtsMP6ZYApE%2F2WY61pxNyxZUTDzdLWBK81%2Ftfile.dat&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;300&quot; height=&quot;78&quot; data-filename=&quot;9T7tobH9QpueIjclQy6EdlBbd-CXNprDfNLQIyq8u3rqv9dxYbI6efgHXsf5tAUqbO6EkpjDUJaKVnsdlOzGKQu5wWBsoPuOIl0k18Nx1z_Tzw6o_3sbYUo6Lvgl51DWkE6n7GGfU32K4G0bpZnHSA.svg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;78&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;포스팅 시작하겠습니다 :)&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;xyz&quot;&gt;&lt;!-- 티스토리 본문에 애드센스 광고를 삽입 합니다. --&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9977447109791049&quot;&gt;&lt;/script&gt;
&lt;!-- 336X280 Size mid 1 --&gt; &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-slot=&quot;3927916504&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;
&lt;script&gt;document.getElementById('abc').appendChild(document.getElementById('xyz'));&lt;/script&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 주제 간단 정리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot; data-start=&quot;1567&quot; data-end=&quot;1717&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;267&quot; data-start=&quot;242&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 멀티 모듈 프로젝트란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;395&quot; data-start=&quot;268&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;멀티 모듈(Multi-Module) 프로젝트는 하나의 프로젝트를 여러 개의 모듈(Module)로 나누어 관리하는 방식&lt;/b&gt;&lt;br /&gt;✔ &lt;b&gt;대규모 애플리케이션에서 코드의 재사용성을 높이고 유지보수를 쉽게 하기 위해 사용됨&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;428&quot; data-start=&quot;397&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;단일 모듈 vs 멀티 모듈 프로젝트 비교&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;비교 항목단일 모듈 프로젝트멀티 모듈 프로젝트
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;718&quot; data-start=&quot;430&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;718&quot; data-start=&quot;514&quot;&gt;
&lt;tr data-end=&quot;565&quot; data-start=&quot;514&quot;&gt;
&lt;td&gt;&lt;b&gt;구조&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;하나의 프로젝트에서 모든 코드 관리&lt;/td&gt;
&lt;td&gt;여러 개의 독립적인 모듈 구성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;620&quot; data-start=&quot;566&quot;&gt;
&lt;td&gt;&lt;b&gt;유지보수&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;규모가 커질수록 유지보수 어려움&lt;/td&gt;
&lt;td&gt;각 모듈별로 관리하여 유지보수 용이&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;668&quot; data-start=&quot;621&quot;&gt;
&lt;td&gt;&lt;b&gt;재사용성&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;재사용이 어려움&lt;/td&gt;
&lt;td&gt;공통 모듈을 활용하여 코드 재사용 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;718&quot; data-start=&quot;669&quot;&gt;
&lt;td&gt;&lt;b&gt;빌드 속도&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;전체 빌드를 해야 함&lt;/td&gt;
&lt;td&gt;변경된 모듈만 개별적으로 빌드 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;777&quot; data-start=&quot;720&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;멀티 모듈 프로젝트를 활용하면 &quot;코드의 모듈화를 통해 유지보수성과 확장성을 향상 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;782&quot; data-start=&quot;779&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;815&quot; data-start=&quot;784&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 멀티 모듈 프로젝트가 필요한 이유&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;932&quot; data-start=&quot;816&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;대규모 애플리케이션에서는 단일 모듈 프로젝트의 복잡성이 증가하므로, 모듈을 분리하여 관리하는 것이 중요&lt;/b&gt;&lt;br /&gt;✔ &lt;b&gt;팀별로 역할을 분리하여 병렬 개발이 가능하고, 빌드 속도를 최적화할 수 있음&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;960&quot; data-start=&quot;934&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;멀티 모듈 프로젝트의 주요 장점&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;장점설명
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1177&quot; data-start=&quot;962&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;1177&quot; data-start=&quot;990&quot;&gt;
&lt;tr data-end=&quot;1032&quot; data-start=&quot;990&quot;&gt;
&lt;td&gt;&lt;b&gt;코드 분리 및 모듈화&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;각 기능을 독립적인 모듈로 분리 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1084&quot; data-start=&quot;1033&quot;&gt;
&lt;td&gt;&lt;b&gt;재사용성 향상&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;공통 기능을 하나의 모듈로 만들어 여러 서비스에서 활용 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1128&quot; data-start=&quot;1085&quot;&gt;
&lt;td&gt;&lt;b&gt;독립적 배포 가능&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;특정 모듈만 변경하여 개별적으로 배포 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1177&quot; data-start=&quot;1129&quot;&gt;
&lt;td&gt;&lt;b&gt;빌드 속도 최적화&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;변경된 모듈만 빌드 가능하여 전체 빌드 시간을 단축&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1232&quot; data-start=&quot;1179&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;멀티 모듈 프로젝트를 활용하면 &quot;대규모 프로젝트에서도 효율적인 코드 관리 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;1237&quot; data-start=&quot;1234&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;1391&quot; data-start=&quot;1239&quot; data-ke-size=&quot;size16&quot;&gt;✅ 여기까지 멀티 모듈 프로젝트의 개념과 필요성을 배웠습니다!&lt;br /&gt;  &lt;b&gt;&quot;그렇다면, Spring Boot에서 실제로 멀티 모듈 프로젝트를 어떻게 설계할까?&quot;&lt;/b&gt;&lt;br /&gt;✅ 2부에서 &lt;b&gt;Spring Boot에서 멀티 모듈 프로젝트를 실제로 구성하는 방법&lt;/b&gt;을 배워봅시다!&lt;/p&gt;
&lt;p data-end=&quot;1391&quot; data-start=&quot;1239&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 상세 주제 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;1474&quot; data-start=&quot;1445&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 멀티 모듈 프로젝트 구조 설계&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1551&quot; data-start=&quot;1475&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Spring Boot 멀티 모듈 프로젝트는 일반적으로 parent 프로젝트와 여러 개의 sub-module로 구성됨&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1590&quot; data-start=&quot;1553&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Spring Boot 멀티 모듈 프로젝트 구조 예시&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385493816&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;multi-module-project/
 ├── parent-project (Root 프로젝트, 공통 설정 관리)
 │   ├── settings.gradle
 │   ├── build.gradle
 │   ├── gradle.properties
 │   ├── modules/
 │   │   ├── common-module (공통 기능 모듈)
 │   │   ├── api-module (API 서비스 모듈)
 │   │   ├── batch-module (배치 작업 모듈)
 │   │   ├── domain-module (도메인 모델 모듈)
 │   │   ├── service-module (비즈니스 로직 모듈)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2255&quot; data-start=&quot;1947&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;parent-project&lt;/b&gt;: 전체 프로젝트를 관리하는 루트 프로젝트&lt;br /&gt;✔ &lt;b&gt;common-module&lt;/b&gt;: 여러 모듈에서 공통으로 사용하는 유틸리티, DTO, 설정 파일 등을 포함&lt;br /&gt;✔ &lt;b&gt;api-module&lt;/b&gt;: REST API를 제공하는 컨트롤러 및 서비스 로직 포함&lt;br /&gt;✔ &lt;b&gt;batch-module&lt;/b&gt;: 배치 처리 관련 기능 포함&lt;br /&gt;✔ &lt;b&gt;domain-module&lt;/b&gt;: 엔티티(Entity) 및 JPA 관련 설정 포함&lt;br /&gt;✔ &lt;b&gt;service-module&lt;/b&gt;: 비즈니스 로직을 담당하는 서비스 계층 포함&lt;/p&gt;
&lt;p data-end=&quot;2312&quot; data-start=&quot;2257&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;멀티 모듈을 활용하면 &quot;각 모듈이 독립적으로 역할을 수행하며, 유지보수성이 향상됨&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;2317&quot; data-start=&quot;2314&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2358&quot; data-start=&quot;2319&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. Parent 프로젝트 설정 (Gradle 기반)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;2410&quot; data-start=&quot;2359&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;멀티 모듈 프로젝트에서는 parent 프로젝트에서 공통 설정을 관리해야 함&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2457&quot; data-start=&quot;2412&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;1️⃣ parent-project/build.gradle 설정&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385501301&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;plugins {
    id 'java'
}

allprojects {
    repositories {
        mavenCentral()
    }
}

subprojects {
    apply plugin: 'java'

    dependencies {
        implementation 'org.springframework.boot:spring-boot-starter'
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2750&quot; data-start=&quot;2701&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;모든 서브모듈에서 공통적으로 사용할 Spring Boot 의존성을 정의&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2785&quot; data-start=&quot;2752&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;2️⃣ settings.gradle 설정&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385506883&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;rootProject.name = 'multi-module-project'

include 'modules:common-module'
include 'modules:api-module'
include 'modules:batch-module'
include 'modules:domain-module'
include 'modules:service-module'&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3050&quot; data-start=&quot;3000&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;각 모듈을 settings.gradle에서 등록하여 빌드 가능하도록 설정&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3119&quot; data-start=&quot;3052&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Parent 프로젝트를 활용하면 &quot;모든 모듈에서 공통적인 설정을 유지하며 일관된 빌드 환경을 제공 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;3124&quot; data-start=&quot;3121&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;3152&quot; data-start=&quot;3126&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 각 모듈별 역할 및 설정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;3194&quot; data-start=&quot;3153&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;각 모듈별로 독립적인 역할을 수행하며, 의존성을 설정해야 함&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3245&quot; data-start=&quot;3196&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;1️⃣ 공통 모듈 (common-module/build.gradle)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385533149&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-validation'
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3456&quot; data-start=&quot;3424&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;공통 유틸리티 및 DTO 등을 포함하는 모듈&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3508&quot; data-start=&quot;3458&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;2️⃣ 도메인 모듈 (domain-module/build.gradle)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385539217&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dependencies {
    implementation project(':modules:common-module')
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3709&quot; data-start=&quot;3668&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;JPA 관련 설정 및 엔티티(Entity) 관리를 위한 모듈&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3758&quot; data-start=&quot;3711&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;3️⃣ API 모듈 (api-module/build.gradle)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385544761&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dependencies {
    implementation project(':modules:service-module')
    implementation 'org.springframework.boot:spring-boot-starter-web'
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3944&quot; data-start=&quot;3914&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;REST API 컨트롤러를 포함하는 모듈&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3997&quot; data-start=&quot;3946&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;4️⃣ 서비스 모듈 (service-module/build.gradle)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385551406&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dependencies {
    implementation project(':modules:domain-module')
    implementation 'org.springframework.boot:spring-boot-starter-aop'
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4176&quot; data-start=&quot;4152&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;비즈니스 로직을 포함하는 모듈&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;4226&quot; data-start=&quot;4178&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;모듈별 역할을 분리하면 &quot;코드의 응집도가 높아지고, 유지보수가 쉬워짐&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;4231&quot; data-start=&quot;4228&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;4385&quot; data-start=&quot;4233&quot; data-ke-size=&quot;size16&quot;&gt;✅ 여기까지 Spring Boot에서 멀티 모듈 프로젝트를 구성하는 방법을 배웠습니다!&lt;br /&gt;  &lt;b&gt;&quot;그렇다면, Spring Boot에서 CQRS 패턴을 적용하려면?&quot;&lt;/b&gt;&lt;br /&gt;✅ 다음 회차에서 &lt;b&gt;Spring Boot에서 CQRS 패턴 적용 및 활용법&lt;/b&gt;을 배워봅시다!&lt;/p&gt;
&lt;p data-end=&quot;4385&quot; data-start=&quot;4233&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;xyz&quot;&gt;&lt;!-- 티스토리 본문에 애드센스 광고를 삽입 합니다. --&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9977447109791049&quot;&gt;&lt;/script&gt;
&lt;!-- 336X280 Size mid 2 --&gt; &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-slot=&quot;8340259647&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot; data-start=&quot;4132&quot; data-end=&quot;4304&quot;&gt;
&lt;script&gt;document.getElementById('abc').appendChild(document.getElementById('xyz'));&lt;/script&gt;
&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-end=&quot;5867&quot; data-start=&quot;5724&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>IT Developer/Spring</category>
      <author>TEMA_</author>
      <guid isPermaLink="true">https://te-ma.tistory.com/342</guid>
      <comments>https://te-ma.tistory.com/342#entry342comment</comments>
      <pubDate>Tue, 22 Apr 2025 13:45:43 +0900</pubDate>
    </item>
    <item>
      <title>Spring 기초 &amp;lt;36. Spring Boot에서 외부 API 호출 (RestTemplate vs WebClient 비교)&amp;gt;</title>
      <link>https://te-ma.tistory.com/341</link>
      <description>&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p style=&quot;clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 18pt;&quot;&gt;스프링 Spring&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;36. Spring&amp;nbsp;Boot에서&amp;nbsp;외부&amp;nbsp;API&amp;nbsp;호출&amp;nbsp;(RestTemplate&amp;nbsp;vs&amp;nbsp;WebClient&amp;nbsp;비교)&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요! 태마입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;Spring&lt;/span&gt;&amp;nbsp;기초 강좌입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;강좌의 경우&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 주제 간단 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 상세 주제 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;으로 이루어져 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;스프링 Spring&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;포스팅 시작하겠습니다 :)&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;xyz&quot;&gt;&lt;!-- 티스토리 본문에 애드센스 광고를 삽입 합니다. --&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9977447109791049&quot;&gt;&lt;/script&gt;
&lt;!-- 336X280 Size mid 1 --&gt; &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-slot=&quot;3927916504&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;
&lt;script&gt;document.getElementById('abc').appendChild(document.getElementById('xyz'));&lt;/script&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 주제 간단 정리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot; data-start=&quot;1567&quot; data-end=&quot;1717&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;323&quot; data-start=&quot;295&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. RestTemplate이란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;452&quot; data-start=&quot;324&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Spring에서 제공하는 동기(Synchronous) 기반의 HTTP 클라이언트&lt;/b&gt;&lt;br /&gt;✔ &lt;b&gt;Spring Boot 2.x까지 많이 사용되었지만, 최신 Spring Boot 3.x에서는 WebClient가 권장됨&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;482&quot; data-start=&quot;454&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;RestTemplate의 주요 특징&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;특징설명
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;649&quot; data-start=&quot;484&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;649&quot; data-start=&quot;512&quot;&gt;
&lt;tr data-end=&quot;561&quot; data-start=&quot;512&quot;&gt;
&lt;td&gt;&lt;b&gt;동기(Synchronous) 방식&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;요청을 보내면 응답이 올 때까지 대기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;608&quot; data-start=&quot;562&quot;&gt;
&lt;td&gt;&lt;b&gt;블로킹 I/O 기반&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;하나의 요청이 완료될 때까지 스레드가 블로킹됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;649&quot; data-start=&quot;609&quot;&gt;
&lt;td&gt;&lt;b&gt;사용법이 간단&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;기존 REST API 호출에 익숙한 방식&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;722&quot; data-start=&quot;651&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;RestTemplate은 &quot;직관적인 API 호출이 가능하지만, 동기 방식으로 인해 성능 문제가 발생할 수 있음&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;727&quot; data-start=&quot;724&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;753&quot; data-start=&quot;729&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. WebClient란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;875&quot; data-start=&quot;754&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Spring WebFlux에서 제공하는 비동기(Asynchronous) 기반의 HTTP 클라이언트&lt;/b&gt;&lt;br /&gt;✔ &lt;b&gt;Spring Boot 3.x에서 공식적으로 RestTemplate의 대체 기술로 권장됨&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;902&quot; data-start=&quot;877&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;WebClient의 주요 특징&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;특징설명
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1094&quot; data-start=&quot;904&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;1094&quot; data-start=&quot;932&quot;&gt;
&lt;tr data-end=&quot;996&quot; data-start=&quot;932&quot;&gt;
&lt;td&gt;&lt;b&gt;비동기(Asynchronous) 방식&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;요청을 보낸 후, 응답을 기다리지 않고 다른 작업 수행 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1052&quot; data-start=&quot;997&quot;&gt;
&lt;td&gt;&lt;b&gt;논블로킹(Non-blocking) 방식&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;리액티브 스트림 기반으로 성능 최적화 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1094&quot; data-start=&quot;1053&quot;&gt;
&lt;td&gt;&lt;b&gt;더 많은 기능 제공&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;스트리밍, 리액티브 데이터 처리 지원&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1149&quot; data-start=&quot;1096&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;WebClient는 &quot;비동기 및 논블로킹 기반으로 고성능 API 호출이 가능함&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;1154&quot; data-start=&quot;1151&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1197&quot; data-start=&quot;1156&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. RestTemplate vs WebClient 비교&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1221&quot; data-start=&quot;1198&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;두 방식의 차이를 비교해보자&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1263&quot; data-start=&quot;1223&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;RestTemplate vs WebClient 주요 비교&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;비교 항목RestTemplateWebClient
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1618&quot; data-start=&quot;1265&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;1618&quot; data-start=&quot;1342&quot;&gt;
&lt;tr data-end=&quot;1390&quot; data-start=&quot;1342&quot;&gt;
&lt;td&gt;&lt;b&gt;방식&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;동기(Synchronous)&lt;/td&gt;
&lt;td&gt;비동기(Asynchronous)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1442&quot; data-start=&quot;1391&quot;&gt;
&lt;td&gt;&lt;b&gt;I/O 처리&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;블로킹(Blocking)&lt;/td&gt;
&lt;td&gt;논블로킹(Non-blocking)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1494&quot; data-start=&quot;1443&quot;&gt;
&lt;td&gt;&lt;b&gt;성능&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;요청당 스레드 점유 (비효율적)&lt;/td&gt;
&lt;td&gt;리액티브 방식으로 처리 (고성능)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1551&quot; data-start=&quot;1495&quot;&gt;
&lt;td&gt;&lt;b&gt;실시간 데이터 스트리밍&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;지원하지 않음&lt;/td&gt;
&lt;td&gt;Flux 기반 실시간 데이터 스트리밍 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1618&quot; data-start=&quot;1552&quot;&gt;
&lt;td&gt;&lt;b&gt;Spring 지원&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Spring Boot 2.x까지 사용 가능&lt;/td&gt;
&lt;td&gt;Spring Boot 3.x에서 권장&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1704&quot; data-start=&quot;1620&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Spring Boot 3.x에서는 &quot;WebClient 사용이 권장되며, RestTemplate는 레거시 코드에서 유지보수용으로만 사용&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;1709&quot; data-start=&quot;1706&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;1887&quot; data-start=&quot;1711&quot; data-ke-size=&quot;size16&quot;&gt;✅ 여기까지 RestTemplate과 WebClient의 개념과 차이점을 배웠습니다!&lt;br /&gt;  &lt;b&gt;&quot;그렇다면, Spring Boot에서 실제로 RestTemplate과 WebClient를 어떻게 사용할까?&quot;&lt;/b&gt;&lt;br /&gt;✅ 2부에서 &lt;b&gt;RestTemplate과 WebClient의 실제 사용법과 예제를 배워봅시다!&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1887&quot; data-start=&quot;1711&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 상세 주제 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;1982&quot; data-start=&quot;1945&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. RestTemplate을 활용한 API 호출&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;2025&quot; data-start=&quot;1983&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;RestTemplate을 사용하여 외부 API를 호출하는 방법&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2081&quot; data-start=&quot;2027&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;1️⃣ RestTemplate Bean 등록 (AppConfig.java)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385324798&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class AppConfig {

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2445&quot; data-start=&quot;2395&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;RestTemplate은 @Bean으로 등록하여 사용하는 것이 일반적&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2504&quot; data-start=&quot;2447&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;2️⃣ RestTemplate을 활용한 GET 요청 (ApiService.java)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385331569&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class ApiService {

    private final RestTemplate restTemplate;

    public ApiService(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public String getDataFromApi() {
        String url = &quot;https://jsonplaceholder.typicode.com/posts/1&quot;;
        return restTemplate.getForObject(url, String.class);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3024&quot; data-start=&quot;2974&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;getForObject() 메서드를 사용하여 외부 API 데이터를 가져옴&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3075&quot; data-start=&quot;3026&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;3️⃣ 컨트롤러에서 API 호출 (ApiController.java)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385337382&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping(&quot;/api&quot;)
public class ApiController {

    private final ApiService apiService;

    public ApiController(ApiService apiService) {
        this.apiService = apiService;
    }

    @GetMapping(&quot;/fetch&quot;)
    public String fetchData() {
        return apiService.getDataFromApi();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3503&quot; data-start=&quot;3456&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;/api/fetch 엔드포인트를 호출하면 외부 API 데이터를 반환&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3560&quot; data-start=&quot;3505&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;RestTemplate을 활용하면 &quot;간단한 REST API 호출을 쉽게 구현 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;3565&quot; data-start=&quot;3562&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;3601&quot; data-start=&quot;3567&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. WebClient를 활용한 API 호출&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;3647&quot; data-start=&quot;3602&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;WebClient를 사용하여 비동기 방식으로 API를 호출하는 방법&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3698&quot; data-start=&quot;3649&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;1️⃣ WebClient Bean 등록 (AppConfig.java)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385344563&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;

@Configuration
public class AppConfig {

    @Bean
    public WebClient webClient() {
        return WebClient.builder().baseUrl(&quot;https://jsonplaceholder.typicode.com&quot;).build();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4131&quot; data-start=&quot;4078&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;WebClient는 baseUrl을 설정하여 API 호출을 쉽게 구성 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;4187&quot; data-start=&quot;4133&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;2️⃣ WebClient를 활용한 GET 요청 (ApiService.java)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385352416&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

@Service
public class ApiService {

    private final WebClient webClient;

    public ApiService(WebClient webClient) {
        this.webClient = webClient;
    }

    public Mono&amp;lt;String&amp;gt; getDataFromApi() {
        return webClient.get()
                .uri(&quot;/posts/1&quot;)
                .retrieve()
                .bodyToMono(String.class);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4756&quot; data-start=&quot;4701&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;WebClient는 Mono&amp;lt;&amp;gt;를 반환하여 비동기 방식으로 API 데이터를 가져옴&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;4807&quot; data-start=&quot;4758&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;3️⃣ 컨트롤러에서 API 호출 (ApiController.java)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385358096&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Mono;

@RestController
@RequestMapping(&quot;/api&quot;)
public class ApiController {

    private final ApiService apiService;

    public ApiController(ApiService apiService) {
        this.apiService = apiService;
    }

    @GetMapping(&quot;/fetch&quot;)
    public Mono&amp;lt;String&amp;gt; fetchData() {
        return apiService.getDataFromApi();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5280&quot; data-start=&quot;5230&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;/api/fetch 엔드포인트를 호출하면 비동기 방식으로 데이터를 가져옴&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;5347&quot; data-start=&quot;5282&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;WebClient를 활용하면 &quot;비동기 방식으로 높은 성능을 유지하며 API 데이터를 가져올 수 있음&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;5352&quot; data-start=&quot;5349&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;5536&quot; data-start=&quot;5354&quot; data-ke-size=&quot;size16&quot;&gt;✅ 여기까지 Spring Boot에서 외부 API를 호출하는 방법을 배웠습니다!&lt;br /&gt;  &lt;b&gt;&quot;그렇다면, Spring Boot에서 멀티 모듈(Multi-Module) 프로젝트를 어떻게 설계할까?&quot;&lt;/b&gt;&lt;br /&gt;✅ 다음 회차에서 &lt;b&gt;Spring Boot에서 멀티 모듈(Multi-Module) 프로젝트 설계 방법&lt;/b&gt;을 배워봅시다!&lt;/p&gt;
&lt;p data-end=&quot;5536&quot; data-start=&quot;5354&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;xyz&quot;&gt;&lt;!-- 티스토리 본문에 애드센스 광고를 삽입 합니다. --&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9977447109791049&quot;&gt;&lt;/script&gt;
&lt;!-- 336X280 Size mid 2 --&gt; &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-slot=&quot;8340259647&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot; data-start=&quot;4132&quot; data-end=&quot;4304&quot;&gt;
&lt;script&gt;document.getElementById('abc').appendChild(document.getElementById('xyz'));&lt;/script&gt;
&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-end=&quot;5867&quot; data-start=&quot;5724&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>IT Developer/Spring</category>
      <author>TEMA_</author>
      <guid isPermaLink="true">https://te-ma.tistory.com/341</guid>
      <comments>https://te-ma.tistory.com/341#entry341comment</comments>
      <pubDate>Mon, 21 Apr 2025 13:56:42 +0900</pubDate>
    </item>
    <item>
      <title>Spring 기초 &amp;lt;35. Spring에서 커스텀 애너테이션(Custom Annotation) 만들기&amp;gt;</title>
      <link>https://te-ma.tistory.com/340</link>
      <description>&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p style=&quot;clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 18pt;&quot;&gt;스프링 Spring&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;35. Spring에서&amp;nbsp;커스텀&amp;nbsp;애너테이션(Custom&amp;nbsp;Annotation)&amp;nbsp;만들기&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요! 태마입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;Spring&lt;/span&gt;&amp;nbsp;기초 강좌입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;강좌의 경우&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 주제 간단 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 상세 주제 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;으로 이루어져 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;스프링 Spring&lt;/span&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;9T7tobH9QpueIjclQy6EdlBbd-CXNprDfNLQIyq8u3rqv9dxYbI6efgHXsf5tAUqbO6EkpjDUJaKVnsdlOzGKQu5wWBsoPuOIl0k18Nx1z_Tzw6o_3sbYUo6Lvgl51DWkE6n7GGfU32K4G0bpZnHSA.svg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;78&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/strHb/btsMPoNRBLC/OP3xZyEaEm4YsmCmkqJfNK/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/strHb/btsMPoNRBLC/OP3xZyEaEm4YsmCmkqJfNK/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/strHb/btsMPoNRBLC/OP3xZyEaEm4YsmCmkqJfNK/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FstrHb%2FbtsMPoNRBLC%2FOP3xZyEaEm4YsmCmkqJfNK%2Ftfile.dat&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;300&quot; height=&quot;78&quot; data-filename=&quot;9T7tobH9QpueIjclQy6EdlBbd-CXNprDfNLQIyq8u3rqv9dxYbI6efgHXsf5tAUqbO6EkpjDUJaKVnsdlOzGKQu5wWBsoPuOIl0k18Nx1z_Tzw6o_3sbYUo6Lvgl51DWkE6n7GGfU32K4G0bpZnHSA.svg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;78&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;포스팅 시작하겠습니다 :)&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;xyz&quot;&gt;&lt;!-- 티스토리 본문에 애드센스 광고를 삽입 합니다. --&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9977447109791049&quot;&gt;&lt;/script&gt;
&lt;!-- 336X280 Size mid 1 --&gt; &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-slot=&quot;3927916504&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;
&lt;script&gt;document.getElementById('abc').appendChild(document.getElementById('xyz'));&lt;/script&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 주제 간단 정리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot; data-start=&quot;1567&quot; data-end=&quot;1717&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;273&quot; data-start=&quot;240&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 애너테이션(Annotation)이란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;430&quot; data-start=&quot;274&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;애너테이션은 코드에 메타데이터를 추가하여, 컴파일러나 런타임 환경에서 특정 동작을 수행하도록 하는 기능&lt;/b&gt;&lt;br /&gt;✔ &lt;b&gt;Spring에서는 @Service, @Transactional, @RestController 등의 애너테이션을 활용하여 기능을 적용 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;453&quot; data-start=&quot;432&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;애너테이션의 주요 역할&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;역할설명
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;647&quot; data-start=&quot;455&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;647&quot; data-start=&quot;483&quot;&gt;
&lt;tr data-end=&quot;516&quot; data-start=&quot;483&quot;&gt;
&lt;td&gt;&lt;b&gt;메타데이터 제공&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;코드의 의미를 명확히 설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;549&quot; data-start=&quot;517&quot;&gt;
&lt;td&gt;&lt;b&gt;컴파일러 지시&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;코드의 검증 및 경고 제어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;598&quot; data-start=&quot;550&quot;&gt;
&lt;td&gt;&lt;b&gt;런타임 동작&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;리플렉션(Reflection)과 조합하여 동적 동작 수행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;647&quot; data-start=&quot;599&quot;&gt;
&lt;td&gt;&lt;b&gt;AOP(관점 지향 프로그래밍)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;특정 로직을 공통화하여 코드 중복 제거&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;701&quot; data-start=&quot;649&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;애너테이션을 활용하면 &quot;반복적인 코드를 줄이고, 유지보수를 쉽게 할 수 있음&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;706&quot; data-start=&quot;703&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;733&quot; data-start=&quot;708&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 애너테이션의 주요 종류&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;773&quot; data-start=&quot;734&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Java와 Spring에서 자주 사용하는 애너테이션 종류&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;800&quot; data-start=&quot;775&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;자주 사용되는 애너테이션 종류&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;애너테이션설명
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1150&quot; data-start=&quot;802&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;1150&quot; data-start=&quot;839&quot;&gt;
&lt;tr data-end=&quot;879&quot; data-start=&quot;839&quot;&gt;
&lt;td&gt;@Override&lt;/td&gt;
&lt;td&gt;부모 클래스의 메서드를 재정의할 때 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;915&quot; data-start=&quot;880&quot;&gt;
&lt;td&gt;@Component&lt;/td&gt;
&lt;td&gt;Spring Bean으로 등록&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;954&quot; data-start=&quot;916&quot;&gt;
&lt;td&gt;@Service&lt;/td&gt;
&lt;td&gt;비즈니스 로직을 담당하는 클래스에 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;992&quot; data-start=&quot;955&quot;&gt;
&lt;td&gt;@Repository&lt;/td&gt;
&lt;td&gt;데이터베이스 관련 클래스에 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1030&quot; data-start=&quot;993&quot;&gt;
&lt;td&gt;@Transactional&lt;/td&gt;
&lt;td&gt;트랜잭션 관리를 위해 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1072&quot; data-start=&quot;1031&quot;&gt;
&lt;td&gt;@RestController&lt;/td&gt;
&lt;td&gt;REST API 컨트롤러에 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1105&quot; data-start=&quot;1073&quot;&gt;
&lt;td&gt;@Autowired&lt;/td&gt;
&lt;td&gt;의존성 주입(DI) 수행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1150&quot; data-start=&quot;1106&quot;&gt;
&lt;td&gt;@PostConstruct&lt;/td&gt;
&lt;td&gt;Bean 생성 후 실행되는 메서드 지정&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1215&quot; data-start=&quot;1152&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Spring에서는 애너테이션을 활용하여 의존성 주입, 트랜잭션 관리, AOP 등을 쉽게 적용 가능&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;1220&quot; data-start=&quot;1217&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;1365&quot; data-start=&quot;1222&quot; data-ke-size=&quot;size16&quot;&gt;✅ 여기까지 애너테이션의 개념과 필요성을 배웠습니다!&lt;br /&gt;  &lt;b&gt;&quot;그렇다면, Spring Boot에서 커스텀 애너테이션을 어떻게 만들까?&quot;&lt;/b&gt;&lt;br /&gt;✅ 2부에서 &lt;b&gt;Spring Boot에서 커스텀 애너테이션을 직접 만들어 활용하는 방법&lt;/b&gt;을 배워봅시다!&lt;/p&gt;
&lt;p data-end=&quot;1365&quot; data-start=&quot;1222&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 상세 주제 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;1448&quot; data-start=&quot;1417&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 기본적인 커스텀 애너테이션 만들기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1572&quot; data-start=&quot;1449&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Spring Boot에서 커스텀 애너테이션을 만들려면 @interface 키워드를 사용&lt;/b&gt;&lt;br /&gt;✔ &lt;b&gt;애너테이션을 정의할 때 @Target, @Retention 등의 메타 애너테이션을 설정해야 함&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1621&quot; data-start=&quot;1574&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;1️⃣ 커스텀 애너테이션 생성 (@LogExecutionTime)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385239181&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD) // 메서드에 적용
@Retention(RetentionPolicy.RUNTIME) // 런타임까지 유지
public @interface LogExecutionTime {
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2050&quot; data-start=&quot;1922&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;@Target(ElementType.METHOD): 이 애너테이션이 메서드에만 적용됨을 의미&lt;/b&gt;&lt;br /&gt;✔ &lt;b&gt;@Retention(RetentionPolicy.RUNTIME): 런타임에도 애너테이션 정보가 유지됨&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;2055&quot; data-start=&quot;2052&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2090&quot; data-start=&quot;2057&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 커스텀 애너테이션을 AOP로 활용하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;2138&quot; data-start=&quot;2091&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;커스텀 애너테이션을 적용하여 특정 기능(AOP)을 수행하도록 설정 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2189&quot; data-start=&quot;2140&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;1️⃣ AOP를 활용한 애너테이션 구현 (LogAspect.java)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385246089&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LogAspect {

    @Around(&quot;@annotation(com.example.annotation.LogExecutionTime)&quot;)
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object proceed = joinPoint.proceed();
        long executionTime = System.currentTimeMillis() - start;

        System.out.println(joinPoint.getSignature() + &quot; executed in &quot; + executionTime + &quot;ms&quot;);
        return proceed;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3005&quot; data-start=&quot;2869&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;@Around(&quot;@annotation(LogExecutionTime)&quot;): @LogExecutionTime이 적용된 메서드의 실행 시간을 측정&lt;/b&gt;&lt;br /&gt;✔ &lt;b&gt;AOP를 활용하면 &quot;공통 로직을 분리하여 코드 중복을 제거 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3051&quot; data-start=&quot;3007&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;커스텀 애너테이션을 활용하면 &quot;성능 모니터링을 쉽게 적용 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;3056&quot; data-start=&quot;3053&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;3092&quot; data-start=&quot;3058&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 커스텀 애너테이션을 적용한 서비스 구현&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;3153&quot; data-start=&quot;3093&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;이제 @LogExecutionTime 애너테이션을 서비스에 적용하여 실행 시간을 측정해보자&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3207&quot; data-start=&quot;3155&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;1️⃣ 서비스 클래스에서 애너테이션 적용 (UserService.java)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385251776&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.stereotype.Service;

@Service
public class UserService {

    @LogExecutionTime
    public void getUserData() {
        try {
            Thread.sleep(1000); // 1초 동안 실행
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(&quot;User data fetched.&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3616&quot; data-start=&quot;3561&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;@LogExecutionTime 애너테이션을 적용하면 실행 시간이 자동으로 로깅됨&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3668&quot; data-start=&quot;3618&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;2️⃣ 컨트롤러에서 서비스 호출 (UserController.java)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385257686&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping(&quot;/users&quot;)
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping(&quot;/fetch&quot;)
    public String fetchUser() {
        userService.getUserData();
        return &quot;User data fetched.&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4140&quot; data-start=&quot;4087&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;이제 /users/fetch 엔드포인트를 호출하면 실행 시간이 자동으로 출력됨&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;4205&quot; data-start=&quot;4142&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;커스텀 애너테이션을 활용하면 &quot;반복되는 로직을 공통화하여 코드의 가독성과 유지보수성을 향상 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;4210&quot; data-start=&quot;4207&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;4428&quot; data-start=&quot;4212&quot; data-ke-size=&quot;size16&quot;&gt;✅ 여기까지 Spring Boot에서 커스텀 애너테이션을 만들어 활용하는 방법을 배웠습니다!&lt;br /&gt;  &lt;b&gt;&quot;그렇다면, Spring Boot에서 외부 API를 호출할 때 RestTemplate vs WebClient는 어떤 차이가 있을까?&quot;&lt;/b&gt;&lt;br /&gt;✅ 다음 회차에서 **Spring Boot에서 외부 API 호출 (RestTemplate vs WebClient 비교)**를 배워봅시다!&lt;/p&gt;
&lt;p data-end=&quot;4428&quot; data-start=&quot;4212&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;xyz&quot;&gt;&lt;!-- 티스토리 본문에 애드센스 광고를 삽입 합니다. --&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9977447109791049&quot;&gt;&lt;/script&gt;
&lt;!-- 336X280 Size mid 2 --&gt; &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-slot=&quot;8340259647&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot; data-start=&quot;4132&quot; data-end=&quot;4304&quot;&gt;
&lt;script&gt;document.getElementById('abc').appendChild(document.getElementById('xyz'));&lt;/script&gt;
&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-end=&quot;5867&quot; data-start=&quot;5724&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>IT Developer/Spring</category>
      <author>TEMA_</author>
      <guid isPermaLink="true">https://te-ma.tistory.com/340</guid>
      <comments>https://te-ma.tistory.com/340#entry340comment</comments>
      <pubDate>Sun, 20 Apr 2025 13:25:29 +0900</pubDate>
    </item>
    <item>
      <title>Spring 기초 &amp;lt;34. Spring Boot 실무 Best Practices 및 최신 트렌드 (Reactive Programming, Cloud Native)&amp;gt;</title>
      <link>https://te-ma.tistory.com/339</link>
      <description>&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p style=&quot;clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 18pt;&quot;&gt;스프링 Spring&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;34. Spring&amp;nbsp;Boot&amp;nbsp;실무&amp;nbsp;Best&amp;nbsp;Practices&amp;nbsp;및&amp;nbsp;최신&amp;nbsp;트렌드&amp;nbsp;(Reactive&amp;nbsp;Programming,&amp;nbsp;Cloud&amp;nbsp;Native)&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요! 태마입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;Spring&lt;/span&gt;&amp;nbsp;기초 강좌입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;강좌의 경우&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 주제 간단 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 상세 주제 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;으로 이루어져 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;스프링 Spring&lt;/span&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;9T7tobH9QpueIjclQy6EdlBbd-CXNprDfNLQIyq8u3rqv9dxYbI6efgHXsf5tAUqbO6EkpjDUJaKVnsdlOzGKQu5wWBsoPuOIl0k18Nx1z_Tzw6o_3sbYUo6Lvgl51DWkE6n7GGfU32K4G0bpZnHSA.svg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;78&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Pi032/btsMPkx21Qy/ayOkdyxgCgtBviuy1b4X4k/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Pi032/btsMPkx21Qy/ayOkdyxgCgtBviuy1b4X4k/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Pi032/btsMPkx21Qy/ayOkdyxgCgtBviuy1b4X4k/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPi032%2FbtsMPkx21Qy%2FayOkdyxgCgtBviuy1b4X4k%2Ftfile.dat&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;300&quot; height=&quot;78&quot; data-filename=&quot;9T7tobH9QpueIjclQy6EdlBbd-CXNprDfNLQIyq8u3rqv9dxYbI6efgHXsf5tAUqbO6EkpjDUJaKVnsdlOzGKQu5wWBsoPuOIl0k18Nx1z_Tzw6o_3sbYUo6Lvgl51DWkE6n7GGfU32K4G0bpZnHSA.svg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;78&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;포스팅 시작하겠습니다 :)&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;xyz&quot;&gt;&lt;!-- 티스토리 본문에 애드센스 광고를 삽입 합니다. --&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9977447109791049&quot;&gt;&lt;/script&gt;
&lt;!-- 336X280 Size mid 1 --&gt; &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-slot=&quot;3927916504&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;
&lt;script&gt;document.getElementById('abc').appendChild(document.getElementById('xyz'));&lt;/script&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 주제 간단 정리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot; data-start=&quot;1567&quot; data-end=&quot;1717&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;292&quot; data-start=&quot;245&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. Spring Boot 프로젝트 설정 Best Practices&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;354&quot; data-start=&quot;293&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Spring Boot 프로젝트를 설정할 때 생산성을 높이고 유지보수를 쉽게 하기 위한 설정 방법&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;390&quot; data-start=&quot;356&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Spring Boot 프로젝트 설정 모범 사례&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;항목Best Practice
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;666&quot; data-start=&quot;392&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;666&quot; data-start=&quot;439&quot;&gt;
&lt;tr data-end=&quot;494&quot; data-start=&quot;439&quot;&gt;
&lt;td&gt;&lt;b&gt;의존성 관리&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;spring-boot-starter를 사용하여 필요한 모듈만 추가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;551&quot; data-start=&quot;495&quot;&gt;
&lt;td&gt;&lt;b&gt;환경 설정 관리&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;application.yml과 .env를 활용하여 설정 분리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;594&quot; data-start=&quot;552&quot;&gt;
&lt;td&gt;&lt;b&gt;버전 관리&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Spring Boot 3.x 최신 버전 유지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;666&quot; data-start=&quot;595&quot;&gt;
&lt;td&gt;&lt;b&gt;Gradle vs Maven&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;빠른 빌드를 위해 Gradle 추천 (단, 팀 환경에 따라 Maven 유지 가능)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;714&quot; data-start=&quot;668&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Spring Boot 최신 버전 사용 시 &quot;안정성과 보안이 강화됨&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;719&quot; data-start=&quot;716&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;762&quot; data-start=&quot;721&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 코드 스타일 및 유지보수 Best Practices&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;804&quot; data-start=&quot;763&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;코드 스타일을 통일하고 유지보수를 쉽게 하기 위한 모범 사례&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;834&quot; data-start=&quot;806&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;코드 스타일 및 유지보수 모범 사례&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;항목Best Practice
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1116&quot; data-start=&quot;836&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;1116&quot; data-start=&quot;883&quot;&gt;
&lt;tr data-end=&quot;940&quot; data-start=&quot;883&quot;&gt;
&lt;td&gt;&lt;b&gt;계층 분리&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Controller &amp;rarr; Service &amp;rarr; Repository 패턴 유지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1005&quot; data-start=&quot;941&quot;&gt;
&lt;td&gt;&lt;b&gt;DTO 사용&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Entity를 직접 노출하지 않고 DTO(Data Transfer Object) 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1065&quot; data-start=&quot;1006&quot;&gt;
&lt;td&gt;&lt;b&gt;예외 처리&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;@ControllerAdvice와 @ExceptionHandler 활용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1116&quot; data-start=&quot;1066&quot;&gt;
&lt;td&gt;&lt;b&gt;로깅 전략&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;SLF4J + Logback을 사용하여 구조적인 로깅 적용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1175&quot; data-start=&quot;1118&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;DTO를 활용하면 &quot;데이터 캡슐화를 통해 보안을 강화하고 유지보수를 쉽게 할 수 있음&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;1180&quot; data-start=&quot;1177&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1216&quot; data-start=&quot;1182&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 성능 최적화 Best Practices&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1263&quot; data-start=&quot;1217&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Spring Boot 애플리케이션의 성능을 최적화하기 위한 주요 전략&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1295&quot; data-start=&quot;1265&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Spring Boot 성능 최적화 전략&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;항목Best Practice
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1547&quot; data-start=&quot;1297&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;1547&quot; data-start=&quot;1344&quot;&gt;
&lt;tr data-end=&quot;1397&quot; data-start=&quot;1344&quot;&gt;
&lt;td&gt;&lt;b&gt;데이터베이스 최적화&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;인덱스 활용, 쿼리 튜닝, JPA + QueryDSL 적용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1440&quot; data-start=&quot;1398&quot;&gt;
&lt;td&gt;&lt;b&gt;캐싱 전략&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Redis를 활용하여 데이터베이스 부하 감소&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1499&quot; data-start=&quot;1441&quot;&gt;
&lt;td&gt;&lt;b&gt;비동기 처리&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;@Async, CompletableFuture, WebFlux 활용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1547&quot; data-start=&quot;1500&quot;&gt;
&lt;td&gt;&lt;b&gt;GC 튜닝&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;G1 GC 및 ZGC 활용하여 JVM 성능 최적화&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1594&quot; data-start=&quot;1549&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Redis를 활용하면 &quot;자주 조회되는 데이터를 빠르게 제공 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;1599&quot; data-start=&quot;1596&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;1744&quot; data-start=&quot;1601&quot; data-ke-size=&quot;size16&quot;&gt;✅ 여기까지 Spring Boot 실무에서 적용할 수 있는 Best Practices를 배웠습니다!&lt;br /&gt;  &lt;b&gt;&quot;그렇다면, 최신 트렌드와 앞으로의 방향은?&quot;&lt;/b&gt;&lt;br /&gt;✅ 2부에서 &lt;b&gt;Spring Boot 최신 트렌드 및 향후 발전 방향&lt;/b&gt;을 배워봅시다!&lt;/p&gt;
&lt;p data-end=&quot;1744&quot; data-start=&quot;1601&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 상세 주제 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;1829&quot; data-start=&quot;1798&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. Spring Boot 최신 트렌드&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1886&quot; data-start=&quot;1830&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Spring Boot 생태계는 빠르게 발전하며, 최근 몇 년 동안 다양한 변화가 있었음&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1915&quot; data-start=&quot;1888&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Spring Boot 최신 트렌드&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;트렌드설명
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2265&quot; data-start=&quot;1917&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;2265&quot; data-start=&quot;1948&quot;&gt;
&lt;tr data-end=&quot;2004&quot; data-start=&quot;1948&quot;&gt;
&lt;td&gt;&lt;b&gt;Spring Boot 3.x&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Jakarta EE 기반으로 전환, 최신 Java 지원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2079&quot; data-start=&quot;2005&quot;&gt;
&lt;td&gt;&lt;b&gt;Virtual Threads 지원&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Spring Boot 3.2에서 JDK 21 Virtual Threads 지원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2142&quot; data-start=&quot;2080&quot;&gt;
&lt;td&gt;&lt;b&gt;GraalVM 네이티브 이미지&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Spring Boot 애플리케이션을 네이티브 실행 파일로 컴파일&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2202&quot; data-start=&quot;2143&quot;&gt;
&lt;td&gt;&lt;b&gt;Spring Modulith&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;모놀리식(Monolithic) 구조를 유지하면서 모듈화 지원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2265&quot; data-start=&quot;2203&quot;&gt;
&lt;td&gt;&lt;b&gt;AI &amp;amp; Observability&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;OpenTelemetry, AI 기반 성능 최적화 도구 등장&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2340&quot; data-start=&quot;2267&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Spring Boot 3.x에서는 &quot;GraalVM과 Virtual Threads를 활용하여 성능을 대폭 개선 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;2345&quot; data-start=&quot;2342&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2388&quot; data-start=&quot;2347&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 실무에서 Spring Boot 최신 기능 적용 방법&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;2441&quot; data-start=&quot;2389&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Spring Boot 최신 트렌드를 반영하여 실무에서 활용할 수 있는 방법 정리&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2487&quot; data-start=&quot;2443&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Spring Boot 최신 기능 적용 Best Practices&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;최신 기술적용 방법
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2801&quot; data-start=&quot;2489&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;2801&quot; data-start=&quot;2531&quot;&gt;
&lt;tr data-end=&quot;2580&quot; data-start=&quot;2531&quot;&gt;
&lt;td&gt;&lt;b&gt;Spring Boot 3.x&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;최신 Jakarta EE 기반 마이그레이션&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2646&quot; data-start=&quot;2581&quot;&gt;
&lt;td&gt;&lt;b&gt;Virtual Threads&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;@EnableVirtualThreads 활용하여 비동기 처리 최적화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2706&quot; data-start=&quot;2647&quot;&gt;
&lt;td&gt;&lt;b&gt;GraalVM 네이티브 빌드&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;spring-native를 활용하여 네이티브 이미지 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2753&quot; data-start=&quot;2707&quot;&gt;
&lt;td&gt;&lt;b&gt;Spring WebFlux&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;블로킹 방식 대신 논블로킹 API 활용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2801&quot; data-start=&quot;2754&quot;&gt;
&lt;td&gt;&lt;b&gt;OpenTelemetry&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;마이크로서비스 모니터링 및 성능 분석 적용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2866&quot; data-start=&quot;2803&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;GraalVM을 활용하면 &quot;Spring Boot 애플리케이션의 실행 속도를 획기적으로 개선 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;2871&quot; data-start=&quot;2868&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2904&quot; data-start=&quot;2873&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. Spring Boot의 미래 전망&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;2958&quot; data-start=&quot;2905&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Spring Boot는 향후에도 Java 생태계의 중심으로 지속적인 발전이 예상됨&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2987&quot; data-start=&quot;2960&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Spring Boot의 미래 전망&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;키워드설명
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;3276&quot; data-start=&quot;2989&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;3276&quot; data-start=&quot;3020&quot;&gt;
&lt;tr data-end=&quot;3074&quot; data-start=&quot;3020&quot;&gt;
&lt;td&gt;&lt;b&gt;Java 21 &amp;amp; Virtual Threads&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;가벼운 스레드 기반으로 성능 향상&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;3130&quot; data-start=&quot;3075&quot;&gt;
&lt;td&gt;&lt;b&gt;AI 기반 Observability&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;OpenTelemetry 및 AI 기반 자동화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;3200&quot; data-start=&quot;3131&quot;&gt;
&lt;td&gt;&lt;b&gt;서버리스(Serverless) &amp;amp; 클라우드 네이티브&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;AWS Lambda, Kubernetes와의 결합 강화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;3276&quot; data-start=&quot;3201&quot;&gt;
&lt;td&gt;&lt;b&gt;모듈형 애플리케이션(Modular Architecture)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Spring Modulith를 통한 모놀리식 아키텍처 개선&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3340&quot; data-start=&quot;3278&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Spring Boot는 &quot;클라우드 네이티브 &amp;amp; AI 기반 자동화 방향으로 발전할 가능성이 높음&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;3345&quot; data-start=&quot;3342&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;3519&quot; data-start=&quot;3347&quot; data-ke-size=&quot;size16&quot;&gt;✅ 여기까지 Spring Boot 실무 Best Practices 및 최신 트렌드를 배웠습니다!&lt;br /&gt;  &lt;b&gt;&quot;그렇다면, Spring에서 커스텀 애너테이션(Custom Annotation)을 어떻게 만들까?&quot;&lt;/b&gt;&lt;br /&gt;✅ 다음 회차에서 &lt;b&gt;Spring에서 커스텀 애너테이션을 활용하는 방법&lt;/b&gt;을 배워봅시다!&lt;/p&gt;
&lt;p data-end=&quot;3519&quot; data-start=&quot;3347&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;xyz&quot;&gt;&lt;!-- 티스토리 본문에 애드센스 광고를 삽입 합니다. --&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9977447109791049&quot;&gt;&lt;/script&gt;
&lt;!-- 336X280 Size mid 2 --&gt; &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-slot=&quot;8340259647&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot; data-start=&quot;4132&quot; data-end=&quot;4304&quot;&gt;
&lt;script&gt;document.getElementById('abc').appendChild(document.getElementById('xyz'));&lt;/script&gt;
&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-end=&quot;5867&quot; data-start=&quot;5724&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>IT Developer/Spring</category>
      <author>TEMA_</author>
      <guid isPermaLink="true">https://te-ma.tistory.com/339</guid>
      <comments>https://te-ma.tistory.com/339#entry339comment</comments>
      <pubDate>Sat, 19 Apr 2025 13:13:08 +0900</pubDate>
    </item>
    <item>
      <title>Spring 기초 &amp;lt;33. Spring Boot에서 A/B 테스트와 Feature Toggle 적용&amp;gt;</title>
      <link>https://te-ma.tistory.com/338</link>
      <description>&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p style=&quot;clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 18pt;&quot;&gt;스프링 Spring&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;33. Spring&amp;nbsp;Boot에서&amp;nbsp;A/B&amp;nbsp;테스트와&amp;nbsp;Feature&amp;nbsp;Toggle&amp;nbsp;적용&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요! 태마입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;Spring&lt;/span&gt;&amp;nbsp;기초 강좌입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;강좌의 경우&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 주제 간단 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 상세 주제 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;으로 이루어져 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;스프링 Spring&lt;/span&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;9T7tobH9QpueIjclQy6EdlBbd-CXNprDfNLQIyq8u3rqv9dxYbI6efgHXsf5tAUqbO6EkpjDUJaKVnsdlOzGKQu5wWBsoPuOIl0k18Nx1z_Tzw6o_3sbYUo6Lvgl51DWkE6n7GGfU32K4G0bpZnHSA.svg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;78&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7dcnE/btsMQ5smn1C/AxTNrF9i66Jm33t5C1zKQK/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7dcnE/btsMQ5smn1C/AxTNrF9i66Jm33t5C1zKQK/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7dcnE/btsMQ5smn1C/AxTNrF9i66Jm33t5C1zKQK/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7dcnE%2FbtsMQ5smn1C%2FAxTNrF9i66Jm33t5C1zKQK%2Ftfile.dat&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;300&quot; height=&quot;78&quot; data-filename=&quot;9T7tobH9QpueIjclQy6EdlBbd-CXNprDfNLQIyq8u3rqv9dxYbI6efgHXsf5tAUqbO6EkpjDUJaKVnsdlOzGKQu5wWBsoPuOIl0k18Nx1z_Tzw6o_3sbYUo6Lvgl51DWkE6n7GGfU32K4G0bpZnHSA.svg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;78&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;포스팅 시작하겠습니다 :)&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;xyz&quot;&gt;&lt;!-- 티스토리 본문에 애드센스 광고를 삽입 합니다. --&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9977447109791049&quot;&gt;&lt;/script&gt;
&lt;!-- 336X280 Size mid 1 --&gt; &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-slot=&quot;3927916504&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script&gt;document.getElementById('abc').appendChild(document.getElementById('xyz'));&lt;/script&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 주제 간단 정리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot; data-start=&quot;1567&quot; data-end=&quot;1717&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;267&quot; data-start=&quot;245&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. A/B 테스트란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;390&quot; data-start=&quot;268&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;A/B 테스트(A/B Testing)는 두 개 이상의 버전을 비교하여 어떤 버전이 더 나은 성과를 내는지 평가하는 실험 방법&lt;/b&gt;&lt;br /&gt;✔ &lt;b&gt;사용자의 반응 데이터를 기반으로 최적의 기능을 선택하는 데 활용됨&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;415&quot; data-start=&quot;392&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;A/B 테스트의 주요 특징&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;특징설명
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;642&quot; data-start=&quot;417&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;642&quot; data-start=&quot;445&quot;&gt;
&lt;tr data-end=&quot;501&quot; data-start=&quot;445&quot;&gt;
&lt;td&gt;&lt;b&gt;실제 사용자 데이터 기반 평가&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;A/B 테스트를 통해 실제 사용자의 반응을 측정 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;551&quot; data-start=&quot;502&quot;&gt;
&lt;td&gt;&lt;b&gt;점진적 배포 가능&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;새로운 기능을 일부 사용자에게만 배포하여 테스트 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;594&quot; data-start=&quot;552&quot;&gt;
&lt;td&gt;&lt;b&gt;빠른 피드백 루프&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;기능을 테스트하고 개선하는 사이클을 단축&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;642&quot; data-start=&quot;595&quot;&gt;
&lt;td&gt;&lt;b&gt;데이터 기반 의사결정&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;감이 아닌 실제 데이터를 기반으로 기능 최적화&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;696&quot; data-start=&quot;644&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;A/B 테스트를 활용하면 &quot;사용자의 반응을 기반으로 최적의 기능을 선택 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;701&quot; data-start=&quot;698&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;733&quot; data-start=&quot;703&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. Feature Toggle이란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;844&quot; data-start=&quot;734&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Feature Toggle(기능 토글)은 애플리케이션의 특정 기능을 실행 여부를 동적으로 제어하는 기법&lt;/b&gt;&lt;br /&gt;✔ &lt;b&gt;코드를 배포한 후에도 특정 기능을 활성화 또는 비활성화할 수 있음&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;876&quot; data-start=&quot;846&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Feature Toggle의 주요 특징&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;특징설명
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1113&quot; data-start=&quot;878&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;1113&quot; data-start=&quot;906&quot;&gt;
&lt;tr data-end=&quot;954&quot; data-start=&quot;906&quot;&gt;
&lt;td&gt;&lt;b&gt;동적 기능 활성화/비활성화&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;배포 없이 특정 기능을 켜거나 끌 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1010&quot; data-start=&quot;955&quot;&gt;
&lt;td&gt;&lt;b&gt;안전한 배포 가능&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;새로운 기능을 점진적으로 출시하고 문제 발생 시 즉시 롤백 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1063&quot; data-start=&quot;1011&quot;&gt;
&lt;td&gt;&lt;b&gt;A/B 테스트와 결합 가능&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;특정 사용자 그룹에게만 기능을 제공하여 실험 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1113&quot; data-start=&quot;1064&quot;&gt;
&lt;td&gt;&lt;b&gt;운영 환경에서 즉시 변경 가능&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;애플리케이션 재배포 없이 설정 변경 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1183&quot; data-start=&quot;1115&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Feature Toggle을 활용하면 &quot;새로운 기능을 안전하게 테스트하고, 필요에 따라 빠르게 롤백 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;1188&quot; data-start=&quot;1185&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;1369&quot; data-start=&quot;1190&quot; data-ke-size=&quot;size16&quot;&gt;✅ 여기까지 A/B 테스트와 Feature Toggle의 개념을 배웠습니다!&lt;br /&gt;  &lt;b&gt;&quot;그렇다면, Spring Boot에서 A/B 테스트와 Feature Toggle을 어떻게 적용할까?&quot;&lt;/b&gt;&lt;br /&gt;✅ 2부에서 &lt;b&gt;Spring Boot에서 A/B 테스트 및 Feature Toggle을 적용하는 방법&lt;/b&gt;을 배워봅시다!&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 상세 주제 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;1476&quot; data-start=&quot;1437&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. Spring Boot에서 A/B 테스트 적용하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1550&quot; data-start=&quot;1477&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Spring Boot 애플리케이션에서 A/B 테스트를 수행하려면 사용자 그룹을 나누고, 서로 다른 기능을 제공해야 함&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1603&quot; data-start=&quot;1552&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;1️⃣ 사용자 그룹을 랜덤으로 배정 (ABTestService.java)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385094542&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.stereotype.Service;

import java.util.Random;

@Service
public class ABTestService {

    public String getFeatureVersion(String userId) {
        int hash = userId.hashCode();
        return (hash % 2 == 0) ? &quot;A&quot; : &quot;B&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1915&quot; data-start=&quot;1872&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;사용자의 userId를 해시하여 A/B 그룹을 랜덤하게 배정&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1973&quot; data-start=&quot;1917&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;2️⃣ A/B 테스트를 적용한 컨트롤러 (ABTestController.java)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385090052&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping(&quot;/test&quot;)
public class ABTestController {

    private final ABTestService abTestService;

    public ABTestController(ABTestService abTestService) {
        this.abTestService = abTestService;
    }

    @GetMapping(&quot;/{userId}&quot;)
    public String getFeature(@PathVariable String userId) {
        String version = abTestService.getFeatureVersion(userId);
        return &quot;User &quot; + userId + &quot; sees version: &quot; + version;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2534&quot; data-start=&quot;2495&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;사용자의 userId에 따라 A 또는 B 버전을 노출&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2585&quot; data-start=&quot;2536&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;A/B 테스트를 활용하면 &quot;사용자별로 다른 기능을 제공하여 테스트 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;2590&quot; data-start=&quot;2587&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2638&quot; data-start=&quot;2592&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. Spring Boot에서 Feature Toggle 적용하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;2705&quot; data-start=&quot;2639&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Spring Boot에서 Feature Toggle을 적용하면 특정 기능을 동적으로 활성화/비활성화 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2774&quot; data-start=&quot;2707&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;1️⃣ Spring Boot 설정에서 Feature Toggle 적용 (application.yml)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385101625&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;feature:
  new-feature-enabled: true&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2865&quot; data-start=&quot;2824&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;YAML 설정을 이용하여 특정 기능을 활성화할지 여부를 지정&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2931&quot; data-start=&quot;2867&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;2️⃣ Feature Toggle 서비스 구현 (FeatureToggleService.java)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385107554&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class FeatureToggleService {

    @Value(&quot;${feature.new-feature-enabled}&quot;)
    private boolean newFeatureEnabled;

    public boolean isNewFeatureEnabled() {
        return newFeatureEnabled;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3315&quot; data-start=&quot;3267&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Spring Boot 설정값을 읽어와 특정 기능을 활성화할지 여부를 판단&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3381&quot; data-start=&quot;3317&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;3️⃣ Feature Toggle을 적용한 컨트롤러 (FeatureController.java)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385115264&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping(&quot;/feature&quot;)
public class FeatureController {

    private final FeatureToggleService featureToggleService;

    public FeatureController(FeatureToggleService featureToggleService) {
        this.featureToggleService = featureToggleService;
    }

    @GetMapping(&quot;/check&quot;)
    public String checkFeature() {
        if (featureToggleService.isNewFeatureEnabled()) {
            return &quot;New Feature is ENABLED&quot;;
        } else {
            return &quot;New Feature is DISABLED&quot;;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4020&quot; data-start=&quot;3969&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Feature Toggle을 사용하여 설정에 따라 기능을 활성화 또는 비활성화&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;4078&quot; data-start=&quot;4022&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Feature Toggle을 활용하면 &quot;배포 없이 특정 기능을 활성화/비활성화 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;4083&quot; data-start=&quot;4080&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;4130&quot; data-start=&quot;4085&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. A/B 테스트와 Feature Toggle을 함께 활용하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;4195&quot; data-start=&quot;4131&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;A/B 테스트와 Feature Toggle을 결합하면 특정 사용자 그룹에게만 새로운 기능을 제공 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;4268&quot; data-start=&quot;4197&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;A/B 테스트와 Feature Toggle을 적용한 컨트롤러 (ABFeatureController.java)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385122771&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping(&quot;/ab-feature&quot;)
public class ABFeatureController {

    private final ABTestService abTestService;
    private final FeatureToggleService featureToggleService;

    public ABFeatureController(ABTestService abTestService, FeatureToggleService featureToggleService) {
        this.abTestService = abTestService;
        this.featureToggleService = featureToggleService;
    }

    @GetMapping(&quot;/{userId}&quot;)
    public String getFeature(@PathVariable String userId) {
        if (!featureToggleService.isNewFeatureEnabled()) {
            return &quot;New Feature is DISABLED for all users&quot;;
        }
        String version = abTestService.getFeatureVersion(userId);
        return &quot;User &quot; + userId + &quot; sees version: &quot; + version;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5139&quot; data-start=&quot;5093&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Feature Toggle이 활성화된 경우에만 A/B 테스트가 수행됨&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;5220&quot; data-start=&quot;5141&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;A/B 테스트와 Feature Toggle을 함께 활용하면 &quot;새로운 기능을 점진적으로 배포하고, 특정 사용자에게만 제공 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;5225&quot; data-start=&quot;5222&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;5409&quot; data-start=&quot;5227&quot; data-ke-size=&quot;size16&quot;&gt;✅ 여기까지 Spring Boot에서 A/B 테스트 및 Feature Toggle 적용 방법을 배웠습니다!&lt;br /&gt;  &lt;b&gt;&quot;그렇다면, Spring Boot 실무 Best Practices 및 최신 트렌드는?&quot;&lt;/b&gt;&lt;br /&gt;✅ 다음 회차에서 &lt;b&gt;Spring Boot 실무 Best Practices 및 최신 트렌드&lt;/b&gt;를 배워봅시다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot; data-start=&quot;4132&quot; data-end=&quot;4304&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;xyz&quot;&gt;&lt;!-- 티스토리 본문에 애드센스 광고를 삽입 합니다. --&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9977447109791049&quot;&gt;&lt;/script&gt;
&lt;!-- 336X280 Size mid 2 --&gt; &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-slot=&quot;8340259647&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot; data-start=&quot;4132&quot; data-end=&quot;4304&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script&gt;document.getElementById('abc').appendChild(document.getElementById('xyz'));&lt;/script&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-end=&quot;5867&quot; data-start=&quot;5724&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>IT Developer/Spring</category>
      <author>TEMA_</author>
      <guid isPermaLink="true">https://te-ma.tistory.com/338</guid>
      <comments>https://te-ma.tistory.com/338#entry338comment</comments>
      <pubDate>Fri, 18 Apr 2025 13:52:09 +0900</pubDate>
    </item>
    <item>
      <title>Spring 기초 &amp;lt;32. Spring Boot에서 OpenTelemetry를 활용한 애플리케이션 모니터링&amp;gt;</title>
      <link>https://te-ma.tistory.com/337</link>
      <description>&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p style=&quot;clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 18pt;&quot;&gt;스프링 Spring&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;32. Spring&amp;nbsp;Boot에서&amp;nbsp;OpenTelemetry를&amp;nbsp;활용한&amp;nbsp;애플리케이션&amp;nbsp;모니터링&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요! 태마입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;Spring&lt;/span&gt;&amp;nbsp;기초 강좌입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;강좌의 경우&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 주제 간단 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 상세 주제 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;으로 이루어져 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;스프링 Spring&lt;/span&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;9T7tobH9QpueIjclQy6EdlBbd-CXNprDfNLQIyq8u3rqv9dxYbI6efgHXsf5tAUqbO6EkpjDUJaKVnsdlOzGKQu5wWBsoPuOIl0k18Nx1z_Tzw6o_3sbYUo6Lvgl51DWkE6n7GGfU32K4G0bpZnHSA.svg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;78&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Gxwxr/btsMQqjsEAH/vS0TglKbmdch6lJAWTKr51/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Gxwxr/btsMQqjsEAH/vS0TglKbmdch6lJAWTKr51/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Gxwxr/btsMQqjsEAH/vS0TglKbmdch6lJAWTKr51/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGxwxr%2FbtsMQqjsEAH%2FvS0TglKbmdch6lJAWTKr51%2Ftfile.dat&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;300&quot; height=&quot;78&quot; data-filename=&quot;9T7tobH9QpueIjclQy6EdlBbd-CXNprDfNLQIyq8u3rqv9dxYbI6efgHXsf5tAUqbO6EkpjDUJaKVnsdlOzGKQu5wWBsoPuOIl0k18Nx1z_Tzw6o_3sbYUo6Lvgl51DWkE6n7GGfU32K4G0bpZnHSA.svg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;78&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;포스팅 시작하겠습니다 :)&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;xyz&quot;&gt;&lt;!-- 티스토리 본문에 애드센스 광고를 삽입 합니다. --&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9977447109791049&quot;&gt;&lt;/script&gt;
&lt;!-- 336X280 Size mid 1 --&gt; &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-slot=&quot;3927916504&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;
&lt;script&gt;document.getElementById('abc').appendChild(document.getElementById('xyz'));&lt;/script&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 주제 간단 정리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot; data-start=&quot;1567&quot; data-end=&quot;1717&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;279&quot; data-start=&quot;251&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. OpenTelemetry란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;439&quot; data-start=&quot;280&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;OpenTelemetry는 애플리케이션의 성능을 모니터링하고 분석하기 위한 오픈소스 관찰 가능성(Observability) 프레임워크&lt;/b&gt;&lt;br /&gt;✔ &lt;b&gt;애플리케이션의 트레이스(Trace), 메트릭(Metrics), 로그(Logs)를 수집하여 시스템 성능을 분석하는 데 활용됨&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;470&quot; data-start=&quot;441&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;OpenTelemetry의 주요 기능&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;기능설명
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;732&quot; data-start=&quot;472&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;732&quot; data-start=&quot;500&quot;&gt;
&lt;tr data-end=&quot;554&quot; data-start=&quot;500&quot;&gt;
&lt;td&gt;&lt;b&gt;분산 트레이싱(Distributed Tracing)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;서비스 간 요청 흐름을 추적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;620&quot; data-start=&quot;555&quot;&gt;
&lt;td&gt;&lt;b&gt;메트릭 수집(Metrics Collection)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;CPU 사용량, 메모리 소비, 요청 응답 시간 측정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;669&quot; data-start=&quot;621&quot;&gt;
&lt;td&gt;&lt;b&gt;로그 분석(Log Analysis)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;애플리케이션의 이벤트 기록을 분석&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;732&quot; data-start=&quot;670&quot;&gt;
&lt;td&gt;&lt;b&gt;다양한 백엔드 지원&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Jaeger, Zipkin, Prometheus, Grafana 연동 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;795&quot; data-start=&quot;734&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;OpenTelemetry를 활용하면 &quot;애플리케이션의 성능을 실시간으로 모니터링하고 분석 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;800&quot; data-start=&quot;797&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;836&quot; data-start=&quot;802&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. OpenTelemetry가 필요한 이유&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;959&quot; data-start=&quot;837&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;마이크로서비스 환경에서는 서비스 간의 요청 흐름을 추적하는 것이 중요함&lt;/b&gt;&lt;br /&gt;✔ &lt;b&gt;OpenTelemetry를 사용하면 장애 발생 시 어느 부분에서 병목(Bottleneck)이 발생했는지 쉽게 파악 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;998&quot; data-start=&quot;961&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;기존 로깅 방식 vs OpenTelemetry 비교&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;방식문제점
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1157&quot; data-start=&quot;1000&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;1157&quot; data-start=&quot;1029&quot;&gt;
&lt;tr data-end=&quot;1070&quot; data-start=&quot;1029&quot;&gt;
&lt;td&gt;&lt;b&gt;기존 로깅 방식&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;서비스 간의 요청 흐름을 추적하기 어려움&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1114&quot; data-start=&quot;1071&quot;&gt;
&lt;td&gt;&lt;b&gt;단일 애플리케이션 로깅&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;마이크로서비스 간의 연관성 분석 불가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1157&quot; data-start=&quot;1115&quot;&gt;
&lt;td&gt;&lt;b&gt;수동 로그 분석&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;대량의 로그 데이터를 수동으로 분석해야 함&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1227&quot; data-start=&quot;1159&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;OpenTelemetry를 활용하면 &quot;서비스 간 요청 흐름을 시각적으로 확인하고 문제를 빠르게 해결 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;1232&quot; data-start=&quot;1229&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;1414&quot; data-start=&quot;1234&quot; data-ke-size=&quot;size16&quot;&gt;✅ 여기까지 OpenTelemetry의 개념과 필요성을 배웠습니다!&lt;br /&gt;  &lt;b&gt;&quot;그렇다면, Spring Boot에서 OpenTelemetry를 어떻게 적용할까?&quot;&lt;/b&gt;&lt;br /&gt;✅ 2부에서 &lt;b&gt;Spring Boot에서 OpenTelemetry를 설정하고, Jaeger 및 Prometheus와 연동하는 방법&lt;/b&gt;을 배워봅시다!&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 상세 주제 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;1503&quot; data-start=&quot;1471&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. OpenTelemetry 환경 설정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1568&quot; data-start=&quot;1504&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Spring Boot 애플리케이션에서 OpenTelemetry를 적용하려면 먼저 의존성을 추가해야 함&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1619&quot; data-start=&quot;1570&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;1️⃣ build.gradle에 OpenTelemetry 의존성 추가&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742384963561&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dependencies {
    implementation 'io.opentelemetry:opentelemetry-api:1.19.0'
    implementation 'io.opentelemetry:opentelemetry-sdk:1.19.0'
    implementation 'io.opentelemetry:opentelemetry-exporter-jaeger:1.19.0'
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1898&quot; data-start=&quot;1852&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;OpenTelemetry API 및 Jaeger Exporter 추가&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1949&quot; data-start=&quot;1900&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;2️⃣ application.yml에서 OpenTelemetry 설정&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742384970352&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;otel:
  traces:
    exporter: jaeger
  metrics:
    exporter: prometheus&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2079&quot; data-start=&quot;2035&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Jaeger와 Prometheus를 통해 트레이스 및 메트릭 수집&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2149&quot; data-start=&quot;2081&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;OpenTelemetry를 활용하면 &quot;Spring Boot 애플리케이션의 성능 모니터링을 쉽게 설정 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;2154&quot; data-start=&quot;2151&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2204&quot; data-start=&quot;2156&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. OpenTelemetry에서 Jaeger를 활용한 트레이싱 적용&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;2254&quot; data-start=&quot;2205&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Jaeger는 OpenTelemetry에서 분산 트레이싱을 시각화하는 도구&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2295&quot; data-start=&quot;2256&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;1️⃣ Jaeger 컨테이너 실행 (Docker 사용)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742384979955&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run -d --name jaeger \
  -p 16686:16686 \
  -p 14268:14268 \
  jaegertracing/all-in-one:latest&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2459&quot; data-start=&quot;2408&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Jaeger UI는 http://localhost:16686에서 확인 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2523&quot; data-start=&quot;2461&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;2️⃣ OpenTelemetry를 활용한 트레이싱 적용 (TracingConfig.java)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742384987611&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.api.trace.TracerProvider;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
import io.opentelemetry.exporter.jaeger.JaegerGrpcSpanExporter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class TracingConfig {

    @Bean
    public Tracer tracer() {
        JaegerGrpcSpanExporter jaegerExporter = JaegerGrpcSpanExporter.builder()
                .setEndpoint(&quot;http://localhost:14268/api/traces&quot;)
                .build();

        SdkTracerProvider tracerProvider = SdkTracerProvider.builder()
                .addSpanProcessor(BatchSpanProcessor.builder(jaegerExporter).build())
                .build();

        OpenTelemetrySdk openTelemetrySdk = OpenTelemetrySdk.builder()
                .setTracerProvider(tracerProvider)
                .build();

        GlobalOpenTelemetry.set(openTelemetrySdk);
        return openTelemetrySdk.getTracer(&quot;my-app&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3754&quot; data-start=&quot;3718&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;트레이싱 데이터를 Jaeger로 전송하여 분석 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3809&quot; data-start=&quot;3756&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Jaeger를 활용하면 &quot;애플리케이션의 트랜잭션 흐름을 실시간으로 시각화 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;3814&quot; data-start=&quot;3811&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;3861&quot; data-start=&quot;3816&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. Prometheus &amp;amp; Grafana를 활용한 메트릭 수집&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;3972&quot; data-start=&quot;3862&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Prometheus는 OpenTelemetry와 연동하여 애플리케이션의 성능 메트릭을 수집하는 도구&lt;/b&gt;&lt;br /&gt;✔ &lt;b&gt;Grafana는 Prometheus 데이터를 시각화하는 대시보드 도구&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;4012&quot; data-start=&quot;3974&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;1️⃣ Prometheus 실행 (Docker 사용)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742384997113&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run -d --name=prometheus -p 9090:9090 \
  -v /path/to/prometheus.yml:/etc/prometheus/prometheus.yml \
  prom/prometheus&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4204&quot; data-start=&quot;4150&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Prometheus UI는 http://localhost:9090에서 확인 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;4251&quot; data-start=&quot;4206&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;2️⃣ Prometheus 설정 (prometheus.yml)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385004280&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'otel-metrics'
    static_configs:
      - targets: ['host.docker.internal:9464']&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4463&quot; data-start=&quot;4408&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;OpenTelemetry에서 수집한 메트릭 데이터를 Prometheus에서 분석 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;4540&quot; data-start=&quot;4465&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Prometheus &amp;amp; Grafana를 활용하면 &quot;Spring Boot 애플리케이션의 성능 모니터링을 실시간으로 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;4545&quot; data-start=&quot;4542&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;4596&quot; data-start=&quot;4547&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. OpenTelemetry 기반의 Observability 아키텍처&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;4678&quot; data-start=&quot;4597&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;OpenTelemetry는 트레이스, 메트릭, 로그를 모두 수집할 수 있는 통합된 관찰 가능성(Observability) 프레임워크&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;4726&quot; data-start=&quot;4680&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;Spring Boot + OpenTelemetry 모니터링 아키텍처&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742385009848&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;+---------------------+       +----------------------+
| Spring Boot App     | ----&amp;gt; | OpenTelemetry Agent |
+---------------------+       +----------------------+
       |                              |
       v                              v
+-----------------+       +-----------------+
| Prometheus     | ----&amp;gt; | Grafana         |
+-----------------+       +-----------------+
       |
       v
+-----------------+
| Jaeger         |
+-----------------+&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5262&quot; data-start=&quot;5193&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Prometheus &amp;amp; Grafana: 메트릭 수집 및 시각화&lt;/b&gt;&lt;br /&gt;✔ &lt;b&gt;Jaeger: 트랜잭션 흐름 분석&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;5323&quot; data-start=&quot;5264&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;OpenTelemetry를 활용하면 &quot;실시간 애플리케이션 성능 분석 및 문제 해결이 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;5328&quot; data-start=&quot;5325&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;5525&quot; data-start=&quot;5330&quot; data-ke-size=&quot;size16&quot;&gt;✅ 여기까지 Spring Boot에서 OpenTelemetry를 활용한 애플리케이션 모니터링 방법을 배웠습니다!&lt;br /&gt;  &lt;b&gt;&quot;그렇다면, Spring Boot에서 A/B 테스트와 Feature Toggle을 적용하려면?&quot;&lt;/b&gt;&lt;br /&gt;✅ 다음 회차에서 &lt;b&gt;Spring Boot에서 A/B 테스트와 Feature Toggle 적용 방법&lt;/b&gt;을 배워봅시다!&lt;/p&gt;
&lt;p data-end=&quot;5525&quot; data-start=&quot;5330&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;xyz&quot;&gt;&lt;!-- 티스토리 본문에 애드센스 광고를 삽입 합니다. --&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9977447109791049&quot;&gt;&lt;/script&gt;
&lt;!-- 336X280 Size mid 2 --&gt; &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-slot=&quot;8340259647&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-end=&quot;5867&quot; data-start=&quot;5724&quot; data-ke-size=&quot;size16&quot;&gt;
&lt;script&gt;document.getElementById('abc').appendChild(document.getElementById('xyz'));&lt;/script&gt;
&lt;/p&gt;</description>
      <category>IT Developer/Spring</category>
      <author>TEMA_</author>
      <guid isPermaLink="true">https://te-ma.tistory.com/337</guid>
      <comments>https://te-ma.tistory.com/337#entry337comment</comments>
      <pubDate>Thu, 17 Apr 2025 13:23:26 +0900</pubDate>
    </item>
    <item>
      <title>Spring 기초 &amp;lt;31. ElasticSearch + Spring Data를 활용한 검색 서비스 구축&amp;gt;</title>
      <link>https://te-ma.tistory.com/336</link>
      <description>&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p style=&quot;clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 18pt;&quot;&gt;스프링 Spring&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666666;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-size: 24px;&quot;&gt;31. ElasticSearch&amp;nbsp;+&amp;nbsp;Spring&amp;nbsp;Data를&amp;nbsp;활용한&amp;nbsp;검색&amp;nbsp;서비스&amp;nbsp;구축&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요! 태마입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;Spring&lt;/span&gt;&amp;nbsp;기초 강좌입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;강좌의 경우&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 주제 간단 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 상세 주제 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;으로 이루어져 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;스프링 Spring&lt;/span&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;9T7tobH9QpueIjclQy6EdlBbd-CXNprDfNLQIyq8u3rqv9dxYbI6efgHXsf5tAUqbO6EkpjDUJaKVnsdlOzGKQu5wWBsoPuOIl0k18Nx1z_Tzw6o_3sbYUo6Lvgl51DWkE6n7GGfU32K4G0bpZnHSA.svg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;78&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VaFUL/btsMPqLB7Np/FnvoRL7BqzqKX0rHXMwqEK/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VaFUL/btsMPqLB7Np/FnvoRL7BqzqKX0rHXMwqEK/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VaFUL/btsMPqLB7Np/FnvoRL7BqzqKX0rHXMwqEK/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVaFUL%2FbtsMPqLB7Np%2FFnvoRL7BqzqKX0rHXMwqEK%2Ftfile.dat&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;300&quot; height=&quot;78&quot; data-filename=&quot;9T7tobH9QpueIjclQy6EdlBbd-CXNprDfNLQIyq8u3rqv9dxYbI6efgHXsf5tAUqbO6EkpjDUJaKVnsdlOzGKQu5wWBsoPuOIl0k18Nx1z_Tzw6o_3sbYUo6Lvgl51DWkE6n7GGfU32K4G0bpZnHSA.svg&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;78&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;포스팅 시작하겠습니다 :)&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;xyz&quot;&gt;&lt;!-- 티스토리 본문에 애드센스 광고를 삽입 합니다. --&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9977447109791049&quot;&gt;&lt;/script&gt;
&lt;!-- 336X280 Size mid 1 --&gt; &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-slot=&quot;3927916504&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;
&lt;script&gt;document.getElementById('abc').appendChild(document.getElementById('xyz'));&lt;/script&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 주제 간단 정리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot; data-start=&quot;1567&quot; data-end=&quot;1717&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;272&quot; data-start=&quot;244&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. ElasticSearch란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;372&quot; data-start=&quot;273&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;ElasticSearch는 분산 검색 및 분석을 위한 오픈소스 검색 엔진&lt;/b&gt;&lt;br /&gt;✔ &lt;b&gt;JSON 기반의 RESTful API를 제공하며, 높은 성능과 확장성을 보장&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;403&quot; data-start=&quot;374&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;ElasticSearch의 주요 특징&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;특징설명
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;693&quot; data-start=&quot;405&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;693&quot; data-start=&quot;433&quot;&gt;
&lt;tr data-end=&quot;476&quot; data-start=&quot;433&quot;&gt;
&lt;td&gt;&lt;b&gt;빠른 검색 속도&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;인덱싱된 데이터를 기반으로 실시간 검색 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;527&quot; data-start=&quot;477&quot;&gt;
&lt;td&gt;&lt;b&gt;확장성(Scalability)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;클러스터를 구성하여 데이터 분산 처리 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;582&quot; data-start=&quot;528&quot;&gt;
&lt;td&gt;&lt;b&gt;RESTful API 제공&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;JSON 기반 API를 통해 손쉽게 데이터 검색 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;645&quot; data-start=&quot;583&quot;&gt;
&lt;td&gt;&lt;b&gt;분산 처리(Distributed Processing)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;노드를 추가하여 대용량 데이터 처리 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;693&quot; data-start=&quot;646&quot;&gt;
&lt;td&gt;&lt;b&gt;다양한 데이터 분석 지원&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Kibana와 연동하여 데이터 시각화 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;749&quot; data-start=&quot;695&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;ElasticSearch를 활용하면 &quot;대용량 데이터를 빠르게 검색하고 분석 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;754&quot; data-start=&quot;751&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;797&quot; data-start=&quot;756&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. ElasticSearch vs RDBMS 검색 비교&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;842&quot; data-start=&quot;798&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;일반적인 RDBMS와 ElasticSearch의 검색 방식은 다름&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;878&quot; data-start=&quot;844&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;RDBMS vs ElasticSearch 비교&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;비교 항목RDBMS (MySQL, PostgreSQL)ElasticSearch
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1210&quot; data-start=&quot;880&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;1210&quot; data-start=&quot;986&quot;&gt;
&lt;tr data-end=&quot;1041&quot; data-start=&quot;986&quot;&gt;
&lt;td&gt;&lt;b&gt;데이터 구조&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;테이블 기반 (정형 데이터)&lt;/td&gt;
&lt;td&gt;JSON 기반 (비정형 데이터 포함)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1105&quot; data-start=&quot;1042&quot;&gt;
&lt;td&gt;&lt;b&gt;검색 속도&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;인덱스 기반 검색 (느림)&lt;/td&gt;
&lt;td&gt;역색인(Inverted Index) 기반 검색 (빠름)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1156&quot; data-start=&quot;1106&quot;&gt;
&lt;td&gt;&lt;b&gt;확장성&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;수직적 확장(Scale-Up)&lt;/td&gt;
&lt;td&gt;수평적 확장(Scale-Out)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1210&quot; data-start=&quot;1157&quot;&gt;
&lt;td&gt;&lt;b&gt;복잡한 쿼리 지원&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;SQL 기반 복잡한 쿼리 가능&lt;/td&gt;
&lt;td&gt;강력한 풀텍스트 검색 지원&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1264&quot; data-start=&quot;1212&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;ElasticSearch는 &quot;정형 및 비정형 데이터를 빠르게 검색할 때 적합&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;1269&quot; data-start=&quot;1266&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;1436&quot; data-start=&quot;1271&quot; data-ke-size=&quot;size16&quot;&gt;✅ 여기까지 ElasticSearch의 개념과 RDBMS와의 차이를 배웠습니다!&lt;br /&gt;  &lt;b&gt;&quot;그렇다면, Spring Boot에서 ElasticSearch를 어떻게 연동할까?&quot;&lt;/b&gt;&lt;br /&gt;✅ 2부에서 &lt;b&gt;Spring Boot에서 ElasticSearch를 연동하고 활용하는 방법&lt;/b&gt;을 배워봅시다!&lt;/p&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 상세 주제 정리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none; line-height: 2;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;1534&quot; data-start=&quot;1502&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. ElasticSearch 환경 설정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1589&quot; data-start=&quot;1535&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Spring Boot에서 ElasticSearch를 사용하려면 의존성을 추가해야 함&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1626&quot; data-start=&quot;1591&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;1️⃣ build.gradle에 의존성 추가&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742384854457&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-elasticsearch'
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1806&quot; data-start=&quot;1743&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Spring Data ElasticSearch를 사용하여 쉽게 ElasticSearch와 연동 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1841&quot; data-start=&quot;1808&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;2️⃣ application.yml 설정&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742384859338&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  elasticsearch:
    uris: http://localhost:9200&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1950&quot; data-start=&quot;1911&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;ElasticSearch 서버와 연결하기 위한 기본 설정&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2020&quot; data-start=&quot;1952&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;ElasticSearch를 활용하면 &quot;Spring Boot 애플리케이션에서 강력한 검색 기능을 구현 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;2025&quot; data-start=&quot;2022&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;2073&quot; data-start=&quot;2027&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. ElasticSearch 엔티티 및 Repository 생성&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;2137&quot; data-start=&quot;2074&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Spring Data ElasticSearch를 사용하여 엔티티 및 Repository를 생성 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2184&quot; data-start=&quot;2139&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;1️⃣ 문서(Document) 정의 (Product.java)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742384866335&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;

@Document(indexName = &quot;products&quot;)
public class Product {

    @Id
    private String id;
    private String name;
    private String description;
    private double price;

    // 기본 생성자 및 Getter, Setter
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2571&quot; data-start=&quot;2519&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;@Document 어노테이션을 사용하여 ElasticSearch 인덱스 매핑&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2626&quot; data-start=&quot;2573&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;2️⃣ Repository 생성 (ProductRepository.java)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742384872513&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import java.util.List;

public interface ProductRepository extends ElasticsearchRepository&amp;lt;Product, String&amp;gt; {
    List&amp;lt;Product&amp;gt; findByName(String name);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2931&quot; data-start=&quot;2876&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;ElasticsearchRepository를 확장하여 기본적인 CRUD 기능 제공&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2988&quot; data-start=&quot;2933&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;ElasticSearch를 활용하면 &quot;간단한 코드로 강력한 검색 기능을 제공 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;2993&quot; data-start=&quot;2990&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;3030&quot; data-start=&quot;2995&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. ElasticSearch 검색 기능 구현&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;3088&quot; data-start=&quot;3031&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;Spring Boot에서 ElasticSearch를 활용하여 다양한 검색 기능 구현 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3135&quot; data-start=&quot;3090&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;1️⃣ 검색 기능 구현 (ProductService.java)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742384878578&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class ProductService {

    private final ProductRepository productRepository;

    public ProductService(ProductRepository productRepository) {
        this.productRepository = productRepository;
    }

    public List&amp;lt;Product&amp;gt; searchByName(String name) {
        return productRepository.findByName(name);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3603&quot; data-start=&quot;3551&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;findByName()을 활용하여 특정 키워드를 포함하는 데이터를 검색 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3654&quot; data-start=&quot;3605&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;2️⃣ 검색 API 구현 (ProductController.java)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742384884168&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping(&quot;/products&quot;)
public class ProductController {

    private final ProductService productService;

    public ProductController(ProductService productService) {
        this.productService = productService;
    }

    @GetMapping(&quot;/search&quot;)
    public List&amp;lt;Product&amp;gt; search(@RequestParam String name) {
        return productService.searchByName(name);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4179&quot; data-start=&quot;4132&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;REST API를 통해 ElasticSearch에서 데이터를 검색 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;4236&quot; data-start=&quot;4181&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;ElasticSearch를 활용하면 &quot;빠르고 효율적인 검색 기능을 쉽게 구현 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;4241&quot; data-start=&quot;4238&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;4284&quot; data-start=&quot;4243&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. ElasticSearch에서 복잡한 검색 기능 적용&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;4324&quot; data-start=&quot;4285&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;다양한 검색 조건을 적용하여 보다 정교한 검색 구현 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;4393&quot; data-start=&quot;4326&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;ElasticSearch의 QueryDSL을 활용한 검색 (ProductRepository.java)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1742384890296&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Repository;
import java.util.List;

import static org.elasticsearch.index.query.QueryBuilders.matchQuery;

@Repository
public class ProductCustomRepository {

    private final ElasticsearchOperations elasticsearchOperations;

    public ProductCustomRepository(ElasticsearchOperations elasticsearchOperations) {
        this.elasticsearchOperations = elasticsearchOperations;
    }

    public List&amp;lt;Product&amp;gt; searchByDescription(String keyword) {
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(matchQuery(&quot;description&quot;, keyword))
                .build();
        
        return elasticsearchOperations.search(searchQuery, Product.class)
                .stream()
                .map(hit -&amp;gt; hit.getContent())
                .toList();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5531&quot; data-start=&quot;5476&quot; data-ke-size=&quot;size16&quot;&gt;✔ &lt;b&gt;QueryDSL을 사용하여 특정 필드(description)에서 키워드 검색 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;5592&quot; data-start=&quot;5533&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;ElasticSearch를 활용하면 &quot;자연어 처리 기반 검색 및 복잡한 조건 검색이 가능&quot;&lt;/b&gt;&lt;/p&gt;
&lt;hr data-end=&quot;5597&quot; data-start=&quot;5594&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-end=&quot;5804&quot; data-start=&quot;5599&quot; data-ke-size=&quot;size16&quot;&gt;✅ 여기까지 Spring Boot에서 ElasticSearch를 활용한 검색 서비스 구축 방법을 배웠습니다!&lt;br /&gt;  &lt;b&gt;&quot;그렇다면, Spring Boot에서 OpenTelemetry를 활용한 애플리케이션 모니터링은 어떻게 할까?&quot;&lt;/b&gt;&lt;br /&gt;✅ 다음 회차에서 &lt;b&gt;Spring Boot에서 OpenTelemetry를 활용한 애플리케이션 모니터링 기법&lt;/b&gt;을 배워봅시다!&lt;/p&gt;
&lt;p data-end=&quot;5804&quot; data-start=&quot;5599&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;xyz&quot;&gt;&lt;!-- 티스토리 본문에 애드센스 광고를 삽입 합니다. --&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9977447109791049&quot;&gt;&lt;/script&gt;
&lt;!-- 336X280 Size mid 2 --&gt; &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-9977447109791049&quot; data-ad-slot=&quot;8340259647&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-end=&quot;5867&quot; data-start=&quot;5724&quot; data-ke-size=&quot;size16&quot;&gt;
&lt;script&gt;document.getElementById('abc').appendChild(document.getElementById('xyz'));&lt;/script&gt;
&lt;/p&gt;</description>
      <category>IT Developer/Spring</category>
      <author>TEMA_</author>
      <guid isPermaLink="true">https://te-ma.tistory.com/336</guid>
      <comments>https://te-ma.tistory.com/336#entry336comment</comments>
      <pubDate>Wed, 16 Apr 2025 13:35:14 +0900</pubDate>
    </item>
  </channel>
</rss>