<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Cloud-DevLog</title>
    <link>https://cloud-grace.tistory.com/</link>
    <description>안녕하세요 :)</description>
    <language>ko</language>
    <pubDate>Wed, 15 Apr 2026 02:46:10 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>cloud-grace</managingEditor>
    <image>
      <title>Cloud-DevLog</title>
      <url>https://tistory1.daumcdn.net/tistory/7014398/attach/40c93e2f34a9416a954b3db2d87edd6d</url>
      <link>https://cloud-grace.tistory.com</link>
    </image>
    <item>
      <title>포스코DX 청년IT전문가 아카데미 8기 합격 후기(서류, 면접, 교육 생활)</title>
      <link>https://cloud-grace.tistory.com/entry/%ED%8F%AC%EC%8A%A4%EC%BD%94DX-%EC%B2%AD%EB%85%84IT%EC%A0%84%EB%AC%B8%EA%B0%80-%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8-8%EA%B8%B0%EC%B1%84%EC%9A%A9%EC%97%B0%EA%B3%84%ED%98%95-IT%EA%B5%90%EC%9C%A1%EC%83%9D-%EC%84%9C%EB%A5%98-%EB%A9%B4%EC%A0%91-%EA%B5%90%EC%9C%A1-%EC%83%9D%ED%99%9C-%ED%9B%84%EA%B8%B0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요 저는 포스코DX 채용연계형 IT교육생 전형인, 청년IT전문가 아카데미 8기 교육생으로서 교육 생활을 보내고 있습니다. 최근 9기 모집 공고가 뜬 것 같은데, 이 전형에 대한 후기나 정보가 많이 없는 듯하여 조금이나마 도움을 드리고자 글을 작성하게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;HR_AFTC_MRG_ADOP_NTIC_SUJX&quot; style=&quot;background-color: #ffffff; color: #222222; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2024년 하반기 포스코DX 신입사원 채용공고(청년IT전문가 아카데미 9기, 채용연계형 IT교육생)&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1725689913258&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;https://recruit.posco.com/h22a01-front/H22A1001.html?id=339000&quot; data-og-description=&quot;&quot; data-og-host=&quot;recruit.posco.com&quot; data-og-source-url=&quot;https://recruit.posco.com/h22a01-front/H22A1001.html?id=339000&quot; data-og-url=&quot;https://recruit.posco.com/h22a01-front/H22A1001.html?id=339000&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://recruit.posco.com/h22a01-front/H22A1001.html?id=339000&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://recruit.posco.com/h22a01-front/H22A1001.html?id=339000&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;https://recruit.posco.com/h22a01-front/H22A1001.html?id=339000&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;recruit.posco.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;8기 전형 관련 후기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 서류/면접 합격 발표날짜는 아래와 같았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;서류 모집&lt;/b&gt; ~3.11&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;서류 합격 발표&lt;/b&gt; 3.19&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;인성 검사&lt;/b&gt; 3.19~3.20&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1차 실무면접/코딩테스트&lt;/b&gt; 3.27&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1차 실무면접 결과&lt;/b&gt; 4.2&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;건강검진&lt;/b&gt; 4.6&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2차 임원면접&lt;/b&gt; 4.9&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;최종 합격 발표&lt;/b&gt; 4.17&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;교육 입과&lt;/b&gt; 4.22~&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*올해는 코딩테스트와 인성검사를 같이 실시하는 것 같습니다. 참고 부탁드립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1차 실무면접&lt;/b&gt;은 교육을 받는 비트교육센터에서 진행되었습니다. 코딩테스트 진행 이후, 1차 면접이 이어졌는데요. 1:多 형식으로 여러 면접자들과 함께 면접을 보는 방식이었고, 자신의 프로젝트 경험과 강점에 대해 간략하게 말씀드리는 형식이었습니다. 많은 사람들 앞에서 내 이력에 대해 말하는 게 다소 어려울 수도 있으나, 최대한 간략하고 자신의 강점을 잘 정리해서 깔끔하게 말씀드리면 좋을 것 같습니다. 저도 타 지원자에 비해 다소 경험이 부족하다고 생각했으나, 자신감있게 말하려고 노력하였고 좋게 봐주신 게 아닐까 싶습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1차 실무면접 합격자를 대상으로 건강검진을 실시하였고, 검진 이후 2차 임원면접이 진행됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2차 임원면접&lt;/b&gt;은 포스코DX 본사인 판교에서 진행하였습니다. 앞 면접 조가 마무리되기 전까지 대기하는 공간에서 인사팀 직원분께서 편한 분위기를 만들어주시고, 회사에 관해 궁금한 점 등에 대해 말씀해 주셨던 기억이 있습니다. 면접관과 면접자는 多:多로, 기술 스택 관련, 인성 관련, 개발 외의 경험관련 질문 등 다양하게 여쭤보셨던 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cyOEr5/btsJusMw5Uy/QlRLqhQQTfeIOhikJ16Jf0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cyOEr5/btsJusMw5Uy/QlRLqhQQTfeIOhikJ16Jf0/img.jpg&quot; data-origin-width=&quot;2268&quot; data-origin-height=&quot;4032&quot; data-is-animation=&quot;false&quot; data-filename=&quot;IMG_1939.jpeg&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cyOEr5/btsJusMw5Uy/QlRLqhQQTfeIOhikJ16Jf0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcyOEr5%2FbtsJusMw5Uy%2FQlRLqhQQTfeIOhikJ16Jf0%2Fimg.jpg&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;2268&quot; height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7LjAk/btsJvlyQc2L/kHHwagCMhLVXF63inlDco1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7LjAk/btsJvlyQc2L/kHHwagCMhLVXF63inlDco1/img.jpg&quot; data-origin-width=&quot;3213&quot; data-origin-height=&quot;5712&quot; data-is-animation=&quot;false&quot; data-filename=&quot;IMG_1950.jpeg&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7LjAk/btsJvlyQc2L/kHHwagCMhLVXF63inlDco1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7LjAk%2FbtsJvlyQc2L%2FkHHwagCMhLVXF63inlDco1%2Fimg.jpg&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;3213&quot; height=&quot;5712&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c7yHj4/btsJurGOvHa/FjpdJG7JiyzZYs1KjjxVXK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c7yHj4/btsJurGOvHa/FjpdJG7JiyzZYs1KjjxVXK/img.jpg&quot; data-origin-width=&quot;3213&quot; data-origin-height=&quot;5712&quot; data-is-animation=&quot;false&quot; data-filename=&quot;IMG_1942.jpeg&quot; data-widthpercent=&quot;33.34&quot; style=&quot;width: 32.5581%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c7yHj4/btsJurGOvHa/FjpdJG7JiyzZYs1KjjxVXK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc7yHj4%2FbtsJurGOvHa%2FFjpdJG7JiyzZYs1KjjxVXK%2Fimg.jpg&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;3213&quot; height=&quot;5712&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;임원면접 가는 도중 벚꽃길로 예뻤던 기억이 있습니다..ㅎㅎ&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;교육 생활 후기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;4월 22일에 입과한 이후, 현재까지 교육을 듣고 있습니다. 저희는 10월 18일이 마지막 수료일 입니다. 강사님도 좋으시고 동기분들과도 친해지고 다들 너무 좋으신 분들이라 매우 만족하면서 교육을 듣고 있습니다. 동기들이 같은 회사 입사 동기로 이어지니 정말 좋은 것 같습니다. 3개월 이론 교육 이후, 3개월 현업 프로젝트를 진행하는데요. 현재 저희는 이론 교육이 끝나고 현업 프로젝트를 진행 중입니다. 프로젝트는 포스코DX 직원분들이 멘토가 되어 한 팀씩 맡아주십니다. 입사 전, 포스코DX의 도메인에 대해 미리 공부할 수 있는 기회가 주어져서 좋다고 생각합니다. 또한, 저는 프론트엔드 위주로 경험이 많았던 터라 백엔드 파트 공부를 깊게 해보고 싶었습니다. 기초부터 여러 스택과 인프라 교육까지, 풀스택으로 교육을 받기에 이점이 가장 마음에 들었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;6개월간 성실히 교육받고 수료하시면 입사하는 데에는 큰 무리가 없는 것 같습니다. 워낙 회사도 안정적인 곳으로 유명하기도 하고, 6개월간 동기들과 동고동락하고 즐겁게 교육받은 후에 입사할 수 있어 정말 좋다고 생각합니다. 입사하신 선배 기수 분들의 이야기를 들어보면 워라밸도 좋은 것 같고 만족하시면서 다니는 것 같았습니다 :)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시 궁금하신 점이 있으시면 언제든 댓글 달아주세요!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사합니다.&lt;/p&gt;</description>
      <category>취준</category>
      <category>청년it전문가 아카데미 8기</category>
      <category>포스코</category>
      <category>포스코DX</category>
      <category>포스코dx 채용연계형 it교육생</category>
      <category>포스코디엑스</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/37</guid>
      <comments>https://cloud-grace.tistory.com/entry/%ED%8F%AC%EC%8A%A4%EC%BD%94DX-%EC%B2%AD%EB%85%84IT%EC%A0%84%EB%AC%B8%EA%B0%80-%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8-8%EA%B8%B0%EC%B1%84%EC%9A%A9%EC%97%B0%EA%B3%84%ED%98%95-IT%EA%B5%90%EC%9C%A1%EC%83%9D-%EC%84%9C%EB%A5%98-%EB%A9%B4%EC%A0%91-%EA%B5%90%EC%9C%A1-%EC%83%9D%ED%99%9C-%ED%9B%84%EA%B8%B0#entry37comment</comments>
      <pubDate>Sat, 7 Sep 2024 16:46:06 +0900</pubDate>
    </item>
    <item>
      <title>[Spring Boot] application.properties VS application.yml</title>
      <link>https://cloud-grace.tistory.com/entry/Spring-Boot-applicationproperties-VS-applicationyml</link>
      <description>&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;310&quot; data-origin-height=&quot;163&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2idyM/btsIrvPHh9a/6wzSxKXuqhAnRAkVW3ApZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2idyM/btsIrvPHh9a/6wzSxKXuqhAnRAkVW3ApZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2idyM/btsIrvPHh9a/6wzSxKXuqhAnRAkVW3ApZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2idyM%2FbtsIrvPHh9a%2F6wzSxKXuqhAnRAkVW3ApZ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;310&quot; height=&quot;163&quot; data-origin-width=&quot;310&quot; data-origin-height=&quot;163&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;Spring Boot는 프로젝트 설정을 application.properties 또는 application.yml 파일로 하게 된다. Spring Initializer로 프로젝트를 만들면 자동으로 application.properties가 생성되지만, application.yml로 설정을 많이 한다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;application.properties와 application.yml 파일의 차이점&lt;/b&gt;&lt;/h3&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;application.properties&lt;/b&gt;&lt;/h4&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;key = value 형태로 모든 줄이 구성되어 있다.&lt;/li&gt;&lt;li&gt;단순하고 직관적이며, 키와 값을 한 줄에 정의한다.&lt;/li&gt;&lt;li&gt;중첩 구조를 표현하기 어렵다.&lt;/li&gt;&lt;/ul&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;# spring configuration
spring.application.name=example

# devtools - live reload
spring.devtools.livereload.enabled=true

# aop
spring.aop.auto=true
spring.aop.proxy-target-class=true

# mvc
spring.mvc.static-path-pattern=/assets/**
spring.mvc.throw-exception-if-no-handler-found=true

# thymeleaf
spring.thymeleaf.check-template-location=true
spring.thymeleaf.mode=HTML
spring.thymeleaf.prefix=classpath:templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.cache=false

# web
spring.web.resources.static-locations=file:/Users/user1234/example-uploads/,classpath:assets/

# message resources (i18n)
spring.messages.basename=messages/message
spring.messages.encoding=utf-8
spring.messages.always-use-message-format=true

# multipart
spring.servlet.multipart.enabled=true
spring.servlet.multipart.max-file-size=50MB
spring.servlet.multipart.max-request-size=10MB

# datasource
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.datasource.url=jdbc:mariadb://192.168.00.0:3306/example?charset=utf8
spring.datasource.username=user1234
spring.datasource.password=1234
spring.datasource.hikari.minimum-idle=10
spring.datasource.hikari.maximum-pool-size=20

# jpa
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MariaDBDialect

# server configuration
server.port=8080
server.servlet.context-path=/example
server.servlet.encoding.charset=utf-8
server.servlet.encoding.enabled=true
server.error.whitelabel.enabled=false
server.error.path=/error

# logging
logging.level.root=INFO
logging.level.com.example.myapp=DEBUG
logging.file.name=logs/myapp.log
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} - %msg%n
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss} - %msg%n&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;application.yml&lt;/b&gt;&lt;/h4&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;들여쓰기로 구분하여 계층 구조로 되어 있으며, key: value 형태로 구성되어 있다.&lt;/li&gt;&lt;li&gt;YAML 형식을 사용하여 설정을 정의한다.&lt;/li&gt;&lt;li&gt;중첩 구조를 간단히 표현하여 가독성이 좋다.&lt;/li&gt;&lt;/ul&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;Unknown&quot; data-ke-language=&quot;Unknown&quot;&gt;&lt;code&gt;# spring configuration
spring:
&amp;nbsp;&amp;nbsp;application:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name: example

&amp;nbsp;&amp;nbsp;# devtools - live reload
&amp;nbsp;&amp;nbsp;devtools:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;livereload:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;enabled: true

&amp;nbsp;&amp;nbsp;# aop
&amp;nbsp;&amp;nbsp;aop:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;auto: true
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;proxy-target-class: true

&amp;nbsp;&amp;nbsp;# mvc
&amp;nbsp;&amp;nbsp;mvc:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static-path-pattern: /assets/**
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;throw-exception-if-no-handler-found: true

&amp;nbsp;&amp;nbsp;# thymeleaf
&amp;nbsp;&amp;nbsp;thymeleaf:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;check-template-location: true
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mode: HTML
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;prefix: classpath:templates/
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;suffix: .html
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;encoding: UTF-8
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cache: false

&amp;nbsp;&amp;nbsp;# web
&amp;nbsp;&amp;nbsp;web:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;resources:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static-locations: file:/Users/user1234/example-uploads/, classpath:assets/

&amp;nbsp;&amp;nbsp;# message resources (i18n)
&amp;nbsp;&amp;nbsp;messages:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;basename: messages/message
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;encoding: utf-8
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;always-use-message-format: true

&amp;nbsp;&amp;nbsp;# multipart
&amp;nbsp;&amp;nbsp;servlet:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;multipart:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;enabled: true
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;max-file-size: 50MB
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;max-request-size: 10MB

&amp;nbsp;&amp;nbsp;# datasource
&amp;nbsp;&amp;nbsp;datasource:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;driver-class-name: org.mariadb.jdbc.Driver
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;url: jdbc:mariadb://192.168.00.0:3306/example?charset=utf8
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;username: user1234
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;password: 1234
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;hikari:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;minimum-idle: 10
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;maximum-pool-size: 20

&amp;nbsp;&amp;nbsp;# jpa
&amp;nbsp;&amp;nbsp;jpa:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;hibernate:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ddl-auto: update
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;show-sql: true
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;properties:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;hibernate.dialect: org.hibernate.dialect.MariaDBDialect

# server configuration
server:
&amp;nbsp;&amp;nbsp;port: 8080
&amp;nbsp;&amp;nbsp;servlet:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;context-path: /example
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;encoding:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;charset: utf-8
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;enabled: true
&amp;nbsp;&amp;nbsp;error:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;whitelabel:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;enabled: false
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;path: /error

# logging
logging:
&amp;nbsp;&amp;nbsp;level:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;root: INFO
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;com.example.myapp: DEBUG
&amp;nbsp;&amp;nbsp;file:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name: logs/myapp.log
&amp;nbsp;&amp;nbsp;pattern:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;console: &quot;%d{yyyy-MM-dd HH:mm:ss} - %msg%n&quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;file: &quot;%d{yyyy-MM-dd HH:mm:ss} - %msg%n&quot;&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;정리&lt;/b&gt;&lt;/h3&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;어떤 것을 사용하더라도 문제는 없다. 자신이 편한 것을 사용하면 된다.&lt;/li&gt;&lt;li&gt;만약, 같은 설정을 두 파일에 동시에 사용한다면 Spring Boot는 두 파일 모두 사용이 가능하다.&lt;/li&gt;&lt;li&gt;동일한 설정이 포함된 경우, application.properties가 우선적으로 적용된다.&lt;/li&gt;&lt;li&gt;하지만, 동시에 사용하는 것은 권장되지 않으며, 구조 파악에 용이한 yml 파일로 사용하는 것이 추천된다.&lt;/li&gt;&lt;/ul&gt;</description>
      <category>Spring</category>
      <category>application.properties</category>
      <category>application.yml</category>
      <category>spring boot</category>
      <category>스프링부트</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/36</guid>
      <comments>https://cloud-grace.tistory.com/entry/Spring-Boot-applicationproperties-VS-applicationyml#entry36comment</comments>
      <pubDate>Sat, 6 Jul 2024 20:10:45 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] Maven VS Gradle</title>
      <link>https://cloud-grace.tistory.com/entry/Spring-Maven-VS-Gradle</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;자바 프로젝트에서 널리 사용되는 빌드 자동화 도구인 Maven과 Gradle에 대해 알아보고 차이점에 대해 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. Maven&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;321&quot; data-origin-height=&quot;157&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6AyRX/btsIpTdc7SQ/4ZszTAQrONCDWYOA7zBo3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6AyRX/btsIpTdc7SQ/4ZszTAQrONCDWYOA7zBo3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6AyRX/btsIpTdc7SQ/4ZszTAQrONCDWYOA7zBo3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6AyRX%2FbtsIpTdc7SQ%2F4ZszTAQrONCDWYOA7zBo3K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;321&quot; height=&quot;157&quot; data-origin-width=&quot;321&quot; data-origin-height=&quot;157&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;과거에는 Apache Ant라는 빌드 도구를 많이 사용하였지만, Ant의 대안으로 출시된 현재는 Maven을 많이 사용한다.&lt;/li&gt;
&lt;li&gt;XML 기반의 pom.xml을 사용하여 프로젝트 설정을 정의한다.&lt;/li&gt;
&lt;li&gt;XML 이라서 정형화된 구조를 보이지만, 설정이 길어지면 가독성이 떨어질 수 있다.&lt;/li&gt;
&lt;li&gt;Apache 라이센스로 배포되는 오픈 소스 소프트웨어이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;POM(Project Object Model)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 pom.xml에 포함된 기능이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로젝트 이름, 라이센스 등의 프로젝트 정보&lt;/li&gt;
&lt;li&gt;소스, 리소스, 라이프사이클 마다 실행한 플러그인 등의 빌드 설정&lt;/li&gt;
&lt;li&gt;환경마다 달라질 수 있는 프로파일 정보가 담긴 빌드 환경&lt;/li&gt;
&lt;li&gt;의존 프로젝트(모듈), 상위 프로젝트, 포함하는 하위 모듈 등의 pom 연관 정보&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. Gradle&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;380&quot; data-origin-height=&quot;132&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dL9fbQ/btsIpsArLEO/dNi6VE0fDCEKrc3nJ7HjGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dL9fbQ/btsIpsArLEO/dNi6VE0fDCEKrc3nJ7HjGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dL9fbQ/btsIpsArLEO/dNi6VE0fDCEKrc3nJ7HjGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdL9fbQ%2FbtsIpsArLEO%2FdNi6VE0fDCEKrc3nJ7HjGK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;380&quot; height=&quot;132&quot; data-origin-width=&quot;380&quot; data-origin-height=&quot;132&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Gradle은 Ant와 Maven의 장점을 모아 개발하여 2012년에 출시된 Groovy를 이용한 빌드 자동화 도구이다.&lt;/li&gt;
&lt;li&gt;안드로이드 앱의 공식 빌드 시스템이다.&lt;/li&gt;
&lt;li&gt;Maven에 비해 빌드 속도가 10~100배나 빠르다.&lt;/li&gt;
&lt;li&gt;Java, C, C++, Python 등 여러 언어를 지원한다.&lt;/li&gt;
&lt;li&gt;별도 빌드 스크립트를 통해 애플리케이션 버전, 라이브러리 등 항목 설정이 가능하다.&lt;/li&gt;
&lt;li&gt;빌드 툴(Ant Builder, Groovy) 기반으로 만들어져 기존 Ant 역할과 배포 스크립트 기능을 모두 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;스크립트 언어로 작성하기 때문에 변수 선언, if, for 등의 코드 로직 구현이 가능하여 가독성이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1720260867232&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Groovy는 Java 가상 머신에서 실행되는 스크립트 언어이다.
Java 가상 머신에서 동작하지만 소스 코드 컴파일은 필요 없다.
스크립트 언어이므로 소스 코드 그대로 실행한다.
Java와 호환되며 Java Class 파일을 그대로 Groovy Class로 사용할 수 있다.
Java 문법과 유사하므로 Gradle은 Java 개발자가 사용하기에 적합하다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Maven VS Gradle&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Ant와 Maven의 장점을 기반으로 만들어진 Gradle이 등장한 이후로 Gradle을 많이 쓰는 추세라고 한다.&lt;/li&gt;
&lt;li&gt;설정 내용이 길어지면 가독성이 떨어지고, 의존 관계가 복잡한 프로젝트는 XML로 정의하기에 어려울 수 있다.&lt;/li&gt;
&lt;li&gt;Groovy를 사용하는 Gradle은 동적 Build를 Groovy 스크립트로 플러그인을 호출하고 코드를 직접 작성할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[Maven] Spring Boot 프로젝트 구조&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1720261198287&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;my-spring-boot-app
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── example
│   │   │           └── demo
│   │   │               └── DemoApplication.java
│   │   └── resources
│   │       └── application.yml
├── pom.xml
└── .gitignore&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[Gradle] Spring Boot 프로젝트 구조&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1720261237706&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;my-spring-boot-app
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── example
│   │   │           └── demo
│   │   │               └── DemoApplication.java
│   │   └── resources
│   │       └── application.yml
├── build.gradle
└── .gitignore&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[Maven] Spring Boot pom.xml&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1720261361448&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot;
         xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
         xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&amp;gt;
    &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;
    &amp;lt;groupId&amp;gt;com.example&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;demo&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;0.0.1-SNAPSHOT&amp;lt;/version&amp;gt;
    &amp;lt;packaging&amp;gt;jar&amp;lt;/packaging&amp;gt;

    &amp;lt;name&amp;gt;demo&amp;lt;/name&amp;gt;
    &amp;lt;description&amp;gt;Demo project for Spring Boot&amp;lt;/description&amp;gt;

    &amp;lt;parent&amp;gt;
        &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;spring-boot-starter-parent&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;3.3.1&amp;lt;/version&amp;gt;
        &amp;lt;relativePath/&amp;gt;
    &amp;lt;/parent&amp;gt;

    &amp;lt;properties&amp;gt;
        &amp;lt;java.version&amp;gt;17&amp;lt;/java.version&amp;gt;
    &amp;lt;/properties&amp;gt;

    &amp;lt;dependencies&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-boot-starter-web&amp;lt;/artifactId&amp;gt;
        &amp;lt;/dependency&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-boot-starter-test&amp;lt;/artifactId&amp;gt;
            &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
        &amp;lt;/dependency&amp;gt;
    &amp;lt;/dependencies&amp;gt;

    &amp;lt;build&amp;gt;
        &amp;lt;plugins&amp;gt;
            &amp;lt;plugin&amp;gt;
                &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
                &amp;lt;artifactId&amp;gt;spring-boot-maven-plugin&amp;lt;/artifactId&amp;gt;
            &amp;lt;/plugin&amp;gt;
        &amp;lt;/plugins&amp;gt;
    &amp;lt;/build&amp;gt;
&amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[Gradle] Spring Boot bundle.gradle&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1720261433095&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;plugins {
    id 'org.springframework.boot' version '3.3.1'
    id 'io.spring.dependency-management' version '1.1.5'
    id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

test {
    useJUnitPlatform()
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;정리&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;코드 길이와 가독성은 gradle이 더 좋다.&lt;/li&gt;
&lt;li&gt;빌드 및 테스트 실행 속도는 gradle이 더 빠르다.&lt;/li&gt;
&lt;li&gt;Maven은 정형화된 구조로 학습하기에 보다 좋을 수 있다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Spring</category>
      <category>build</category>
      <category>bundle.gradle</category>
      <category>gradle</category>
      <category>Maven</category>
      <category>pom.xml</category>
      <category>그래들</category>
      <category>메이븐</category>
      <category>빌드</category>
      <category>빌드 관리 도구</category>
      <category>빌드 자동화 도구</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/35</guid>
      <comments>https://cloud-grace.tistory.com/entry/Spring-Maven-VS-Gradle#entry35comment</comments>
      <pubDate>Sat, 6 Jul 2024 19:31:18 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] JAR VS WAR</title>
      <link>https://cloud-grace.tistory.com/entry/Spring-JAR-VS-WAR</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;JAR? WAR?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JAR과 WAR은 모두 Java의 jar 옵션을 이용하여 생성된 압축(아카이브)한 파일로 애플리케이션을 쉽게 배포하고 동작시킬 수 있게 파일들을 패키징한 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;JAR(Java ARchive)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;JAR은 패키지 파일 형식으로 .jar 확장자를 가진다.&lt;/li&gt;
&lt;li&gt;Java 애플리케이션이 동작하도록 Java 프로젝트를 압축한 파일이다.&lt;/li&gt;
&lt;li&gt;Class (Java 리소스, 속성 파일), 라이브러리 등을 포함한다.&lt;/li&gt;
&lt;li&gt;JRE(Java Runtime Environment)만 있어도 실행 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1720259094322&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;java -jar 프로젝트명.jar&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;WAR(Web Application ARchive)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;WAR은 웹 애플리케이션 아카이브 or 웹 애플리케이션 리소스를 나타내며, .war 확장자를 가진다.&lt;/li&gt;
&lt;li&gt;모든 Servlet/JSP 컨테이너에 배포할 수 있는 웹 애플리케이션을 패키징하는 데에 사용되는 압축파일 포맷이다.&lt;/li&gt;
&lt;li&gt;웹 관련 자원(JSP, Servlet, JAR, Class, XML, HTML, JavaScript)을 포함한다.&lt;/li&gt;
&lt;li&gt;사전 정의된 구조(WEB-INF, META-INF)를 사용한다.&lt;/li&gt;
&lt;li&gt;별도 웹 컨테이너(WAS)가 필요하다. (ex. Apache Tomcat, Jetty 등)&lt;/li&gt;
&lt;li&gt;JAR 파일의 일종으로 웹 애플리케이션 전체를 패키징한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;정리&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;파일 확장자 차이 : .jar VS .war&lt;/li&gt;
&lt;li&gt;아카이브 구조 차이 : JAR은 원하는 구조로 구성 가능하지만, WAR는 WEB-INF, META-INF 등 미리 정의된 구조가 있다.&lt;/li&gt;
&lt;li&gt;실행 차이 : JAR은 별도의 웹 컨테이너나 서버 없이도 단순 명령어로 실행이 가능하지만, WAR는 필요하다.&lt;/li&gt;
&lt;li&gt;JAR 파일을 사용하면 여러 파일을 패키징하여 라이브러리, 플러그인, 모든 종류의 애플리케이션으로 사용 가능하며, Spring Boot에서 많이 활용된다.&lt;/li&gt;
&lt;li&gt;WAR 파일은 웹 애플리케이션에서만 사용된다.&lt;/li&gt;
&lt;li&gt;JAR 파일은 JSP나 서블릿 컨테이너에 대한 표준 기능을 활용하기 어렵다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Spring</category>
      <category>jar</category>
      <category>spring</category>
      <category>spring boot</category>
      <category>War</category>
      <category>web</category>
      <category>배포</category>
      <category>스프링</category>
      <category>스프링 부트</category>
      <category>웹</category>
      <category>웹 애플리케이션</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/34</guid>
      <comments>https://cloud-grace.tistory.com/entry/Spring-JAR-VS-WAR#entry34comment</comments>
      <pubDate>Sat, 6 Jul 2024 18:43:46 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] Spring VS Spring Boot</title>
      <link>https://cloud-grace.tistory.com/entry/Spring-Spring-VS-Spring-Boot</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Spring VS Spring Boot&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring과 Spring Boot는 Java 애플리케이션 개발을 위해 널리 사용되는 오픈 소스 프레임워크이다. 둘 다 개발을 위한 강력한 기능을 제공하지만 용도와 접근 방식에서 차이가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Spring Framework(Spring)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring은 엔터프라이즈급 애플리케이션을 개발하기 위한 종합적인 프레임워크이다. 애플리케이션의 다양한 계층(Web, Data Access, Business Logic 등)를 쉽게 관리하고 통합할 수 있게 해준다. Spring의 주요 모듈로는 Spring Core, Spring MVC, Spring Data, Spring Security 등이 있다. 여러 설정 파일과 어노테이션을 통해 애플리케이션 동작을 세밀히 조정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Spring Framework 주요 특징&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IoC(Inversion of Control) - 객체의 생성, 의존 관계 설정 등을 프레임워크가 대신 해주며 개발자 대신 제어권을 가진다.&lt;/li&gt;
&lt;li&gt;DI(Dependency Injection) - 의존성 주입을 통해 객체 간 결합을 느슨하게 한다.&lt;/li&gt;
&lt;li&gt;AOP(Aspect Oriented Programming) - 핵심 기능을 제외하고 반복되는 logging, security 등의 부수 기능들을 추가한다.&lt;/li&gt;
&lt;li&gt;중복된 코드를 줄여준다.&lt;/li&gt;
&lt;li&gt;JUnit과 같은 단위 테스트 프레임워크와 통합이 쉽다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Spring의 특징에 대한 글은 아래 포스팅을 통해 작성하였다.&lt;/p&gt;
&lt;figure id=&quot;og_1720251423535&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Spring] 스프링의 삼각형(IoC/DI, AOP, PSA)&quot; data-og-description=&quot;스프링의 삼각형, 3대 요소(Spring Triangle)스프링의 삼각형(Spring Triangle), 즉, 스프링의 핵심 3요소가 있다.&amp;nbsp;1. IoC/DIIoC란 제어의 역전으로 스프링 컨테이너가 객체에 대한 제어권을 가지고 있는 것이&quot; data-og-host=&quot;cloud-grace.tistory.com&quot; data-og-source-url=&quot;https://cloud-grace.tistory.com/entry/Spring-%EC%8A%A4%ED%94%84%EB%A7%81%EC%9D%98-%EC%82%BC%EA%B0%81%ED%98%95-IoCDI-AOP-PSA&quot; data-og-url=&quot;https://cloud-grace.tistory.com/entry/Spring-%EC%8A%A4%ED%94%84%EB%A7%81%EC%9D%98-%EC%82%BC%EA%B0%81%ED%98%95-IoCDI-AOP-PSA&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cJvaIl/hyWvWUasZC/ppV9mN3SV0saYTVDWbvNYk/img.png?width=319&amp;amp;height=283&amp;amp;face=0_0_319_283,https://scrap.kakaocdn.net/dn/TADtf/hyWvN3ZIlv/1gSukSWxLpNnVRWoelk0S0/img.png?width=319&amp;amp;height=283&amp;amp;face=0_0_319_283,https://scrap.kakaocdn.net/dn/bR9xyO/hyWvRrNrcw/QSBA9IuN62OZv3o0cSIel0/img.jpg?width=420&amp;amp;height=420&amp;amp;face=0_0_420_420&quot;&gt;&lt;a href=&quot;https://cloud-grace.tistory.com/entry/Spring-%EC%8A%A4%ED%94%84%EB%A7%81%EC%9D%98-%EC%82%BC%EA%B0%81%ED%98%95-IoCDI-AOP-PSA&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cloud-grace.tistory.com/entry/Spring-%EC%8A%A4%ED%94%84%EB%A7%81%EC%9D%98-%EC%82%BC%EA%B0%81%ED%98%95-IoCDI-AOP-PSA&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cJvaIl/hyWvWUasZC/ppV9mN3SV0saYTVDWbvNYk/img.png?width=319&amp;amp;height=283&amp;amp;face=0_0_319_283,https://scrap.kakaocdn.net/dn/TADtf/hyWvN3ZIlv/1gSukSWxLpNnVRWoelk0S0/img.png?width=319&amp;amp;height=283&amp;amp;face=0_0_319_283,https://scrap.kakaocdn.net/dn/bR9xyO/hyWvRrNrcw/QSBA9IuN62OZv3o0cSIel0/img.jpg?width=420&amp;amp;height=420&amp;amp;face=0_0_420_420');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Spring] 스프링의 삼각형(IoC/DI, AOP, PSA)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;스프링의 삼각형, 3대 요소(Spring Triangle)스프링의 삼각형(Spring Triangle), 즉, 스프링의 핵심 3요소가 있다.&amp;nbsp;1. IoC/DIIoC란 제어의 역전으로 스프링 컨테이너가 객체에 대한 제어권을 가지고 있는 것이&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cloud-grace.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Spring Boot&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Boot는 Spring Framework를 더욱 간편히 사용할 수 있도록 도와주는 프레임워크이다. 설정을 최소화하고, 빠르게 애플리케이션을 시작할 수 있도록 해준다. Spring의 기능을 그대로 사용하면서도, 기본 설정과 자동 구성 기능을 제공하여 개발자들이 설정에 신경 쓰지 않고 비즈니스 로직에 집중할 수 있도록 도와준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;차이점 1) Dependency (Gradle, Maven 모두 비교)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Spring (Maven)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1720248624022&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;dependencies&amp;gt;
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;spring-core&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;5.3.9&amp;lt;/version&amp;gt;
    &amp;lt;/dependency&amp;gt;
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;spring-context&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;5.3.9&amp;lt;/version&amp;gt;
    &amp;lt;/dependency&amp;gt;
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;spring-webmvc&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;5.3.9&amp;lt;/version&amp;gt;
    &amp;lt;/dependency&amp;gt;
    &amp;lt;!-- 기타 의존성들 --&amp;gt;
&amp;lt;/dependencies&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Spring (Gradle)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1720248697236&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:spring-core:5.3.9'
    implementation 'org.springframework:spring-context:5.3.9'
    implementation 'org.springframework:spring-webmvc:5.3.9'
    // 기타 의존성들
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Spring Boot (Maven)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1720248815274&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;parent&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-boot-starter-parent&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;3.3.1&amp;lt;/version&amp;gt;
&amp;lt;/parent&amp;gt;

&amp;lt;dependencies&amp;gt;
    &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;spring-boot-starter-web&amp;lt;/artifactId&amp;gt;
    &amp;lt;/dependency&amp;gt;
    &amp;lt;!-- 기타 의존성들 --&amp;gt;
&amp;lt;/dependencies&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Spring Boot (Gradle)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1720248908025&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;plugins {
    id 'org.springframework.boot' version '3.3.1'
    id 'io.spring.dependency-management' version '1.1.5'
    id 'java'
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    // 기타 의존성들
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Boot는 spring-boot-starter 의존성만 추가하면 대부분의 필요한 의존성을 자동으로 포함하여 편리하다. 반면, Spring은 필요한 의존성을 직접 추가해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;차이점 2-1) Configuration&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시로 타임리프를 설정하는 방법을 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Spring의 Java Config&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1720249523956&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
public class WebConfig implements WebMvcConfigurer {
	
	// Thymeleaf Template Engine
	@Bean
	public SpringResourceTemplateResolver templateResolver(ApplicationContext applicationContext) {
		SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();

		templateResolver.setApplicationContext(applicationContext);
		templateResolver.setPrefix(&quot;classpath:templates/&quot;);
		templateResolver.setSuffix(&quot;.html&quot;);
		templateResolver.setTemplateMode(TemplateMode.HTML);
		templateResolver.setCharacterEncoding(&quot;UTF-8&quot;);
		templateResolver.setCacheable(false);
		
		return templateResolver;
	}
	
	@Bean
	public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
		SpringTemplateEngine templateEngine = new SpringTemplateEngine();

		templateEngine.setTemplateResolver(templateResolver);
		templateEngine.setEnableSpringELCompiler(true);
		templateEngine.setTemplateEngineMessageSource(messageSource());

		return templateEngine;
	}

	// Thymeleaf View Resolver
	@Bean
	public ViewResolver thymeleafViewResolver(ISpringTemplateEngine templateEngine) {
		ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();

		viewResolver.setTemplateEngine(templateEngine);
		viewResolver.setCharacterEncoding(&quot;UTF-8&quot;);
		viewResolver.setOrder(1);

		return viewResolver;
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Spring Boot의 설정 파일&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;application.properties&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1720249925213&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring.thymeleaf.prefix=classpath:templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.cache=false
spring.thymeleaf.enabled=true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;application.yml&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1720249623607&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  #thymeleaf
  thymeleaf:
    prefix: classpath:templates/
    suffix: .html
    mode: HTML
    encoding: UTF-8
    cache: false
    enabled: true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Boot에서는 application.properties나 application.yml 파일을 사용하여 설정할 수 있어 훨씬 간편하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;차이점 2-2) AutoConfiguration&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Spring의 Java Config인 경우&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1720250300645&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@ComponentScan(basePackages = &quot;com.example&quot;)
public class AppConfig {
    
    @Bean
    public DataSource dataSource() {
        return new DriverManagerDataSource(&quot;jdbc:h2:mem:testdb&quot;, &quot;hi&quot;, &quot;hi&quot;);
    }
    
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource());
        em.setPackagesToScan(new String[] { &quot;com.example&quot; });
        return em;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Spring의 Xml Config인 경우&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1720250337695&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
       xmlns:context=&quot;http://www.springframework.org/schema/context&quot;
       xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd&quot;&amp;gt;

    &amp;lt;context:component-scan base-package=&quot;com.example&quot;/&amp;gt;

    &amp;lt;bean id=&quot;dataSource&quot; class=&quot;org.springframework.jdbc.datasource.DriverManagerDataSource&quot;&amp;gt;
        &amp;lt;property name=&quot;driverClassName&quot; value=&quot;org.h2.Driver&quot;/&amp;gt;
        &amp;lt;property name=&quot;url&quot; value=&quot;jdbc:h2:mem:testdb&quot;/&amp;gt;
        &amp;lt;property name=&quot;username&quot; value=&quot;hi&quot;/&amp;gt;
        &amp;lt;property name=&quot;password&quot; value=&quot;hi&quot;/&amp;gt;
    &amp;lt;/bean&amp;gt;

    &amp;lt;bean id=&quot;entityManagerFactory&quot; class=&quot;org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean&quot;&amp;gt;
        &amp;lt;property name=&quot;dataSource&quot; ref=&quot;dataSource&quot;/&amp;gt;
        &amp;lt;property name=&quot;packagesToScan&quot; value=&quot;com.example&quot;/&amp;gt;
    &amp;lt;/bean&amp;gt;

&amp;lt;/beans&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Spring Boot&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Boot의 @SpringBootApplication 어노테이션은 @EnableAutoConfiguration, @ComponentScan, @Configuration을 포함하고 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;998&quot; data-origin-height=&quot;848&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7Jh5w/btsIqQ03u82/9YIvVm7y9CqAwg6aFKUDx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7Jh5w/btsIqQ03u82/9YIvVm7y9CqAwg6aFKUDx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7Jh5w/btsIqQ03u82/9YIvVm7y9CqAwg6aFKUDx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7Jh5w%2FbtsIqQ03u82%2F9YIvVm7y9CqAwg6aFKUDx1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;540&quot; height=&quot;459&quot; data-origin-width=&quot;998&quot; data-origin-height=&quot;848&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1720250452349&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@SpringBootApplication
public class MySpringBootApplication {
    public static void main(String[] args) {
        SpringApplication.run(MySpringBootApplication.class, args);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 위와 동일한 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1720250523225&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@EnableAutoConfiguration
@ComponentScan
public class MySpringBootApplication {
    public static void main(String[] args) {
        SpringApplication.run(MySpringBootApplication.class, args);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring에서는 XML 또는 Java Config로 설정해야 하지만, Spring Boot에서는 @SpringBootApplication 이라는 어노테이션이 외부 라이브러리, 내장 톰캣 서버 등을 실행시켜준다. 만약, 이 어노테이션을 제거하고 프로그램을 실행하면 기본 자바 프로그램과 같이 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@ComponentScan은 @Component, @Controller, @Repository, @Service라는 어노테이션이 붙어 있으면 객체로 스캔하여 자동으로 Bean으로 등록해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@EnableAutoConfiguration은 클래스패스(classpath) 상에 존재하는 의존성들을 기반으로 애플리케이션의 설정을 자동으로 구성해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;차이점 3) 배포가 편리하다.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Spring&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring 애플리케이션을 배포하려면, 보통 War 파일로 패키징하여 이를 서블릿 컨테이너(Tomcat, Jetty)에 배포해야 한다. 이 과정은 설정과 관리가 복잡할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Spring Boot&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Boot 애플리케이션은 독립 실행형 Jar 파일로 패키징하여 실행할 수 있다. 내장 서블릿 컨테이너(Tomcat, Jetty) 을 포함하고 있어서 별도의 컨테이너 설치가 필요 없다. 즉, 단일 Jar 파일로 배포할 수 있어 설정과 배포가 매우 간편하다.&lt;/p&gt;</description>
      <category>Spring</category>
      <category>spring</category>
      <category>spring boot</category>
      <category>스프링</category>
      <category>스프링부트</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/33</guid>
      <comments>https://cloud-grace.tistory.com/entry/Spring-Spring-VS-Spring-Boot#entry33comment</comments>
      <pubDate>Sat, 6 Jul 2024 16:43:24 +0900</pubDate>
    </item>
    <item>
      <title>[Spring MVC] 웹 애플리케이션 이해</title>
      <link>https://cloud-grace.tistory.com/entry/Spring-%EC%9B%B9-%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%EC%9D%B4%ED%95%B4</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;웹 서버, 웹 애플리케이션 서버&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;웹(HTTP 기반)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML 메시지로 HTML, TEXT, 이미지, 음성, 영상, JSON, XML 등등 모든 형태의 데이터를 전송할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;웹 서버(Web Server)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML 기반으로 동작하고 정적 리소스를 제공하며 기타 부가 기능을 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정적 리소스는 HTML, CSS, JS, 이미지, 영상 등이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기술: Nginx, Apache&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;웹 애플리케이션 서버(Web Application Server - WAS)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML 기반으로 동작하고 웹 서버의 기능을 포함한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램 코드를 실행하여 애플리케이션 로직을 수행한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;동적 HTML, HTTP API(JSON)&lt;/li&gt;
&lt;li&gt;서블릿, JSP, 스프링 MVC&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기술: Tomcat, Jetty, Undertow&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;웹 서버(Web Server) VS 웹 애플리케이션 서버(WAS)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 서버는 정적 리소스(파일), WAS는 애플리케이션 로직으로 일반적으로 분류하지만 사실 둘의 경계가 모호하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java의 경우, 서블릿 컨테이너 기능을 제공하면 WAS라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WAS는 애플리케이션 코드를 실행하는 데에 특화되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;웹 시스템 구성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. WAS, DB&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;[웹 브라우저]&amp;nbsp;▶ [애플리케이션 로직-WAS-HTML/CSS/JS-이미지] ▶ [DB]&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WAS와 DB 만으로 시스템을 구성할 수는 있지만 몇 가지 단점이 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;WAS가 너무 많은 역할을 담당하여 서버가 과부하될 수 있다.&lt;/li&gt;
&lt;li&gt;가장 비싼 애플리케이션 로직이 정적 리소스로 인해 로직 수행이 어려울 수 있다.&lt;/li&gt;
&lt;li&gt;WAS에 장애가 생기면 오류 화면 조차 노출되지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. WEB, WAS, DB&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;[웹 브라우저] ▶ [Web Server-HTML/CSS/JS-이미지] ▶ [WAS-애플리케이션 로직] ▶ [DB]&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 문제점으로 인해 웹 서버를 따로 두어 정적 리소스를 처리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션 로직과 같은 동적인 처리가 필요하면 WAS에 위임하고, WAS는 중요한 애플리케이션 로직 처리만 맡는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 몇 가지 장점을 가지게 된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;정적 리소스가 많이 사용되면 웹 서버를 증설하고, 애플리케이션 리소스가 많이 사용되면 WAS를 증설하는 등 효율적인 리소스 관리가 가능하다.&lt;/li&gt;
&lt;li&gt;애플리케이션 로직이 동작하는 WAS는 잘 죽지만 정적 리소스만 제공하는 웹 서버는 잘 죽지 않기 때문에 WAS나 DB 장애 시 웹 서버가 오류 화면을 제공할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;서블릿(Servlet)&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;서블릿이란?&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;클라이언트 요청을 처리하고, 그 결과를 반환하는 Servlet 클래스의 구현 규칙을 지킨 자바 웹 프로그래밍 기술&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;484&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zc74L/btsH98uYUMN/aGEZ4E46ZU2N9XHvQsekKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zc74L/btsH98uYUMN/aGEZ4E46ZU2N9XHvQsekKk/img.png&quot; data-alt=&quot;출처 : 인프런 김영한님 강의 [스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zc74L/btsH98uYUMN/aGEZ4E46ZU2N9XHvQsekKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fzc74L%2FbtsH98uYUMN%2FaGEZ4E46ZU2N9XHvQsekKk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;484&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;484&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 인프런 김영한님 강의 [스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트가 웹 페이지에서 전송 버튼을 누를 경우 위와 같이 웹 브라우저가 요청 HTTP 메시지를 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;548&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2l3gq/btsIbKfDu5e/raCodCkckjYQyrWmw0XrGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2l3gq/btsIbKfDu5e/raCodCkckjYQyrWmw0XrGk/img.png&quot; data-alt=&quot;출처 : 인프런 김영한님 강의 [스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2l3gq/btsIbKfDu5e/raCodCkckjYQyrWmw0XrGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2l3gq%2FbtsIbKfDu5e%2FraCodCkckjYQyrWmw0XrGk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;548&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;548&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 인프런 김영한님 강의 [스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 애플리케이션 서버를 직접 구현한다면 왼쪽 로직을 모두 구현해야 하며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서블릿을 지원하는 WAS를 사용할 경우 개발자들은 의미있는 비즈니스 로직만 구현하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;서블릿 특징&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;urlPatterns의 URL이 호출되면 서블릿 코드가 실행된다.&lt;/li&gt;
&lt;li&gt;HTTP 요청 정보를 편리하게 사용할 수 있는 HttpServletRequest&lt;/li&gt;
&lt;li&gt;HTTP 응답 정보를 편리하게 제공할 수 있는 HttpServletResponse&lt;/li&gt;
&lt;li&gt;개발자는 HTTP 스펙을 매우 편리하게 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;HTTP 관련 기본 지식은 필수로 알아야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1719238779006&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@WebServlet(name = &quot;helloServlet&quot;, urlPatterns = &quot;/hello&quot;)
public class HelloServlet extends HttpServlet {
	
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) {
		// 애플리케이션 로직
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;HTTP 요청, 응답 흐름&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;699&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6cTII/btsIbwPd4Jf/Z4cBsm30NTM4UjpTVRH0TK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6cTII/btsIbwPd4Jf/Z4cBsm30NTM4UjpTVRH0TK/img.png&quot; data-alt=&quot;출처 : 인프런 김영한님 강의 [스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6cTII/btsIbwPd4Jf/Z4cBsm30NTM4UjpTVRH0TK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6cTII%2FbtsIbwPd4Jf%2FZ4cBsm30NTM4UjpTVRH0TK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;699&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;699&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 인프런 김영한님 강의 [스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;HTTP 요청 시 WAS는 Request, Response 객체를 새로 만들어서 서블릿 객체를 호출한다.&lt;/li&gt;
&lt;li&gt;개발자는 Request 객체에서 HTTP 요청 정보를 편리하게 꺼내서 사용한다.&lt;/li&gt;
&lt;li&gt;개발자는 Response 객체에 HTTP 응답 정보를 편리하게 입력한다.&lt;/li&gt;
&lt;li&gt;WAS는 Response 객체에 담겨있는 내용으로 HTTP 응답 정보를 생성한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;서블릿 컨테이너&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Tomcat과 같이 서블릿을 지원하는 WAS를 서블릿 컨테이너라고 한다.&lt;/li&gt;
&lt;li&gt;서블릿 컨테이너는 서블릿 객체를 생성, 초기화, 호출, 종료를 하는 생명주기를 관리한다.&lt;/li&gt;
&lt;li&gt;서블릿 객체는 싱글톤으로 관리된다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;따라서 고객 요청이 올 때 마다 계속 객체를 생성하는 것은 비효율적이다.&lt;/li&gt;
&lt;li&gt;최초 로딩 시점에 서블릿 객체를 미리 만들어두고 재활용한다.&lt;/li&gt;
&lt;li&gt;즉, 모든 고객 요청은 동일한 서블릿 객체 인스턴스에 접근한다.&lt;/li&gt;
&lt;li&gt;공유 변수 사용 주의를 해야 한다. (예: 로그인할 때 다른 사람의 계정에 접속하는 경우)&lt;/li&gt;
&lt;li&gt;서블릿 컨테이너 종료 시 함께 종료된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;JSP도 서블릿으로 변환되어 사용한다.&lt;/li&gt;
&lt;li&gt;동시 요청을 위한 멀티 쓰레드 처리를 지원한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, WAS는 Web Server + Web Container(Servlet Container)로 구성되어 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;WAS 구조.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;832&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/H1keY/btsIqNwAIwK/DekOU2RlMiXkBgEiOFJjSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/H1keY/btsIqNwAIwK/DekOU2RlMiXkBgEiOFJjSk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/H1keY/btsIqNwAIwK/DekOU2RlMiXkBgEiOFJjSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FH1keY%2FbtsIqNwAIwK%2FDekOU2RlMiXkBgEiOFJjSk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;832&quot; data-filename=&quot;WAS 구조.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;832&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림의 service()는 서블릿이 브라우저 요청을 처리하는 단계이며, doGet(), doPost()는 각각 GET, POST 등과 같은 HTTP 요청을 처리하는 과정이다. init()은 객체 생성 후 최초 1회이며, doGet(), doPost()는 요청이 들어올 때마다 매번 호출된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;동시 요청 - 멀티 쓰레드&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;쓰레드&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1240&quot; data-origin-height=&quot;528&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOcKpI/btsIbr8sh9K/3JQjkL1CB4ovKRHVThucMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOcKpI/btsIbr8sh9K/3JQjkL1CB4ovKRHVThucMK/img.png&quot; data-alt=&quot;출처 : 인프런 김영한님 강의 [스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOcKpI/btsIbr8sh9K/3JQjkL1CB4ovKRHVThucMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOcKpI%2FbtsIbr8sh9K%2F3JQjkL1CB4ovKRHVThucMK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1240&quot; height=&quot;528&quot; data-origin-width=&quot;1240&quot; data-origin-height=&quot;528&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 인프런 김영한님 강의 [스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;쓰레드는 애플리케이션 코드를 실행하는 것으로 서블릿 객체를 호출한다.&lt;/li&gt;
&lt;li&gt;자바 main 메서드를 처음 실행하면 main 이라는 쓰레드의 이름으로 실행된다.&lt;/li&gt;
&lt;li&gt;쓰레드는 한 번에 하나의 코드 라인만을 실행하므로 동시 처리가 필요할 경우 쓰레드를 추가로 생성해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1220&quot; data-origin-height=&quot;614&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ceBpXt/btsIbJ15yqf/TBnfsQE7oMkVV199QxySB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ceBpXt/btsIbJ15yqf/TBnfsQE7oMkVV199QxySB0/img.png&quot; data-alt=&quot;출처 : 인프런 김영한님 강의 [스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ceBpXt/btsIbJ15yqf/TBnfsQE7oMkVV199QxySB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FceBpXt%2FbtsIbJ15yqf%2FTBnfsQE7oMkVV199QxySB0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1220&quot; height=&quot;614&quot; data-origin-width=&quot;1220&quot; data-origin-height=&quot;614&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 인프런 김영한님 강의 [스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만약, DB 작업 등으로 인해 요청 처리가 지연된다면 새로운 쓰레드를 생성하는 것으로 새로운 요청을 처리할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;하지만, 요청마다 쓰레드를 새로 생성한다면 어떨까?&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: left;&quot;&gt;동시 요청 처리 가능&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: left;&quot;&gt;쓰레드 생성 비용 매우 비싸서 요청마다 쓰레드 생성 시 응답 속도가 늦어짐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: left;&quot;&gt;리소스(CPU, 메모리)가 허용할 때까지 처리가 가능하여 리소스를 최대한 활용함&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: left;&quot;&gt;컨텍스트 스위칭 비용이 발생함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: left;&quot;&gt;하나의 쓰레드가 지연되어도 나머지 쓰레드는 정상 동작함&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: left;&quot;&gt;쓰레드 생성에 제한이 없어 고객 요청이 너무 많이 오면 서버가 죽을 수도 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;쓰레드 풀&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1222&quot; data-origin-height=&quot;516&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Mov59/btsH9h0tJbl/mf0aDKNeWIfG7aqhKScx4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Mov59/btsH9h0tJbl/mf0aDKNeWIfG7aqhKScx4K/img.png&quot; data-alt=&quot;출처 : 인프런 김영한님 강의 [스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Mov59/btsH9h0tJbl/mf0aDKNeWIfG7aqhKScx4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMov59%2FbtsH9h0tJbl%2Fmf0aDKNeWIfG7aqhKScx4K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1222&quot; height=&quot;516&quot; data-origin-width=&quot;1222&quot; data-origin-height=&quot;516&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 인프런 김영한님 강의 [스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1222&quot; data-origin-height=&quot;526&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/B8Gqf/btsH9GsdLFH/aDJa2kgNall191vOdsvvjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/B8Gqf/btsH9GsdLFH/aDJa2kgNall191vOdsvvjk/img.png&quot; data-alt=&quot;출처 : 인프런 김영한님 강의 [스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/B8Gqf/btsH9GsdLFH/aDJa2kgNall191vOdsvvjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FB8Gqf%2FbtsH9GsdLFH%2FaDJa2kgNall191vOdsvvjk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1222&quot; height=&quot;526&quot; data-origin-width=&quot;1222&quot; data-origin-height=&quot;526&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 인프런 김영한님 강의 [스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;쓰레드 풀은 요청마다 쓰레드를 생성하는 방식을 보완하기 위해 사용한다.&lt;/li&gt;
&lt;li&gt;필요한 쓰레드를 쓰레드 풀에 보관하고 관리한다.&lt;/li&gt;
&lt;li&gt;쓰레드 풀에서 생성 가능한 쓰레드의 최대치를 관리한다.&lt;/li&gt;
&lt;li&gt;톰캣은 최대 200개가 기본이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;사용&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;쓰레드가 필요할 경우 쓰레드 풀에서 이미 생성된 쓰레드를 사용한다.&lt;/li&gt;
&lt;li&gt;사용을 종료하면 쓰레드 풀에 해당 쓰레드를 반납한다.&lt;/li&gt;
&lt;li&gt;쓰레드가 모두 사용 중이어서 쓰레드 풀에 쓰레드가 없을 경우 거절하거나 특정 숫자만큼 대기할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;쓰레드가 미리 생성되어 있어 쓰레드를 생성하고 종료하는 CPU 비용이 절약되고 응답 시간이 향상된다.&lt;/li&gt;
&lt;li&gt;생성 가능한 쓰레드의 최대치를 정하여 너무 많은 요청이 들어와도 기존 요청을 안전하게 처리 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;실무 Tip&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;최대 쓰레드 수는 WAS의 주요 튜닝 포인트이다.&lt;/li&gt;
&lt;li&gt;너무 낮으면 서버 리소스는 여유롭지만 클라이언트는 금방 응답 지연을 겪게 된다.&lt;/li&gt;
&lt;li&gt;너무 높으면 서버가 다운될 위험성이 커진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;쓰레드 풀의 적정한 숫자&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;애플리케이션 로직의 복잡도, CPU, 메모리, I/O 리소스 상황에 따라 천차만별이다.&lt;/li&gt;
&lt;li&gt;최대한 실제 서비스와 유사하게 성능 테스트를 시도하는 것이 좋다. (Apache AB, JMETER, nGrinder)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;WAS의 멀티 쓰레드 지원&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;멀티 쓰레드에 대한 부분은 WAS가 처리한다.&lt;/li&gt;
&lt;li&gt;개발자가 멀티 쓰레드 관련 코드를 고려하지 않아도 된다.&lt;/li&gt;
&lt;li&gt;마치 싱글 쓰레드 프로그래밍 하듯이 편리하게 소스 코드를 개발하면 된다.&lt;/li&gt;
&lt;li&gt;멀티 쓰레드 환경이므로 싱글톤 객체(서블릿, 스프링 빈)는 주의해서 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;HTML, HTTP API, CSR, SSR&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;정적 리소스(Static Resource)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고정된 HTML 파일, CSS, JS, 이미지, 영상 등을 주로 웹 브라우저로 제공한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;웹 브라우저(요청 /hello.html)&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;rarr; Web Server&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;rarr; /폴더/web/hello.html&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; /폴더/web/hello.css&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; /폴더/web/hello.js&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; /폴더/image/hello.jpg&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;rarr; 웹 브라우저&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;HTML 페이지&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동적으로 필요한 HTML 파일을 생성해서 웹 브라우저에 전달하고 웹 브라우저는 HTML을 해석한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;웹 브라우저(요청 /orders.html)&lt;br /&gt;&lt;b&gt;&amp;rarr; WAS&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;rarr; 주문 정보 조회 DB&lt;/b&gt; &lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;rarr; WAS &amp;rarr; 동적으로 HTML 생성, JSP, 타임리프 &amp;rarr; HTML &amp;rarr; 웹 브라우저&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;HTML API&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML이 아닌 JSON 등의 데이터를 전달하며, 다양한 시스템에서 호출한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;API를 통해서는 데이터만 주고 받고 UI가 필요한 경우 클라이언트에서 별도로 처리한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;웹 클라이언트(JavaScript, React, Vue.js) to 서버&lt;/li&gt;
&lt;li&gt;앱 클라이언트(아이폰, 안드로이드, PC 앱) to 서버&lt;/li&gt;
&lt;li&gt;서버 to 서버(주문 서버 &amp;rarr; 결제 서버, 기업 간 데이터 통신)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;웹 브라우저???(요청 /orders)&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;rarr; WAS &amp;rarr; 주문 정보 조회 DB&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;rarr; WAS &amp;rarr; DATA(JSON {&quot;주문번호&quot;: 100, &quot;금액&quot;: 5000}) &lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;&amp;rarr; 웹 브라우저???&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;서버 사이드 렌더링(SSR)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML 최종 결과를 서버에서 만들어 웹 브라우저에 전달한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주로 정적인 화면에서 사용하며, JSP와 Thymeleaf 등이 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;웹 브라우저(요청 /orders.html)&amp;rarr; 서버 &amp;rarr; 주문 정보 조회 DB&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;rarr; WAS &amp;rarr; 동적으로 HTML 생성, JSP, 타임리프 &amp;rarr; HTML &amp;rarr; 웹 브라우저&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;클라이언트 사이드 렌더링(CSR)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML 결과를 JavaScript로 웹 브라우저에서 동적으로 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주로 동적인 화면에 사용하며, 웹 환경을 마치 앱처럼 필요한 부분마다 변경할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JavaScript로 HTML 결과를 렌더링한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React, Vue.js 등이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;참고 자료&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;내용 참고 : 인프런 김영한 님의 강의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1#&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&quot;스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술&quot;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Spring</category>
      <category>spring</category>
      <category>spring mvc</category>
      <category>스프링</category>
      <category>스프링 mvc</category>
      <category>웹</category>
      <category>웹 개발 핵심 기술</category>
      <category>웹 애플리케이션</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/32</guid>
      <comments>https://cloud-grace.tistory.com/entry/Spring-%EC%9B%B9-%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%EC%9D%B4%ED%95%B4#entry32comment</comments>
      <pubDate>Mon, 24 Jun 2024 23:41:41 +0900</pubDate>
    </item>
    <item>
      <title>[Web/HTTP] URI, URL, URN, 웹 브라우저 요청 흐름</title>
      <link>https://cloud-grace.tistory.com/entry/WebHTTP-URI-URL-URN-%EC%9B%B9-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EC%9A%94%EC%B2%AD-%ED%9D%90%EB%A6%84</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;URI, URL, URN&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Uniform : 리소스를 식별하는 통일된 방식&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Resource : 자원 = URI로 식별할 수 있는 모든 것(제한되지 않음)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;URI(Uniform Resource Identifier) =&amp;nbsp;&lt;/b&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;URL(Uniform Resource Locater) +&amp;nbsp;&lt;/b&gt;&lt;b&gt;URN(Uniform Resource Name)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Identifier : 다른 항목과 구분할 때 필요한 정보&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Locater : 리소스가 있는 위치를 지정함&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Name : 리소스에 이름을 부여함&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;URN으로만 실제 리소스를 찾는 것은 보편화되어 있지 않기 때문에, URI, URL만 알아두고 이 둘은 같은 의미로 생각하자.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;URL 문법&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;343&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uQKsx/btsHVDCOSkd/VFDxi3rKyIggX3nZpWZdw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uQKsx/btsHVDCOSkd/VFDxi3rKyIggX3nZpWZdw0/img.png&quot; data-alt=&quot;출처 : 인프런 김영한님 강의 [모든 개발자를 위한 HTTP 웹 기본 지식]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uQKsx/btsHVDCOSkd/VFDxi3rKyIggX3nZpWZdw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuQKsx%2FbtsHVDCOSkd%2FVFDxi3rKyIggX3nZpWZdw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;804&quot; height=&quot;343&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;343&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 인프런 김영한님 강의 [모든 개발자를 위한 HTTP 웹 기본 지식]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;URL 예시로 분석해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;https&lt;/span&gt;://&lt;span style=&quot;color: #8a3db6;&quot;&gt;www.google.com&lt;span style=&quot;color: #ee2323;&quot;&gt;:443&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;/search&lt;/span&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;?q=hello&amp;amp;hl=ko&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;scheme&lt;/span&gt;://&lt;span style=&quot;color: #f89009;&quot;&gt;[userinfo@]&lt;/span&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;host&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;[:port]&lt;/span&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;[/path]&lt;/span&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;[?query]&lt;/span&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;[#fragment]&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;scheme : 프로토콜&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;host : 호스트명&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;port : 포트번호&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;path : 경로&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;query : 쿼리 파라미터&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;scheme&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;https&lt;/span&gt;://&lt;span style=&quot;color: #000000;&quot;&gt;www.google.com:443/search?q=hello&amp;amp;hl=ko&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;scheme&lt;/span&gt;://&lt;span style=&quot;color: #000000;&quot;&gt;[userinfo@]host[:port][/path][?query][#fragment]&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;scheme에는 주로 프로토콜을 사용한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;프로토콜 : 어떤 방식으로 자원에 접근할 것인가에 관한 클라이언트 서버 간의 정해진 약속 및 규칙이다.&lt;br /&gt;&lt;/b&gt;ex) http, https, ftp 등&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;http : 80 포트&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;https : 443 포트&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;https는 http에 보안을 추가한 것이며, 요즘은 대부분 https로 동작한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;userinfo&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;https://www.google.com:443/search?q=hello&amp;amp;hl=ko&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;scheme&lt;/span&gt;://&lt;span style=&quot;color: #f89009;&quot;&gt;[userinfo@]&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;host[:port][/path][?query][#fragment]&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;userinfo는 URL에 사용자 정보를 포함해서 인증한다. 하지만 거의 사용하지 않는다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;host&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;https:/&lt;/span&gt;/&lt;span style=&quot;color: #8a3db6;&quot;&gt;www.google.com&lt;span style=&quot;color: #000000;&quot;&gt;:443&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;/search?q=hello&amp;amp;hl=ko&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;scheme://[userinfo@]&lt;/span&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;host&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;[:port][/path][?query][#fragment]&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;host는 호스트명으로, 호스트명에는 도메인명이나 IP 주소를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;port&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;https&lt;/span&gt;://&lt;span style=&quot;color: #8a3db6;&quot;&gt;www.google.com&lt;span style=&quot;color: #ee2323;&quot;&gt;:443&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;/search&lt;/span&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;?q=hello&amp;amp;hl=ko&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;scheme&lt;/span&gt;://&lt;span style=&quot;color: #f89009;&quot;&gt;[userinfo@]&lt;/span&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;host&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;[:port]&lt;/span&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;[/path]&lt;/span&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;[?query]&lt;/span&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;[#fragment]&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;port는 접속 포트로 일반적으로 생략한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;path&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;https&lt;/span&gt;://&lt;span style=&quot;color: #8a3db6;&quot;&gt;www.google.com&lt;span style=&quot;color: #ee2323;&quot;&gt;:443&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;/search&lt;/span&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;?q=hello&amp;amp;hl=ko&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;scheme&lt;/span&gt;://&lt;span style=&quot;color: #f89009;&quot;&gt;[userinfo@]&lt;/span&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;host&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;[:port]&lt;/span&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;[/path]&lt;/span&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;[?query]&lt;/span&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;[#fragment]&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;path는 리소스 경로이며 계층적 구조이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;/home/file1.jpg&lt;/li&gt;
&lt;li&gt;/members&lt;/li&gt;
&lt;li&gt;/members/100&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;query&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;https&lt;/span&gt;://&lt;span style=&quot;color: #8a3db6;&quot;&gt;www.google.com&lt;span style=&quot;color: #ee2323;&quot;&gt;:443&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;/search&lt;/span&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;?q=hello&amp;amp;hl=ko&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;scheme&lt;/span&gt;://&lt;span style=&quot;color: #f89009;&quot;&gt;[userinfo@]&lt;/span&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;host&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;[:port]&lt;/span&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;[/path]&lt;/span&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;[?query]&lt;/span&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;[#fragment]&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;query는 쿼리 파라미터, 쿼리 스트링이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;웹 서버에서 제공하는 파라미터, 문자 형태이다.&lt;/li&gt;
&lt;li&gt;key-value 형태이다.&lt;/li&gt;
&lt;li&gt;?로 시작하고, &amp;amp;로 추가한다. (ex. keyA=valueA&amp;amp;keyB=valueB)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;fragment&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;https&lt;/span&gt;://&lt;span style=&quot;color: #8a3db6;&quot;&gt;www.google.com&lt;span style=&quot;color: #ee2323;&quot;&gt;:443&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;/search&lt;/span&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;?q=hello&amp;amp;hl=ko&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;scheme&lt;/span&gt;://&lt;span style=&quot;color: #f89009;&quot;&gt;[userinfo@]&lt;/span&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;host&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;[:port]&lt;/span&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;[/path]&lt;/span&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;[?query]&lt;/span&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;[#fragment]&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fragment는 html 내부 북마크 등에서 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버에 전송하는 정보가 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;웹 브라우저 요청 흐름&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. 웹 브라우저에 URL 입력&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. IP, PORT 정보로 HTTP 요청 메시지 생성&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;517&quot; data-origin-height=&quot;216&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNUDhU/btsHWTSeY7z/VOsHPxeuWfcvCEfp2neL3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNUDhU/btsHWTSeY7z/VOsHPxeuWfcvCEfp2neL3K/img.png&quot; data-alt=&quot;출처 : 인프런 김영한님 강의 [모든 개발자를 위한 HTTP 웹 기본 지식]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNUDhU/btsHWTSeY7z/VOsHPxeuWfcvCEfp2neL3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNUDhU%2FbtsHWTSeY7z%2FVOsHPxeuWfcvCEfp2neL3K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;433&quot; height=&quot;181&quot; data-origin-width=&quot;517&quot; data-origin-height=&quot;216&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 인프런 김영한님 강의 [모든 개발자를 위한 HTTP 웹 기본 지식]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3. HTTP 메시지 전송&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;339&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/U3PFq/btsHVVJZ1Ws/CeiF84y52D4MV8dIEXnMOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/U3PFq/btsHVVJZ1Ws/CeiF84y52D4MV8dIEXnMOK/img.png&quot; data-alt=&quot;출처 : 인프런 김영한님 강의 [모든 개발자를 위한 HTTP 웹 기본 지식]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/U3PFq/btsHVVJZ1Ws/CeiF84y52D4MV8dIEXnMOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FU3PFq%2FbtsHVVJZ1Ws%2FCeiF84y52D4MV8dIEXnMOK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;672&quot; height=&quot;313&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;339&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 인프런 김영한님 강의 [모든 개발자를 위한 HTTP 웹 기본 지식]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) SOCKET 라이브러리를 통해 헤더 부분에 IP, PORT 정보를 넣어 3 way handshake로 웹 브라우저와 웹 서버를 연결한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) 연결 후 HTTP 메시지를 TCP/IP 계층에 전달한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;4. 패킷 생성&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;869&quot; data-origin-height=&quot;395&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chpbz9/btsHW6X7Oon/iv0wMVOBeati6WPcJSdQ7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chpbz9/btsHW6X7Oon/iv0wMVOBeati6WPcJSdQ7k/img.png&quot; data-alt=&quot;출처 : 인프런 김영한님 강의 [모든 개발자를 위한 HTTP 웹 기본 지식]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chpbz9/btsHW6X7Oon/iv0wMVOBeati6WPcJSdQ7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fchpbz9%2FbtsHW6X7Oon%2Fiv0wMVOBeati6WPcJSdQ7k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;618&quot; height=&quot;281&quot; data-origin-width=&quot;869&quot; data-origin-height=&quot;395&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 인프런 김영한님 강의 [모든 개발자를 위한 HTTP 웹 기본 지식]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;헤더 부분에 출발지 IP, 출발지 PORT, 목적지 IP, 목적지 PORT 정보 등을 담고 데이터 부분에 HTTP 메시지를 담아 TCP./IP 패킷을 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;5. 요청 패킷 전달&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TCP/IP 패킷을 웹 브라우저에 서 수많은 중간 노드를 거쳐 웹 서버에 전달한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;6. 서버에 요청 패킷 도착&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;7. 서버에서 HTTP 응답 메시지 생성&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;519&quot; data-origin-height=&quot;242&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rcV7W/btsHWy1ROEg/fsZIYdFTrihnMghFH9pbtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rcV7W/btsHWy1ROEg/fsZIYdFTrihnMghFH9pbtK/img.png&quot; data-alt=&quot;출처 : 인프런 김영한님 강의 [모든 개발자를 위한 HTTP 웹 기본 지식]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rcV7W/btsHWy1ROEg/fsZIYdFTrihnMghFH9pbtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrcV7W%2FbtsHWy1ROEg%2FfsZIYdFTrihnMghFH9pbtK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;468&quot; height=&quot;218&quot; data-origin-width=&quot;519&quot; data-origin-height=&quot;242&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 인프런 김영한님 강의 [모든 개발자를 위한 HTTP 웹 기본 지식]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 서버에 도착한 패킷의 헤더 부분은 버리고 HTTP 메시지(데이터 부분)를 서버가 해석하여 HTTP 응답 메시지를 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;8. 서버에서 응답 패킷 전달&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;헤더 부분에 출발지 IP, 출발지 PORT, 목적지 IP, 목적지 PORT 정보 등을 담고 데이터 부분에 HTTP 응답 메시지를 담아 응답 패킷을 웹 브라우저에 전달한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;9. 웹 브라우저에 응답 패킷 도착&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;10. 웹 브라우저 HTML 렌더링&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 브라우저가 웹 서버로부터 받은 응답 패킷에서 헤더 부분을 버리고 HTTP 응답 메시지의 데이터(HTML)를 렌더링하여 화면에 뿌려준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;참고 자료&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;내용 참고 : 인프런 김영한 님의 강의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://www.inflearn.com/course/http-%EC%9B%B9-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC&quot;&gt;&quot;모든 개발자를 위한 HTTP 웹 기본 지식&quot;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Web</category>
      <category>HTTP</category>
      <category>URI</category>
      <category>url</category>
      <category>URN</category>
      <category>web</category>
      <category>웹 브라우저</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/31</guid>
      <comments>https://cloud-grace.tistory.com/entry/WebHTTP-URI-URL-URN-%EC%9B%B9-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EC%9A%94%EC%B2%AD-%ED%9D%90%EB%A6%84#entry31comment</comments>
      <pubDate>Wed, 12 Jun 2024 23:48:34 +0900</pubDate>
    </item>
    <item>
      <title>[Web/HTTP] 인터넷 네트워크(인터넷 통신, IP, TCP, UDP, PORT, DNS)</title>
      <link>https://cloud-grace.tistory.com/entry/WebHTTP-%EC%9D%B8%ED%84%B0%EB%84%B7-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC%EC%9D%B8%ED%84%B0%EB%84%B7-%ED%86%B5%EC%8B%A0-IP-TCP-UDP-PORT-DNS</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 인터넷 통신&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트와 서버가 가까이 있으면 케이블로 두 PC를 연결하여 통신이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, 클라이언트와 서버의 거리가 멀면 그 사이에 존재하는 인터넷망으로 통신해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트에서 인터넷망은 내부의 수많은 중간 노드를 거쳐 목적지로 도착한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 인터넷망은 매우 복잡하기 때문에 &lt;b&gt;정해진 규칙과 목적지&lt;/b&gt;가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;즉, 클라이언트(출발지)와 서버(목적지)의 IP 주소가 부여되어 있어야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;클라이언트 IP : 100.100.100.1&amp;nbsp;&amp;rarr; 서버 IP : 200.200.200.2&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. IP(인터넷 프로토콜, Internet Protocol)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;지정한 IP 주소(IP Address)에 데이터를 전달한다.&lt;/li&gt;
&lt;li&gt;패킷(Packet)이라는 통신 단위로 데이터를 전달한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;IP 패킷 정보&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;IP 패킷 = 출발지 IP + 목적지 IP + 전송 데이터 + etc...&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전송 데이터와 함께 출발지 IP와 목적지 IP를 함께 묶어서 패킷으로 만들어 전달한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;IP 프로토콜의 한계점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;비연결성&lt;/b&gt; : 패킷을 받을 대상이 없거나 서비스가 불가능한 경우&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비신뢰성&lt;/b&gt; : 중간에 패킷이 사라지거나(패킷 소실), 패킷이 순서대로 오지 않는 경우(패킷 순서 문제)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;패킷 소실&lt;/b&gt; - 인터넷 망의 중간 노드의 문제 발생 시 패킷 소실 가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;패킷 순서 문제&lt;/b&gt; - 패킷 용량이 클 때 분리해서 보내고 모두 같은 경로로 이동하는 것이 아님&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로그램 구분의 어려움&lt;/b&gt; : 같은 IP를 사용하는 서버에서 통신하는 애플리케이션이 2개 이상인 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;인터넷 프로토콜 스택의 4계층&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;애플리케이션 계층 - HTTP, FTP&lt;/b&gt;&lt;br /&gt;&lt;b&gt;전송 계층 - TCP, UDP&lt;/b&gt;&lt;br /&gt;&lt;b&gt;인터넷 계층 - IP&lt;/b&gt;&lt;br /&gt;&lt;b&gt;네트워크 인터페이스 계층&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;프로토콜 계층&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;780&quot; data-origin-height=&quot;372&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UFKoZ/btsHWvRysJg/Naa8sea1CDe3ylHWtbJyV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UFKoZ/btsHWvRysJg/Naa8sea1CDe3ylHWtbJyV0/img.png&quot; data-alt=&quot;출처 : 인프런 김영한님 강의 [모든 개발자를 위한 HTTP 웹 기본 지식]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UFKoZ/btsHWvRysJg/Naa8sea1CDe3ylHWtbJyV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUFKoZ%2FbtsHWvRysJg%2FNaa8sea1CDe3ylHWtbJyV0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;702&quot; height=&quot;335&quot; data-origin-width=&quot;780&quot; data-origin-height=&quot;372&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 인프런 김영한님 강의 [모든 개발자를 위한 HTTP 웹 기본 지식]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약, 채팅 프로그램에서 Hello, world! 를 전달한다고 가정해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;1. 채팅 프로그램이 Hello, world! 메시지 데이터를 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;2. 생성된 메시지를 SOCKET 라이브러리를 통해 OS 계층에 넘긴다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;3. OS 계층의 TCP 계층에서 메시지 데이터를 포함하여 TCP 정보를 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;4. OS 계층의 IP 계층에서 TCP 정보를 포함하여 IP 패킷을 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;IP 패킷 : [IP 관련 정보 + [TCP 관련 정보 + [메시지 데이터]]]&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;5. IP 패킷이 LAN 카드를 통해 나갈 때 Ethernet Frame이 포함되어 나간다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;Ethernet Frame : LAN 카드의 MAC 주소 등 물리적 정보가 포함된다.&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;TCP/IP 패킷 정보&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;689&quot; data-origin-height=&quot;393&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EjRGU/btsHX4rrRdA/P2knDrK32kJwEyh6bTGuy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EjRGU/btsHX4rrRdA/P2knDrK32kJwEyh6bTGuy1/img.png&quot; data-alt=&quot;출처 : 인프런 김영한님 강의 [모든 개발자를 위한 HTTP 웹 기본 지식]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EjRGU/btsHX4rrRdA/P2knDrK32kJwEyh6bTGuy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEjRGU%2FbtsHX4rrRdA%2FP2knDrK32kJwEyh6bTGuy1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;431&quot; height=&quot;246&quot; data-origin-width=&quot;689&quot; data-origin-height=&quot;393&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 인프런 김영한님 강의 [모든 개발자를 위한 HTTP 웹 기본 지식]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;IP 패킷 = 출발지 IP + 목적지 IP + etc...&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TCP 세그먼트 = 출발지 PORT + 목적지 PORT + 전송 제어 + 순서 + 검증 정보 + etc...&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TCP/IP 패킷 = IP 패킷 + TCP 세그먼트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, IP 패킷에 TCP 정보가 추가되면서 IP의 한계점이 해결되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. TCP(전송 제어 프로토콜, Transmission Control Protocol)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 연결 지향 TCP 3 way handshake (가상 연결)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 연결(논리적인 연결)한 후, 메시지를 보낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;TCP 3 way handshake&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;716&quot; data-origin-height=&quot;424&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEZzMR/btsHXRTm2GF/tvP0GK35NklxOPKl0k2zN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEZzMR/btsHXRTm2GF/tvP0GK35NklxOPKl0k2zN1/img.png&quot; data-alt=&quot;출처 : 인프런 김영한님 강의 [모든 개발자를 위한 HTTP 웹 기본 지식]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEZzMR/btsHXRTm2GF/tvP0GK35NklxOPKl0k2zN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEZzMR%2FbtsHXRTm2GF%2FtvP0GK35NklxOPKl0k2zN1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;492&quot; height=&quot;291&quot; data-origin-width=&quot;716&quot; data-origin-height=&quot;424&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 인프런 김영한님 강의 [모든 개발자를 위한 HTTP 웹 기본 지식]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SYN : 접속 요청&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ACK : 요청 수락&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; (1) SYN : 클라이언트가 서버에게 접속을 요청하는 SYN 보낸다.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;▶ (2) SYN + ACK : 서버가 SYN을 받으면 서버에서 클라이언트로 접속을 요청하는 SYN과 함께 ACK를 보낸다.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;▶ (3) ACK : 클라이언트가 SYN을 받았으면, 서버로 ACK를 보낸다.&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;▶ (4) 데이터 전송 : 클라이언트가 서버로 데이터를 전송한다. (3단계에서 ACK와 함께 데이터를 보내기도 한다.)&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 데이터 전달 보증&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트가 데이터를 전송하면 서버가 데이터를 받았다고 응답을 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;패킷 손실로 인해 서버가 메시지를 받지 못하면 클라이언트가 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 순서 보장&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트에서 패킷을 보낸 순서대로 서버로 오지 않으면 서버가 클라이언트에 다시 순서대로 패킷이 전송되도록 요청한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 신뢰 가능한 프로토콜&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. 현재는 대부분 TCP를 사용한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. UDP(사용자 데이터그램 프로토콜, User Datagram Protocol)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 3 way handshake&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 데이터 전달 보증이 되지 않음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 순서 보장이 되지 않음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 단순하고 빠름&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. IP와 거의 유사하다. (PORT와 checksum 정도만 추가되었다.)&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;체크섬(checksum)은 중복 검사의 한 형태로, 오류 정정을 통해 공간(전자 통신)이나 시간(기억 장치) 속에서 송신된 자료의 무결성을 보호하는 단순한 방법이다.&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. 애플리케이션에서 추가 작업이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5. PORT&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 한 번에 2곳 이상 연결을 해야 하면 어떻게 해야 할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 클라이언트에서 게임, 화상 통화, 웹 브라우저 요청 이 3가지를 동시에 하고 있다고 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 클라이언트 PC가 여러 개의 서버와 통신을 해야 하며, 서버가 클라이언트 IP로 패킷을 보내야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;하지만, IP만 사용하면 클라이언트는 받은 패킷이 게임, 화상 통화, 웹 브라우저 요청 중 어떤 곳으로 온 패킷인지 알 수 없다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;즉, 이 프로그램을 구분하기 위해 PORT를 사용한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;TCP/IP 패킷 정보&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 TCP/IP 패킷에는 &lt;b&gt;출발지 IP, 목적지 IP, 출발지 PORT, 목적지 PORT&lt;/b&gt;가 함께 포함되어 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;IP : 목적지 서버를 찾는 용도&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;PORT : 서버 내부에서 돌아가는 애플리케이션을 구분하는 용도&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PORT 할당 범위&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;0 ~ 65535 : 할당 가능&lt;/li&gt;
&lt;li&gt;0 ~ 1023 : 잘 알려진 PORT이므로 사용하지 않는 것이 좋다.&lt;/li&gt;
&lt;li&gt;FTP : 20, 21&lt;/li&gt;
&lt;li&gt;TELNET : 23&lt;/li&gt;
&lt;li&gt;&lt;b&gt;HTTP : 80&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;HTTPS : 443&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;6. DNS(Domain Name System)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IP 주소는 기억하기 어렵게 생겼다. 또한, IP는 변경될 수 있다. 이러한 단점을 보완하기 위해 DNS를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DNS는 Domain Name System으로 도메인 명을 IP 주소로 변환시켜주는 것이다. 마치 전화번호부와 같다.&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;b&gt;도메인 명&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;b&gt;IP&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;google.com&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;200.200.200.2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;aaa.com&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;210.210.210.3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DNS 서버에 위 표처럼 도메인 명에 대한 IP 주소를 등록해둔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(1) 클라이언트가 DNS 서버에 도메인 명에 대한 IP 주소를 요청한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(2) DNS 서버는 해당 도메인 명에 대한 IP 주소를 클라이언트에 전달한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(3) 클라이언트는 해당 IP 주소로 서버에 접근한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;따라서 DNS를 사용하여 IP 주소를 기억하기 어려운 점과 변경될 수 있는 문제를 해결해준다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;참고 자료&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;내용 참고 : 인프런 김영한 님의 강의 &lt;a href=&quot;https://www.inflearn.com/course/http-%EC%9B%B9-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&quot;모든 개발자를 위한 HTTP 웹 기본 지식&quot;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Web</category>
      <category>dns</category>
      <category>HTTP</category>
      <category>IP</category>
      <category>network</category>
      <category>PORT</category>
      <category>Protocol</category>
      <category>TCP</category>
      <category>TCP/IP</category>
      <category>web</category>
      <category>네트워크</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/30</guid>
      <comments>https://cloud-grace.tistory.com/entry/WebHTTP-%EC%9D%B8%ED%84%B0%EB%84%B7-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC%EC%9D%B8%ED%84%B0%EB%84%B7-%ED%86%B5%EC%8B%A0-IP-TCP-UDP-PORT-DNS#entry30comment</comments>
      <pubDate>Wed, 12 Jun 2024 22:56:24 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] 스프링 빈 스코프(Bean Scope)</title>
      <link>https://cloud-grace.tistory.com/entry/Spring-%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B9%88-%EC%8A%A4%EC%BD%94%ED%94%84Bean-Scope</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;빈 스코프(Bean Scope)란?&lt;/b&gt;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 빈(Spring Bean)이 스프링 컨테이너에 시작과 동시에 만들어지고, 컨테이너가 종료될 때까지 유지된다고 지금까지 배웠으며, 이는 스프링 빈이 기본적으로 싱글톤 스코프(Singleton Scope)로 생성되기 때문이였다. 즉, &lt;b&gt;빈 스코프(Bean Scope)는 빈이 존재할 수 있는 범위를 말한다.&lt;/b&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;하지만, 요구사항과 여러 구현할 기능에 의해 싱글톤이 아닌 스코프도 필요한 경우가 많다. 이를 명시적으로 구분하려고 Scope라는 키워드가 존재한다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;빈 스코프 종류&lt;/b&gt;&lt;/h3&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;싱글톤 스코프&lt;/b&gt;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 프레임워크의 기본 스코프이며, 스프링 컨테이너 시작과 종료 사이에 유지되는 가장 넓은 범위의 스코프이다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;프로토타입 스코프&lt;/b&gt;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;프로토타입 빈의 생성과 의존 관계 주입까지만 관여하고 그 외에는 관리하지 않는 매우 짧은 범위의 스코프이다.&lt;br&gt;요청이 오게 되면 새로운 인스턴스 생성 후 반환하며, 그 이후 관여하지 않는다.&lt;br&gt;프로토타입을 받은 클라이언트가 객체를 관리해야 한다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;웹 관련 스코프&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;request : 웹 요청이 들어오고 나갈 때까지 유지되는 스코프. 즉, HTTP 요청 하나가 들어오고 나갈 때까지 유지되는 스코프이다. 각각 HTTP 요청마다 별도의 빈 인스턴스가 생성되고 관리된다.&lt;/li&gt;&lt;li&gt;session : 웹 세션이 생성되고 종료될 때까지 유지되는 스코프. HTTP Session과 동일한 생명주기를 가지는 스코프이다.&lt;/li&gt;&lt;li&gt;application : 웹 서블릿 컨텍스트와 같은 범위(생명주기)로 유지되는 스코프&lt;/li&gt;&lt;li&gt;websocket : 웹 소켓과 동일한 생명주기를 가지는 스코프&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;빈 스코프 사용 방법&lt;/b&gt;&lt;/h3&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;컴포넌트 스캔 자동 등록&lt;/li&gt;&lt;/ul&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Scope(&quot;prototype&quot;)
@Component
public class PrototypeBean {
}&lt;/code&gt;&lt;/pre&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;수동 등록&lt;/li&gt;&lt;/ul&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Scope(&quot;prototype&quot;)
@Bean
PrototypeBean prototypeBean() {
	return new PrototypeBean();
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;싱글톤 스코프&lt;/b&gt;&lt;/h3&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;싱글톤 빈은 기본값이며, @Scope 또는 @Scope(&quot;singleton&quot;)이라고 붙여 사용할 수 있다.&lt;/li&gt;&lt;li&gt;스프링 컨테이너에서 한 번만 생성되며, 컨테이너 종료 시 소멸된다.&lt;/li&gt;&lt;li&gt;싱글톤 스코프의 스프링 빈은 하나의 공유 인스턴스만 관리하며, 동일 참조를 보장한다.&lt;/li&gt;&lt;li&gt;private 생성자를 통해 외부에서 new를 못하도록 해야 한다.&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;싱글톤으로 다루기에 알맞은 객체&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;읽기 전용 상태의 객체&lt;/li&gt;&lt;li&gt;쓰기 가능한 상태를 가져도 사용 빈도가 매우 높은 객체(동기화 필요)&lt;/li&gt;&lt;li&gt;상태가 없는 공유 객체&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;싱글톤 스코프 빈 테스트&lt;/b&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class SingletonTest {

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Test
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;void singletonBeanFind() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SingletonBean.class);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SingletonBean singletonBean1 = ac.getBean(SingletonBean.class);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SingletonBean singletonBean2 = ac.getBean(SingletonBean.class);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;singletonBean1 = &quot; + singletonBean1);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;singletonBean2 = &quot; + singletonBean2);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Assertions.assertThat(singletonBean1).isSameAs(singletonBean2);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ac.close();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Scope(&quot;singleton&quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static class SingletonBean {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@PostConstruct
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void init() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;SingletonBean.init&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@PreDestroy
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void destroy() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;SingletonBean.destroy&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;출력&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;같은 인스턴스의 빈을 조회한다.&lt;/li&gt;&lt;li&gt;컨테이너 생성 시점에 초기화 메서드 실행이 된다.&lt;/li&gt;&lt;li&gt;컨테이너 종료 시점에 종료 메서드 실행이 된다.&lt;/li&gt;&lt;/ul&gt;&lt;blockquote data-ke-style=&quot;style3&quot;&gt;SingletonBean.init&lt;br&gt;singletonBean1 = hello.core.scope.SingletonTest$SingletonBean@24561357&lt;br&gt;singletonBean2 = hello.core.scope.SingletonTest$SingletonBean@24561357&lt;br&gt;16:45:26.527 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext ..........&lt;br&gt;SingletonBean.destroy&lt;/blockquote&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;프로토타입 스코프&lt;/b&gt;&lt;/h3&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;프로토타입 빈 대상 클래스에 @Scope(&quot;prototype&quot;)을 붙인다.&lt;/li&gt;&lt;li&gt;의존 관계 주입이 될 때마다 새로운 객체가 생성과 의존 관계 주입까지만 관여한다.&lt;/li&gt;&lt;li&gt;컨테이너에서 조회하면 컨테이너는 항상 새로운 인스턴스를 생성하여 반환한다.&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;프로토타입으로 다루기에 알맞은 객체 &lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;쓰기가 가능한 상태가 있는 객체&lt;/li&gt;&lt;li&gt;사용할 때마다 상태가 달라져야 되는 객체&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;프로토타입 스코프 빈 테스트&lt;/b&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class PrototypeTest {

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Test
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;void prototypeBeanFind() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ProtoTypeBean.class);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;find prototypeBean1&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ProtoTypeBean prototypeBean1 = ac.getBean(ProtoTypeBean.class);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;find prototypeBean2&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ProtoTypeBean prototypeBean2 = ac.getBean(ProtoTypeBean.class);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;prototypeBean1 = &quot; + prototypeBean1);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;prototypeBean2 = &quot; + prototypeBean2);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assertThat(prototypeBean1).isNotSameAs(prototypeBean2);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ac.close();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Scope(&quot;prototype&quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static class ProtoTypeBean {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@PostConstruct
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void init() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;ProtoTypeBean.init&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@PreDestroy
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void destroy() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;ProtoTypeBean.destroy&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;출력&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;컨테이너에서 빈을 조회할 때 생성되면서 초기화 메서드도 실행된다.&lt;/li&gt;&lt;li&gt;2번째 조회일 때 서로 다른 빈이 생성되며, 초기화도 2번 수행된다.&lt;/li&gt;&lt;li&gt;객체 생성과 의존 관계 주입까지만 관여하기 때문에 종료 메서드가 수행되지 않는다.&lt;/li&gt;&lt;/ul&gt;&lt;blockquote data-ke-style=&quot;style3&quot;&gt;find prototypeBean1&lt;br&gt;ProtoTypeBean.init&lt;br&gt;find prototypeBean2&lt;br&gt;ProtoTypeBean.init&lt;br&gt;prototypeBean1 = hello.core.scope.PrototypeTest$ProtoTypeBean@24561357&lt;br&gt;prototypeBean2 = hello.core.scope.PrototypeTest$ProtoTypeBean@21s6d2a5&lt;br&gt;16:55:22.251 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext ..........&lt;/blockquote&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;싱글톤 빈과 프로토타입 빈을 같이 사용하면 발생하는 문제점&lt;/b&gt;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;프로토타입 빈에서 싱글톤 빈을 사용하면 문제가 생기지 않는다.&lt;br&gt;그러나, 싱글톤 빈에서 프로토타입 빈을 사용하면 문제가 발생할 수 있다.&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;예제 코드&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;프로토타입 빈 호출 시 count를 1씩 늘리는 테스트 코드&lt;/li&gt;&lt;/ul&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class SingletonWithPrototypeTest1 {

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 프로토타입 빈만 사용
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Test
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;void prototypeFind() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(PrototypeBean.class);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PrototypeBean prototypeBean1 = ac.getBean(PrototypeBean.class);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;prototypeBean1.addCount();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assertThat(prototypeBean1.getCount()).isEqualTo(1);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PrototypeBean prototypeBean2 = ac.getBean(PrototypeBean.class);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;prototypeBean2.addCount();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assertThat(prototypeBean2.getCount()).isEqualTo(1);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 싱글톤 빈에서 프로토타입 빈 사용
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Test
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;void singletonClientUsePrototype() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ClientBean.class, PrototypeBean.class);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ClientBean clientBean1 = ac.getBean(ClientBean.class);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int count1 = clientBean1.logic();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assertThat(count1).isEqualTo(1);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ClientBean clientBean2 = ac.getBean(ClientBean.class);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int count2 = clientBean2.logic();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assertThat(count2).isEqualTo(2);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Scope(&quot;singleton&quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static class ClientBean {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private final PrototypeBean prototypeBean;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Autowired
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public ClientBean(PrototypeBean prototypeBean) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.prototypeBean = prototypeBean;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public int logic() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;prototypeBean.addCount();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return prototypeBean.getCount();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Scope(&quot;prototype&quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;static class PrototypeBean {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private int count = 0;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void addCount() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;count++;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public int getCount() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return count;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@PostConstruct
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void init() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;PrototypeBean.init&quot; + this);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@PreDestroy
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void destroy() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;PrototypeBean.destroy&quot; + this);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;테스트 결과&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;프로토타입 빈은 항상 새로운 인스턴스를 반환하므로 계속 1이 되어야 한다.&lt;/li&gt;&lt;/ul&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1142&quot; data-origin-height=&quot;113&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xv4SS/btsHR6LbOoG/MYyQJoN9PyjjOZwTAsvKWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xv4SS/btsHR6LbOoG/MYyQJoN9PyjjOZwTAsvKWk/img.png&quot; data-alt=&quot;prototypeFind()&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xv4SS/btsHR6LbOoG/MYyQJoN9PyjjOZwTAsvKWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fxv4SS%2FbtsHR6LbOoG%2FMYyQJoN9PyjjOZwTAsvKWk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1142&quot; height=&quot;113&quot; data-origin-width=&quot;1142&quot; data-origin-height=&quot;113&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;prototypeFind()&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;싱글톤 빈에서 프로토타입 빈을 사용할 경우, 싱글톤이 생성되는 시점에 의존 관계 주입을 받으며 프로토타입 빈이 생성되지만 싱글톤 빈과 함께 계속 유지가 된다.&lt;/li&gt;&lt;/ul&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1151&quot; data-origin-height=&quot;110&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clGlGP/btsHSudJQEg/GTxKi3XhJz6kbOuOJXQAZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clGlGP/btsHSudJQEg/GTxKi3XhJz6kbOuOJXQAZk/img.png&quot; data-alt=&quot;singletonClientUsePrototype()&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clGlGP/btsHSudJQEg/GTxKi3XhJz6kbOuOJXQAZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclGlGP%2FbtsHSudJQEg%2FGTxKi3XhJz6kbOuOJXQAZk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1151&quot; height=&quot;110&quot; data-origin-width=&quot;1151&quot; data-origin-height=&quot;110&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;singletonClientUsePrototype()&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;DL(Dependency Lookup) 의존 관계 탐색&lt;/b&gt;&lt;/h3&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Scope(&quot;singleton&quot;)
static class ClientBean {

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Autowired private ApplicationContext ac;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public int logic() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PrototypeBean prototypeBean = ac.getBean(PrototypeBean.class);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;prototypeBean.addCount();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return prototypeBean.getCount();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;DL은 싱글톤 빈이 프로토타입 빈을 사용할 때마다 컨테이너에게 새로운 요청을 한다.&lt;/li&gt;&lt;li&gt;login() 안의 ac.getBean()을 통해 항상 새로운 프로토타입 빈을 생성한다.&lt;/li&gt;&lt;li&gt;외부에서 의존 관계 주입을 받는 것이 아니라, 직접 필요에 따라 의존 관계를 탐색하는 방법이다.&lt;/li&gt;&lt;li&gt;하지만, ApplicationContext를 주입받게 되면 컨테이너에 종속적이며 단위 테스트도 하기 힘들다.&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Provider&lt;/b&gt;&lt;/h3&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;ObjectProvider&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;위의 DL의 문제점을 해결하기 위해 지정한 프로토타입 빈을 컨테이너에서 대신 찾아주는 DL 기능을 제공하는 것이다.&lt;/li&gt;&lt;li&gt;getObject() 메서드를 통해 항상 새로운 프로토타입 빈을 만들 수 있으며, 이 메서드는 컨테이너를 통해 해당 빈을 찾아 반환하는 DL 기능을 한다.&lt;/li&gt;&lt;li&gt;Spring이 제공하는 기능이며, 단순하여 단위 테스트 활용과 mock 코드 만들기에 쉽다.&lt;/li&gt;&lt;li&gt;&lt;b&gt;ObjectFactory&lt;/b&gt; : 기능이 단순하고 라이브러리가 필요 없으며 스프링에 의존한다.&lt;/li&gt;&lt;li&gt;&lt;b&gt;ObjectProvider&lt;/b&gt; : 상속, 옵션, 스트림 처리 등의 편한 기능이 많으면서 라이브러리 역시 필요 없고 스프링에 의존한다.&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1) 필드 주입 ObjectProvider&lt;/b&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Scope(&quot;singleton&quot;)
static class ClientBean {

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Autowired
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private ObjectProvider&amp;lt;PrototypeBean&amp;gt; prototypeBeanProvider;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public int logic() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PrototypeBean prototypeBean = prototypeBeanProvider.getObject();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;prototypeBean.addCount();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return prototypeBean.getCount();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2) 생성자 주입 ObjectProvider&lt;/b&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Scope(&quot;singleton&quot;)
static class ClientBean {

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private final ObjectProvider&amp;lt;PrototypeBean&amp;gt; prototypeBeanProvider;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Autowired
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public ClientBean(ObjectProvider&amp;lt;PrototypeBean&amp;gt; prototypeBeanProvider) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.prototypeBeanProvider = prototypeBeanProvider;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public int logic() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PrototypeBean prototypeBean = prototypeBeanProvider.getObject();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;prototypeBean.addCount();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return prototypeBean.getCount();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;JSR-330 Provider&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;위의 ObjectProvider는 스프링에 의존한다는 단점이 있기에, Java 표준으로 스프링이 아니여도 사용할 수 있는 JSR-330 Provider이 있다.&lt;/li&gt;&lt;li&gt;이것을 사용하려면&amp;nbsp;javax.inject:javax.inject:1&amp;nbsp;라이브러리를 추가하자.&lt;/li&gt;&lt;li&gt;get() 메서드를 통해 새로운 프로토타입 빈을 생성할 수 있으며, 이 메서드는 컨테이너를 통해 해당 빈을 찾아 반환하는 DL 기능을 한다.&lt;/li&gt;&lt;li&gt;Java 표준이며 기능이 단순하고 단위 테스트 및 mock 코드 작성에 용이하다.&lt;/li&gt;&lt;/ul&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// javax.inject:javax.inject:1 라이브러리 추가 필수
@Scope(&quot;singleton&quot;)
static class ClientBean {

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Autowired
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private Provider&amp;lt;PrototypeBean&amp;gt; prototypeBeanProvider;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public int logic() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PrototypeBean prototypeBean = prototypeBeanProvider.get();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;prototypeBean.addCount();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return prototypeBean.getCount();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ObjectProvider VS JSR-330 Provider&lt;/b&gt;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;ObjectProvider과 JSR-330 Provider는 프로토타입 뿐만이 아닌, DL 기능이 필요할 때도 사용이 가능하다.&lt;br&gt;이 둘 이외에는 스프링이 제공하는 @Lookup 어노테이션을 활용하는 방법이 있다.&lt;br&gt;이 둘은 DL을 위해 편의 기능이 많으며, 별도의 의존 관계 추가가 필요 없다.&lt;br&gt;스프링에서는 ObjectProvider, 이외에는 JSR-330 Provider를 사용해야 한다.&lt;br&gt;그래도 타 컨테이너를 사용하는 특별한 이유가 없다면 스프링이 제공하는 ObjectProvider를 사용하는 것이 좋다고 한다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;웹 스코프&lt;/b&gt;&lt;/h3&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;웹 환경에서만 동작한다.&lt;/li&gt;&lt;li&gt;프로토타입과 달리 해당 스코프 종료 시점까지 스프링이 관여한다. 즉, 종료 메서드가 호출된다.&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;웹 스코프 종류&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;request : 웹 요청이 들어오고 나갈 때까지 유지되는 스코프. 즉, HTTP 요청 하나가 들어오고 나갈 때까지 유지되는 스코프이다. 각각 HTTP 요청마다 별도의 빈 인스턴스가 생성되고 관리된다.&lt;/li&gt;&lt;li&gt;session : 웹 세션이 생성되고 종료될 때까지 유지되는 스코프. HTTP Session과 동일한 생명주기를 가지는 스코프이다.&lt;/li&gt;&lt;li&gt;application : 웹 서블릿 컨텍스트와 같은 범위(생명주기)로 유지되는 스코프&lt;/li&gt;&lt;li&gt;websocket : 웹 소켓과 동일한 생명주기를 가지는 스코프&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;request&lt;/b&gt;&lt;/h3&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;request 스코프는 클라이언트 요청에 따라, 해당 클라이언트 전용 빈 인스턴스를 생성해서 요청이 끝날 때까지 관리하는 스코프이다.&lt;/li&gt;&lt;li&gt;만약, 클라이언트 A &amp;amp; B가 동시에 요청을 보내더라도, 각각의 A &amp;amp; B 각각의 전용 빈 인스턴스를 생성하여 Service 로직을 통해 각각의 결과를 반환한다. 이때 각각의 전용 빈 객체는 소멸된다.&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;request 스코프 예제 코드&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;&lt;b&gt;MyLogger : 로그를 출력하기 위한 클래스&lt;/b&gt;&lt;/li&gt;&lt;li&gt;request 스코프는 @Scope(value = “request”)로 지정&lt;/li&gt;&lt;li&gt;HTTP 요청 당 하나씩 빈 인스턴스가 생성되며, HTTP 요청이 끝나는 시점에 빈 객체는 소멸된다.&lt;/li&gt;&lt;li&gt;빈이 생성되는 시점에 @PostConstruct 초기화 메서드를 통해 uuid를 생성하며, 다른 HTTP 요청과 구분할 수 있도록 저장한다.&lt;/li&gt;&lt;li&gt;빈이 소멸되는 시점에 @PreDestroy를 사용해서 종료 메시지를 출력한다.&lt;/li&gt;&lt;li&gt;requestURL은 외부에서 빈이 setter로 입력 받는다.&lt;/li&gt;&lt;/ul&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Component
@Scope(value = &quot;request&quot;)
public class MyLogger {

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private String uuid;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private String requestURL;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void setRequestURL(String requestURL) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.requestURL = requestURL;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void log(String message) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;[&quot; + uuid + &quot;]&quot; + &quot;[&quot; + requestURL + &quot;] &quot; + message);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@PostConstruct
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void init() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;uuid = UUID.randomUUID().toString();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;[&quot; + uuid + &quot;]&quot; + &quot;request scope bean create:&quot; + this);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@PreDestroy
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void close() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;[&quot; + uuid + &quot;]&quot; + &quot;request scope bean close:&quot; + this);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;&lt;b&gt;LogDemoController는 MyLogger 클래스가 잘 작동하는지 확인하기 위한 테스트용 컨트롤러&lt;/b&gt;&lt;/li&gt;&lt;li&gt;HttpServletRequest를 통해 요청 URL을 받는다.&lt;/li&gt;&lt;li&gt;requestURL : http://localhost:8080/log-demo&lt;/li&gt;&lt;li&gt;requestURL 값을 myLogger에 저장하며, controller test라는 로그를 출력한다.&lt;/li&gt;&lt;li&gt;requestURL을 MyLogger에 저장하는 곳은 컨트롤러보다 공통 처리가 가능한 스프링 인터셉터(Spring Interceptor)나 서블릿 필터(Servlet Filter) 같은 곳을 활용하는 것이 좋다.&lt;/li&gt;&lt;/ul&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Controller
@RequiredArgsConstructor
public class LogDemoController {

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private final LogDemoService logDemoService;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private final MyLogger myLogger;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@RequestMapping(&quot;log-demo&quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@ResponseBody
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public String logDemo(HttpServletRequest request) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String requestURL = request.getRequestURL().toString();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;myLogger.setRequestURL(requestURL);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;myLogger.log(&quot;controller test&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logDemoService.logic(&quot;testId&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return &quot;OK&quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;&lt;b&gt;LogDemoService&amp;nbsp;:&amp;nbsp;비즈니스&amp;nbsp;로직이&amp;nbsp;존재하는&amp;nbsp;서비스&amp;nbsp;계층에서도&amp;nbsp;로그를&amp;nbsp;출력하기&amp;nbsp;위한&amp;nbsp;코드&lt;/b&gt;&lt;/li&gt;&lt;li&gt;서비스 계층은 웹과 관련 없는 계층이기 때문에, 웹과 관련된 부분은 컨트롤러까지만 사용해야 한다.&lt;/li&gt;&lt;li&gt;서비스 계층은 웹 기술에 종속되지 않게 순수한 상태로 유지하는 것이 유지보수성에 좋다.&lt;/li&gt;&lt;li&gt;request scope의 MyLogger로 인해 MyLogger의 멤버 변수에 저장해서 코드와 계층을 깔끔히 유지할 수 있다.&lt;/li&gt;&lt;li&gt;하지만, 이 상태로 스프링 애플리케이션을 실행시키면 오류가 발생한다.&lt;/li&gt;&lt;li&gt;스프링 실행 시점에서, 싱글톤 빈은 생성해서 주입이 가능하지만, request 스코프 빈은 생성되지 않는다.&lt;/li&gt;&lt;li&gt;&lt;b&gt;request&amp;nbsp;스코프&amp;nbsp;빈은&amp;nbsp;실제&amp;nbsp;HTTP&amp;nbsp;요청이&amp;nbsp;올&amp;nbsp;때&amp;nbsp;생성되기&amp;nbsp;때문이다.&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Service
@RequiredArgsConstructor
public class LogDemoService {

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private final MyLogger myLogger;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void logic(String id) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;myLogger.log(&quot;service id = &quot; + id);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;웹 스코프와 Provider&lt;/b&gt;&lt;/h3&gt;&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;ObjectProvider를 통해 getObject() 메서드를 호출하는 시점까지 request scope 빈의 생성을 늦출 수 있다.&lt;/b&gt;&lt;br&gt;&lt;b&gt;getObject() 메서드 호출 시점은 HTTP 요청이 진행 중인 때이므로, request scope 빈 생성이 정상적으로 작동한다.&lt;/b&gt;&lt;b&gt;&lt;br&gt;&lt;/b&gt;따라서 스프링 실행 후, 브라우저 접속할 때마다 서로 다른 request 빈 생성 시점과 소멸의 로그를 출력할 수 있다.&lt;/blockquote&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;&lt;b&gt;LogDemoController&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Controller
@RequiredArgsConstructor
public class LogDemoController {

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private final LogDemoService logDemoService;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ObjectProvider 적용
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private final ObjectProvider&amp;lt;MyLogger&amp;gt; myLoggerProvider;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@RequestMapping(&quot;log-demo&quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@ResponseBody
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public String logDemo(HttpServletRequest request) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String requestURL = request.getRequestURL().toString();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// getObject() 메서드 : 빈 인스턴스 생성
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;MyLogger myLogger = myLoggerProvider.getObject();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;myLogger.setRequestURL(requestURL);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;myLogger.log(&quot;controller test&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;logDemoService.logic(&quot;testId&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return &quot;OK&quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;&lt;b&gt;LogDemoService&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Service
@RequiredArgsConstructor
public class LogDemoService {

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ObjectProvider 적용
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private final ObjectProvider&amp;lt;MyLogger&amp;gt; myLoggerProvider;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void logic(String id) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// getObject() 메서드 : 빈 인스턴스 생성
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;MyLogger myLogger = myLoggerProvider.getObject();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;myLogger.log(&quot;service id = &quot; + id);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;웹 스코프와 프록시&lt;/b&gt;&lt;/h3&gt;&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
 &lt;b&gt;&lt;b&gt;프록시 방식은 @Scope 어노테이션에서 proxyMode = ScopedProxyMode.TARGET_CLASS로 사용할 수 있다.&lt;br&gt;&lt;/b&gt;&lt;/b&gt; 
 &lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br&gt;ScopedProxyMode에서&lt;/b&gt;&lt;/p&gt; 
 &lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt; 
  &lt;li&gt;적용 대상이 클래스이면 TARGET_CLASS&lt;/li&gt; 
  &lt;li&gt;적용 대상이 인터페이스이면 INTERFACES&lt;/li&gt; 
 &lt;/ul&gt; 
&lt;/blockquote&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;proxyMode를 설정하면 가짜 프록시 클래스를 만들어서 HTTP request와 상관없이 가짜 프록시 클래스를 다른 빈에 request scope를 미리 주입해 둘 수 있다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;웹&amp;nbsp;스코프와&amp;nbsp;프록시&amp;nbsp;특징&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;무조건 웹 스코프가 아니어도 프록시는 사용할 수 있다.&lt;/li&gt;&lt;li&gt;Provider 방식 &amp;amp; 프록시 방식의 핵심은 객체 조회를 필요한 시점까지 지연 처리를 하는 것이다.&lt;/li&gt;&lt;li&gt;프록시 객체를 통해 클라이언트는 싱글톤 빈을 사용하듯이 편리하게 request scope를 사용할 수 있다.&lt;/li&gt;&lt;li&gt;어노테이션&amp;nbsp;설정&amp;nbsp;변경만으로&amp;nbsp;원본&amp;nbsp;객체를&amp;nbsp;프록시&amp;nbsp;객체로&amp;nbsp;대체할&amp;nbsp;수&amp;nbsp;있다.&lt;/li&gt;&lt;/ul&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Component
@Scope(value = &quot;request&quot;, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyLogger {
}&lt;/code&gt;&lt;/pre&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;Controller와 Service를 Provider를 적용하기 이전의 코드로 되돌려 놓는다.&lt;/li&gt;&lt;li&gt;그리고 MyLogger 클래스의 @Scope에 proxyMode를 추가한다.&lt;/li&gt;&lt;li&gt;단순한 설정으로 Provider를 적용한 것과 동일하게 수행한다.&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;color: #666666;&quot;&gt;따라서 위의 Provider 적용하였을 때처럼, 스프링 실행 후, 브라우저 접속할 때마다 서로 다른 request 빈 생성 시점과 소멸의 로그를 출력할 수 있다.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;웹 스코프와 프록시 동작 원리&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;proxyMode로 가짜&amp;nbsp;프록시&amp;nbsp;클래스&amp;nbsp;만들어서 다른&amp;nbsp;빈에&amp;nbsp;request&amp;nbsp;스코프&amp;nbsp;빈을&amp;nbsp;주입한다.&lt;/li&gt;&lt;/ul&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;System.out.println(&quot;myLogger.getClass() = &quot; + myLogger.getClass());&lt;/code&gt;&lt;/pre&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;출력하여 확인하면 CGLIB&amp;nbsp;라이브러리로&amp;nbsp;작성한&amp;nbsp;클래스를&amp;nbsp;상속받은&amp;nbsp;가짜&amp;nbsp;프록시&amp;nbsp;객체를&amp;nbsp;만들어&amp;nbsp;주입한다.&lt;/li&gt;&lt;/ul&gt;&lt;blockquote data-ke-style=&quot;style3&quot;&gt;myLogger.getClass() = class hello.core.common.MyLogger$$EnhancerBySpringCGLIB$$35920143&lt;/blockquote&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;MyLogger를 상속받은 가짜 프록시 객체를 생성하고 있다.&lt;/li&gt;&lt;li&gt;순수 MyLogger 클래스가 아닌 MyLogger$$EnhancerBySpringCGLIB 클래스로 만들어진 객체가 대신하여 등록되어 있다.&lt;/li&gt;&lt;li&gt;ac.getBean()&amp;nbsp;메서드를&amp;nbsp;통해&amp;nbsp;조회해도&amp;nbsp;같은&amp;nbsp;결과를&amp;nbsp;확인할&amp;nbsp;수&amp;nbsp;있다.&lt;/li&gt;&lt;li&gt;의존관계 주입 역시 가짜 프록시 객체가 주입된다.&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;가짜 프록시 객체에는 HTTP 요청이 오게 되면 이때 내부에서 진짜 빈을 요청하는 로직이 포함되어 있다.&lt;/b&gt;&lt;/blockquote&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;가짜 프록시 객체는 내부에 진짜 myLogger 클래스를 찾는 방법을 알고 있기 때문이다.&lt;/li&gt;&lt;li&gt;클라이언트가 myLogger.logic()을 호출하면 가짜 프록시 객체 메서드를 호출한 것이다.&lt;/li&gt;&lt;li&gt;이후, 가짜 프록시 객체가 request 스코프의 myLogger.logic()을 호출한다.&lt;/li&gt;&lt;li&gt;클라이언트 입장에서는 이것이 가짜 or 진짜인지 알 수 없는 상태에서 동일하게 사용할 수 있다.&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;주의점&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;마치 싱글톤을 사용하는 것 같지만 다르게 동작하므로 주의해서 사용해야 한다.&lt;/li&gt;&lt;li&gt;특별한 scope는 꼭 필요한 곳에서만 최소화해서 사용해야 하며, 무분별하게 사용할 경우 유지보수성이 낮아진다.&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;참고 자료&lt;/span&gt;&lt;br&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt; 내용 참고 : 인프런 김영한 님의 강의&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8&quot; target=&quot;_self&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&quot;스프링 핵심 원리 - 기본편&quot;&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt; &lt;/span&gt;&lt;br&gt;&lt;a href=&quot;https://catsbi.oopy.io/b2de2693-fd8c-46e3-908a-188b3dd961f3&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;https://catsbi.oopy.io/b2de2693-fd8c-46e3-908a-188b3dd961f3&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;https://daegwonkim.tistory.com/286?category=1026270&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;https://daegwonkim.tistory.com/286?category=1026270&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;https://ittrue.tistory.com/225&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;https://ittrue.tistory.com/225&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</description>
      <category>Spring</category>
      <category>Bean Scope</category>
      <category>provider</category>
      <category>spring</category>
      <category>Spring Bean</category>
      <category>빈 스코프</category>
      <category>스프링</category>
      <category>스프링 빈</category>
      <category>싱글톤</category>
      <category>웹</category>
      <category>프로토타입</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/29</guid>
      <comments>https://cloud-grace.tistory.com/entry/Spring-%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B9%88-%EC%8A%A4%EC%BD%94%ED%94%84Bean-Scope#entry29comment</comments>
      <pubDate>Sun, 9 Jun 2024 01:07:08 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] 빈 생명주기 콜백(Bean LifeCycle Callback)</title>
      <link>https://cloud-grace.tistory.com/entry/Spring-%EB%B9%88-%EC%83%9D%EB%AA%85%EC%A3%BC%EA%B8%B0-%EC%BD%9C%EB%B0%B1Bean-LifeCycle-Callback</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;빈 생명주기 콜백(Bean LifeCycle Callback)이 필요한 이유?&lt;/b&gt;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 컨테이너가 객체를 관리한다는 것은 객체가 생성하고 소멸하는 생명주기 LifeCycle를 관리한다는 것이다.&lt;br&gt;&amp;nbsp;&lt;br&gt;여기서 콜백 함수란, 특정 이벤트나 조건이 발생했을 때 호출되는 함수이다.&lt;br&gt;&amp;nbsp;&lt;br&gt;Spring 프로젝트 시작 시, DB 연결, 소켓 연결 등 시간이 걸려 미리 연결을 하고, 애플리케이션 종료 시점에 연결을 종료해야 하는 경우가 있다. 이 경우에는 객체를 초기화하고 종료하는 작업을 해줘야 한다.&lt;br&gt;예 : Connection Pool의 Connect, Disconnect&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;스프링 빈도 초기화와 종료 작업이 진행된다. 객체 생성, 의존 관계 주입의 생명주기를 가지고 있다.&lt;/b&gt;&lt;br&gt;&lt;b&gt;결국, Spring Bean은 객체 생성과 의존 관계 주입이 완료되어야 필요한 데이터를 사용할 준비가 된다.&lt;/b&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;내가 직접 어떠한 빈의 초기화 작업을 해주고 싶다면, 의존관계가 모두 주입된 이후 초기화 메서드를 호출해야 한다.&lt;br&gt;개발자가 의존 관계 주입이 완료되는 것을 알려면, 스프링이 Bean의 의존 관계 주입 이후 콜백 메서드를 활용하여 초기화 시점을 알려주는 기능을 갖추었기 때문에 이를 활용하면 된다. 또한, 소멸 역시 소멸 직전에 소멸 콜백 메서드를 활용하여 컨테이너가 종료되기 전, 로직을 수행할 수 있다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;DI 의존 관계 주입&lt;/b&gt;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://cloud-grace.tistory.com/entry/Spring-IoCInversion-of-Control-%EC%A0%9C%EC%96%B4%EC%9D%98-%EC%97%AD%EC%A0%84-DIDependency-Injection-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EB%B0%A9%EB%B2%95-3%EA%B0%80%EC%A7%80&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;&lt;b&gt;의존 관계 주입 관련 내용 포스팅&lt;/b&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;figure data-ke-type=&quot;opengraph&quot; data-og-title=&quot;[Spring] IoC(Inversion of Control 제어의 역전), DI(Dependency Injection 의존성 주입), 의존성 주입 3가지 방법&quot; data-ke-align=&quot;alignCenter&quot; data-og-description=&quot;IoC(Inversion of Control, 제어의 역전)객체 생성 및 의존성 주입 등의 제어를 개발자가 아닌 프레임워크가 담당하도록 하는 설계 원칙이다.사용할 객체를 직접 생성하지 않고, 객체 생명주기 관리를 &quot; data-og-host=&quot;cloud-grace.tistory.com&quot; data-og-source-url=&quot;https://cloud-grace.tistory.com/entry/Spring-IoCInversion-of-Control-%EC%A0%9C%EC%96%B4%EC%9D%98-%EC%97%AD%EC%A0%84-DIDependency-Injection-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EB%B0%A9%EB%B2%95-3%EA%B0%80%EC%A7%80&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Iobpk/hyWg1aNgDU/pQas9oK4LKisB4CZkaoBjK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/MZgzy/hyWhaS8wku/xoH0JCmrDPCUGWVX1rkmXK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/Q4phW/hyWljU9zMy/n6tABavkDa56nsbEpbeLZ1/img.jpg?width=420&amp;amp;height=420&amp;amp;face=0_0_420_420&quot; data-og-url=&quot;https://cloud-grace.tistory.com/entry/Spring-IoCInversion-of-Control-%EC%A0%9C%EC%96%B4%EC%9D%98-%EC%97%AD%EC%A0%84-DIDependency-Injection-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EB%B0%A9%EB%B2%95-3%EA%B0%80%EC%A7%80&quot;&gt;&lt;a href=&quot;https://cloud-grace.tistory.com/entry/Spring-IoCInversion-of-Control-%EC%A0%9C%EC%96%B4%EC%9D%98-%EC%97%AD%EC%A0%84-DIDependency-Injection-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EB%B0%A9%EB%B2%95-3%EA%B0%80%EC%A7%80&quot; target=&quot;_blank&quot; data-source-url=&quot;https://cloud-grace.tistory.com/entry/Spring-IoCInversion-of-Control-%EC%A0%9C%EC%96%B4%EC%9D%98-%EC%97%AD%EC%A0%84-DIDependency-Injection-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EB%B0%A9%EB%B2%95-3%EA%B0%80%EC%A7%80&quot;&gt;&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Iobpk/hyWg1aNgDU/pQas9oK4LKisB4CZkaoBjK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/MZgzy/hyWhaS8wku/xoH0JCmrDPCUGWVX1rkmXK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/Q4phW/hyWljU9zMy/n6tABavkDa56nsbEpbeLZ1/img.jpg?width=420&amp;amp;height=420&amp;amp;face=0_0_420_420')&quot;&gt; &lt;/div&gt;&lt;div class=&quot;og-text&quot;&gt;&lt;p class=&quot;og-title&quot;&gt;[Spring] IoC(Inversion of Control 제어의 역전), DI(Dependency Injection 의존성 주입), 의존성 주입 3가지 방법&lt;/p&gt;&lt;p class=&quot;og-desc&quot;&gt;IoC(Inversion of Control, 제어의 역전)객체 생성 및 의존성 주입 등의 제어를 개발자가 아닌 프레임워크가 담당하도록 하는 설계 원칙이다.사용할 객체를 직접 생성하지 않고, 객체 생명주기 관리를 &lt;/p&gt;&lt;p class=&quot;og-host&quot;&gt;cloud-grace.tistory.com&lt;/p&gt;&lt;/div&gt;&lt;/a&gt;&lt;/figure&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;자세한 내용은 포스팅에 담겨 있다.&lt;br&gt;&amp;nbsp;&lt;br&gt;해당 포스팅에 따라, 의존 관계를 주입하는 데에는 3가지 방법이 있다고 나와있다.&lt;br&gt;의존 관계 주입 이전에는 객체 생성이 이루어지는 데, 객체 생성과 의존 관계 주입이 3가지 방법마다 진행되는 것이 조금 다르다.&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;&lt;b&gt;수정자 주입 &amp;amp; 필드 주입 : 객체 생성 → 의존 관계 주입 (생명주기 나뉘어짐)&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;생성자 주입 : 객체 생성 &amp;amp; 의존 관계 주입 (동시에 수행됨)&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;생성자 주입이 동시에 수행되는 이유&lt;/b&gt;&lt;/h3&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;아래는 CafeService 객체에 AmericanoRecipe 객체와 의존 관계가 존재한다.&lt;/li&gt;&lt;/ul&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Service
public class CafeService {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private final AmericanoRecipe americanoRecipe;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Autowired
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public CafeService(AmericanoRecipe americanoRecipe) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.americanoRecipe = new AmericanoRecipe();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;만약, 의존 관계가 존재하지 않는다면, 아래처럼 객체 생성을 할 수 없다.&lt;/li&gt;&lt;li&gt;즉, 객체 생성과 의존 관계 주입이 동시에 일어난다.&lt;/li&gt;&lt;li&gt;이를 통해, null 주입 이외의 NullPointerException을 방지할 수 있다.&lt;/li&gt;&lt;li&gt;의존 관계 주입을 하지 않았다면 객체 생성을 할 수 없으므로 의존 관계에 대한 내용이 잘 보이고, 컴파일 단계에서 에러를 잡을 수 있다.&lt;/li&gt;&lt;/ul&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class Main {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public static void main(String[] args) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CafeService cafeService = new CafeService(new AmericanoRecipe());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// CafeService cafeService = new CafeService(); Error
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스프링 빈 이벤트 라이프 사이클&lt;/b&gt;&lt;/h3&gt;&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;스프링 컨테이너 생성 → 스프링 빈 생성 → 의존 관계 주입 → 초기화 콜백 메서드 호출 → 사용 → 소멸 전 콜백 메서드 호출 → 스프링 종료&lt;/b&gt;&lt;/blockquote&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;&lt;b&gt;초기화 콜백 : 빈 생성 및 의존 관계 주입 완료 후 호출&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;소멸 전 콜백 : 빈 소멸 직전 호출&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;객체 생성 &amp;amp; 초기화 분리&lt;/b&gt;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;생성자는 parameter를 받으며, 메모리 할당 및 객체 생성하는 책임이 있다.&lt;br&gt;초기화는 이와 같이 생성된 값을 통해 외부 연결 등의 여러 무거운 일을 수행한다. 따라서 생성과 초기화를 분리하지 않으면 SRP(단일 책임 원칙)에 어긋나기도 하여 객체 지향 및 유지 보수성을 높이기 위해서 이 둘을 분리해야 한다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스프링 빈 생명주기 콜백 관리 방법 3가지&lt;/b&gt;&lt;/h3&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. 인터페이스 InitializingBean, DisposableBean&lt;/b&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class Client implements InitializingBean, DisposableBean {

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Override
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void afterPropertiesSet() throws Exception {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Override
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void destroy() throws Exception {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;&lt;b&gt;InitializingBean : afterPropertiesSet() 메서드로 초기화 지원, 의존 관계 주입 이후 초기화 진행&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;DisposableBean : destroy() 메서드로 소멸 지원, Bean 종료 직전 마무리 작업(ex. close() 등의 자원 해제)&lt;/b&gt;&lt;/li&gt;&lt;li&gt;이 2가지 인터페이스는 Spring 전용이며, 코드들이 인터페이스에 의존한다.&lt;/li&gt;&lt;li&gt;메서드명 변경도 어렵고, 코드를 직접 변경하여 외부 라이브러리에 적용을 하지 못한다.&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. 빈 등록 초기화, 소멸 메서드&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;&lt;b&gt;스프링 빈 등록 시 사용하는 @Bean 어노테이션과 해당 속성으로 초기화 &amp;amp; 소멸 메서드 이름을 지정할 수 있다.&lt;/b&gt;&lt;/li&gt;&lt;li&gt;메서드 이름을 자유롭게 지정 가능하다.&lt;/li&gt;&lt;li&gt;스프링 코드에 의존하지 않는다.&lt;/li&gt;&lt;li&gt;외부 라이브러리에도 적용 가능하다.&lt;/li&gt;&lt;li&gt;하지만, 직접 Bean 등록 시 직접 지정해야 해서 번거롭다.&lt;/li&gt;&lt;/ul&gt;&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;@Bean(initMethod = &quot;초기화 메서드 이름&quot;, destroyMethod=&quot;소멸 메서드 이름&quot;)&lt;/b&gt;&lt;/blockquote&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Configuration
public class LifeCycleAppConfig {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Bean(initMethod = &quot;init&quot;, destroyMethod = &quot;close&quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public Client client() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Client client = new Client();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return client;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class Client{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void init() { // 초기화 콜백(의존 관계 주입 이후 호출)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void close() { // 소멸 전 콜백(연결 종료 및 메모리 해제 수행)

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;종료 메서드 추론&lt;/b&gt;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;Bean의 소멸 메서드는 주로 close, shutdown 등의 이름이 많아, 이를 소멸 메서드로 추론(inferred)하고 자동으로 호출해준다. 따로 소멸 메서드를 부여하지 않아도 된다. 추론 기능을 사용하지 않으려면 destroyMethod = &quot; &quot; 이렇게 공백으로 지정하면 된다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 어노테이션 @PostConstruct, @PreDestroy&lt;/b&gt;&lt;/h3&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;&lt;b&gt;가장 권장하는 방법이며, 초기화 메서드에 @PostConstruct, 소멸 메서드에 @PreDestroy 어노테이션을 각각 지정하면 되기 때문에 매우 편하다.&lt;/b&gt;&lt;/li&gt;&lt;li&gt;이는 스프링 종속이 아닌 자바 표준이다.&lt;/li&gt;&lt;li&gt;외부 라이브러리 적용은 불가능하다.&lt;/li&gt;&lt;/ul&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class Client{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@PostConstruct
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void init() { // 초기화 콜백(의존 관계 주입 이후 호출)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@PreDestroy
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void close() { // 소멸 전 콜백(연결 종료 및 메모리 해제 수행)

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;참고 자료&lt;/span&gt;&lt;br&gt;내용 참고 : 인프런 김영한 님의 강의&amp;nbsp;&lt;a href=&quot;https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8&quot; target=&quot;_self&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&quot;스프링 핵심 원리 - 기본편&quot;&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;https://daegwonkim.tistory.com/284&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;https://daegwonkim.tistory.com/284&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;https://catsbi.oopy.io/3a9e3492-f511-483d-bc65-183bb0c166b3&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;https://catsbi.oopy.io/3a9e3492-f511-483d-bc65-183bb0c166b3&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;https://dev-coco.tistory.com/170&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;https://dev-coco.tistory.com/170&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</description>
      <category>Spring</category>
      <category>bean</category>
      <category>bean lifecycle</category>
      <category>spring</category>
      <category>Spring Bean</category>
      <category>빈 생명주기</category>
      <category>빈 생명주기 콜백</category>
      <category>스프링</category>
      <category>스프링 빈</category>
      <category>콜백 함수</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/28</guid>
      <comments>https://cloud-grace.tistory.com/entry/Spring-%EB%B9%88-%EC%83%9D%EB%AA%85%EC%A3%BC%EA%B8%B0-%EC%BD%9C%EB%B0%B1Bean-LifeCycle-Callback#entry28comment</comments>
      <pubDate>Sat, 8 Jun 2024 22:36:12 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] 컴포넌트 스캔(Component Scan)</title>
      <link>https://cloud-grace.tistory.com/entry/Spring-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%8A%A4%EC%BA%94Component-Scan</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;컴포넌트 스캔&lt;/b&gt;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;@Component를 가진 모든 대상을 가져와 Bean에 등록하기 위해 찾는 과정을 말한다. 즉, 빈 설정 파일과 @Bean을 통해 빈을 일일이 지정할 필요가 없다. 즉, 명시적인 등록과 달리, 자동으로 빈을 등록하는 방법이다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. xml 파일에 설정하기&lt;/b&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;html&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;&amp;lt;context:component-scan base-package=&quot;com.dx&quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. Java 파일 안에서 설정하기 (*실무에서 많이 쓰는 방법)&lt;/b&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Configuration
@ComponentScan(basePackages = &quot;com.dx&quot;)
public class AppConfig {
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;컴포넌트 스캔 대상&lt;/b&gt;&lt;/h3&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;@Component : 컴포넌트 스캔에서 사용한다.&lt;/li&gt;&lt;li&gt;@Controller : Spring MVC Controller에서 사용한다.&lt;/li&gt;&lt;li&gt;@Service : Spring Business 로직에서 사용한다.&lt;/li&gt;&lt;li&gt;@Repository : Spring Data Access 계층에서 사용한다.&lt;/li&gt;&lt;li&gt;@Configuration : Spring 설정 정보에서 사용한다.&lt;/li&gt;&lt;li&gt;아래 클래스 코드를 살펴보면 @Component를 포함하고 있다. (*이 상속 관계는 Spring 지원 기능, Java의 문법 X)&lt;/li&gt;&lt;/ul&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Component
public @interface Controller {

}

@Component
public @interface Repository {

}

@Component
public @interface Configuration {

}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;@ComponentScan&lt;/b&gt;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;이 어노테이션이 있는 파일의 패키지 아래를 스캔한다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;탐색 위치&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;basePackages를 사용하면 탐색할 패키지 시작 위치를 지정한다.&lt;/li&gt;&lt;li&gt;이 패키지를 포함하여 하위 패키지를 모두 탐색한다.&lt;/li&gt;&lt;li&gt;basePackageClasses를 사용하면 지정한 클래스가 있는 패키지를 시작 패키지로 설정한다.&lt;/li&gt;&lt;/ul&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;Java&quot; data-ke-language=&quot;Java&quot;&gt;&lt;code&gt;@ComponentScan (
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;basePackages = &quot;com.dx.springEx&quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// basePackages = {&quot;com.dx.springEx01&quot;, &quot;com.dx.springEx02&quot;} 여러 개도 지정 가능하다.
)&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;권장 방법&lt;/b&gt;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;구성 파일에 등록한다면 패키지 위치를 지정하지 않고, 설정 정보 클래스 위치를 Project 최상단에 둔다.&lt;br&gt;만약, Spring Boot를 사용한다면 @SpringBootApplication 안에 @ComponentScan이 포함되어 있으므로 자동으로 최상단으로 유지가 된다.&lt;br&gt;&amp;nbsp;&lt;br&gt;만약, 프로젝트 구조가 아래와 같다면,&lt;br&gt;1) com.dx&lt;br&gt;2) com.dx.service&lt;br&gt;3) com.dx.controller&lt;br&gt;4) com.dx.repository&lt;br&gt;~~~&lt;br&gt;1)번인 com.dx가 프로젝트 시작 루트이다. 이 위치에 AppConfig.java 로의 설정 정보 파일을 두고, @ComponentScan을 설정하면 된다. 결국 com.hello를 포함한 하위 패키지는 모두 컴포넌트 스캔의 대상이 된다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt; @Autowired &lt;/b&gt;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;이 어노테이션을 활용하여 생성자에 지정하면 스프링 컨테이너가 자동으로 조건에 맞는 Type을 찾아 의존성 주입을 자동으로 해준다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;필터&lt;/b&gt;&lt;/h3&gt;&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;&lt;li&gt;includeFilters : 컴포넌트 스캔 대상을 추가로 지정한다.&lt;/li&gt;&lt;li&gt;excludeFilters : 컴포넌트 스캔에서 제외할 대상을 지정한다.&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;필터 등록 방법&lt;/b&gt;&lt;/h3&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. 커스텀 어노테이션 정의&lt;/b&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// 컴포넌트 스캔 대상에 추가
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyIncludeComponent {
}

// 컴포넌트 스캔 대상에서 제외
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyExcludeComponent {
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. 커스텀 어노테이션 대상 클래스에 적용&lt;/b&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@MyIncludeComponent
public class ExampleA { // 컴포넌트 스캔 대상에서 추가
}

@MyExcludeComponent
public class ExampleB { // 컴포넌트 스캔 대상에서 제외
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3. 컴포넌트 스캔 필터 설정&lt;/b&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Configuration
@ComponentScan(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyExcludeComponent.class),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;includeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyIncludeComponent.class))
static class ComponentFilterAppConfig {

}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;4. 테스트 코드&lt;/b&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class ComponentFilterAppConfigTest {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Test
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void filterScan() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 애플리케이션 컨텍스트 로드
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ApplicationContext ac = new AnnotationConfigApplicationContext(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ComponentFilterAppConfig.class);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ExampleA 타입의 빈을 가져온다.
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ExampleA exampleA = ac.getBean(ExampleA.class);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ExampleB 타입의 빈을 가져오려고 시도할 때 발생하는 예외를 캡처한다.
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Throwable throwable = Assertions.catchThrowable(() -&amp;gt; ac.getBean(ExampleB.class));

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ExampleA 빈이 컨텍스트에 존재함을 확인한다.
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Assertions.assertThat(exampleA).isNotNull();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// ExampleB 빈을 가져올 때 NoSuchBeanDefinitionException이 발생했음을 확인한다.
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Assertions.assertThat(throwable).isInstanceOf(NoSuchBeanDefinitionException.class);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;참고 자료&lt;/span&gt;&lt;br&gt;내용 참고 : 인프런 김영한 님의 강의 &lt;a href=&quot;https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8&quot; target=&quot;_self&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&quot;스프링 핵심 원리 - 기본편&quot;&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;https://blogshine.tistory.com/217&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;https://blogshine.tistory.com/217&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;https://velog.io/@hyun-jii/%EC%8A%A4%ED%94%84%EB%A7%81-component-scan-%EA%B0%9C%EB%85%90-%EB%B0%8F-%EB%8F%99%EC%9E%91-%EA%B3%BC%EC%A0%95&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;https://velog.io/@hyun-jii/%EC%8A%A4%ED%94%84%EB%A7%81-component-scan-%EA%B0%9C%EB%85%90-%EB%B0%8F-%EB%8F%99%EC%9E%91-%EA%B3%BC%EC%A0%95&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;br&gt;&lt;a href=&quot;https://velog.io/@neity16/Spring-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8-6-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%8A%A4%EC%BA%94Component-Scan-DI&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;https://velog.io/@neity16/Spring-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8-6-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%8A%A4%EC%BA%94Component-Scan-DI&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring</category>
      <category>bean</category>
      <category>Component</category>
      <category>Component Scan</category>
      <category>Configuration</category>
      <category>spring</category>
      <category>스프링</category>
      <category>컴포넌트 스캔</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/27</guid>
      <comments>https://cloud-grace.tistory.com/entry/Spring-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%8A%A4%EC%BA%94Component-Scan#entry27comment</comments>
      <pubDate>Sat, 8 Jun 2024 16:04:15 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] 스프링 싱글톤 컨테이너(Singleton Container)</title>
      <link>https://cloud-grace.tistory.com/entry/Spring-%EC%8A%A4%ED%94%84%EB%A7%81-%EC%8B%B1%EA%B8%80%ED%86%A4-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88Singleton-Container</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;싱글톤이 등장한 배경&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링은 엔터프라이즈 웹 애플리케이션 기술을 지원하는 프레임워크이다. 주로 여러 클라이언트가 동시에 요청을 한다. 요청이 들어올 때마다 새로운 객체를 생성하는 것은 비효율적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;싱글톤 패턴&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://cloud-grace.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EC%8B%B1%EA%B8%80%ED%86%A4-%ED%8C%A8%ED%84%B4Singleton-Pattern&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;싱글톤 패턴 포스팅 링크&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1717648407511&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[디자인 패턴] 싱글톤 패턴(Singleton Pattern)&quot; data-og-description=&quot;싱글톤 패턴(Singleton Pattern)이란?싱글톤 패턴은 디자인 패턴(Design Pattern) 중 생성 패턴(Creational Pattern)이다.생성 패턴 : 객체의 생성과 관련된 패턴이며, 객체의 생성 절차를 추상화하는 패턴객체&quot; data-og-host=&quot;cloud-grace.tistory.com&quot; data-og-source-url=&quot;https://cloud-grace.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EC%8B%B1%EA%B8%80%ED%86%A4-%ED%8C%A8%ED%84%B4Singleton-Pattern&quot; data-og-url=&quot;https://cloud-grace.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EC%8B%B1%EA%B8%80%ED%86%A4-%ED%8C%A8%ED%84%B4Singleton-Pattern&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bXDTyN/hyWg3Mt4Cn/QFSEj5nL2BJwRQkpH0h5gk/img.png?width=800&amp;amp;height=474&amp;amp;face=0_0_800_474,https://scrap.kakaocdn.net/dn/5SQqs/hyWg6bnYMp/1khloyhbv44EeOSlUZQ7ZK/img.png?width=800&amp;amp;height=474&amp;amp;face=0_0_800_474,https://scrap.kakaocdn.net/dn/31yOz/hyWg2fLBXL/4a9poWR8VZCzOCqOrK2GfK/img.jpg?width=420&amp;amp;height=420&amp;amp;face=0_0_420_420&quot;&gt;&lt;a href=&quot;https://cloud-grace.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EC%8B%B1%EA%B8%80%ED%86%A4-%ED%8C%A8%ED%84%B4Singleton-Pattern&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cloud-grace.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EC%8B%B1%EA%B8%80%ED%86%A4-%ED%8C%A8%ED%84%B4Singleton-Pattern&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bXDTyN/hyWg3Mt4Cn/QFSEj5nL2BJwRQkpH0h5gk/img.png?width=800&amp;amp;height=474&amp;amp;face=0_0_800_474,https://scrap.kakaocdn.net/dn/5SQqs/hyWg6bnYMp/1khloyhbv44EeOSlUZQ7ZK/img.png?width=800&amp;amp;height=474&amp;amp;face=0_0_800_474,https://scrap.kakaocdn.net/dn/31yOz/hyWg2fLBXL/4a9poWR8VZCzOCqOrK2GfK/img.jpg?width=420&amp;amp;height=420&amp;amp;face=0_0_420_420');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[디자인 패턴] 싱글톤 패턴(Singleton Pattern)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;싱글톤 패턴(Singleton Pattern)이란?싱글톤 패턴은 디자인 패턴(Design Pattern) 중 생성 패턴(Creational Pattern)이다.생성 패턴 : 객체의 생성과 관련된 패턴이며, 객체의 생성 절차를 추상화하는 패턴객체&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cloud-grace.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;싱글톤 패턴에 대한 자세한 내용은 위 포스팅을 참고하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;싱글톤 예제 코드&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구현 방법은 여러 가지이지만, 객체를 미리 생성해두는 가장 단순하면서도 안전한 방법을 이용하자.&lt;/li&gt;
&lt;li&gt;Singleton 클래스 안에서 private static final으로 미리 객체를 생성하고 이를 참조하는 instance 변수를 만든다.&lt;/li&gt;
&lt;li&gt;static 영역에 딱 1개의 인스턴스만 생성된다.&lt;/li&gt;
&lt;li&gt;getInstance()로 외부에서 인스턴스를 조회한다.&lt;/li&gt;
&lt;li&gt;외부에서 new로 객체 생성을 막도록 private 생성자를 만든다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717649741339&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Singleton {
    private static final Singleton instance = new Singleton();

    public static Singleton getInstance() {
        return instance;
    }

    private Singleton() {
        System.out.println(&quot;Singleton 객체 생성&quot;);
    }

    public void logic() {
        System.out.println(&quot;Singleton 객체 로직 호출&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Singleton 인스턴스 호출 시 두 객체가 같은지 테스트 한다.&lt;/li&gt;
&lt;li&gt;이렇게 싱글톤 패턴은 여러 요청이 들어왔을 때 객체 생성을 하는 것이 아닌, 이미 만들어진 객체를 공유하여 효율적으로 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717650053019&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import static org.junit.jupiter.api.Assertions.assertSame;
import org.junit.jupiter.api.Test;

public class SingletonTest {

    @Test
    public void testSingletonInstance() {
        // 싱글톤 객체
        Singleton instance1 = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();

        // 같은 객체인지 확인
        assertSame(instance1, instance2, &quot;두 객체는 같습니다.&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;싱글톤 패턴의 문제점&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;싱글톤 코드 구현 자체가 많고, 구체 클래스에 의존하여 DIP, OCP에 위반된다.&lt;/li&gt;
&lt;li&gt;테스트를 유연하게 하기 어렵고, 내부 속성을 바꾸고 초기화하기도 어렵다.&lt;/li&gt;
&lt;li&gt;private 생성자로는 자식 클래스를 만들기에 어렵다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스프링 싱글톤 컨테이너&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1089&quot; data-origin-height=&quot;544&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/erSGsC/btsHQRfcyX3/JMKrxlMi6ygKb5D52yEQO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/erSGsC/btsHQRfcyX3/JMKrxlMi6ygKb5D52yEQO1/img.png&quot; data-alt=&quot;출처 : 인프런 김영한님 강의 [스프링 핵심 원리 - 기본편]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/erSGsC/btsHQRfcyX3/JMKrxlMi6ygKb5D52yEQO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FerSGsC%2FbtsHQRfcyX3%2FJMKrxlMi6ygKb5D52yEQO1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;672&quot; height=&quot;336&quot; data-origin-width=&quot;1089&quot; data-origin-height=&quot;544&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 인프런 김영한님 강의 [스프링 핵심 원리 - 기본편]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스프링 컨테이너(Spring Container)는 싱글톤 패턴의 문제점을 해결하면서도 객체 인스턴스를 1개만 생성하여 관리할 수 있다.&lt;/li&gt;
&lt;li&gt;스프링 빈(Spring Bean)이 싱글톤으로 관리된다.&lt;/li&gt;
&lt;li&gt;즉, 싱글톤 패턴을 적용하지 않아도 객체 인스턴스를 싱글톤으로 관리한다.&lt;/li&gt;
&lt;li&gt;싱글톤 컨테이너 역할을 하며, 싱글톤 객체를 생성하고 관리하는 기능을 싱글톤 레지스트리라고 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;고객의 요청이 올 때마다 객체를 생성하는 것이 아닌, 이미 만들어진 객체를 공유하여 재사용할 수 있어 효율적이다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;스프링의 기본 빈 등록은 싱글톤 방식을 활용하지만, 요청할 때마다 새로운 객체를 생성하여 반환할 수 있는 Prototype Scope, Web 관련 Scope 등의 방식도 있다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;스프링 싱글톤 컨테이너 Test&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1717652541107&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import singleton.AppConfig;
import singleton.ExampleService;

public class SingletonTest {

    @Test
    @DisplayName(&quot;스프링 싱글톤 컨테이너 Test&quot;)
    void springContainer() {
        ApplicationContext appConfig= new AnnotationConfigApplicationContext(AppConfig.class);
        ExampleService exampleService1 = appConfig.getBean(ExampleService.class);
        ExampleService exampleService2 = appConfig.getBean(ExampleService.class);

        System.out.println(&quot;exampleService1 : &quot; + exampleService1);
        System.out.println(&quot;exampleService2 : &quot; + exampleService2);

        Assertions.assertThat(exampleService1).isSameAs(exampleService2);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Test 결과&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1242&quot; data-origin-height=&quot;317&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XxxvA/btsHO1wZVLU/m86LV1BvHdAjuALI11GA51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XxxvA/btsHO1wZVLU/m86LV1BvHdAjuALI11GA51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XxxvA/btsHO1wZVLU/m86LV1BvHdAjuALI11GA51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXxxvA%2FbtsHO1wZVLU%2Fm86LV1BvHdAjuALI11GA51%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1242&quot; height=&quot;317&quot; data-origin-width=&quot;1242&quot; data-origin-height=&quot;317&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;싱글톤 관련 코드를 따로 작성하지 않았지만 스프링 컨테이너가 빈을 싱글톤으로 관리하는 것을 알 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&amp;lt;Test 결과&amp;gt;&lt;br /&gt;exampleService1&amp;nbsp;:&amp;nbsp;singleton.ExampleService@5e21e98f &lt;br /&gt;exampleService2&amp;nbsp;:&amp;nbsp;singleton.ExampleService@5e21e98f&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;싱글톤 방식 주의할 점&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;싱글톤 객체는 전역에서 공유되므로 멀티쓰레드 환경의 동시성 문제가 있다.&lt;/li&gt;
&lt;li&gt;메모리 Heap 영역에서 프로세스 전체에 공유된다.&lt;/li&gt;
&lt;li&gt;동시성 문제로 인해 발생하는 문제가 많기 때문에 객체 상태를 Stateful하게 설계하면 안된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;무상태(Stateless)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;stateful로 상태를 유지하지 않는다.&lt;/li&gt;
&lt;li&gt;읽기만 가능하도록 하는 것이 좋다.&lt;/li&gt;
&lt;li&gt;특정 Client에 의존적이거나 값을 바꿀 수 있는 field가 없어야 한다.&lt;/li&gt;
&lt;li&gt;field 말고 지역 변수, 파라미터, ThreadLocal 등을 사용해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;무상태 설계를 실패한 예제 코드&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 클라이언트가 주문을 요청하고, price 필드가 공유되는데 변경될 때 A의 price가 20000으로 출력되는 예제 코드이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717653540372&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.stereotype.Component;

@Component
public class ExampleService {
    private int price; // Stateful price

    public int getPrice() {
        return price;
    }

    public void order(String name, int price) {
        System.out.println(&quot;name: &quot; + name + &quot; price: &quot; + price);
        this.price = price; // 문제 발생(특정 클라이언트로 인해 가격 값이 변경된다.)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1717653578225&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import singleton.AppConfig;
import singleton.ExampleService;

public class StatefulTest {

    @Test
    @DisplayName(&quot;Stateful Test&quot;)
    void springContainer() {
        ApplicationContext appConfig= new AnnotationConfigApplicationContext(AppConfig.class);
        ExampleService exampleService1 = appConfig.getBean(ExampleService.class);
        ExampleService exampleService2 = appConfig.getBean(ExampleService.class);

        exampleService1.order(&quot;A&quot;, 10000);
        exampleService2.order(&quot;B&quot;, 20000);

        int price = exampleService1.getPrice();
        System.out.println(&quot;A의 price: &quot; + price);

        Assertions.assertThat(exampleService1.getPrice()).isEqualTo(20000);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;A의 price가 20000으로 출력된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;296&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjajNI/btsHRoX1t5q/SKHaIN69MYPCxkdKQKBLS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjajNI/btsHRoX1t5q/SKHaIN69MYPCxkdKQKBLS1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjajNI/btsHRoX1t5q/SKHaIN69MYPCxkdKQKBLS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjajNI%2FbtsHRoX1t5q%2FSKHaIN69MYPCxkdKQKBLS1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;602&quot; height=&quot;296&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;296&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다같이 공유되는 변수를 제고하고, 해당 메서드 내에서만 지역 변수를 사용할 수 있도록 바꿔야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;@Configuration과 바이트 코드 조작&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;710&quot; data-origin-height=&quot;377&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s50N6/btsHRnx26nP/3gMQSI2FkWa4kQDsxQqqfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s50N6/btsHRnx26nP/3gMQSI2FkWa4kQDsxQqqfK/img.png&quot; data-alt=&quot;출처 : 인프런 김영한님 강의 [스프링 핵심 원리 - 기본편]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s50N6/btsHRnx26nP/3gMQSI2FkWa4kQDsxQqqfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs50N6%2FbtsHRnx26nP%2F3gMQSI2FkWa4kQDsxQqqfK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;530&quot; height=&quot;281&quot; data-origin-width=&quot;710&quot; data-origin-height=&quot;377&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 인프런 김영한님 강의 [스프링 핵심 원리 - 기본편]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@Configuration : 설정 파일을 만드는 어노테이션이며 Bean을 등록한다.&lt;/li&gt;
&lt;li&gt;@Configuration을 적용한 AppConfig는 바이트 코드를 조작한 CGLIB라는 라이브러리를 활용하여 AppConfig를 상속받은 임의의 클래스를 만들며, 그것을 스프링 빈으로 등록한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;hello.core.AppConfig$$EnhancedBySpring&lt;b&gt;CGLIB&lt;/b&gt;$$pc917d12&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@Configuration을 사용하지 않고 @Bean만 사용하면 빈 등록은 되지만 싱글톤 보장은 되지 않는다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;즉, @Configuration을 설정할 때 사용해야 싱글톤을 보장받을 수 있다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;참고 자료&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt; &lt;span style=&quot;text-align: start;&quot;&gt;이미지 출처 및 내용 참고 : 인프런 김영한 님의 강의&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8&quot;&gt;&quot;스프링 핵심 원리 - 기본편&quot;&lt;/a&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://scoring.tistory.com/entry/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EC%8B%B1%EA%B8%80%ED%86%A4-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-Configuration&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://scoring.tistory.com/entry/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EC%8B%B1%EA%B8%80%ED%86%A4-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-Configuration&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://velog.io/@syleemk/Spring-Core-%EC%8B%B1%EA%B8%80%ED%86%A4-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://velog.io/@syleemk/Spring-Core-%EC%8B%B1%EA%B8%80%ED%86%A4-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://dream-and-develop.tistory.com/419&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dream-and-develop.tistory.com/419&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Spring</category>
      <category>Configuration</category>
      <category>singleton container</category>
      <category>spring</category>
      <category>스프링</category>
      <category>스프링 싱글톤 컨테이너</category>
      <category>스프링 컨테이너</category>
      <category>싱글톤</category>
      <category>싱글톤 컨테이너</category>
      <category>싱글톤 패턴</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/26</guid>
      <comments>https://cloud-grace.tistory.com/entry/Spring-%EC%8A%A4%ED%94%84%EB%A7%81-%EC%8B%B1%EA%B8%80%ED%86%A4-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88Singleton-Container#entry26comment</comments>
      <pubDate>Thu, 6 Jun 2024 15:22:44 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] POJO(Plain Old Java Object)란?</title>
      <link>https://cloud-grace.tistory.com/entry/Spring-POJOPlain-Old-Java-Object%EB%9E%80</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;POJO(Plain Old Java Object)란?&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;319&quot; data-origin-height=&quot;283&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/x24QD/btsHPbMZIyP/oak23H0p8YgQ4nxwPnsuxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/x24QD/btsHPbMZIyP/oak23H0p8YgQ4nxwPnsuxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/x24QD/btsHPbMZIyP/oak23H0p8YgQ4nxwPnsuxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fx24QD%2FbtsHPbMZIyP%2Foak23H0p8YgQ4nxwPnsuxk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;319&quot; height=&quot;283&quot; data-origin-width=&quot;319&quot; data-origin-height=&quot;283&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 포스팅에서 스프링의 삼각형으로 이루어진 스프링의 3대 요소 IoC/DI, AOP, PSA에 대해 알아보았다. 그럼 중앙에 있는 POJO는 무엇일까? 위 그림처럼 &lt;b&gt;POJO는 3대 요소를 통해 POJO를 달성할 수 있다&lt;/b&gt;는 의미이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;POJO는 Plain Old Java Object의 약자이며, 말 그대로 &lt;b&gt;오래된 방식의 간단한 자바 객체&lt;/b&gt;이다. 즉, 자바로 만드는 순수한 객체를 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중량 프레임워크들을 사용하게 되면서 해당 프레임워크에 종속된 &quot;무거운&quot; 객체를 만들게 된 것에 반발하여 사용되었으며, 2009년 9월, 마틴 파울러 등이 사용하기 시작하였고, 아래와 같이 기원을 밝히고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt; &lt;span style=&quot;background-color: #ffffff; color: #202122; text-align: start;&quot;&gt;우리는 사람들이 자기네 시스템에 보통의 객체를 사용하는 것을 왜 그렇게 반대하는지 궁금하였는데,&lt;br /&gt;간단한 객체는 폼 나는 명칭이 없기 때문에 그랬던 것이라고 결론지었다.&lt;br /&gt;그래서 적당한 이름을 하나 만들어 붙였더니, 아 글쎄, 다들 좋아하더라고.&lt;/span&gt; &lt;br /&gt;&lt;span style=&quot;background-color: #ffffff; color: #202122; text-align: right;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;mdash; 마틴 파울러&lt;/span&gt; &lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;POJO라는 용어는 이후 특정 자바 모델, 기능, 프레임워크 등을 따르지 않은 자바 오브젝트를 지칭하는 말로 쓰이게 되었다. 다시 말해, 특정 기술을 사용하기 위해 특정 프레임워크를 의존하게 되면 그것은 POJO라고 할 수 없다. 특정 기술에 종속되어 있기 때문이다. &lt;b&gt;Spring은 POJO 방식의 프레임워크이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. POJO 예제 코드&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아래 코드는 getter와 setter만 가지고 있는 기본적인 형태의 Java 객체이며, POJO이다.&lt;/li&gt;
&lt;li&gt;특정 기술에 종속되어 있지 않은 순수 자바 객체이므로 POJO라고 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717601537103&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class User {
    private String name;
    private String id;
    private String password;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. POJO가 아닌, 특정 기술에 종속적인 예제 코드&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아래 코드는 Java Servlet API를 사용하여 작성된 Servlet 클래스이며, POJO가 아니다.&lt;/li&gt;
&lt;li&gt;특정 API에 종속적이고, 특정 규약을 따라야 하며, 특정 라이프사이클 메서드를 구현해야 하기 때문이다.&lt;/li&gt;
&lt;li&gt;Java Servlet 코드를 작성할 때는 반드시 HttpServlet를 상속받아야 하며, 타 상속이 추가될 수 없어 객체 지향적 설계가 어렵고, HttpServlet의 어떤 기능을 어떻게 재사용할지 판단하기가 어렵다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717602340184&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HelloServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType(&quot;text/html&quot;);
        resp.getWriter().println(&quot;&amp;lt;h1&amp;gt;Hello, World!&amp;lt;/h1&amp;gt;&quot;);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // Post request handling logic
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;POJO 프레임워크&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;POJO 프레임워크는 POJO의 장점과 EJB(Enterprise Java Bean)의 엔터프라이즈 서비스 및 기술을 모두 사용할 수 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;EJB(Enterprise Java Bean)&lt;/b&gt; : 과거, 엔터프라이즈급 애플리케이션 개발을 단순화하기 위해 사용했던 스펙이다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 하이버네이트(Hibernate)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hibernate는 Java 기반의 ORM(Object-Relational Mapping) 프레임워크로, POJO를 데이터베이스 테이블에 매핑한다. POJO 엔티티들은 SQL 쿼리를 직접 작성할 필요 없이 객체 지향 방식으로 DB 작업을 수행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나, 특정 기술에 종속적이면 POJO가 아니다. POJO라고 할 수 있는 이유는 스프링에서 Hibernate를 쓸 때 스프링에서 정한 표준 인터페이스가 있기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ORM을 사용하기 위해 JPA라는 표준 인터페이스를 정해두었으며, ORM 프레임워크 중 하나인 Hibernate는 스프링에 기술로 쓰이면서도 POJO를 유지할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 스프링(Spring)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring은 POJO 방식의 프레임워크이다. 다른 환경 및 기술에 종속적이지 않도록 Spring에서는 IoC/DI, AOP, PSA를 지원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;POJO 프로그래밍 장점&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;객체 지향적인 설계&lt;/b&gt;를 무한하게 적용 가능하다.&lt;/li&gt;
&lt;li&gt;저수준 레벨 기술 및 환경에 종속적인 코드를 없애 간결한 코드를 갖고, 디버깅에도 용이해진다.&lt;/li&gt;
&lt;li&gt;종속적이지 않으면 재사용성, 확장 가능성, 유연성이 높아지며, &lt;b&gt;테스트가 단순해진다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;POJO의 정의(by 토비의 스프링)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;그럼 특정 기술규약과 환경에 종속되지 않으면 모두 POJO라고 말할 수 있는가?&lt;br /&gt;많은 개발자가 크게 오해하는 것 중의 하나가 바로 이것이다.&lt;br /&gt;&lt;br /&gt;... (중략) ...&amp;nbsp;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;진정한 POJO란 객체지향적인 원리에 충실하면서,&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;환경과 기술에 종속되지 않고 필요에 따라 재활용될 수 있는 방식으로 설계된 오브젝트를 말한다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;참고 자료&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://yoo11052.tistory.com/133&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://yoo11052.tistory.com/133&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://dev-coco.tistory.com/82&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dev-coco.tistory.com/82&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://ittrue.tistory.com/211&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://ittrue.tistory.com/211&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Spring</category>
      <category>hibernate</category>
      <category>Java</category>
      <category>plain old java object</category>
      <category>POJO</category>
      <category>spring</category>
      <category>Spring Framework</category>
      <category>스프링</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/25</guid>
      <comments>https://cloud-grace.tistory.com/entry/Spring-POJOPlain-Old-Java-Object%EB%9E%80#entry25comment</comments>
      <pubDate>Thu, 6 Jun 2024 01:03:40 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] 스프링의 삼각형(IoC/DI, AOP, PSA)</title>
      <link>https://cloud-grace.tistory.com/entry/Spring-%EC%8A%A4%ED%94%84%EB%A7%81%EC%9D%98-%EC%82%BC%EA%B0%81%ED%98%95-IoCDI-AOP-PSA</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스프링의 삼각형, 3대 요소(Spring Triangle)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링의 삼각형(Spring Triangle), 즉, 스프링의 핵심 3요소가 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;319&quot; data-origin-height=&quot;283&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PF06N/btsHQkhGjPL/o1I4q0y0oJlAHo0ISLleUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PF06N/btsHQkhGjPL/o1I4q0y0oJlAHo0ISLleUk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PF06N/btsHQkhGjPL/o1I4q0y0oJlAHo0ISLleUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPF06N%2FbtsHQkhGjPL%2Fo1I4q0y0oJlAHo0ISLleUk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;319&quot; height=&quot;283&quot; data-origin-width=&quot;319&quot; data-origin-height=&quot;283&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. IoC/DI&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IoC란 제어의 역전으로 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;스프링 컨테이너가 객체에 대한 제어권&lt;/b&gt;&lt;/span&gt;을 가지고 있는 것이며, DI는 의존 관계 주입으로 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;의존 관계를 외부에서 결정하는 것&lt;/b&gt;&lt;/span&gt;을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IoC/DI 예제 코드 및 의존성 주입 3가지 방법 등에 대한 자세한 내용은 아래 포스팅에서 작성했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;background-color: #e6f5ff; color: #0070d1; text-align: start;&quot; href=&quot;https://cloud-grace.tistory.com/entry/Spring-IoCInversion-of-Control-%EC%A0%9C%EC%96%B4%EC%9D%98-%EC%97%AD%EC%A0%84-DIDependency-Injection-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EB%B0%A9%EB%B2%95-3%EA%B0%80%EC%A7%80&quot;&gt;IoC/DI 포스팅 링크&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1717574695810&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Spring] IoC(Inversion of Control 제어의 역전), DI(Dependency Injection 의존성 주입), 의존성 주입 3가지 방법&quot; data-og-description=&quot;IoC(Inversion of Control, 제어의 역전)객체 생성 및 의존성 주입 등의 제어를 개발자가 아닌 프레임워크가 담당하도록 하는 설계 원칙이다.사용할 객체를 직접 생성하지 않고, 객체 생명주기 관리를 &quot; data-og-host=&quot;cloud-grace.tistory.com&quot; data-og-source-url=&quot;https://cloud-grace.tistory.com/entry/Spring-IoCInversion-of-Control-%EC%A0%9C%EC%96%B4%EC%9D%98-%EC%97%AD%EC%A0%84-DIDependency-Injection-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EB%B0%A9%EB%B2%95-3%EA%B0%80%EC%A7%80&quot; data-og-url=&quot;https://cloud-grace.tistory.com/entry/Spring-IoCInversion-of-Control-%EC%A0%9C%EC%96%B4%EC%9D%98-%EC%97%AD%EC%A0%84-DIDependency-Injection-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EB%B0%A9%EB%B2%95-3%EA%B0%80%EC%A7%80&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/fvI5N/hyWg1AUcXe/hoeOwNSL0PpuedC94KKkCK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/r3inB/hyWg7ODHG6/SF3vkm05ZZRPlf5OOF0oSK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bAFwVq/hyWgXkYnM0/1743M1HRKz1QVWIetqj6u0/img.jpg?width=420&amp;amp;height=420&amp;amp;face=0_0_420_420&quot;&gt;&lt;a href=&quot;https://cloud-grace.tistory.com/entry/Spring-IoCInversion-of-Control-%EC%A0%9C%EC%96%B4%EC%9D%98-%EC%97%AD%EC%A0%84-DIDependency-Injection-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EB%B0%A9%EB%B2%95-3%EA%B0%80%EC%A7%80&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cloud-grace.tistory.com/entry/Spring-IoCInversion-of-Control-%EC%A0%9C%EC%96%B4%EC%9D%98-%EC%97%AD%EC%A0%84-DIDependency-Injection-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EB%B0%A9%EB%B2%95-3%EA%B0%80%EC%A7%80&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/fvI5N/hyWg1AUcXe/hoeOwNSL0PpuedC94KKkCK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/r3inB/hyWg7ODHG6/SF3vkm05ZZRPlf5OOF0oSK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bAFwVq/hyWgXkYnM0/1743M1HRKz1QVWIetqj6u0/img.jpg?width=420&amp;amp;height=420&amp;amp;face=0_0_420_420');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Spring] IoC(Inversion of Control 제어의 역전), DI(Dependency Injection 의존성 주입), 의존성 주입 3가지 방법&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;IoC(Inversion of Control, 제어의 역전)객체 생성 및 의존성 주입 등의 제어를 개발자가 아닌 프레임워크가 담당하도록 하는 설계 원칙이다.사용할 객체를 직접 생성하지 않고, 객체 생명주기 관리를&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cloud-grace.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. &lt;/b&gt;&lt;b&gt;AOP&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;AOP는 Aspect-Oriented Programming을 줄인 표현이며, 관점 지향 프로그래밍이다. 프로그래밍에 대한 관심을 핵심 관심 사항과 부가 관심 사항으로 나누어서 관심 기준에 따라 모듈화하는 것을 말한다. 즉, &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;로직을 바라볼 때, 책임과 관심사에 따라 코드를 분리하는 방식의 프로그래밍&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;개발을 하다보면 서비스에 공통적으로 필요한 보안, 인증, 로그 기록 등의 기능들과 서비스의 핵심 비즈니스 로직이 따로 존재한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;AOP가 필요한 이유&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;코드의 간결성 유지&lt;/li&gt;
&lt;li&gt;객체 지향 설계 원칙에 맞는 코드 작성&lt;/li&gt;
&lt;li&gt;코드의 재사용성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, Spring에서는 @Transactional 어노테이션을 활용하여 AOP 기능을 통해 트랜잭션을 적용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. &lt;/b&gt;&lt;b&gt;PSA&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PSA는 Portable Service Abstraction으로 환경 변화와 관계 없이 일관된 방식의 기술로 접근 환경을 제공하는 추상화 구조이다. 즉, &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;스프링에서 제공하는 다양한 기술들을 개발자가 쉽게 사용하는 인터페이스&lt;/b&gt;&lt;/span&gt;를 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;PSA가 필요한 이유&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;어떤 서비스를 이용하기 위한 접근 방식을 일관되게 유지하면 애플리케이션의 기술이 바뀌더라도 최소한의 수정으로 요구사항을 반영할 수 있다.&lt;/li&gt;
&lt;li&gt;즉, 요구사항 변경에 유연하게 대처할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring은&amp;nbsp;하나의&amp;nbsp;추상화&amp;nbsp;아키텍쳐를&amp;nbsp;제시하며,&amp;nbsp;각각의&amp;nbsp;계층별로&amp;nbsp;수행할&amp;nbsp;책임과&amp;nbsp;관심사를&amp;nbsp;표방하는&amp;nbsp;인터페이스를&amp;nbsp;제공함으로써&amp;nbsp;개발자는&amp;nbsp;특정&amp;nbsp;기술에&amp;nbsp;종속되지&amp;nbsp;않는&amp;nbsp;PSA를&amp;nbsp;수행할&amp;nbsp;수&amp;nbsp;있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;클라이언트&amp;nbsp;&amp;harr; 프레젠테이션 계층&amp;nbsp;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;&amp;harr; 서비스 계층 &lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;&amp;harr; 데이터 액세스 계층 &lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;&amp;harr; DB/Legacy&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring은 Spring Web MVC, Spring Transaction, Spring Cache, MyBatis-Spring 등 다양한 PSA를 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;참고 자료&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://mininkorea.tistory.com/44&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://mininkorea.tistory.com/44&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://devloper-dreaming.tistory.com/147&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://devloper-dreaming.tistory.com/147&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://blogshine.tistory.com/480&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://blogshine.tistory.com/480&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://dev-coco.tistory.com/83&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dev-coco.tistory.com/83&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Spring</category>
      <category>AOP</category>
      <category>Di</category>
      <category>IOC</category>
      <category>PSA</category>
      <category>spring</category>
      <category>Spring Framework</category>
      <category>Spring Triangle</category>
      <category>스프링</category>
      <category>스프링 3대 요소</category>
      <category>스프링 삼각형</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/24</guid>
      <comments>https://cloud-grace.tistory.com/entry/Spring-%EC%8A%A4%ED%94%84%EB%A7%81%EC%9D%98-%EC%82%BC%EA%B0%81%ED%98%95-IoCDI-AOP-PSA#entry24comment</comments>
      <pubDate>Wed, 5 Jun 2024 23:09:21 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] 스프링 컨테이너(Spring Container), 스프링 빈(Bean), 빈 설정 방법(XML, Java 기반, Annotation 기반)</title>
      <link>https://cloud-grace.tistory.com/entry/Spring-%EC%8A%A4%ED%94%84%EB%A7%81-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88Spring-Container-%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B9%88Bean-%EB%B9%88-%EC%84%A4%EC%A0%95-%EB%B0%A9%EC%8B%9D</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스프링 빈(Spring Bean)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;스프링 빈(Spring Bean)은 &lt;b&gt;스프링 컨테이너에 등록하여 관리하는 자바 객체&lt;/b&gt;이다.&lt;/li&gt;
&lt;li&gt;스프링의 &lt;b&gt;IoC는 제어의 역전&lt;/b&gt;에서 객체 생성과 제어권을 스프링에게 넘겨주는 것이다. 여기서 사용자가 new 연산으로 객체를 생성하는 것이 아닌, 스프링에 의해 관리되는 자바 객체를 사용하며, 이를 빈(Bean)이라고 한다.&lt;/li&gt;
&lt;li&gt;또한, 자바 어플리케이션 동작을 책임지는 객체들은 독립적이지 않고 상호작용하여 동작한다. 서로 상호작용하는 객체들은 서로 의존 관계를 가진다. 따라서 스프링 컨테이너에 생성된 빈들에게 &lt;b&gt;의존성 주입(Dependency Injection)&lt;/b&gt;을 해주는 역할도 가지고 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스프링 컨테이너(Spring Container)&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Spring Container 기능.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;663&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TUHFH/btsHNA6YIC5/wv5JX7UubTCNjInoKj3z50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TUHFH/btsHNA6YIC5/wv5JX7UubTCNjInoKj3z50/img.png&quot; data-alt=&quot;출처 : 인프런 김영한님 강의 [스프링 핵심 원리 - 기본편]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TUHFH/btsHNA6YIC5/wv5JX7UubTCNjInoKj3z50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTUHFH%2FbtsHNA6YIC5%2Fwv5JX7UubTCNjInoKj3z50%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;607&quot; height=&quot;314&quot; data-filename=&quot;Spring Container 기능.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;663&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 인프런 김영한님 강의 [스프링 핵심 원리 - 기본편]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;스프링에서 빈(객체)들을 관리하는 공간이며, 빈의 생성부터 소멸까지 관리해준다.&lt;/li&gt;
&lt;li&gt;빈의 생명 주기를 관리하고 이 객체들에게 추가적인 기능도 제공한다.&lt;/li&gt;
&lt;li&gt;또한, 의존성 주입을 통해 애플리케이션 컴포넌트들을 관리하며, 서로 다른 빈들을 연결하여 애플리케이션의 빈을 연결해주는 역할을 한다.&lt;/li&gt;
&lt;li&gt;스프링 컨테이너는 &lt;b&gt;ApplicationContext이며, IoC 컨테이너 혹은 DI 컨테이너&lt;/b&gt;라고도 부른다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스프링 컨테이너 종류&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Spring Container.png&quot; data-origin-width=&quot;836&quot; data-origin-height=&quot;495&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEEl5b/btsHNv5NLy3/V4Bw1HaIaXAMMcqOAtqft1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEEl5b/btsHNv5NLy3/V4Bw1HaIaXAMMcqOAtqft1/img.png&quot; data-alt=&quot;출처 : 인프런 김영한님 강의 [스프링 핵심 원리 - 기본편]&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEEl5b/btsHNv5NLy3/V4Bw1HaIaXAMMcqOAtqft1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEEl5b%2FbtsHNv5NLy3%2FV4Bw1HaIaXAMMcqOAtqft1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;632&quot; height=&quot;374&quot; data-filename=&quot;Spring Container.png&quot; data-origin-width=&quot;836&quot; data-origin-height=&quot;495&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 인프런 김영한님 강의 [스프링 핵심 원리 - 기본편]&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1.&lt;/b&gt; &lt;b&gt;BeanFactory&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;빈 팩토리(BeanFactory)는 스프링 컨테이너의 최상위 인터페이스이다.&lt;/li&gt;
&lt;li&gt;빈 등록, 생성, 조회 등의 관리 역할을 맡고, getBean() 메서드로 빈을 인스턴스화도 할 수 있다.&lt;/li&gt;
&lt;li&gt;BeanFactory 계열의 인터페이스만 구현한 클래스는 단순 객체 생성 및 DI 기능만 제공한다.&lt;/li&gt;
&lt;li&gt;또한, 팩토리 디자인 패턴을 구현한 것이다. 주로, BeanFactory보다 이를 확장한 ApplicationContext를 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. ApplicationContext&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;애플리케이션 컨텍스트(ApplicationContext)는 BeanFactory의 기능을 상속받아 제공한다.&lt;/li&gt;
&lt;li&gt;빈 관리 기능은 BeanFactory가 제공하고, 그 외의 부가 기능들은 ApplicationContext가 제공한다.&lt;/li&gt;
&lt;li&gt;부가 기능
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;MessageSource : 메시지 다국화 인터페이스&lt;/li&gt;
&lt;li&gt;EnvironmentCapable : 개발, 운영, 환경 변수 등으로 나누어 수행하고, 애플리케이션을 구동할 때 필요한 정보를 관리하는 인터페이스&lt;/li&gt;
&lt;li&gt;ApplicationEventPublisher : 이벤트 관련 기능 인터페이스&lt;/li&gt;
&lt;li&gt;ResourceLoader : 클래스 패스, 파일, 외부 리소스를 편하게 조회하는 인터페이스&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스프링 컨테이너 사용하는 이유&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체 생성을 위해 new 생성자를 사용하면 객체 수가 많아질수록 서로를 참조하는 객체가 많아진다.&lt;/li&gt;
&lt;li&gt;이는 자연스레 의존성이 높아지고, 결합도가 강해진다.&lt;/li&gt;
&lt;li&gt;객체 지향 프로그래밍의 지향점에 맞게 느슨한 결합도와 높은 캡슐화가 필요하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스프링 컨테이너에 빈(Bean) 등록 방법&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너는 BeanDefinition을 기반으로 빈을 생성하고 구성한다. 빈 등록을 위해서 BeanDefinition 메타데이터를 구성해 주어야 하며, Spring은 XML 문서, Annotation, 프로퍼티 파일과 같은 외부 리소스로 빈의 메타 정보를 작성하고, 이것을 ApplicationContext가 사용할 수 있는 정보로 변환해준다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;XML 문서 or 어노테이션 or 자바 코드 ▶ BeanDefinition 메타 정보 ▶ 스프링 컨테이너&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. 직접 스프링 빈 등록&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1-1. XML 기반 설정&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;applicationContext.xml&lt;/li&gt;
&lt;li&gt;id : 빈 식별자&lt;/li&gt;
&lt;li&gt;class : 빈 클래스 지정&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717510635351&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;bean id=&quot;myBean&quot; class=&quot;com.example.MyBean&quot;&amp;gt;
    &amp;lt;property name=&quot;property&quot; value=&quot;value&quot;/&amp;gt;
&amp;lt;/bean&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1-2. Java 기반 설정(Java Configuration)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AppConfig Class&lt;/li&gt;
&lt;li&gt;@Bean은 @Configuration 설정된 클래스의 메서드에서 사용한다.&lt;/li&gt;
&lt;li&gt;메서드의 리턴 객체가 스프링 빈 객체임을 선언한다.&lt;/li&gt;
&lt;li&gt;빈의 이름은 기본적으로 메서드 이름이다. (@Bean(name=&quot;name&quot;)으로 변경이 가능하다.)&lt;/li&gt;
&lt;li&gt;@Scope를 통해 객체 생성을 조정할 수 있다.&lt;/li&gt;
&lt;li&gt;빈 객체에서 init(), destroy() 등의 라이프사이클 메서드를 추가하여 @Bean에서 지정할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717510621345&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
public class AppConfig {

    @Bean
    public MyBean myBean() {
        return new MyBean();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. 컴포넌트 스캔&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 2-1. XML 기반 설정&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;applicationContext.xml&lt;/li&gt;
&lt;li&gt;XML을 이용하여 빈 스캐너 등록&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717510709978&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;context:component-scan base-package=&quot;com.example&quot;/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2-2. Java 기반 설정(Java Configuration)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AppConfig Class&lt;/li&gt;
&lt;li&gt;클래스에서 @Component 어노테이션을 붙이면 스프링 빈으로 등록한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717510695162&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@ComponentScan(basePackages = &quot;com.example&quot;)
public class AppConfig {
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2-3. 어노테이션 기반 설정(Annotation Configuration) (*&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;스프링 부트 활용 시&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스 선언부에 @Configuration나 Java 설정 파일 없이 @Component 어노테이션만을 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;스프링 컨테이너에 의해 자동으로 생성되어 스프링 빈으로 등록된다.&lt;/li&gt;
&lt;li&gt;@Component는 일반적인 컴포넌트 역할을 하는 빈을 등록할 때 사용하며, @Component를 확장한 특적 목적 클래스를 빈으로 등록하기 위해 많이 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717510749157&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Component
public class MyBean {
    public void doSomething() {
        System.out.println(&quot;Doing something&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@Component를 확장한 어노테이션으로는 @Controller, @Service, @Repository가 있다.&lt;/li&gt;
&lt;li&gt;이들은 스테레오타입 어노테이션으로 불리며 @Component 메타 어노테이션을 갖고 있어 자동으로 빈을 등록한다.&lt;/li&gt;
&lt;li&gt;@Repository : Data Access 데이터 접근 계층의 DAO, Repository 클래스에서 사용된다.&lt;/li&gt;
&lt;li&gt;@Service : Service 계층 클래스에서 사용되며, 스프링 비즈니스 로직에서 사용한다.&lt;/li&gt;
&lt;li&gt;@Controller : 프레젠테이션 계층의 MVC Controller에서 사용된다. 스프링의 Web Servlet에 의해 웹 요청을 처리하는 컨트롤러 빈으로 등록된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;참고 자료&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;이미지 출처 및 내용 참고 : 인프런 김영한 님의 강의 &lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&quot;스프링 핵심 원리 - 기본편&quot;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://jie0025.tistory.com/269&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://jie0025.tistory.com/269&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://dev-coco.tistory.com/69&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dev-coco.tistory.com/69&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://dev-coco.tistory.com/80&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dev-coco.tistory.com/80&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://kkkdh.tistory.com/entry/Spring-%EC%8A%A4%ED%94%84%EB%A7%81-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88%EC%99%80-%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B9%88-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kkkdh.tistory.com/entry/Spring-%EC%8A%A4%ED%94%84%EB%A7%81-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88%EC%99%80-%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B9%88-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://steady-coding.tistory.com/459&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://steady-coding.tistory.com/459&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Spring</category>
      <category>application context</category>
      <category>beanfactory</category>
      <category>Component Scan</category>
      <category>Configuration</category>
      <category>spring</category>
      <category>Spring Bean</category>
      <category>Spring Container</category>
      <category>스프링</category>
      <category>스프링 빈</category>
      <category>스프링 컨테이너</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/23</guid>
      <comments>https://cloud-grace.tistory.com/entry/Spring-%EC%8A%A4%ED%94%84%EB%A7%81-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88Spring-Container-%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B9%88Bean-%EB%B9%88-%EC%84%A4%EC%A0%95-%EB%B0%A9%EC%8B%9D#entry23comment</comments>
      <pubDate>Tue, 4 Jun 2024 23:40:55 +0900</pubDate>
    </item>
    <item>
      <title>[디자인 패턴] 전략 패턴(Strategy Pattern)</title>
      <link>https://cloud-grace.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EC%A0%84%EB%9E%B5-%ED%8C%A8%ED%84%B4Strategy-Pattern</link>
      <description>&lt;h3 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;전략 패턴(Strategy Pattern)이란?&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;전략 패턴은 디자인 패턴(Design Pattern)중&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;행위 패턴(Behavioral Pattern)&lt;/b&gt;이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;행위 패턴 : 클래스나 객체들이 서로 상호작용하는 방법이나 어떤 알고리즘, 작업을 어떤 객체에 할당하는 것이 좋을지 정의하는 패턴이다.&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;즉, 객체나 클래스의 교류 방법에 대해 정의하는 것이다. 하나의 객체만으로 수행할 수 없는 작업을 여러 객체로 나누면서 결합도를 최소화하게 해준다. 행위 클래스 패턴은 상속을 통해 알고리즘, 제어 흐름을 기술하고, 행위 객체 해턴은 하나의 작업을 수행하기 위해 객체 집합이 어떻게 협력하는지를 기술한다.&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;GoF 디자인 패턴에 의하면 전략 패턴은 &lt;span style=&quot;background-color: #ffffff; color: #343638; text-align: start;&quot;&gt;동일 계열의 알고리즘군을 정의하고 캡슐화하여 &lt;b&gt;상호 교환&lt;/b&gt;이 가능하도록 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;전략 패턴 : 실행(Runtime) 중에 알고리즘 전략을 선택하여 객체 동작을 실시간으로 바뀌도록 할 수 있게 하는 패턴이다. 알고리즘을 정의하고, 캡슐화하며, 실행 시간에 서로 교환 가능하도록 만든다.&lt;/b&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;전략 패턴은 알고리즘 변형이나 확장을 쉽게 할 수 있고, 객체 간의 결합도를 낮출 수 있다. 따라서 알고리즘 변경에 따라 코드 변경을 최소화할 수 있다. 즉, 어떤 일을 수행하는 알고리즘이 여러가지일 때, 동작들을 미리 전략으로 정의하고 손쉽게 전략을 바꿀 수 있으며, 알고리즘 변형을 자주 일으킬 경우에 적합하다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;전략 패턴 구조&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Strategy Pattern.png&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;294&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o3nqr/btsHOYlbzS5/bWRjQaPRVHfAeDuErE3k51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o3nqr/btsHOYlbzS5/bWRjQaPRVHfAeDuErE3k51/img.png&quot; data-alt=&quot;출처 : https://velog.io/@y_dragonrise/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o3nqr/btsHOYlbzS5/bWRjQaPRVHfAeDuErE3k51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo3nqr%2FbtsHOYlbzS5%2FbWRjQaPRVHfAeDuErE3k51%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;616&quot; height=&quot;246&quot; data-filename=&quot;Strategy Pattern.png&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;294&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : https://velog.io/@y_dragonrise/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Strategy&lt;/b&gt; : 모든 전략 구현체에 대한 공용 인터페이스이다. 알고리즘이 추상화되어 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ConcreteStrategy&lt;/b&gt; : 알고리즘, 행위, 동작을 객체로 정의한 구현체이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Context&lt;/b&gt; : 알고리즘을 수행할 때마다 각각 알고리즘과 연결된 전략 객체 메소드를 호출한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Client&lt;/b&gt; : 특정 전략 객체를 컨텍스트에 전달하면서 전략을 등록하고 변경하며 각각의 전략 알고리즘 수행 결과를 도출한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;전략 패턴 예제 코드&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Strategy Interface&lt;/b&gt; : Context Class에서 사용하는 전략 인터페이스이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717502100410&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Strategy interface
public interface Strategy {
    public int execute(int num1, int num2);
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Concrete Strategy&lt;/b&gt; : AddOperation(), SubtractOperation(), MultiplyOperation() 클래스들은 execute() 메서드를 구현하여 각각 정수를 계산한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717502120833&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Concrete Strategy: Addition
public class AddOperation implements Strategy {
    @Override
    public int execute(int num1, int num2) {
        return num1 + num2;
    }
}

// Concrete Strategy: Subtraction
public class SubtractOperation implements Strategy {
    @Override
    public int execute(int num1, int num2) {
        return num1 - num2;
    }
}

// Concrete Strategy: Multiplication
public class MultiplyOperation implements Strategy {
    @Override
    public int execute(int num1, int num2) {
        return num1 * num2;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Context Class&lt;/b&gt; : 전략 선택을 수행하는 컨텍스트 클래스이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717502144526&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Context class
public class Context {
    private Strategy strategy;

    public Context(Strategy strategy) {
        this.strategy = strategy;
    }

    public int executeStrategy(int num1, int num2) {
        return strategy.execute(num1, num2);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Client&lt;/b&gt; : 전략 패턴을 사용하는 클라이언트 코드이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717502311693&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Client {
    public static void main(String[] args) {
        Strategy addOperation = new AddOperation(); // 전략 객체
        Strategy subtractOperation = new SubtractOperation();
        Strategy multiplyOperation = new MultiplyOperation();
        
        Context addContext = new Context(addOperation); // 컨택스트 객체
        System.out.println(&quot;10 + 5 = &quot; + addContext.executeStrategy(10, 5)); // 연산 수행

        Context subtractContext = new Context(subtractOperation);
        System.out.println(&quot;10 - 5 = &quot; + subtractContext.executeStrategy(10, 5));

        Context multiplyContext = new Context(multiplyOperation);
        System.out.println(&quot;10 * 5 = &quot; + multiplyContext.executeStrategy(10, 5));
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;전략 패턴의 장점&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0d0d0d; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코드 재사용성이 높고, 객체 간 결합도가 낮아지며 유지보수에 용이하다.&lt;/li&gt;
&lt;li&gt;알고리즘을 변형하고 확장하는 데에 용이하다&lt;/li&gt;
&lt;li&gt;테스트 수행에 용이하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;참고 자료&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://brightstarit.tistory.com/39&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://brightstarit.tistory.com/39&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://shan0325.tistory.com/35&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://shan0325.tistory.com/35&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://4z7l.github.io/2020/12/25/design_pattern_GoF.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://4z7l.github.io/2020/12/25/design_pattern_GoF.html&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://brightstarit.tistory.com/39&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://brightstarit.tistory.com/39&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>디자인 패턴 &amp;amp; OOP</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/22</guid>
      <comments>https://cloud-grace.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EC%A0%84%EB%9E%B5-%ED%8C%A8%ED%84%B4Strategy-Pattern#entry22comment</comments>
      <pubDate>Tue, 4 Jun 2024 21:18:28 +0900</pubDate>
    </item>
    <item>
      <title>[디자인 패턴] 템플릿 메서드 패턴(Template Method Pattern)</title>
      <link>https://cloud-grace.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%ED%85%9C%ED%94%8C%EB%A6%BF-%EB%A9%94%EC%84%9C%EB%93%9C-%ED%8C%A8%ED%84%B4Template-Method-Pattern</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;템플릿 메서드 패턴(Template Method Pattern)이란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;템플릿 메서드 패턴은 디자인 패턴(Design Pattern)중 &lt;b&gt;행위 패턴(Behavioral Pattern)&lt;/b&gt;이다.&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;행위 패턴 : 클래스나 객체들이 서로 상호작용하는 방법이나 어떤 알고리즘, 작업을 어떤 객체에 할당하는 것이 좋을지 정의하는 패턴이다.&lt;/b&gt; 즉, 객체나 클래스의 교류 방법에 대해 정의하는 것이다. 하나의 객체만으로 수행할 수 없는 작업을 여러 객체로 나누면서 결합도를 최소화하게 해준다. 행위 클래스 패턴은 상속을 통해 알고리즘, 제어 흐름을 기술하고, 행위 객체 해턴은 하나의 작업을 수행하기 위해 객체 집합이 어떻게 협력하는지를 기술한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;GoF 디자인 패턴에 의하면 템플릿 메서드 패턴은 상위클래스는 알고리즘의 골격만을 작성하고 구체적인 처리는 서브클래스로 위임한다.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;템플릿 메서드 패턴 : 상속을 통해 상위 클래스의 기능을 확장할 때 사용하는 가장 대표적인 방법이다. 변하지 않는 기능은 상위 클래스에 만들어두고 자주 변경되며 확장할 기능은 하위 클래스에서 만들도록 한다.&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;템플릿 메서드 패턴은 알고리즘의 뼈대를 맞추는 것이 목적이라 할 수 있다. 즉, 전체적인 템플릿을 통일하지만 상속받은 클래스는 Hook 메서드를 이용하여 확장할 수 있도록 유연성을 주는 디자인 패턴이다.&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;템플릿 메서드 패턴 구조&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;778&quot; data-origin-height=&quot;490&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QL8G2/btsHOBDRiLG/hE8c6cjHUF9KSSXHaG7WX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QL8G2/btsHOBDRiLG/hE8c6cjHUF9KSSXHaG7WX0/img.png&quot; data-alt=&quot;출처 : https://yaboong.github.io/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QL8G2/btsHOBDRiLG/hE8c6cjHUF9KSSXHaG7WX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQL8G2%2FbtsHOBDRiLG%2FhE8c6cjHUF9KSSXHaG7WX0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;315&quot; data-origin-width=&quot;778&quot; data-origin-height=&quot;490&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : https://yaboong.github.io/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AbstractClass : templateMethod()를 정의하며, 하위 클래스에서 확장하는 Hook 메서드를 제공한다. templateMethod()는 일반 메서드, 훅 메서드 모두 이용한다.&lt;/li&gt;
&lt;li&gt;SubClass : 훅 메서드를 상속받아 재정의한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;템플릿 메서드 패턴 예제 코드&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;패턴 적용 전&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위 코드를 보면 라떼를 제조하는 데에는 얼음, 커피, 우유를 넣는 행위는 동일한 코드이다. 즉, LatteTemplate&amp;nbsp;라는 클래스를 정의하여 중복된 코드를 제거할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class VanillaLatte {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void addIce() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;얼음을 넣는다.&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void addCoffee() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;커피를 넣는다.&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void addMilk() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;우유를 넣는다.&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void addVanillaSyrup() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;바닐라 시럽을 넣는다.&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class CaramelLatte {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void addIce() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;얼음을 넣는다.&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void addCoffee() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;커피를 넣는다.&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void addMilk() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;우유를 넣는다.&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void addCaramelSyrup() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;카라멜 시럽을 넣는다.&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;패턴 적용 후&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LatteTemplate 클래스를 추상 클래스로 선언한다.&lt;/li&gt;
&lt;li&gt;추상화할 메소드 1개를 추상 메소드로 선언한다.&lt;/li&gt;
&lt;li&gt;makeLatte()은 템플릿 메소드이고, addSyrup()는 훅 메소드라고 볼 수 있다.&lt;/li&gt;
&lt;li&gt;VanillaLatte 클래스와 CaramelLatte 클래스는 Latte 클래스를 상속받아 추상 메서드를 재정의한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// 추상 클래스: 알고리즘의 기본 구조를 정의
public abstract class LatteTemplate {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void makeLatte() { // 템플릿 메서드
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;addIce();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;addCoffee();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;addMilk();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;addSyrup();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private void addIce() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;얼음을 넣는다.&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private void addCoffee() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;커피를 넣는다.&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;private void addMilk() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;우유를 넣는다.&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 추상 메서드: 하위 클래스에서 구체화
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;protected abstract void addSyrup();
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// 구체적인 구현 클래스 1
class VanillaLatte extends LatteTemplate {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Override
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;protected void addSyrup() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;바닐라 시럽을 넣는다.&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// 구체적인 구현 클래스 2
class CaramelLatte extends LatteTemplate {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Override
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;protected void addSyrup() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;카라멜 시럽을 넣는다.&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// 실행 클래스
public class Main {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public static void main(String[] args) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;LatteTemplate vanillaLatte = new VanillaLatte();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;vanillaLatte.makeLatte();

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;LatteTemplate caramelLatte = new CaramelLatte();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;caramelLatte.makeLatte();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;템플릿 메서드 패턴의 장점&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코드 재사용성 증가 : 공통된 알고리즘은 상위 클래스에서 정의되고, 세부 구현만 하위 클래스에서 정의하므로 중복 코드가 줄어든다.&lt;/li&gt;
&lt;li&gt;확장성 증가 : 새로운 라떼 종류를 추가할 때, 새로운 클래스만 작성하면 되므로 기존 코드를 수정할 필요가 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;참고 자료&lt;/span&gt;&lt;br /&gt;&lt;a href=&quot;https://steady-coding.tistory.com/384&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;https://steady-coding.tistory.com/384&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://4z7l.github.io/2020/12/25/design_pattern_GoF.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;https://4z7l.github.io/2020/12/25/design_pattern_GoF.html&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</description>
      <category>디자인 패턴 &amp;amp; OOP</category>
      <category>Behavioral pattern</category>
      <category>Design Pattern</category>
      <category>Template Method Pattern</category>
      <category>디자인 패턴</category>
      <category>템플릿 메서드 패턴</category>
      <category>행위 패턴</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/21</guid>
      <comments>https://cloud-grace.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%ED%85%9C%ED%94%8C%EB%A6%BF-%EB%A9%94%EC%84%9C%EB%93%9C-%ED%8C%A8%ED%84%B4Template-Method-Pattern#entry21comment</comments>
      <pubDate>Tue, 4 Jun 2024 14:40:47 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] IoC(Inversion of Control 제어의 역전), DI(Dependency Injection 의존성 주입), 의존성 주입 3가지 방법</title>
      <link>https://cloud-grace.tistory.com/entry/Spring-IoCInversion-of-Control-%EC%A0%9C%EC%96%B4%EC%9D%98-%EC%97%AD%EC%A0%84-DIDependency-Injection-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EB%B0%A9%EB%B2%95-3%EA%B0%80%EC%A7%80</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;IoC(Inversion of Control, 제어의 역전)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 생성 및 의존성 주입 등의 제어를 개발자가 아닌 프레임워크가 담당하도록 하는 설계 원칙이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용할 객체를 직접 생성하지 않고, 객체 생명주기 관리를 외부에 위임한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 애플리케이션의 구조를 더 유연하고 테스트 가능하게 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, IoC의 핵심 개념은 애플리케이션의 제어 흐름을 프레임워크가 관리한다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통해 객체 간 결합도를 낮추고, 코드의 재사용성과 유연성을 높인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스프링에서의 IoC&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링에서는 스프링 컨테이너가 오브젝트인 빈(Bean)의 생성, 의존 관계 설정 등의 작업을 스프링 컨테이너가 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;스프링에서 IoC, 제어의 역전은 &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;코드 대신 객체에 대한 제어권을 스프링 컨테이너에 넘겨 스프링 컨테이너가 흐름을 제어하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 스프링 컨테이너를 IoC 컨테이너라고도 부른다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아래 예제는 A 클래스에서 B 필드를 가지고 있으며 생성자에서 직접 객체를 생성하여 필드를 초기화한다.&lt;/li&gt;
&lt;li&gt;객체 생명주기 및 메서드 호출을 개발자가 직접 제어하고 있는 상황이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717316703607&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class A {
    private B b;
    
    public A() {
    	b = new B();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;B라는 객체가 스프링 컨테이너에서 관리하는 Bean이라면 @Autowired를 통해 객체를 주입받을 수 있다.&lt;/li&gt;
&lt;li&gt;개발자가 직접 객체를 관리하는 것이 아닌, 스프링 컨테이너에서 객체를 생성하여 객체를 주입시켜주었다.&lt;/li&gt;
&lt;li&gt;이것이 IoC, 제어의 역전이며, 프로그램 제어권이 역전된 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717316740558&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class A {

    @Autowired
    private B b; // 필드 주입
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;DI(Dependency Injection, 의존성 주입)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의존 관계란?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DI는 의존성 주입 또는 의존 관계 주입을 말한다. 여기서 의존 관계란, &lt;u&gt;&lt;b&gt;A가 B에 의존한다.&lt;/b&gt;&lt;/u&gt;라는 문장에서 의미를 파헤쳐볼 수 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;By 토비의 스프링 3.1, &lt;b&gt;의존 대상인 B가 변하면 그것이 A에 영향을 미친다.&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;B의 기능이 변화함에 따라 A에 영향을 미치며, 이를 A가 B에 의존한다고 말할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;의존 관계 주입(의존성 주입)이란?&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;의존성 주입 : 사용할 객체를 직접 생성하지 않고, 외부 컨테이너가 생성한 객체를 주입받아 사용하는 방식&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의존 관계를 객체 외부에서 결정해주는 것이다. 즉, 외부에서 두 객체 간의 관계를 결정해주며, 프로그램 내에서는 각 구현체는 구체화가 아닌 추상화에 의존하게 된다. 즉, 객체가 아니라 인터페이스에 의존한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;애플리케이션을 실행하는 Runtime에 외부에서 실제 구현체를 만들고 클라이언트에 전달한다.&lt;/li&gt;
&lt;li&gt;외부인 AppConfig에서 객체 인스턴스 생성을 하고, 참조 값을 전달해서 연결한다.&lt;/li&gt;
&lt;li&gt;이를 통해 클라이언트 코드 변경을 하지 않고, 클라이언트가 호출하는 구현체, 구체화 종류를 변경할 수 있다.&lt;/li&gt;
&lt;li&gt;즉, 정적인 클래스 의존 관계는 변경하지 않고(=코드 변경 X), 동적인 의존 관계를 쉽게 변경할 수 있게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;의존성 주입이 필요한 이유&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아래에 커피를 판매하는 CafeService Class와 AmericanoRecipe라는 커피 레시피가 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717459577674&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
public class CafeService {
    private AmericanoRecipe americanoRecipe;
    
    public CafeService() {
        this.americanoRecipe = new AmericanoRecipe();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;위 예제의 문제점&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;강하게 결합된 CafeService Class와 AmericanoRecipe Class
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;만약, CafeService Class에서 LatteRecipe Class를 활용하여 다른 커피 메뉴를 판매하려면 CafeService Class의 생성자를 수정해야 한다.&lt;/li&gt;
&lt;li&gt;만약, CafeService Class는 AmericanoRecipe Class에 의존하기 때문에 AmericanoRecipe 생성자에 변경이 생긴다면 CafeService Class 또한 변경이 되어야 한다. 또한, CafeService Class가 사용된 모든 곳에 영향을 받으며, 유연성이 떨어진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;객체와의 관계 X, 클래스 간의 관계 O
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;다른 객체의 구체 클래스( AmericanoRecipe , LatteRecipe)를 모르더라도 Class가 Interface를 구현했다면 Interface 타입으로 사용 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;의존성 주입 3가지 방법&lt;/b&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;생성자 주입(Constructor Injection) (*추천)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;수정자 주입(Setter Injection)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;필드 주입(Field Injection)&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;스프링은 @Autowired 어노테이션으로 의존성 주입을 명시한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;(*스프링 4.3 이후는 생성자 주입에서 생성자가 1개이면 @Autowired 생략 가능)&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 생성자 주입(Constructor Injection)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1717461843019&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
public class CafeService {
    private final AmericanoRecipe americanoRecipe;
    
    @Autowired
    public CafeService(AmericanoRecipe americanoRecipe) {
        this.americanoRecipe = new AmericanoRecipe();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;생성자를 통해 의존성을 주입하며 생성자 호출 시 딱 1번만 호출되는 것을 보장한다.&lt;/li&gt;
&lt;li&gt;생성자가 1개만 존재하면 @Autowired 생략해도 자동 주입된다.&lt;/li&gt;
&lt;li&gt;주입받은 객체가 변하지 않거나 반드시 객체 주입이 필요하면 강제하기 위해 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;주입받을 field를 불변 보장 final 키워드로 선언 가능하다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;NPE(NullPointException)을 방지할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;순환 참조를 컴파일 단계에서 찾을 수 있다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;테스트 코드 작성에 용이하다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;순환 참조 감지 기능을 스프링에서 제공하며, 순환 참조 시 에러를 보여준다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;생성자 인자가 많아지면 코드가 길어질 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1-1. 생성자 주입 + Lombok 라이브러리 활용 &lt;b&gt;(*가장 추천)&lt;/b&gt; &lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1717465731069&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
@RequiredArgsConstructor
public class CafeService {
    private final AmericanoRecipe americanoRecipe;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;개발 편의성 라이브러리인 Lombok에서 @RequiredArgsConstructor를 활용하면 더욱 간결하게 만들 수 있다.&lt;/li&gt;
&lt;li&gt;@RequiredArgsConstructor 어노테이션은 NotNull이거나 final이 붙은 변수들에 대해 생성자를 만들어준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 수정자 주입(Setter Injection)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1717462437446&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
public class CafeService {
    private AmericanoRecipe americanoRecipe;
    
    @Autowired
    public void setAmericanoRecipe(AmericanoRecipe americanoRecipe) {
        this.americanoRecipe = new AmericanoRecipe();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;생성자 주입과는 다르게 주입받는 객체가 변경될 가능성이 있으면 사용한다.&lt;/li&gt;
&lt;li&gt;선택과 변경 가능성이 있을 때 사용하며, Setter는 언제든 변경의 위험이 있다.&lt;/li&gt;
&lt;li&gt;@Autowired가 없으면 컴파일은 되지만 실행할 때 NPE(NullPointException)가 발생한다.&lt;/li&gt;
&lt;li&gt;final 키워드 선언이 불가능하다.&lt;/li&gt;
&lt;li&gt;한번 주입이 되면 변경 가능성이 거의 없기에 사용을 지양하자.&lt;/li&gt;
&lt;li&gt;순환 참조 문제가 발생할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 필드 주입(Field Injection)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1717463789580&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
public class CafeService {
    @Autowired
    private AmericanoRecipe americanoRecipe;
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;필드에 바로 의존성을 주입하는 방법이다.&lt;/li&gt;
&lt;li&gt;코드가 짧아진다.&lt;/li&gt;
&lt;li&gt;외부 변경이 불가능해서 Test가 어렵다.&lt;/li&gt;
&lt;li&gt;애플리케이션 실제 코드와 상관없는 특정 Test를 할 때 사용한다.&lt;/li&gt;
&lt;li&gt;하나의 클래스가 여러 책임(기능)을 갖게 될 가능성이 크고, 의존 관계를 파악하기에 어렵다.&lt;/li&gt;
&lt;li&gt;DI 컨테이너와 결합도도 커진다.&lt;/li&gt;
&lt;li&gt;불변성 보장이 없다.&lt;/li&gt;
&lt;li&gt;순환 참조가 발생할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;순환 참조란?&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1717464782281&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
public class CafeServiceImpl implements CafeService {

    private final ShopService shopService;

    @Autowired
    public CafeServiceImpl(ShopService shopService) {
        this.shopService = shopService;
    }

    @Override
    public void cafeMethod() {
        shopService.shopMethod();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1717464794190&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
public class ShopServiceImpl implements ShopService {

    private final CafeService cafeService;

    @Autowired
    public ShopServiceImpl(CafeService cafeService) {
        this.cafeService = cafeService;
    }

    @Override
    public void shopMethod() {
        cafeService.cafeMethod();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;ShopServiceImpl의 shopMethod()는 CafeServiceImpl의 cafeMethod()를 호출한다.&lt;/li&gt;
&lt;li&gt;CafeServiceImpl의 cafeMethod()는 ShopServiceImpl의 shopMethod()를 호출한다.&lt;/li&gt;
&lt;li&gt;서로 호출을 반복하면서 결국 StackOverflowError를 발생시키고 죽게 된다.&lt;/li&gt;
&lt;li&gt;수정자 주입, 필드 주입은 객체(빈)를 생성하고 비즈니스 로직 상에서 순환 참조가 일어나며, 즉, 컴파일 단계에서 순환 참조를 잡아낼 수 없다.&lt;/li&gt;
&lt;li&gt;생성자 주입은 스프링 컨테이너가 객체(빈) 생성 시점에 순환 참조를 확인하며, 즉, 컴파일 단계에서 순환 참조를 잡을 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;참고 자료&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://nosy-rabbit.tistory.com/entry/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85Dependency-Injection-%EB%B0%A9%EC%8B%9D&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://nosy-rabbit.tistory.com/entry/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85Dependency-Injection-%EB%B0%A9%EC%8B%9D&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://mozzi-devlog.tistory.com/18&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://mozzi-devlog.tistory.com/18&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://mangkyu.tistory.com/150&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://mangkyu.tistory.com/150&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://innovation123.tistory.com/167#DI(Dependency%20Injection)%20%3A%20%EC%9D%98%EC%A1%B4%EC%84%B1%20%EC%A3%BC%EC%9E%85-1&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://innovation123.tistory.com/167#DI(Dependency%20Injection)%20%3A%20%EC%9D%98%EC%A1%B4%EC%84%B1%20%EC%A3%BC%EC%9E%85-1&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://steady-coding.tistory.com/600&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://steady-coding.tistory.com/600&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://kkkdh.tistory.com/entry/IoC-DI-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC#%EC%9D%98%EC%A1%B4%EA%B4%80%EA%B3%84-%EC%A3%BC%EC%9E%85-didependency-injection&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kkkdh.tistory.com/entry/IoC-DI-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC#%EC%9D%98%EC%A1%B4%EA%B4%80%EA%B3%84-%EC%A3%BC%EC%9E%85-didependency-injection&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://kkkdh.tistory.com/entry/Dependency-Injection-%EC%9D%98%EC%A1%B4%EA%B4%80%EA%B3%84%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kkkdh.tistory.com/entry/Dependency-Injection-%EC%9D%98%EC%A1%B4%EA%B4%80%EA%B3%84%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Spring</category>
      <category>Dependency Injection</category>
      <category>Di</category>
      <category>IOC</category>
      <category>IOC Container</category>
      <category>spring</category>
      <category>순환 참조</category>
      <category>스프링</category>
      <category>의존 관계</category>
      <category>의존성 주입</category>
      <category>제어의 역전</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/20</guid>
      <comments>https://cloud-grace.tistory.com/entry/Spring-IoCInversion-of-Control-%EC%A0%9C%EC%96%B4%EC%9D%98-%EC%97%AD%EC%A0%84-DIDependency-Injection-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%A3%BC%EC%9E%85-%EB%B0%A9%EB%B2%95-3%EA%B0%80%EC%A7%80#entry20comment</comments>
      <pubDate>Tue, 4 Jun 2024 11:03:12 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] 스프링 프레임워크(Spring Framework)란?</title>
      <link>https://cloud-grace.tistory.com/entry/Spring-Spring-Framework%EB%9E%80</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스프링 유래 및 어원&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;spring.png&quot; data-origin-width=&quot;361&quot; data-origin-height=&quot;95&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c6Ccgf/btsHMw2YQyK/ySw4BLseE8KjarqzxumKL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c6Ccgf/btsHMw2YQyK/ySw4BLseE8KjarqzxumKL0/img.png&quot; data-alt=&quot;출처 : 나무위키&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c6Ccgf/btsHMw2YQyK/ySw4BLseE8KjarqzxumKL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc6Ccgf%2FbtsHMw2YQyK%2FySw4BLseE8KjarqzxumKL0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;361&quot; height=&quot;95&quot; data-filename=&quot;spring.png&quot; data-origin-width=&quot;361&quot; data-origin-height=&quot;95&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 나무위키&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과거 &lt;b&gt;EJB&lt;/b&gt;라는 기술을 통해 웹 애플리케이션을 개발하였다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;EJB(Enterprise Java Bean)&lt;/b&gt; : 엔터프라이즈급 애플리케이션 개발을 단순화하기 위해 발표한 스펙이다. Java bean이라는 자바 객체를 재사용할 수 있도록 컴포넌트화 시킬 수 있는 코딩 방식을 활용하였으며, 비즈니스 객체들을 관리하는 컨테이너를 만들어 컨테이너로부터 객체를 받는 식으로 관리한다.&lt;br /&gt;&lt;br /&gt;하지만, 서비스는 실제 비즈니스 로직보다 EJB 컨테이너를 사용하기 위한 상속, 구현할 클래스 등이 많아 불편하다. 즉, 비즈니스 로직에 특정 기술이 종속된다는 문제점이 있었다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2002년 로드 존슨(Rod Johnson)에 의해 처음 개발되었으며, 그의 책 &quot;Expert One-on-One J2EE Design and Development&quot;에서 소개되었다. 과거 EJB라는 겨울을 지나 새로운 봄을 맞이하는 스프링을 개발하여 혁신적인 변화를 만들어냈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;프레임워크(Framework)? 라이브러리(Library)?&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;라이브러리(Library)&lt;/b&gt;는 특정 기능을 구현한 코드의 집합으로, 개발자가 필요할 때 호출하여 사용할 수 있다. 개발자가 애플리케이션 흐름을 제어한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프레임워크(Framework)&lt;/b&gt;는 애플리케이션 구조를 정의하고, 전체적인 흐름을 제어하는 반면, 개발자는 그 구조 안에서 필요한 코드를 작성한다. 즉, 제어의 역전(Inversion of Control, IoC) 원칙을 따른다. 스프링 프레임워크는 IoC 원칙을 중심으로 설계되었다.&lt;/li&gt;
&lt;li&gt;소프트웨어에서의 프레임워크란, 소프트웨어의 특정 문제를 해결하기 위해 상호 협력하는 클래스와 인터페이스 집합이라 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스프링 프레임워크(Spring Framework)&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;spring-structure.png&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;385&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVA4b3/btsHLuroowH/gUlZeEHLVVEQKhMK2fYpN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVA4b3/btsHLuroowH/gUlZeEHLVVEQKhMK2fYpN1/img.png&quot; data-alt=&quot;출처 : www.devkuma.com&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVA4b3/btsHLuroowH/gUlZeEHLVVEQKhMK2fYpN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVA4b3%2FbtsHLuroowH%2FgUlZeEHLVVEQKhMK2fYpN1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;385&quot; data-filename=&quot;spring-structure.png&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;385&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : www.devkuma.com&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;자바 엔터프라이즈 개발을 편하게 해주는 오픈 소스 경량급 애플리케이션 프레임워크&lt;/b&gt;&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔터프라이즈 애플리케이션 개발을 단순화하고, 복잡한 코드를 줄이고, 테스트를 쉽게 할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스프링 코어&lt;/b&gt; : 기본적인 기능을 제공하며, IoC와 의존성 주입(Dependency Injection, DI)을 지원한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스프링 AOP&lt;/b&gt; : 관점 지향 프로그래밍(Aspect-Oriented Programming)을 지원하여, 애플리케이션의 각 모듈에 대한 공통 관심사를 분리한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스프링 데이터&lt;/b&gt; : 데이터 접근을 단순화하며, 다양한 데이터베이스와의 통합을 지원한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스프링 웹&lt;/b&gt; : 웹 애플리케이션 개발을 위한 기능을 제공하며, MVC 패턴을 지원한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스프링 특징&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. 경량 컨테이너&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt; 스프링은 경량 컨테이너로서 자바 객체를 관리하고 생명주기를 제어한다. EJB(Enterprise JavaBeans)와 비교하여 훨씬 가벼우며, 단순한 POJO(Plain Old Java Object)를 사용하여 애플리케이션을 구성할 수 있다.&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2. POJO 기반의 구성&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링은 복잡한 엔터프라이즈 애플리케이션도 단순한 POJO&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;(Plain Old Java Object, 평범한 자바 객체)&lt;/span&gt;를 사용하여 구성할 수 있도록 한다. 이는 코드가 특정 프레임워크에 종속되지 않게 하며, 유연성과 테스트 용이성을 높인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;&lt;b&gt;3. DI를 통해 객체 간 관계 구성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의존성 주입(Dependency Injection)은 객체 간의 의존 관계를 코드가 아닌 설정 파일이나 어노테이션을 통해 주입하는 방식이다. 이를 통해 객체 간의 결합도를 낮추고, 코드의 유연성과 재사용성을 높일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;&lt;b&gt;4. AOP 지원&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링은&amp;nbsp;관점&amp;nbsp;지향&amp;nbsp;프로그래밍(Aspect-Oriented&amp;nbsp;Programming,&amp;nbsp;AOP)을&amp;nbsp;지원하여,&amp;nbsp;트랜잭션&amp;nbsp;관리,&amp;nbsp;보안,&amp;nbsp;로깅&amp;nbsp;등과&amp;nbsp;같은&amp;nbsp;&lt;u&gt;횡단&amp;nbsp;관심사&lt;/u&gt;를 분리할 수 있다. 이는 코드의 모듈성을 높이고, 유지보수를 용이하게 한다. 또한, 개발자가 비즈니스 로직에 집중할 수 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;횡단 관심사(Cross-Cutting Concerns)&lt;/b&gt;는 소프트웨어 시스템의 여러 모듈에서 공통적으로 발생하는 기능이나 관리를 말한다. 이는 애플리케이션의 핵심 비즈니스 로직과는 별개로, 여러 부분에서 반복적으로 필요로 하는 기능이다. 횡단 관심사의 예로는 &lt;u&gt;로그(logging), 보안(security), 트랜잭션 관리(transaction management), 캐싱(caching), 에러 처리(error handling), 모니터링 및 성능 관리(performance monitoring)&lt;/u&gt;이 있다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;&lt;b&gt;5. WAS에 독립적인 개발 환경&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링은 특정 웹 애플리케이션 서버(WAS)에 종속되지 않으며, 다양한 WAS에서 동일하게 동작할 수 있다. 이는 개발자가 특정 서버에 종속되지 않고 자유롭게 애플리케이션을 배포할 수 있게 한다. 톰캣(Tomcat), 제티(Jetty)와 같은 단순한 서버 환경에서 완벽하게 동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스프링 부트(Spring&amp;nbsp;Boot)&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;spring boot.png&quot; data-origin-width=&quot;389&quot; data-origin-height=&quot;130&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btgW2q/btsHLL7mBMi/1cCUfrou7KwjnLJSvUnpL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btgW2q/btsHLL7mBMi/1cCUfrou7KwjnLJSvUnpL1/img.png&quot; data-alt=&quot;출처 : 나무위키&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btgW2q/btsHLL7mBMi/1cCUfrou7KwjnLJSvUnpL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtgW2q%2FbtsHLL7mBMi%2F1cCUfrou7KwjnLJSvUnpL1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;389&quot; height=&quot;130&quot; data-filename=&quot;spring boot.png&quot; data-origin-width=&quot;389&quot; data-origin-height=&quot;130&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 나무위키&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 프레임워크를 더욱 간편하게 사용할 수 있도록 도와주는 확장 도구이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. 설정의 자동화&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 부트는 많은 설정을 자동으로 해주기 때문에 개발자가 설정 파일을 일일이 작성할 필요가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;&lt;b&gt;2. 독립 실행형 애플리케이션&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tomcat과 같은 내장 웹 서버를 사용하여 독립적으로 실행 가능한 애플리케이션을 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;&lt;b&gt;3. 빠른 시작&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미리 정의된 스타터 프로젝트를 사용하여 빠르게 프로젝트를 시작할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;&lt;b&gt;4. 프로덕션 준비 기능&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모니터링, 로깅, 외부 설정 등의 기능을 제공하여, 프로덕션 환경에서 바로 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;&lt;b&gt;5. 빠른 개발과 배포&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 부트를 사용하면 개발자는 더 적은 설정과 코드로 애플리케이션을 빠르게 개발하고 배포할 수 있다. 이는 애자일 개발 방법론을 지원하며, DevOps와 같은 현대적인 소프트웨어 개발 및 운영 환경에 적합하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;참고 자료&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://www.devkuma.com/docs/spring-framework/overview/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.devkuma.com/docs/spring-framework/overview/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://steady-coding.tistory.com/457&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://steady-coding.tistory.com/457&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://kkkdh.tistory.com/entry/Spring-%EC%9D%B4%EB%9E%80&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kkkdh.tistory.com/entry/Spring-%EC%9D%B4%EB%9E%80&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://hoon93.tistory.com/56&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://hoon93.tistory.com/56&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Spring</category>
      <category>EJB</category>
      <category>framework</category>
      <category>Java</category>
      <category>spring</category>
      <category>spring boot</category>
      <category>Spring Framework</category>
      <category>스프링</category>
      <category>스프링 부트</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/19</guid>
      <comments>https://cloud-grace.tistory.com/entry/Spring-Spring-Framework%EB%9E%80#entry19comment</comments>
      <pubDate>Sun, 2 Jun 2024 16:18:47 +0900</pubDate>
    </item>
    <item>
      <title>[OOP] SOLID 객체 지향 설계 5가지 원칙</title>
      <link>https://cloud-grace.tistory.com/entry/OOP-SOLID-%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5-%EC%84%A4%EA%B3%84-5%EA%B0%80%EC%A7%80-%EC%9B%90%EC%B9%99</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;SOLID란? &lt;/b&gt;&lt;b&gt;객체 지향 설계 5가지 원칙&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SOLID 원칙이란, 객체 지향 프로그래밍에서 소프트웨어 설계를 더 이해하기 쉽고 유지보수가 용이하며 확장 가능하게 만드는 다섯 가지 기본 원칙이다. 이 원칙들은 코드 품질을 높이고, 코드 변경 시 발생할 수 있는 오류를 최소화하는 데 도움을 준다. 그리고 디자인 패턴은 SOLID 원칙을 기반으로 만들어진 것이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. SRP(Single Responsibility Principle) 단일 책임 원칙&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스(객체)는 단 하나의 책임(기능)만 가져야 하며, 변경되어야 하는 이유가 오직 하나뿐이어야 한다는 원칙이다.&lt;/li&gt;
&lt;li&gt;하나의 클래스 : 하나의 기능 담당&lt;/li&gt;
&lt;li&gt;하나의 클래스에 여러 기능이 있다면 수정 시 변경 사항이 많아지며 가독성 및 유지보수성이 떨어진다.&lt;/li&gt;
&lt;li&gt;클래스가 변경되는 이유는 오직 하나 뿐이어야 한다.&lt;/li&gt;
&lt;li&gt;만약, 클래스가 여러 기능을 가지고 있다면 여러 액터에게 변경 요구를 받고 수정할 사항이 여러 개가 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;SRP 단일 책임 원칙 위반 예제 코드&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Employee 클래스는 직원 데이터 관리, 월급 계산, 보고서 작성 등 여러 책임을 가지고 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717302858365&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Employee {
    private String name;
    private String position;

    public Employee(String name, String position) {
        this.name = name;
        this.position = position;
    }

    public void calculateSalary() {
        // Salary calculation logic
    }

    public void generateReport() {
        // Report generation logic
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;SRP 단일 책임 원칙에 맞춰 수정&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Employee 클래스는 직원 데이터 관리에 집중하며, 월급 계산 및 보고서 작성은 각각 클래스로 분리한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717302948458&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Employee {
    private String name;
    private String position;

    public Employee(String name, String position) {
        this.name = name;
        this.position = position;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1717302975794&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class SalaryCalculator {
    public void calculateSalary(Employee employee) {
        // Salary calculation logic
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1717303007124&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class ReportGenerator {
    public void generateReport(Employee employee) {
        // Report generation logic
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. OCP(Open Closed Principle) 개방 폐쇄 원칙&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;확장에는 열려 있어야 하고, 수정에는 닫혀 있어야 한다는 원칙이다.&lt;/li&gt;
&lt;li&gt;새로운 기능을 추가할 때 기존 코드를 수정하지 않도록 설계하는 것을 의미한다.&lt;/li&gt;
&lt;li&gt;즉, 기능이 추가될 때 확장은 손쉽게, 수정은 최소화하도록 설계해야 한다.&lt;/li&gt;
&lt;li&gt;따라서 추상화를 사용하여 관계를 구축하고 다형성과 확장을 통해 객체 지향을 극대화한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;OCP 개방 폐쇄 원칙 위반 예제 코드&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;새로운 도형을 추가하려면 Shape 클래스를 수정해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717303353367&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Shape {
    public void draw(String shapeType) {
        if (shapeType.equals(&quot;Circle&quot;)) {
            drawCircle();
        } else if (shapeType.equals(&quot;Rectangle&quot;)) {
            drawRectangle();
        }
    }

    private void drawCircle() {
        // Draw Circle
    }

    private void drawRectangle() {
        // Draw Rectangle
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;OCP 개방 폐쇄 원칙&lt;/b&gt;&lt;b&gt;에 맞춰 수정&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이제 새로운 도형을 추가하려면 Shape 클래스를 상속 받아 새로운 도형 클래스를 구현하면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717303494788&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;abstract class Shape {
    public abstract void draw();
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1717303502836&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Circle extends Shape {
    @Override
    public void draw() {
        // Draw Circle
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1717303506548&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Rectangle extends Shape {
    @Override
    public void draw() {
        // Draw Rectangle
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. LSP(Liskov Substitution Principle) 리스코프 치환 원칙&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자식 클래스는 언제나 자신의 부모 클래스를 대체할 수 있어야 한다.&lt;/li&gt;
&lt;li&gt;이는 자식 클래스가 부모 클래스의 기능을 확장하더라도 기본적인 계약을 준수해야 함을 의미한다.&lt;/li&gt;
&lt;li&gt;따라서 해당 객체를 사용하는 클라이언트는 상위 타입이 하위 타입으로 바뀌어도 상위 타입의 public interface를 통해 사용할 수 있어야 한다.&lt;/li&gt;
&lt;li&gt;즉, 클라이언트와 객체 사이 계약이 존재하고 이를 준수해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;LSP 리스코프 치환 원칙 위반 예제 코드&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Square 클래스는 Rectangle 클래스를 상속받지만, 직사각형 Rectangle의 계약을 준수하지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717305397138&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Rectangle {
    private int width;
    private int height;

    public void setWidth(int width) {
        this.width = width;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getArea() {
        return width * height;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1717305404572&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Square extends Rectangle {
    @Override
    public void setWidth(int width) {
        super.setWidth(width);
        super.setHeight(width);
    }

    @Override
    public void setHeight(int height) {
        super.setWidth(height);
        super.setHeight(height);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;LSP 리스코프 치환 원칙&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;에 맞춰 수정&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이제 Square와 Rectangle은 공통의 Shape 클래스를 상속 받아 각각의 면적 계산 방법을 제공한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717305825092&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;abstract class Shape {
    public abstract int getArea();
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1717305835442&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Rectangle extends Shape {
    private int width;
    private int height;

    public void setWidth(int width) {
        this.width = width;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    @Override
    public int getArea() {
        return width * height;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1717305842300&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Square extends Shape {
    private int side;

    public void setSide(int side) {
        this.side = side;
    }

    @Override
    public int getArea() {
        return side * side;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4. ISP(Interface Segregation Principle) 인터페이스 분리 원칙&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트는 자신이 사용하지 않는 메서드에 의존하지 않아야 한다.&lt;/li&gt;
&lt;li&gt;이는 큰 인터페이스를 작고 구체적인 인터페이스로 분리하는 것을 의미한다.&lt;/li&gt;
&lt;li&gt;목적과 관심에 맞는 인터페이스만 클라이언트에게 제공하도록 인터페이스의 분리가 필요하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;ISP 인터페이스 분리 원칙 위반 예제 코드&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Robot 클래스는 eat 메서드를 구현할 필요가 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717306088837&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface Worker {
    void work();
    void eat();
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1717306096799&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Developer implements Worker {
    @Override
    public void work() {
        // Work
    }

    @Override
    public void eat() {
        // Eat
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1717306102223&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Robot implements Worker {
    @Override
    public void work() {
        // Work
    }

    @Override
    public void eat() {
        // Do nothing (robots don't eat)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;ISP 인터페이스 분리 원칙&lt;/b&gt;&lt;b&gt;에 맞춰 수정&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이제 Robot 클래스는 필요 없는 eat 메서드를 구현할 필요가 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717306132557&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface Workable {
    void work();
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1717306137589&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface Eatable {
    void eat();
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1717306146035&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Developer implements Workable, Eatable {
    @Override
    public void work() {
        // Work
    }

    @Override
    public void eat() {
        // Eat
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1717306152869&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Robot implements Workable {
    @Override
    public void work() {
        // Work
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;5. DIP(Dependency Inversion Principle) 의존 역전 원칙&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;고수준 모듈은 저수준 모듈에 의존해서는 안 된다.&lt;/li&gt;
&lt;li&gt;둘 다 추상화에 의존해야 한다.&lt;/li&gt;
&lt;li&gt;이는 구체적인 구현이 아닌 추상화에 의존하도록 만드는 것을 의미한다.&lt;/li&gt;
&lt;li&gt;즉, 어떤 클래스를 참조해야 한다면, 직접 참조가 아닌 그 클래스의 상위 요소(abstract class, interface)로 참조해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;DIP 의존 역전 원칙 위반 예제 코드&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Switch 클래스는 LightBulb 라는 구체적인 클래스에 의존한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717306397433&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class LightBulb {
    public void turnOn() {
        // Turn on the light
    }

    public void turnOff() {
        // Turn off the light
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1717306402754&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Switch {
    private LightBulb lightBulb;

    public Switch(LightBulb lightBulb) {
        this.lightBulb = lightBulb;
    }

    public void operate() {
        lightBulb.turnOn();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;DIP 의존 역전 원칙&lt;/b&gt;&lt;b&gt;에 맞춰 수정&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이제 Switch 클래스는 Switchable 인터페이스에 의존하며, 이는 구체적인 구현이 아닌 추상화에 의존하도록 만든다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1717306416891&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface Switchable {
    void turnOn();
    void turnOff();
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1717306425376&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class LightBulb implements Switchable {
    @Override
    public void turnOn() {
        // Turn on the light
    }

    @Override
    public void turnOff() {
        // Turn off the light
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1717306435478&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Switch {
    private Switchable device;

    public Switch(Switchable device) {
        this.device = device;
    }

    public void operate() {
        device.turnOn();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;참고 자료&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://inpa.tistory.com/entry/OOP-%F0%9F%92%A0-%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5-%EC%84%A4%EA%B3%84%EC%9D%98-5%EA%B0%80%EC%A7%80-%EC%9B%90%EC%B9%99-SOLID&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://inpa.tistory.com/entry/OOP-%F0%9F%92%A0-%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5-%EC%84%A4%EA%B3%84%EC%9D%98-5%EA%B0%80%EC%A7%80-%EC%9B%90%EC%B9%99-SOLID&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;a style=&quot;color: #9d9d9d;&quot; href=&quot;https://mangkyu.tistory.com/194&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://mangkyu.tistory.com/194&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>디자인 패턴 &amp;amp; OOP</category>
      <category>dip</category>
      <category>ISP</category>
      <category>LSP</category>
      <category>ocp</category>
      <category>Solid</category>
      <category>SRP</category>
      <category>객체 지향</category>
      <category>객체 지향 설계 5원칙</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/18</guid>
      <comments>https://cloud-grace.tistory.com/entry/OOP-SOLID-%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5-%EC%84%A4%EA%B3%84-5%EA%B0%80%EC%A7%80-%EC%9B%90%EC%B9%99#entry18comment</comments>
      <pubDate>Sun, 2 Jun 2024 14:37:35 +0900</pubDate>
    </item>
    <item>
      <title>[디자인 패턴] 팩토리 메서드 패턴(Factory Method Pattern)</title>
      <link>https://cloud-grace.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%ED%8C%A9%ED%86%A0%EB%A6%AC-%EB%A9%94%EC%84%9C%EB%93%9C-%ED%8C%A8%ED%84%B4Factory-Method-Pattern</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;팩토리 메서드 패턴(Factory Method Pattern)이란?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팩토리 메서드 패턴은 디자인 패턴(Design Pattern) 중&amp;nbsp;&lt;b&gt;생성 패턴(Creational Pattern)&lt;/b&gt;이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;생성 패턴 : 객체의 생성과 관련된 패턴이며, 객체의 생성 절차를 추상화하는 패턴&lt;/b&gt;&lt;br /&gt;객체를 생성 및 합성하는 방법과 객체의 표현 방법과 시스템을 분리한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;GoF 디자인 패턴에 의하면 팩토리 메서드 패턴은 객체 생성을 서브 클래스로 위임하여 캡슐화한다고 한다.&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;팩토리 메서드 패턴 : 객체를 생성하는 인터페이스를 정의하지만, 어떤 클래스의 인스턴스를 만들지는 서브 클래스가 결정하도록 하는 디자인 패턴이다. 따라서 서브 클래스에게 클래스 인스턴스 생성과 관련한 것을 맡긴다. 이는 객체 생성 코드를 캡슐화하고, 새로운 객체가 추가되더라도 기존 코드를 수정하지 않게 해준다. 즉, 종속성을 줄여준다.&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;팩토리 메서드 패턴은 객체를 생성하는 코드를 한 곳에 모아 두어 객체 생성 과정을 캡슐화하고, 객체 생성 과정을 숨길 경우에 사용한다. 또한, 기존 코드를 수정하지 않고 확장할 수 있는 확장성을 통해 &lt;b&gt;개방-폐쇄 원칙&lt;/b&gt;을 준수한다. 코드 재사용성과 유지보수에 용이하며, 객체 생성 방법을 서브 클래스에서 정의하여 다양한 객체 생성 방식을 유연하게 처리할 수 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;팩토리 메서드 패턴 구조&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oixIk/btsHCVB8dtj/Fx9JKvSyqgRfPAfB6yQOk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oixIk/btsHCVB8dtj/Fx9JKvSyqgRfPAfB6yQOk0/img.png&quot; data-alt=&quot;출처 : pngwing&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oixIk/btsHCVB8dtj/Fx9JKvSyqgRfPAfB6yQOk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoixIk%2FbtsHCVB8dtj%2FFx9JKvSyqgRfPAfB6yQOk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;596&quot; height=&quot;298&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : pngwing&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Creator&lt;/b&gt;&amp;nbsp;: 객체를 생성하기 위한 인터페이스를 정의하며 최상위 공장 클래스이다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;factoryMethod()&lt;/b&gt; : 팩토리 메서드로 서브 공장 클래스에서 재정의할 객체 생성 추상 메서드이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;anOperation()&lt;/b&gt; : 객체 생성을 처리하는 메서드로 객체 생성 전처리 및 후처리를 템플릿처럼 만든다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ConcreteCreator&lt;/b&gt;&amp;nbsp;: Creator 클래스를 상속 받아 팩토리 메서드를 구현하여 구체적인 Product 객체를 생성한다. 각 서브 공장 클래스에 맞는 Product 객체를 반환하도록 한다.&lt;b&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Product&lt;/b&gt;&amp;nbsp;: 생성될 Product 구현체를 추상화한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ConcreateProduct&lt;/b&gt;&amp;nbsp;: Product 구현체이며 구체적인 제품을 정의한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;팩토리 메서드 패턴 예제 코드&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Product 제품 인터페이스 정의&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// Product interface
interface Product {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;void use();
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;ConcreteProduct 구체적인 제품 구현체&lt;/b&gt; : Product 인터페이스 구현 및 각 제품별 로직을 구성한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// ConcreteProduct class
class ConcreteProductA implements Product {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Override
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void use() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;Using ConcreteProductA&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// ConcreteProduct class
class ConcreteProductB implements Product {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Override
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void use() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;System.out.println(&quot;Using ConcreteProductB&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Creator 최상위 공장 추상 클래스&lt;/b&gt; : 외부에서 Product 생성할 때는 anOperation() 메서드 호출, 실제로 어떤 객체를 생성할 지는 추상 메서드(factoryMethod())로 정의해서 서브 클래스에서 정의한다. 또한, protected로 접근을 제한하고 싶을 때 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// Creator Class
abstract class Creator {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;protected abstract Product factoryMethod();

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void anOperation() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Factory Method를 사용하여 객체를 생성
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Product product = factoryMethod();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;product.use();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;ConcreteCreator 공장 객체 반환&lt;/b&gt; : Creator을 상속받아 각 제품별 객체를 반환하도록 오버라이드한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// ConcreteCreator class
class ConcreteCreatorA extends Creator {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Override
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public Product factoryMethod() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return new ConcreteProductA();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// ConcreteCreator class
class ConcreteCreatorB extends Creator {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Override
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public Product factoryMethod() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return new ConcreteProductB();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Client&lt;/b&gt; : ConcreteProduct에 대한 의존성 없이 사용 가능하다. 의존성 주입을 사용하여 외부의 Creator 클래스를 가져온다면 ConcreteCreator에 대한 의존성도 제거가 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class FactoryMethodPatternExample {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public static void main(String[] args) {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Creator creatorA = new ConcreteCreatorA();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;creatorA.someOperation();

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Creator creatorB = new ConcreteCreatorB();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;creatorB.someOperation();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;팩토리 메서드 패턴의 장점&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체 생성 코드를 한 곳에 모아두어 재사용이 가능하다.&lt;/li&gt;
&lt;li&gt;객체 생성 로직을 서브 클래스에서 결정할 수 있어 유연하고 확장성이 높다.&lt;/li&gt;
&lt;li&gt;캡슐화 및 추상화로 객체 타입을 숨길 수 있다.&lt;/li&gt;
&lt;li&gt;Creator과 ConcreteProduct 간의 강한 결합을 피할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;팩토리 매서드 패턴의 단점&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스 수가 늘어나면 코드 구조가 복잡해진다.&lt;/li&gt;
&lt;li&gt;즉, 각 Product 구현체마다 Factory(Creator) 객체를 모두 구현해야 해서 구현체 증가 시 서브 클래스 수가 급증한다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>디자인 패턴 &amp;amp; OOP</category>
      <category>Creational Pattern</category>
      <category>Design Pattern</category>
      <category>Factory Method Pattern</category>
      <category>디자인 패턴</category>
      <category>생성 패턴</category>
      <category>팩토리 메서드 패턴</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/17</guid>
      <comments>https://cloud-grace.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%ED%8C%A9%ED%86%A0%EB%A6%AC-%EB%A9%94%EC%84%9C%EB%93%9C-%ED%8C%A8%ED%84%B4Factory-Method-Pattern#entry17comment</comments>
      <pubDate>Sun, 26 May 2024 00:54:40 +0900</pubDate>
    </item>
    <item>
      <title>[Java] Persistence Framework : SQL Mapper VS ORM</title>
      <link>https://cloud-grace.tistory.com/entry/Java-Persistence-Framework-SQL-Mapper-VS-ORM</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;영속성(Persistence)이란?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영속성(Persistence)은 프로그램이 종료되거나 재시작 되더라도 데이터가 지속적으로 유지되는 특성을 말한다. 쉽게 말해, 데이터를 영구 저장소인 파일 시스템, 데이터베이스 등에 저장하는 것이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;JDBC VS Persistence Framework&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;JDBC (Java Database Connectivity)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JDBC는 Java Database Connectivity로 Java에서 데이터베이스와 연결하여 데이터 저장 및 수정, 저장된 데이터를 사용할 수 있게 해주는 Java API이다. SQL 쿼리를 직접 작성하고 실행할 수 있는 기능을 제공한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;JDBC 예제 코드&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1716621408720&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.sql.*;

public class SelectExample {
    public static void main(String[] args) {
        search(&quot;pat&quot;);
    }
    public static void search(String keyword) {
        Connection connection = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            // 1. JDBC Driver 로딩
            Class.forName(&quot;org.mariadb.jdbc.Driver&quot;);

            // 2. 연결하기
            String url = &quot;jdbc:mariadb://localhost:3306/employees?charset=utf8&quot;;
            connection = DriverManager.getConnection(url, &quot;아이디&quot;, &quot;비밀번호&quot;);

            // 3. Statement 생성하기
            stmt = connection.createStatement();

            // 4. SQL 실행
            String sql =
                            &quot;select emp_no, first_name, last_name&quot; +
                            &quot; from employees&quot; +
                            &quot; where first_name like '%&quot; + keyword + &quot;%'&quot;;
            rs = stmt.executeQuery(sql);

            // 5. 결과 처리
            while (rs.next()) {
                Long empNo = rs.getLong(1);
                String firstName = rs.getString(2);
                String lastName = rs.getString(3);
                System.out.println(empNo + &quot; : &quot; + firstName + &quot; : &quot; + lastName);
            }
        } catch (ClassNotFoundException e) {
            System.out.println(&quot;드라이버 로딩 실패: &quot; + e);
        } catch (SQLException e) {
            System.out.println(&quot;error: &quot; + e);
        } finally {
            try {
                if (stmt!= null) {
                    stmt.close();
                }
                if (rs!= null) {
                    rs.close();
                }
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;JDBC 장단점&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;장점 : SQL을 직접 작성하여 세밀하게 제어가 가능하다.&lt;/li&gt;
&lt;li&gt;단점 : 반복적인 코드 작성과 하드 코딩으로 인해 변경 시 많은 수정이 필요하다. 위 코드만 봐도 예외 처리해야 할 부분이 많다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;영속성 프레임워크(Persistence Framework)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영속성 프레임워크(Persistence Framework)는 데이터베이스와 상호 작용을 추상화하여 개발자가 더 쉽게 데이터를 저장하고 검색할 수 있게 해주는 도구이다. JDBC와 같이 복잡하고 번거로운 작업이 필요 없다. 즉, 자동화된 소프트웨어이며, DB와 맵핑하는 방식에 따라 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;SQL Mapper과 ORM(Object-Relational Mapping)로 나뉜다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Persistence Framework (1) SQL Mapper&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SQL Mapper는 SQL 쿼리를 Java 객체와 맵핑하여 관계형 데이터베이스 작업을 단순화하는 프레임워크이다.&lt;/li&gt;
&lt;li&gt;대표적으로 MyBatis가 있다.&lt;/li&gt;
&lt;li&gt;SQL 쿼리를 XML 파일에 작성하여 독립적인 파일에 작성하여 가독성이 좋고 JDBC에서 제공하는 대부분의 기능을 수행할 수 있다.&lt;/li&gt;
&lt;li&gt;하지만, 객체 모델링보다 데이터 중심 모델링에 더욱 신경을 쓰는 구조이므로 객체지향 측면에서는 좋지 않다.&lt;/li&gt;
&lt;li&gt;따라서 이를 보완하기 위해 ORM이 등장하였다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;MyBatis 예제 코드&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt; &lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;mybatis-config.xml&lt;/span&gt; (MyBatis 설정 파일)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716623558843&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;configuration&amp;gt;
    &amp;lt;environments default=&quot;development&quot;&amp;gt;
        &amp;lt;environment id=&quot;development&quot;&amp;gt;
            &amp;lt;transactionManager type=&quot;JDBC&quot;/&amp;gt;
            &amp;lt;dataSource type=&quot;POOLED&quot;&amp;gt;
                &amp;lt;property name=&quot;driver&quot; value=&quot;org.h2.Driver&quot;/&amp;gt;
                &amp;lt;property name=&quot;url&quot; value=&quot;jdbc:h2:mem:test;DB_CLOSE_DELAY=-1&quot;/&amp;gt;
                &amp;lt;property name=&quot;username&quot; value=&quot;sa&quot;/&amp;gt;
                &amp;lt;property name=&quot;password&quot; value=&quot;&quot;/&amp;gt;
            &amp;lt;/dataSource&amp;gt;
        &amp;lt;/environment&amp;gt;
    &amp;lt;/environments&amp;gt;
    &amp;lt;mappers&amp;gt;
        &amp;lt;mapper resource=&quot;UserMapper.xml&quot;/&amp;gt;
    &amp;lt;/mappers&amp;gt;
&amp;lt;/configuration&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;UserMapper.xml&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716623465439&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;mapper namespace=&quot;com.example.mapper.UserMapper&quot;&amp;gt;
    &amp;lt;select id=&quot;getUserById&quot; parameterType=&quot;int&quot; resultType=&quot;com.example.model.User&quot;&amp;gt;
        SELECT * FROM users WHERE id = #{id}
    &amp;lt;/select&amp;gt;
&amp;lt;/mapper&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;MyBatisExample.java&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716623670838&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package com.example;

import com.example.mapper.UserMapper;
import com.example.model.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.Reader;

public class MyBatisExample {
    public static void main(String[] args) {
        try {
            // MyBatis 설정 파일 읽기
            Reader reader = Resources.getResourceAsReader(&quot;mybatis-config.xml&quot;);
            
            // SqlSessionFactory 생성
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            
            // SqlSession 생성
            SqlSession session = sqlSessionFactory.openSession();
            
            // UserMapper 인터페이스 구현체 생성
            UserMapper mapper = session.getMapper(UserMapper.class);
            
            // 사용자 정보 가져오기
            User user = mapper.getUserById(1);
            
            System.out.println(&quot;사용자 이름: &quot; + user.getName());
            System.out.println(&quot;사용자 이메일: &quot; + user.getEmail());
            
            session.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Persistence Framework (2) ORM (Object-Relational Mapping)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ORM은 객체지향 프로그래밍 언어의 객체와 관계형 데이터베이스의 테이블을 자동으로 맵핑해주는 기술이다.&lt;/li&gt;
&lt;li&gt;대표적으로 Hibernate, JPA(Java Persistence API), Spring Data JPA가 있다.&lt;/li&gt;
&lt;li&gt;CRUD 관련 메서드를 사용해서 쿼리 생성 및 실행을 자동으로 처리해준다.&lt;/li&gt;
&lt;li&gt;복잡한 쿼리일 경우 SQL Mapper와 함께 사용해도 된다.&lt;/li&gt;
&lt;li&gt;JPA는 Java에서 ORM 기술에 대한 인터페이스 표준이며, 이를 구현한 구현체가 대표적으로 Hibernate이다.&lt;/li&gt;
&lt;li&gt;객체 모델 중심의 설계로 DBMS에 의존하지 않으며 비즈니스 로직 개발에 초점을 맞출 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;JPA&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;JPA는 Java Persistence API의 약자로 Java의 ORM 표준 명세이다.&lt;/li&gt;
&lt;li&gt;ORM 기술을 사용하기 위해 인터페이스를 모아둔 것이다. 즉, 구현체가 필요하다.&lt;/li&gt;
&lt;li&gt;내부적으로 &lt;u&gt;&lt;b&gt;영속성 컨텍스트&lt;/b&gt;&lt;/u&gt;를 생성하여 Entity를 관리한다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;u&gt;&lt;b&gt;영속성 컨텍스트&lt;/b&gt;&lt;/u&gt; : 엔티티를 영구 저장하는 환경이다.&lt;/li&gt;
&lt;li&gt;애플레케이션과 데이터베이스 사이에서 객체를 보관하는 가상의 데이터베이스와 같은 역할을 한다.&lt;/li&gt;
&lt;li&gt;엔티티 매니저를 통해 엔티티를 저장 or 조회하면 엔티티 매니저는 영속성 컨텍스트에 엔티티를 보관하고 관리한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;변경이 감지되면 Entity를 수정해도 알맞게 쿼리가 생성되며, 쓰기 지연 방식을 통해서 쿼리 저장소에 있는 쿼리를 한번에 flush하며 Connection을 최소화하여 성능을 향상시킬 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Hibernate&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;JPA의 구현체 중 하나로, 많은 기능과 강력한 ORM 기능을 제공하는 인기있는 오픈 소스 프레임워크이다.&lt;/li&gt;
&lt;li&gt;JPA 표준을 따르며, JPA에서 정의한 인터페이스를 구현한다.&lt;/li&gt;
&lt;li&gt;내부적으로 쿼리를 생성하고 JDBC API를 호출한다.&lt;/li&gt;
&lt;li&gt;하지만 모든 부분에서 쿼리가 적합할 순 없기에 개발자가 능동적으로 쿼리를 수정할 필요가 있고, 이럴 때는 Spring Data JPA를 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Spring Data JPA&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;JPA를 한 단계 더 추상화를 한 Repository라는 것이 있으며, Repository Interface에 JPARepository를 상속하면 구현화된 객체를 주입해준다.&lt;/li&gt;
&lt;li&gt;Repository Interface 내부에 작성한 메서드를 스프링이 알맞은 쿼리를 만들어 전송하게 해준다.&lt;/li&gt;
&lt;li&gt;쿼리 어노테이션을 활용하여 개발자가 만든 쿼리를 전송할 수도 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;예제 코드&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;엔티티 클래스&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716626100684&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import javax.persistence.*;
import lombok.Data;

@Entity
@Table(name = &quot;employees&quot;)
@Data
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private String department;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Repository 인터페이스&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716626143591&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.data.jpa.repository.JpaRepository;

public interface EmployeeRepository extends JpaRepository&amp;lt;Employee, Long&amp;gt; {
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;서비스 클래스&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1716626180186&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class EmployeeService {
    @Autowired
    private EmployeeRepository employeeRepository;

    public List&amp;lt;Employee&amp;gt; getAllEmployees() {
        return employeeRepository.findAll();
    }

    public Employee saveEmployee(Employee employee) {
        return employeeRepository.save(employee);
    }

    // 기타 메서드...
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Java</category>
      <category>hibernate</category>
      <category>Java</category>
      <category>JDBC</category>
      <category>JPA</category>
      <category>mybatis</category>
      <category>ORM</category>
      <category>Persistence Framework</category>
      <category>Spring Data JPA</category>
      <category>SQL Mapper</category>
      <category>영속성</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/16</guid>
      <comments>https://cloud-grace.tistory.com/entry/Java-Persistence-Framework-SQL-Mapper-VS-ORM#entry16comment</comments>
      <pubDate>Sat, 25 May 2024 17:39:12 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 박싱(Boxing), 언박싱(UnBoxing), 오토박싱(AutoBoxing), 오토언박싱(AutoUnBoxing), 래퍼 클래스(Wrapper Class)</title>
      <link>https://cloud-grace.tistory.com/entry/Java-%EB%B0%95%EC%8B%B1Boxing-%EC%96%B8%EB%B0%95%EC%8B%B1UnBoxing-%EC%98%A4%ED%86%A0%EB%B0%95%EC%8B%B1AutoBoxing-%EC%98%A4%ED%86%A0%EC%96%B8%EB%B0%95%EC%8B%B1AutoUnBoxing-%EB%9E%98%ED%8D%BC-%ED%81%B4%EB%9E%98%EC%8A%A4Wrapper-Class</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Java 데이터 타입&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java의 데이터 타입은 크게 2가지로 나뉜다. 원시 타입(Primitive Type)과 참조 타입(Reference Type)으로 존재하며, 종종 원시 타입으로 사용하는 데이터를 객체로 표현해야 하는 경우가 있다. 원시 타입은 int, char, boolean, float, double 등의 기본 데이터 타입이다. 이 타입들은 래퍼 클래스(Wrapper Class)를 활용해서 객체로 사용할 수 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;래퍼 클래스(Wrapper Class)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;래퍼 클래스(Wrapper Class)는 원시 타입을 객체로 사용하기 위해 사용하는 클래스이다.&lt;/li&gt;
&lt;li&gt;Java는 모든 원시 타입을 객체로 만들 수 있다.&lt;/li&gt;
&lt;li&gt;래퍼 클래스는 값을 포장해서 객체로 만드는 것이다.&lt;/li&gt;
&lt;li&gt;래퍼 클래스는 java.lang package에서 제공된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 154px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style11&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 18px;&quot;&gt;&lt;b&gt;기본 타입&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 18px;&quot;&gt;&lt;b&gt;래퍼 클래스&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 17px;&quot;&gt;byte&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 17px;&quot;&gt;Byte&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 17px;&quot;&gt;short&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 17px;&quot;&gt;Short&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 17px;&quot;&gt;int&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 17px;&quot;&gt;Integer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 17px;&quot;&gt;long&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 17px;&quot;&gt;Long&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 17px;&quot;&gt;float&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 17px;&quot;&gt;Float&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 17px;&quot;&gt;double&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 17px;&quot;&gt;Double&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 17px;&quot;&gt;char&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 17px;&quot;&gt;Character&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 17px;&quot;&gt;boolean&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 17px;&quot;&gt;Boolean&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;원시 타입을 객체로 표현해야 하는 경우&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1) 컬렉션&amp;nbsp;프레임워크(Collection&amp;nbsp;Framework)를&amp;nbsp;사용할&amp;nbsp;때&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Java의 컬렉션 프레임워크(List, Set, Map 등)는 객체만 다룬다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716614326081&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;Integer&amp;gt; intList = new ArrayList&amp;lt;&amp;gt;();
intList.add(10);  // Autoboxing: int 10이 Integer 객체로 변환됨&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2) 메서드 인자로 객체가 필요할 때&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메서드 인자로 객체를 요구할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716614533028&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public void printObject(Object obj) {
    System.out.println(obj);
}

printObject(10);  // Autoboxing: int 10이 Integer 객체로 변환됨&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3) 제네릭(Generic)을 사용할 때&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;제네릭은 원시 타입을 사용할 수 없고, 객체 타입만 사용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716614547886&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Box&amp;lt;T&amp;gt; {
    private T value;

    public void setValue(T value) {
        this.value = value;
    }

    public T getValue() {
        return value;
    }
}

Box&amp;lt;Integer&amp;gt; intBox = new Box&amp;lt;&amp;gt;();
intBox.setValue(10);  // Autoboxing: int 10이 Integer 객체로 변환됨&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;4) 객체 메서드를 사용해야 할 때&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;원시 타입에는 메서드가 없지만, 래퍼 클래스에는 다양한 메서드가 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716614559011&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String number = &quot;123&quot;;
int result = Integer.parseInt(number); // Integer 클래스의 parseInt 메서드가 있다.&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;5) 동기화(synchronization)가 필요할 때&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;원시 타입은 동기화 블록에서 직접 사용할 수 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716614582264&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Integer count = 0;

synchronized(count) {
    count++;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;6) 함수형 프로그래밍과 람다 표현식을 사용할 때&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Java 8 이후 도입된 함수형 인터페이스와 람다 표현식에서도 원시 타입을 바로 사용할 수 없고, 객체 타입을 사용해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716614598091&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;Integer&amp;gt; numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream().mapToInt(Integer::intValue).sum();&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;박싱 Boxing &amp;amp; 언박싱 UnBoxing&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;박싱 Boxing : 원시 타입&amp;nbsp;&amp;rarr; 래퍼 클래스&lt;/li&gt;
&lt;li&gt;언박싱 UnBoxing : 래퍼 클래스 &amp;rarr; 원시 타입&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;오토박싱 AutoBoxing &amp;amp; 오토언박싱 AutoUnBoxing&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;오토박싱 AutoBoxing과 오토언박싱 AutoUnBoxing은 Java 컴파일러가 박싱 &amp;amp; 언박싱이 필요한 상황에 자동으로 수행해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716615687351&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class AutoboxingUnboxingExample {
    public static void main(String[] args) {
        // 오토 박싱: 원시 타입 int가 Integer 객체로 변환됨
        Integer boxedInt = 100;  // Autoboxing

        // 오토 언박싱: Integer 객체가 원시 타입 int로 변환됨
        int primitiveInt = boxedInt;  // Unboxing

        // 오토 박싱을 이용한 리스트 생성
        List&amp;lt;Integer&amp;gt; list = new ArrayList&amp;lt;&amp;gt;();
        list.add(10);  // Autoboxing
        list.add(20);  // Autoboxing

        // 오토 언박싱을 이용한 합계 계산
        int sum = 0;
        for (int num : list) {  // Unboxing
            sum += num;
        }

        // 결과
        System.out.println(&quot;Boxed Integer: &quot; + boxedInt);
        System.out.println(&quot;Primitive int: &quot; + primitiveInt);
        System.out.println(&quot;Sum of list elements: &quot; + sum);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;래퍼 클래스 값 비교&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;참조 타입인 래퍼 클래스 값 비교는 equals, 인스턴스의 주소 비교는 == 를 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716616214615&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class WrapperClassComparison {
    public static void main(String[] args) {
        Integer a = 100;
        Integer b = 100;
        Integer c = 200;
        Integer d = 200;

        // 객체 참조 비교 (자동 언박싱)
        System.out.println(a == b);  // true, -128부터 127까지는 캐싱되어 동일한 참조
        System.out.println(c == d);  // false, 128 이상의 값은 새로 객체가 생성됨

        // 값 비교
        System.out.println(a.equals(b));  // true
        System.out.println(c.equals(d));  // true
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;NullPointException 에러&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;래퍼 클래스 객체를 사용하면 NullPointException 에러를 많이 보게 된다.&lt;/li&gt;
&lt;li&gt;원시 타입과 Null을 가지는 래퍼 클래스 객체와 연산을 하면 이 에러가 발생한다.&lt;/li&gt;
&lt;li&gt;아래 예시는 + 연산을 하면서 n이 오토언박싱이 되는 도중 에러가 발생한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716616638173&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class NullPointExceptionError {
    public static void main(String[] args) {
        Integer n = null;
        int a = 10;
        
        System.out.println(n + a);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;자료형 변환 예제&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;래퍼 클래스의 parseType() 메서드로 데이터 타입 변환 시 자주 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716616860748&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class WrapperClassConversionExample {
    public static void main(String[] args) {
        // Integer 객체를 다양한 타입으로 변환
        Integer integerObject = 42;
        int primitiveInt = integerObject.intValue();
        long primitiveLong = integerObject.longValue();
        float primitiveFloat = integerObject.floatValue();
        double primitiveDoubleFromInt = integerObject.doubleValue();

        // Double 객체를 다양한 타입으로 변환
        Double doubleObject = 42.0;
        double primitiveDouble = doubleObject.doubleValue();
        int primitiveIntFromDouble = doubleObject.intValue();

        // Boolean 객체를 boolean 타입으로 변환
        Boolean booleanObject = true;
        boolean primitiveBoolean = booleanObject.booleanValue();

        // String 객체를 원시 타입으로 변환
        String numberStr = &quot;42&quot;;
        int parsedInt = Integer.parseInt(numberStr);

        String doubleStr = &quot;42.0&quot;;
        double parsedDouble = Double.parseDouble(doubleStr);

        String booleanStr = &quot;true&quot;;
        boolean parsedBoolean = Boolean.parseBoolean(booleanStr);

        // 결과
        System.out.println(&quot;Integer to int: &quot; + primitiveInt);
        System.out.println(&quot;Integer to long: &quot; + primitiveLong);
        System.out.println(&quot;Integer to float: &quot; + primitiveFloat);
        System.out.println(&quot;Integer to double: &quot; + primitiveDoubleFromInt);

        System.out.println(&quot;Double to double: &quot; + primitiveDouble);
        System.out.println(&quot;Double to int: &quot; + primitiveIntFromDouble);

        System.out.println(&quot;Boolean to boolean: &quot; + primitiveBoolean);

        System.out.println(&quot;String to int: &quot; + parsedInt);
        System.out.println(&quot;String to double: &quot; + parsedDouble);
        System.out.println(&quot;String to boolean: &quot; + parsedBoolean);
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Java</category>
      <category>Java</category>
      <category>Wrapper class</category>
      <category>래퍼 클래스</category>
      <category>박싱</category>
      <category>언박싱</category>
      <category>오토박싱</category>
      <category>오토언박싱</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/15</guid>
      <comments>https://cloud-grace.tistory.com/entry/Java-%EB%B0%95%EC%8B%B1Boxing-%EC%96%B8%EB%B0%95%EC%8B%B1UnBoxing-%EC%98%A4%ED%86%A0%EB%B0%95%EC%8B%B1AutoBoxing-%EC%98%A4%ED%86%A0%EC%96%B8%EB%B0%95%EC%8B%B1AutoUnBoxing-%EB%9E%98%ED%8D%BC-%ED%81%B4%EB%9E%98%EC%8A%A4Wrapper-Class#entry15comment</comments>
      <pubDate>Sat, 25 May 2024 15:05:04 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 변수 원시 타입(Primitive Type) VS 참조 타입(Reference Type)</title>
      <link>https://cloud-grace.tistory.com/entry/Java-%EB%B3%80%EC%88%98-%EC%9B%90%EC%8B%9C-%ED%83%80%EC%9E%85Primitive-Type-VS-%EC%B0%B8%EC%A1%B0-%ED%83%80%EC%9E%85Reference-Type</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Java에서는 데이터 타입이 2가지로 나뉜다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Java 변수 원시 타입(Primitive Type)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;원시 타입(Primitive Type)은 정수, 실수, 문자, 논리 리터럴 등의 실제 데이터 값을 저장하는 타입이다.&lt;/li&gt;
&lt;li&gt;JVM의 정적 메모리 Stack 영역에 변수 이름의 메모리 공간이 생성되고 실제 값이 데이터 값이 들어간다.&lt;/li&gt;
&lt;li&gt;원시 타입은 Null을 담을 수 없으며, 값이 없으면 default 값을 반환한다. (예를 들어, int는 0, boolean은 false)&lt;/li&gt;
&lt;li&gt;원시 타입은 제네릭(generic) 타입에서 사용할 수 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 156px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 9.76744%; text-align: center; height: 18px;&quot;&gt;&lt;b&gt;종류&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 13.9535%; text-align: center; height: 18px;&quot;&gt;&lt;b&gt;데이터형&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.3954%; text-align: center; height: 18px;&quot;&gt;&lt;b&gt;크기(byte/bit)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 59.8837%; text-align: center; height: 18px;&quot;&gt;&lt;b&gt;표현 범위&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 9.76744%; text-align: center; height: 18px;&quot;&gt;논리형&lt;/td&gt;
&lt;td style=&quot;width: 13.9535%; text-align: center; height: 18px;&quot;&gt;boolean&lt;/td&gt;
&lt;td style=&quot;width: 16.3954%; text-align: center; height: 18px;&quot;&gt;1/8&lt;/td&gt;
&lt;td style=&quot;width: 59.8837%; text-align: center; height: 18px;&quot;&gt;true or false&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 9.76744%; text-align: center; height: 18px;&quot;&gt;문자형&lt;/td&gt;
&lt;td style=&quot;width: 13.9535%; text-align: center; height: 18px;&quot;&gt;char&lt;/td&gt;
&lt;td style=&quot;width: 16.3954%; text-align: center; height: 18px;&quot;&gt;2/16&lt;/td&gt;
&lt;td style=&quot;width: 59.8837%; text-align: center; height: 18px;&quot;&gt;'\u0000' ~ \uFFFF' 16bit 유니코드 문자 데이터&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 9.76744%; text-align: center; height: 17px;&quot;&gt;정수형&lt;/td&gt;
&lt;td style=&quot;width: 13.9535%; text-align: center; height: 17px;&quot;&gt;byte&lt;/td&gt;
&lt;td style=&quot;width: 16.3954%; text-align: center; height: 17px;&quot;&gt;1/8&lt;/td&gt;
&lt;td style=&quot;width: 59.8837%; text-align: center; height: 17px;&quot;&gt;-128 ~ 127&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 9.76744%; text-align: center; height: 17px;&quot;&gt;정수형&lt;/td&gt;
&lt;td style=&quot;width: 13.9535%; text-align: center; height: 17px;&quot;&gt;short&lt;/td&gt;
&lt;td style=&quot;width: 16.3954%; text-align: center; height: 17px;&quot;&gt;2/16&lt;/td&gt;
&lt;td style=&quot;width: 59.8837%; text-align: center; height: 17px;&quot;&gt;-32768 ~ 32767&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 9.76744%; text-align: center; height: 17px;&quot;&gt;정수형&lt;/td&gt;
&lt;td style=&quot;width: 13.9535%; text-align: center; height: 17px;&quot;&gt;int&lt;/td&gt;
&lt;td style=&quot;width: 16.3954%; text-align: center; height: 17px;&quot;&gt;4/32&lt;/td&gt;
&lt;td style=&quot;width: 59.8837%; text-align: center; height: 17px;&quot;&gt;-2147483648 ~ 2147483647(-21억&amp;nbsp; ~ +21억)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 9.76744%; text-align: center; height: 17px;&quot;&gt;정수형&lt;/td&gt;
&lt;td style=&quot;width: 13.9535%; text-align: center; height: 17px;&quot;&gt;long&lt;/td&gt;
&lt;td style=&quot;width: 16.3954%; text-align: center; height: 17px;&quot;&gt;8/64&lt;/td&gt;
&lt;td style=&quot;width: 59.8837%; text-align: center; height: 17px;&quot;&gt;-9223372036854775808 ~ 9223372036854775807(-100경 ~ +100경)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 9.76744%; text-align: center; height: 17px;&quot;&gt;실수형&lt;/td&gt;
&lt;td style=&quot;width: 13.9535%; text-align: center; height: 17px;&quot;&gt;float&lt;/td&gt;
&lt;td style=&quot;width: 16.3954%; text-align: center; height: 17px;&quot;&gt;4/32&lt;/td&gt;
&lt;td style=&quot;width: 59.8837%; text-align: center; height: 17px;&quot;&gt;1.4E-45 ~ 3.4028235E38&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 9.76744%; text-align: center; height: 17px;&quot;&gt;실수형&lt;/td&gt;
&lt;td style=&quot;width: 13.9535%; text-align: center; height: 17px;&quot;&gt;double&lt;/td&gt;
&lt;td style=&quot;width: 16.3954%; text-align: center; height: 17px;&quot;&gt;8/64&lt;/td&gt;
&lt;td style=&quot;width: 59.8837%; text-align: center; height: 17px;&quot;&gt;4.9E-324 ~ 1.7976931348623157E308&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Java 변수 참조 타입(Reference Type)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;참조 타입(Reference Type)은 문자열(String), 배열(Array), 열거형(Enum), 상수(Constant), 클래스(Class), 인터페이스(Interface) 등, 객체(Object)의 주소를 저장하는 타입이다.&lt;/li&gt;
&lt;li&gt;추가로, 사용자가 필요하면 참조형 타입을 정의할 수도 있다.&lt;/li&gt;
&lt;li&gt;JVM의 동적 메모리 Heap 영역에 실제 객체가 저장되고 참조 타입 변수는 JVM Stack 영역에 실제 객체 주소를 저장한다.&lt;/li&gt;
&lt;li&gt;이 객체를 사용할 때 참조 변수에 저장된 객체 주소를 불러와서 사용한다.&lt;/li&gt;
&lt;li&gt;원시 타입과 달리 참조 타입은 실제 값이 Heap 영역에 있기 때문에 최소 2번 메모리 접근을 해야해서 언박싱 과정에서 원시 타입에 비해 접근 속도가 느리다.&lt;/li&gt;
&lt;li&gt;또한, 참조 타입이 원시 타입보다 메모리 양이 훨씬 크다.&lt;/li&gt;
&lt;li&gt;참조 타입은 Null을 담을 수 있다.&lt;/li&gt;
&lt;li&gt;참조 타입은 제네릭(generic) 타입에서 사용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Java</category>
      <category>Java</category>
      <category>Primitive type</category>
      <category>reference type</category>
      <category>원시 타입</category>
      <category>참조 타입</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/14</guid>
      <comments>https://cloud-grace.tistory.com/entry/Java-%EB%B3%80%EC%88%98-%EC%9B%90%EC%8B%9C-%ED%83%80%EC%9E%85Primitive-Type-VS-%EC%B0%B8%EC%A1%B0-%ED%83%80%EC%9E%85Reference-Type#entry14comment</comments>
      <pubDate>Sat, 25 May 2024 14:01:36 +0900</pubDate>
    </item>
    <item>
      <title>[Java] JUnit이란? Assert(단정 메서드), Lifecycle(라이프사이클 메서드)</title>
      <link>https://cloud-grace.tistory.com/entry/Java-JUnit-Assert%EB%8B%A8%EC%A0%95-%EB%A9%94%EC%84%9C%EB%93%9C-Lifecycle%EB%9D%BC%EC%9D%B4%ED%94%84%EC%82%AC%EC%9D%B4%ED%81%B4-%EB%A9%94%EC%84%9C%EB%93%9C</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;JUnit이란?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;/b&gt;JUnit은 Java 로 단위 테스트를 할 수 있는 라이브러리이다. 개발자들은 개별 코드 단위(메서드, 클래스 등)를 테스트 하고 그 동작이 기대한 대로 수행되는지 확인할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단정 메서드(assert~~)로 테스트 케이스의 수행 결과를 판별할 수 있다.&lt;/li&gt;
&lt;li&gt;테스트 메서드를 정의하고 관리하기 위해 다양한 어노테이션을 제공한다.&lt;/li&gt;
&lt;li&gt;테스트 결과로 성공 or 실패를 확인하고 오류를 확인하고 저장할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;br /&gt;&lt;b&gt;Unit&amp;nbsp;Test&amp;nbsp;단위&amp;nbsp;테스트&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단위 테스트는 소프트웨어 개발에서 개별 단위(주로 메서드, 클래스)를 테스트하는 것이다. 각 단위가 올바르게 작동하는지 확인하고 의도대로 정확히 동작하는지 테스트한다.&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;JUnit 어노테이션&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@Test&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해당 메서드가 테스트 메서드임을 나타낸다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@Test(expected=예외)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해당 테스트 메소드가 예외 발생이 되었는지 성공 or 실패를 확인할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Test(expected = ArithmeticException.class)
public void testDivideByZero() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int result = calculator.divide(1, 0);
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다른 방법으로 assertThrows 메서드를 사용해서 특정 예외가 발생하는지 검증 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Test
void testDivideByZero() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assertThrows(ArithmeticException.class, () -&amp;gt; calculator.divide(1, 0));
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@Test(timeout=밀리초)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테스트 메서드가 지정된 시간 내에 완료되지 않으면 실패로 간주한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Test(timeout = 1000)
public void testDivideByZero() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int result = calculator.divide(1, 0);
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다른 방법으로 @Timeout을 사용해서 테스트 메서드 실행 시간을 제한할 수 도 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import org.junit.jupiter.api.Timeout;
import java.util.concurrent.TimeUnit;

@Test
@Timeout(value = 1, unit = TimeUnit.SECONDS)
void testDivideByZero() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assertThrows(ArithmeticException.class, () -&amp;gt; calculator.divide(1, 0));
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@Disabled (@Ignore in JUnit 4)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 테스트 메서드를 비활성화한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;JUnit Lifecycle 라이프사이클 메서드 (JUnit 5)&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;실행 순서&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( ) 괄호 부분이 반복된다.&lt;br /&gt;@BeforeAll &amp;rarr; (@BeforeEach &amp;rarr; @Test &amp;rarr; @AfterEach &amp;rarr;&amp;nbsp;@BeforeEach&amp;nbsp;&amp;rarr;&amp;nbsp;@Test&amp;nbsp;&amp;rarr;&amp;nbsp;@AfterEach) &amp;rarr; @AfterAll&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@BeforeEach (@Before in JUnit4)&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각각의 모든 테스트 메서드가 실행되기 전에 실행될 메서드를 지정한다.&lt;/li&gt;
&lt;li&gt;@Test 메서드에서 공통으로 사용될 코드나 리셋되어야 할 부분을 넣으면 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@AfterEach (@After &lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;in JUnit4)&lt;/b&gt;&lt;/span&gt;&lt;b&gt; &lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각각의 모든 테스트 메서드가 실행되고 난 후에 실행될 메서드를 지정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@BeforeAll (@BeforeClass &lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;in JUnit4)&lt;/b&gt;&lt;/span&gt;&lt;b&gt; &lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 테스트 클래스 실행되기 전 딱 1번만 실행되는 메서드이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;@AfterAll (@AfterClass &lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;in JUnit4)&lt;/b&gt;&lt;/span&gt;&lt;b&gt; &lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 테스트 클래스 실행된 후에 딱 1번만 실행되는 메서드이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;JUnit&amp;nbsp;assert&amp;nbsp;메서드&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;assertEquals(expected, actual): 예상 값과 실제 값이 같은지 확인한다.&lt;/li&gt;
&lt;li&gt;assertEquals(expected, actual, delta): 부동 소수점 비교를 위한 허용 오차를 포함하는 메서드이다. delta는 오차 범위이다.&lt;/li&gt;
&lt;li&gt;assertTrue(condition): 조건이 참인지 확인한다.&lt;/li&gt;
&lt;li&gt;assertFalse(condition): 조건이 거짓인지 확인한다.&lt;/li&gt;
&lt;li&gt;assertNull(object): 객체가 NULL인지 확인한다.&lt;/li&gt;
&lt;li&gt;assertNotNull(object): 객체가 NULL이 아닌지 확인한다.&lt;/li&gt;
&lt;li&gt;assertThrows(expectedType, executable): 지정된 타입의 예외가 발생하는지 확인한다.&lt;/li&gt;
&lt;li&gt;assertArrayEquals(expectedArray, actualArray): 두 배열의 모든 요소가 같은지 비교한다.&lt;/li&gt;
&lt;li&gt;assertSame(expected, actual): 두 객체가 동일한 객체(참조가 같은지)인지 비교한다.&lt;/li&gt;
&lt;li&gt;assertTimeout(duration, executable): 지정된 시간 내에 실행이 완료되는지 확인한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;예제 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import java.util.Arrays;

public class AssertionExamples {

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Test
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;void testAssertEquals() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int expected = 5;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int actual = 2 + 3;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assertEquals(expected, actual); // 5 == 5, 통과
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Test
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;void testAssertArrayEquals() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int[] expected = {1, 2, 3};
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int[] actual = {1, 2, 3};
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assertArrayEquals(expected, actual); // 통과
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Test
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;void testAssertSame() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String a = &quot;hello&quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String b = &quot;hello&quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String c = new String(&quot;hello&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assertSame(a, b); // 통과
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assertNotSame(a, c); // 통과
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Test
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;void testAssertTimeout() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assertTimeout(ofSeconds(1), () -&amp;gt; {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// 1초 이내 완료되는 작업
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Thread.sleep(500);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}); // 1초 이내 완료되므로 통과
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;AssertJ란?&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Java JUnit의 기본 assertion 메서드를 보완하여 더 직관적이고 가독성 좋은 테스트 코드를 작성하게 해준다.&lt;/li&gt;
&lt;li&gt;체이닝 기법을 통해 다양한 검증을 한 줄로 작성할 수 있다.&lt;/li&gt;
&lt;li&gt;테스트에 필요한 메서드가 매우 많다.&lt;/li&gt;
&lt;li&gt;AssertJ의 모든 테스트 코드는 assertThat(actual)로 검증을 시작한다.&lt;/li&gt;
&lt;li&gt;메서드 체이닝 기법을 통해 assertThat(actual).메서드().메서드().메서드()... 이런 형식으로 작성한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;AssertJ&amp;nbsp;메서드&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;assertThat(actual): 검증을 시작한다.&lt;/li&gt;
&lt;li&gt;isEqualTo(expected): 예상 값과 실제 값이 같은지 확인한다.&lt;/li&gt;
&lt;li&gt;isNotNull(): 객체가 null이 아닌지 확인한다.&lt;/li&gt;
&lt;li&gt;isTrue(): 조건이 참인지 확인한다.&lt;/li&gt;
&lt;li&gt;isFalse(): 조건이 거짓인지 확인한다.&lt;/li&gt;
&lt;li&gt;contains(expected): 컬렉션이나 배열에 특정 값이 포함되어 있는지 확인한다.&lt;/li&gt;
&lt;li&gt;hasSize(size): 컬렉션이나 배열의 크기를 확인한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;AssertJ&amp;nbsp;예제&amp;nbsp;코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;java&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.*;

public class AssertionExamples {

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@Test
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;void testAssertJ() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String text = &quot;Hello, World!&quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int[] numbers = {1, 2, 3, 4, 5};
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Object obj = new Object();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;boolean condition = true;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assertThat(text).startsWith(&quot;Hello&quot;).endsWith(&quot;!&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assertThat(numbers).hasSize(5).contains(3).doesNotContain(6);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assertThat(obj).isNotNull().isInstanceOf(Object.class);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;assertThat(condition).isTrue();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Java</category>
      <category>Java</category>
      <category>junit</category>
      <category>junit5</category>
      <category>test</category>
      <category>단위테스트</category>
      <category>단정 메서드</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/13</guid>
      <comments>https://cloud-grace.tistory.com/entry/Java-JUnit-Assert%EB%8B%A8%EC%A0%95-%EB%A9%94%EC%84%9C%EB%93%9C-Lifecycle%EB%9D%BC%EC%9D%B4%ED%94%84%EC%82%AC%EC%9D%B4%ED%81%B4-%EB%A9%94%EC%84%9C%EB%93%9C#entry13comment</comments>
      <pubDate>Fri, 24 May 2024 17:54:38 +0900</pubDate>
    </item>
    <item>
      <title>[Java] try-with-resources로 자원 반납하기</title>
      <link>https://cloud-grace.tistory.com/entry/Java-Try-with-resources%EB%A1%9C-%EC%9E%90%EC%9B%90-%EB%B0%98%EB%82%A9%ED%95%98%EA%B8%B0</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Java Resource&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java에서 외부 데이터를 활용해서 코드를 작성할 때는 마지막에 꼭 자원을 닫으면서 정리를 해야한다. 주로 Resource로는 외부 데이터로 쓰이는 &lt;b&gt;Database, Network, File&lt;/b&gt;들이 있다. 이를 활용하려면 &lt;b&gt;항상 예외가 발생할 가능성&lt;/b&gt;이 존재한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;try-catch-finally 자원 반납 처리&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아래와 같이 example.txt 파일을 읽기 위해 BufferedReader를 사용하는 예시이다.&lt;/li&gt;
&lt;li&gt;가장 먼저 이 파일을 읽는데 예상치 못한 오류가 생길 수 있고, Checked Exception인 IOException 예외 처리를 해준다.&lt;/li&gt;
&lt;li&gt;그 다음, 외부 Resource인 txt 파일을 사용하고 반드시 닫아야 하기 때문에 finally 문으로 close()를 해준다.&lt;/li&gt;
&lt;li&gt;close()를 할 때도 IOException 발생 여지가 있기 때문에 역시나 finally 내부 안에서도 try-catch를 작성하여 예외 처리를 해준다.&lt;/li&gt;
&lt;li&gt;단순히 파일 1개를 열고 닫는 것이지만 코드는 &lt;b&gt;꽤나 가독성이 떨어진다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;여기서 더 간편히 예외 처리를 할 수 있는 &lt;b&gt;try-with-resources 문법&lt;/b&gt;이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716384010252&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class FileReadExample {
    public static void main(String[] args) {
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader(&quot;example.txt&quot;));
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;try-with-resources 자원 반납 처리&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Java 7부터 도입된 try-with-resources 문법은 자원을 자동으로 닫을 수 있다.&lt;/li&gt;
&lt;li&gt;이를 사용하면 코드가 더 간결하고, 자원 누수의 위험을 줄일 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716384969649&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;try (열고 닫는 파일과 할당할 자원이 들어가는 명령문) {

} catch (Exception e) {

}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;AutoCloseable 인터페이스&lt;/b&gt;를 구현한 자원들은 try 블록이 끝나면 자동으로 close()를 호출해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716384876645&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class FileReadExample {
    public static void main(String[] args) {
        try (BufferedReader reader = new BufferedReader(new FileReader(&quot;example.txt&quot;))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아래와 같이 객체 문장 2개 이상 넣을 수 있다.&lt;/li&gt;
&lt;li&gt;문장 사이에 &lt;b&gt;세미콜론 ;&lt;/b&gt; 으로 구분해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716385162475&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class MultiReadExample {
    public static void main(String[] args) {
        try (
            BufferedReader reader1 = new BufferedReader(new FileReader(&quot;example1.txt&quot;));
            BufferedReader reader2 = new BufferedReader(new FileReader(&quot;example2.txt&quot;))
        ) {
            String line1, line2;
            while ((line1 = reader1.readLine()) != null) {
                System.out.println(line1);
            }
            while ((line2 = reader2.readLine()) != null) {
                System.out.println(line2);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;AutoCloseable Interface&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;AutoCloseable 인터페이스&lt;/b&gt;를 구현한 자원들은 try 블록이 끝나면 자동으로 close()를 호출한다고 앞서 언급했었다.&lt;/li&gt;
&lt;li&gt;역시 Java 7에서 도입되었으며, 이 인터페이스가 구현되어 있어야 try-with-resources를 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;단 하나의 메서드인 close()가 정의되어 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716385479709&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface AutoCloseable {
    void close() throws Exception;
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대부분의 &lt;b&gt;자원 관리 클래스&lt;/b&gt;는 AutoCloseable를 구현하고 있다.&lt;/li&gt;
&lt;li&gt;io : BufferedReader &amp;amp; Writer, FileInputStream &amp;amp; Output, FileReader &amp;amp; Writer, InputStream &amp;amp; Output, Reader &amp;amp; Writer&lt;/li&gt;
&lt;li&gt;sql : Connection, Driver, PreparedStatement, ResultSet, Statement&lt;/li&gt;
&lt;li&gt;nio : FileChannel, SocketChannel&lt;/li&gt;
&lt;li&gt;util : Scanner, Formatter&lt;/li&gt;
&lt;li&gt;net : Socket, ServerSocket&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Java</category>
      <category>AutoCloseable</category>
      <category>Java</category>
      <category>java resource</category>
      <category>try-catch</category>
      <category>Try-catch-finally</category>
      <category>try-with-resources</category>
      <category>예외처리</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/12</guid>
      <comments>https://cloud-grace.tistory.com/entry/Java-Try-with-resources%EB%A1%9C-%EC%9E%90%EC%9B%90-%EB%B0%98%EB%82%A9%ED%95%98%EA%B8%B0#entry12comment</comments>
      <pubDate>Wed, 22 May 2024 22:52:39 +0900</pubDate>
    </item>
    <item>
      <title>[Java] DAO, DTO, VO, Entity란?</title>
      <link>https://cloud-grace.tistory.com/entry/Java-DAO-DTO-VO-Entity%EB%9E%80</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;DAO(Data Access Object)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DAO는 실제 데이터베이스의 데이터에 접근하기 위한 객체이다.&lt;/li&gt;
&lt;li&gt;Database 접근 로직과 비즈니스 로직을 분리하기 위해 DAO를 사용한다.&lt;/li&gt;
&lt;li&gt;DB에 접근하여 CRUD 작업을 수행한다.&lt;/li&gt;
&lt;li&gt;코드의 재사용성과 유지보수성을 높인다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;DAO 예제 코드(JDBC)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JDBC는 Java에서 데이터베이스와 연결하고 SQL 쿼리를 실행할 수 있는 API이다.&lt;/li&gt;
&lt;li&gt;JDBC는 SQL을 직접 사용하여 데이터베이스와 상호작용한다.&lt;/li&gt;
&lt;li&gt;&lt;u&gt;JDBC에서 DAO 역할은 Connection, PreparedStatement, ResultSet 등을 사용하여 직접 SQL 쿼리를 실행하고 결과를 처리한다.&lt;/u&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716338845066&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package bookshop.dao;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import bookshop.vo.BookVo;

public class BookDao {
	// DB Connect
    private Connection getConnection() throws SQLException {
        Connection conn = null;

        try {
        	// 1. JDBC Driver 로딩
            Class.forName(&quot;org.mariadb.jdbc.Driver&quot;);
            // 2. 연결하기
            String url = &quot;jdbc:mariadb://localhost:3306/webdb?charset=utf8&quot;;
            conn = DriverManager.getConnection(url, &quot;webdb&quot;, &quot;webdb&quot;);
        } catch (ClassNotFoundException e) {
            System.out.println(&quot;드라이버 로딩 실패:&quot; + e);
        }

        return conn;
    }
	// Insert
    public int insert(BookVo vo) {
        int result = 0;

        try (
                Connection conn = getConnection();
                // 3. Statement 준비
                PreparedStatement pstmt1 = conn.prepareStatement(&quot;insert into book(title, author_no) values(?, ?)&quot;);
                PreparedStatement pstmt2 = conn.prepareStatement(&quot;select last_insert_id() from dual&quot;);
        ) {
        	// 4.binding
            pstmt1.setString(1, vo.getTitle());
            pstmt1.setLong(2, vo.getAuthorNo());
            // 5. SQL 실행
            result = pstmt1.executeUpdate();
			// 6. 결과 처리
            ResultSet rs = pstmt2.executeQuery();
            vo.setNo(rs.next() ?  rs.getLong(1) : null);
            rs.close();
        } catch (SQLException e) {
            System.out.println(&quot;error:&quot; + e);
        }

        return result;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;MyBatis&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MyBatis는 SQL을 매퍼 파일로 분리하여 SQL 쿼리를 명시적으로 관리할 수 있는 프레임워크이다.&lt;/li&gt;
&lt;li&gt;동적 SQL을 쉽게 처리할 수 있으며, SQL 쿼리를 XML파일이나 annotation으로 관리한다.&lt;/li&gt;
&lt;li&gt;&lt;u&gt;MyBatis의 DAO 역할은 DB Connection을 하는 config.xml 파일과 SQL 쿼리를 담고 있는 mapper.xml이 수행한다.&lt;/u&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;JDBC Template&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JDBC Template는 Spring에서 제공하는 JDBC의 주요 클래스이다.&lt;/li&gt;
&lt;li&gt;반복적인 JDBC 코드를 줄이고, 예외 처리를 일관되게 할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;u&gt;JDBC Template의 DAO 역할은 JdbcTemplate 객체를 사용해서 SQL 쿼리를 실행하고 그 결과를 맵핑하는 방식으로 수행한다.&lt;/u&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;JPA&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JPA는 Java Persistent API로 Java가 ORM 기술을 통해 작성한 API 표준 명세이다.&lt;/li&gt;
&lt;li&gt;JPA를 통해 Java 객체와 관계형 데이터베이스 간의 맵핑을 정의하고, 상호작용할 수 있다.&lt;/li&gt;
&lt;li&gt;인터페이스를 모아놓은 것이므로 구현체가 필요하다. (ex. Hibernate..)&lt;/li&gt;
&lt;li&gt;&lt;u&gt;JPA의 DAO는 EntityManager를 사용해서 데이터베이스의 CRUD 작업을 수행한다.&lt;/u&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Spring Data JPA&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Spring Data JPA는 JPA를 기반으로 데이터 접근 계층을 단순화하고 자동화한다.&lt;/li&gt;
&lt;li&gt;CRUD를 간단히 처리하고 메서드 이름으로 자동으로 쿼리를 생성한다.&lt;/li&gt;
&lt;li&gt;&lt;u&gt;Spring Data JPA의 DAO는 Repository 인터페이스로 구현한다.&lt;/u&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;DTO(Data Transfer Object)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DTO는 계층(Layer) 간의 데이터 교환을 목적으로 만들어진 객체이다.&lt;/li&gt;
&lt;li&gt;네트워크로 데이터 전송하는 데에 사용한다.&lt;/li&gt;
&lt;li&gt;여러 데이터 항목을 하나의 객체로 그룹화한다.&lt;/li&gt;
&lt;li&gt;계층 : Controller, View, Business, Persistent 등&lt;/li&gt;
&lt;li&gt;오직 데이터 교환을 목적으로 하므로 서비스 로직을 가지고 있지 않다.&lt;/li&gt;
&lt;li&gt;순수 Data 객체이며, Getter, Setter만 포함한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;DTO 예제 코드&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1716366175457&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class UserDTO {
    private String username;

    // Constructor
    public UserDTO(String username) {
        this.username = username;
    }

    // Getter &amp;amp; Setter
    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }
    
    // toString
    @Override
    public String toString() {
        return &quot;UserDTO{&quot; +
                &quot;username='&quot; + username + '\'' +
                '}';
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;lombok으로 더 간단히 표현하면 아래와 같다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716366257463&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import lombok.*;

@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class UserDTO {
    private String username;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;VO(Value Object)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;VO는 데이터를 표현하기 위한 객체이다.&lt;/li&gt;
&lt;li&gt;VO는 비즈니스 로직이 없으며, 단순 데이터 전달 역할을 한다.&lt;/li&gt;
&lt;li&gt;주로 불변 객체로 설계된다.&lt;/li&gt;
&lt;li&gt;즉, 생성할 시점의 상태 변경이 불가능하다.&lt;/li&gt;
&lt;li&gt;DTO와 함께 많이 불리지만, DTO와 달리 Setter가 없다.&lt;/li&gt;
&lt;li&gt;즉, DTO는 데이터 조작이 가능하지만 VO는 단순 데이터 이동만을 위한 것이다. (Read-Only)&lt;/li&gt;
&lt;li&gt;아래와 같이 @Value 어노테이션을 사용하여 불변 VO를 생성한다.&lt;/li&gt;
&lt;li&gt;final 필드를 가지고 getter 메서드를 자동으로 생성한다.&lt;/li&gt;
&lt;li&gt;toString, equals, hashCode도 자동 생성이 되어 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716366494363&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import lombok.Value;

@Value
public class UserVO {
    private String username;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Entity&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Entity는 데이터베이스 테이블과 1:1로 맵핑되는 객체이다.&lt;/li&gt;
&lt;li&gt;ORM(Object-Relational Mapping) 프레임워크에서는 Entity를 사용해서 데이터베이스와 객체지향 코드를 맵핑한다.&lt;/li&gt;
&lt;li&gt;Entity는 데이터베이스 테이블의 Row를 표현하며, 고유 식별자 ID를 가지고 있다.&lt;/li&gt;
&lt;li&gt;DB 테이블에 존재하는 컬럼만을 필드로 가져야 한다.&lt;/li&gt;
&lt;li&gt;Entity는 DB와 1:1 객체, DTO는 계층 간 데이터 교환 객체이므로 분리해서 사용해야 한다.&lt;/li&gt;
&lt;li&gt;JPA 사용 시 주로 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716366945082&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import lombok.Data;
import javax.persistence.*;

@Entity
@Table(name = &quot;users&quot;)
@Data // getter, setter, equals, hashCode, toString, RequiredArgsConstructor
public class UserEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = &quot;username&quot;)
    private String username;

    @Column(name = &quot;email&quot;)
    private String email;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Java</category>
      <category>DAO</category>
      <category>DTO</category>
      <category>Entity</category>
      <category>Java</category>
      <category>Vo</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/11</guid>
      <comments>https://cloud-grace.tistory.com/entry/Java-DAO-DTO-VO-Entity%EB%9E%80#entry11comment</comments>
      <pubDate>Wed, 22 May 2024 17:37:42 +0900</pubDate>
    </item>
    <item>
      <title>[디자인 패턴] 데코레이터 패턴(Decorator Pattern)</title>
      <link>https://cloud-grace.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EB%8D%B0%EC%BD%94%EB%A0%88%EC%9D%B4%ED%84%B0-%ED%8C%A8%ED%84%B4Decorator-Pattern</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;데코레이터 패턴(Decorator Pattern)이란?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데코레이터 패턴은 디자인 패턴(Design Pattern) 중 &lt;b&gt;구조 패턴(Structural Pattern)&lt;/b&gt;이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;구조 패턴 : 클래스나 객체를 조합해서 더 큰 구조를 만드는 패턴&lt;/b&gt;&lt;br /&gt;예를 들어, 서로 다른 인터페이스를 지닌 객체 2개를 묶어서 단일 인터페이스를 제공하거나 객체들을 서로 묶어서 새로운 기능을 제공하는 패턴이다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GoF 디자인 패턴에 의하면 데코레이터 패턴은 주어진 상황 및 용도에 따라 어떤 객체에 다른 객체를 덧붙이는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용 목적은 클래스의 요소들을 계속 수정하면서 사용하는 구조가 필요할 때, 여러 요소들을 조합해서 사용하는 구조일 때 사용한다. 예를 들어, 캐싱, 로깅, 검증과 같은 기능에 사용된다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;데코레이터 패턴 : 주어진 상황과 용도에 따라 어떤 객체에 책임(기능)을 덧붙이는 패턴으로, 기능 확장이 필요할 때 서브클래싱 대신 쓸 수 있는 유연한 대안이 될 수 있다. 말 그대로 장식이라고 생각하면 된다. 기본 기능을 가지고 있는 클래스를 만들고 여기다가 추가할 수 있는 기능들을 추가하기 편하도록 설계하는 방식이다.&lt;br /&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 데코레이터 패턴은 기본 틀에 새롭게 추가될 수 있는 정보들을 따로 분리하면서, 확장하기 용이하도록 융통성을 제공한다. 기존 객체를 '행위'를 가진 특별한 래퍼 객체(데코레이터)에 넣어 객체가 그 '행위'를 할 수 있게 만들어준다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;데코레이터 패턴 구조&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Decorator Pattern.png&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;577&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mzX60/btsHtIKNIeJ/FEkbgUEAweixg48nvaeHg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mzX60/btsHtIKNIeJ/FEkbgUEAweixg48nvaeHg1/img.png&quot; data-alt=&quot;출처 : 위키백과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mzX60/btsHtIKNIeJ/FEkbgUEAweixg48nvaeHg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmzX60%2FbtsHtIKNIeJ%2FFEkbgUEAweixg48nvaeHg1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;438&quot; height=&quot;343&quot; data-filename=&quot;Decorator Pattern.png&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;577&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 위키백과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Component&lt;/b&gt; : 부모 Class로 구성 요소들을 의미하는 추상 클래스이자, 구체적인 객체와 데코레이터가 구현해야 하는 인터페이스이다. operation을 하위 클래스가 재정의하도록 한다. 실질적인 인스턴스를 컨트롤하는 역할을 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ConcreteComponent&lt;/b&gt; : 기본 기능을 구현하는 구체적인 클래스이다. Component의 실질적인 인스턴스 부분으로 책임의 주체 역할을 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Decorator&lt;/b&gt; : 인터페이스를 구현하며, Component 객체를 포함하는 추상 클래스이다. 부수적인 기능, 장식이 되는 기능을 추가한다. Component와 ConcreteDecorator를 동일하게 해주는 역할을 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ConcreteDecorator&lt;/b&gt; : 데코레이터의 구체적인 구현 클래스이다. Decorator를 상속 받아 구현한다. 상속이 아닌 aggregation을 이용한다는 점에서 더욱 융통적이다. 즉, 이 클래스는 Component 객체에 새로운 기능을 추가한다. 실질적인 장식 인스턴스와 정의이며 추가된 책임의 주체이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;데코레이터 패턴 예제 코드&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;예제 : 커피 제조&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Component&lt;/b&gt; : 커피를 제조할 때 비용과 재료 설명을 필요로 하며 이 함수를 Component 인터페이스에서 구현한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716099858368&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface Coffee {
    double cost(); // 비용
    String description(); // 재료 설명
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;ConcreteComponent&lt;/b&gt; : Component를 상속 받아 기본 커피의 비용은 5.0, 재료 설명은 Simple Coffee로 정의한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716100084046&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class SimpleCoffee implements Coffee {
    @Override
    public double cost() {
        return 5.0;
    }

    @Override
    public String description() {
        return &quot;Simple Coffee&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Decorator&lt;/b&gt; : 커피 비용과 재료 설명의 근간이 되는 추상 클래스이다. 재료는 이 Decorator를 상속 받아 재료를 추가한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716100135346&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;abstract class CoffeeDecorator implements Coffee {
    protected Coffee decoratedCoffee;

    public CoffeeDecorator(Coffee coffee) {
        this.decoratedCoffee = coffee;
    }

    @Override
    public double cost() {
        return decoratedCoffee.cost();
    }

    @Override
    public String description() {
        return decoratedCoffee.description();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;ConcreteDecorator&lt;/b&gt; : MilkDecorator는 우유를 추가하는 것으로 cost()와 description()을 정의해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716100197992&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public double cost() {
        return decoratedCoffee.cost() + 1.5;
    }

    @Override
    public String description() {
        return decoratedCoffee.description() + &quot;, Milk&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;ConcreteDecorator&lt;/b&gt;&amp;nbsp;: SugarDecorator는 설탕을 추가하는 것으로 cost()와 description()을 정의해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716100207165&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public double cost() {
        return decoratedCoffee.cost() + 0.5;
    }

    @Override
    public String description() {
        return decoratedCoffee.description() + &quot;, Sugar&quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Main&lt;/b&gt; : 클라이언트 코드는 SimpleCoffee 객체를 생성하고 필요에 따라 데코레이터를 적용하여 커피의 기능을 확장한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716100237837&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {
        Coffee simpleCoffee = new SimpleCoffee();
        System.out.println(simpleCoffee.description() + &quot; : $&quot; + simpleCoffee.cost());
        // Simple Coffee : $5.0

        Coffee milkCoffee = new MilkDecorator(simpleCoffee);
        System.out.println(milkCoffee.description() + &quot; : $&quot; + milkCoffee.cost());
        // Simple Coffee, Milk : $6.5

        Coffee milkSugarCoffee = new SugarDecorator(milkCoffee);
        System.out.println(milkSugarCoffee.description() + &quot; : $&quot; + milkSugarCoffee.cost());
        // Simple Coffee, Milk, Sugar : $7.0
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데코레이터 패턴을 사용하면 자기가 감싸고 있는 구성 요소의 메소드를 호출한 결과에 새로운 기능을 더하면서 행동을 확장할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;데코레이터 패턴의 장점&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데코레이터(래퍼 클래스)를 이용해 기능을 조합할 수 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상속은 조합이 불가능해서 유연하지 못했지만, 조합 순서에도 상관없이 조합이 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;또한, 컴파일 타임에 기능 내용이 확정되는 것이 아닌, 런타임에 기능 내용을 변경할 수 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상속의 경우에는 이미 컴파일 타임에 관계가 확정되어 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;데코레이터 패턴의 단점&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데코레이터를 조합하는 코드가 조금 복잡해질 수 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;작은 객체들이 많이 늘어나지만 상속보다는 많이 늘어나지는 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>디자인 패턴 &amp;amp; OOP</category>
      <category>Decorator Pattern</category>
      <category>Design Pattern</category>
      <category>Structural Pattern</category>
      <category>구조 패턴</category>
      <category>데코레이터 패턴</category>
      <category>디자인 패턴</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/10</guid>
      <comments>https://cloud-grace.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EB%8D%B0%EC%BD%94%EB%A0%88%EC%9D%B4%ED%84%B0-%ED%8C%A8%ED%84%B4Decorator-Pattern#entry10comment</comments>
      <pubDate>Sun, 19 May 2024 15:48:09 +0900</pubDate>
    </item>
    <item>
      <title>[Database] 카디널리티(Cardinality) 2가지 의미</title>
      <link>https://cloud-grace.tistory.com/entry/Database-%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0Cardinality-2%EA%B0%80%EC%A7%80-%EC%9D%98%EB%AF%B8</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;카디널리티(Cardinality)란?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카디널리티는 2가지 의미로 사용된다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;테이블 간의 관계에서의 카디널리티&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;두 테이블 사이의 관계를 말한다.&lt;/li&gt;
&lt;li&gt;각각의 레코드가 서로 어떻게 연결되는지를 설명한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컬럼에 있는 고유한 값에서의 카디널리티&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;간단하게 말하면 튜플/행의 수이다.&lt;/li&gt;
&lt;li&gt;데이터베이스 테이블 내의 데이터 값의 다양성 또는 고유 값을 말한다.&lt;/li&gt;
&lt;li&gt;테이블의 특정 컬럼에 대한 고유한 값의 수를 카디널리티라고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;카디널리티 : (1) 테이블 간의 관계&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;일대일(One-to-One) 관계&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;일대일관계.png&quot; data-origin-width=&quot;467&quot; data-origin-height=&quot;167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pWfQx/btsHtLgiQU6/HukSYPmSsabkYcscunIOX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pWfQx/btsHtLgiQU6/HukSYPmSsabkYcscunIOX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pWfQx/btsHtLgiQU6/HukSYPmSsabkYcscunIOX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpWfQx%2FbtsHtLgiQU6%2FHukSYPmSsabkYcscunIOX0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;389&quot; height=&quot;139&quot; data-filename=&quot;일대일관계.png&quot; data-origin-width=&quot;467&quot; data-origin-height=&quot;167&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사람 1명은 여권 1개만 가질 수 있다. 주민번호는 여권 테이블의 외래 키(Foreign Key)이자 유니크 키(Unique Key)이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;일대다(One-to-Many) 관계&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;일대다관계.png&quot; data-origin-width=&quot;456&quot; data-origin-height=&quot;148&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYnVAg/btsHtu60txi/PPMnkwGOCjJNoQ28oHMwsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYnVAg/btsHtu60txi/PPMnkwGOCjJNoQ28oHMwsk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYnVAg/btsHtu60txi/PPMnkwGOCjJNoQ28oHMwsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYnVAg%2FbtsHtu60txi%2FPPMnkwGOCjJNoQ28oHMwsk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;394&quot; height=&quot;128&quot; data-filename=&quot;일대다관계.png&quot; data-origin-width=&quot;456&quot; data-origin-height=&quot;148&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;고객 1명은 여러 주문을 할 수 있지만, 각 주문은 1명의 고객에게만 속한다. 고객ID는 주문 테이블의 &lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;외래 키(Foreign Key)이다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;다대일(Many-to-One)&amp;nbsp;관계&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다대일관계.png&quot; data-origin-width=&quot;462&quot; data-origin-height=&quot;143&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n3mWq/btsHtXU7BC5/yqXXLObzU2L2lKIBNGuiSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n3mWq/btsHtXU7BC5/yqXXLObzU2L2lKIBNGuiSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n3mWq/btsHtXU7BC5/yqXXLObzU2L2lKIBNGuiSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn3mWq%2FbtsHtXU7BC5%2FyqXXLObzU2L2lKIBNGuiSK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;404&quot; height=&quot;125&quot; data-filename=&quot;다대일관계.png&quot; data-origin-width=&quot;462&quot; data-origin-height=&quot;143&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 주문 제품은 같은 제품을 참조할 수 있다. 즉, 여러 주문 제품이 하나의 제품에 대응된다. 제품ID는 주문제품 테이블의 외래 키(Foreign Key)이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;다대다(Many-to-Many)&amp;nbsp;관계&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다대다관계.png&quot; data-origin-width=&quot;430&quot; data-origin-height=&quot;117&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btThkQ/btsHtt1hTQz/GIQv4Pb1AzTJiPuQ9hofZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btThkQ/btsHtt1hTQz/GIQv4Pb1AzTJiPuQ9hofZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btThkQ/btsHtt1hTQz/GIQv4Pb1AzTJiPuQ9hofZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtThkQ%2FbtsHtt1hTQz%2FGIQv4Pb1AzTJiPuQ9hofZ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;382&quot; height=&quot;104&quot; data-filename=&quot;다대다관계.png&quot; data-origin-width=&quot;430&quot; data-origin-height=&quot;117&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;학생 1명은 여러 과목을 수강할 수 있으며, 과목 1개는 여러 학생이 수강할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;다대다(Many-to-Many) &lt;u&gt;관계 해소&lt;/u&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다대다관계해소.png&quot; data-origin-width=&quot;646&quot; data-origin-height=&quot;117&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckjOUf/btsHuM6n7FV/HCZlkakzaCGvMvv9YfFAq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckjOUf/btsHuM6n7FV/HCZlkakzaCGvMvv9YfFAq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckjOUf/btsHuM6n7FV/HCZlkakzaCGvMvv9YfFAq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckjOUf%2FbtsHuM6n7FV%2FHCZlkakzaCGvMvv9YfFAq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;541&quot; height=&quot;98&quot; data-filename=&quot;다대다관계해소.png&quot; data-origin-width=&quot;646&quot; data-origin-height=&quot;117&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;두 엔터티가 다대다 관계라면 두 개의 엔터티만으로는 서로 표현하는 데에 부족한 점이 있다.&lt;/li&gt;
&lt;li&gt;데이터 모델링에서는 다대다 관계는 미완성인 모델이기 때문에 이를 일대다, 다대일 관계로 나누는 세부적인 작업이 추가로 필요하다.&lt;/li&gt;
&lt;li&gt;두 엔터티의 관계를 표현하기 위해 두 엔터티 사이에 추가적인 엔터티가 필요하다.&lt;/li&gt;
&lt;li&gt;추가적인 엔터티는 &lt;b&gt;두 엔터티의 공유 속성&lt;/b&gt; 역할을 하며 위의 예시는 학생별수강과목 엔터티에 해당한다.&lt;/li&gt;
&lt;li&gt;데이터 모델링에서 자연스레 이루어지는 공식과도 같은 부분이며 위의 예시처럼 중간 테이블을 사용한다.&lt;/li&gt;
&lt;li&gt;학생별 수강과목의 학생ID와 과목ID는 각각 학생 테이블과 과목 테이블을 참조하는 외래 키(Foreign Key)이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;카디널리티 : (2) 컬럼에 있는 고유한 값&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스 테이블의 컬럼(Column)의 카디널리티(Cardinality)는 &lt;b&gt;해당 컬럼에 있는 고유(Distinct)한 값의 개수&lt;/b&gt;를 말한다. 예를 들어, 성별(Gender) 컬럼의 남성, 여성 2가지 값이 존재하므로 이 컬럼의 카디널리티는 2이다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;높은 카디널리티&lt;/b&gt; : 컬럼의 값이 매우 다양할 때 사용된다. 즉, 많은 고유 값을 포함한다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;예시 : 주민등록번호, 이메일 주소&lt;/li&gt;
&lt;li&gt;대부분의 값이 고유해서 높은 카디널리티를 가진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;중간 카디널리티&lt;/b&gt; : 컬럼의 값이 중간 정도로 다양할 때 사용된다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;예시 : 우편번호, 도시 이름&lt;/li&gt;
&lt;li&gt;일부 값이 고유하지만, 많은 값이 반복된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;낮은 카디널리티&lt;/b&gt; : 컬럼의 값이 적고 반복되는 값이 많을 때 사용된다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;예시 : 성별, 상태 코드&lt;/li&gt;
&lt;li&gt;적은 수의 고유 값을 포함하며, 낮은 카디널리티를 가진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;카디널리티 활용 측면&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;쿼리 최적화&lt;/b&gt; : 고유한 값이 많은 컬럼이라면 인덱스를 통해 검색 성능을 향상시킬 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;중복 데이터 확인&lt;/b&gt; : 높은 카디널리티를 가진 컬럼은 중복 데이터를 쉽게 확인할 수 있도록 도와준다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터베이스 설계&lt;/b&gt; : 테이블을 설계할 때, 각 컬럼의 카디널리티를 고려해서 테이블 간의 관계 생성과 인덱스 생성에 도움이 된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 분석&lt;/b&gt; : 데이터의 다양성을 파악하는 데에 도움이 된다. 카디널리티가 높은 컬럼은 데이터의 다양성이 큰 것이며, 이를 통해 여러 인사이트를 얻을 수 있다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Database</category>
      <category>Cardinality</category>
      <category>Database</category>
      <category>데이터베이스</category>
      <category>카디널리티</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/9</guid>
      <comments>https://cloud-grace.tistory.com/entry/Database-%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0Cardinality-2%EA%B0%80%EC%A7%80-%EC%9D%98%EB%AF%B8#entry9comment</comments>
      <pubDate>Sun, 19 May 2024 14:38:23 +0900</pubDate>
    </item>
    <item>
      <title>[Database] 식별자 관계 vs 비식별자 관계</title>
      <link>https://cloud-grace.tistory.com/entry/Database-%EC%8B%9D%EB%B3%84%EC%9E%90-%EA%B4%80%EA%B3%84-vs-%EB%B9%84%EC%8B%9D%EB%B3%84%EC%9E%90-%EA%B4%80%EA%B3%84</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;식별자(Identifiers)란?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔터티는 인스턴스의 집합이며 각각의 인스턴스는 구별이 되어야 한다. 구별이 되는 요소가 식별자이며, 하나의 엔터티가 가지고 있는 속성 중 대표성을 가지는 속성이 식별자가 되어야 한다. 식별자(Identifiers)와 키(key)의 개념이 헷갈릴 수 있지만, &lt;b&gt;식별자는 업무적인 정보로 사용하며 논리적 모델링에서 활용&lt;/b&gt;하며, &lt;b&gt;키(key)는 데이터베이스에서 테이블 접근을 위한 매개체로 물리적 모델링에서 활용&lt;/b&gt;한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;주식별자 특징&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;유일성 : 주식별자에 의해 엔터티 내에 모든 인스턴스가 유일하게 구분되어야 한다.&lt;/li&gt;
&lt;li&gt;최소성 : 주식별자를 구성하는 속성의 수는 유일성을 만족하는 최소의 수여야 한다.&lt;/li&gt;
&lt;li&gt;불변성 : 지정된 주식별자의 값은 자주 변하지 않아야 한다.&lt;/li&gt;
&lt;li&gt;존재성 : 주식별자가 정해지면 반드시 값이 존재해야 한다.&lt;/li&gt;
&lt;li&gt;대표성 : 엔터티 내에서 대표성을 가져야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;식별자 분류&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주식별자 VS 보조식별자 : 자신의 엔터티에서 대표성을 가지는가&lt;/li&gt;
&lt;li&gt;내부식별자 VS 외부식별자 : 엔터티 내에서 스스로 만들어 졌는가&lt;/li&gt;
&lt;li&gt;단일식별자 VS 복합식별자 : 단일 속성으로 식별이 되는가&lt;/li&gt;
&lt;li&gt;본질식별자 : 업무적으로 의미가 있는 식별자&lt;/li&gt;
&lt;li&gt;인조식별자 : 필요에 따라 새롭게 일련번호를 만들어 대체하는 식별자&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;식별자 관계 VS 비식별자 관계&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;식별자 관계&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;식별자관계.png&quot; data-origin-width=&quot;433&quot; data-origin-height=&quot;147&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eOdHO7/btsHtp5DRwy/mfhKhTJWBczLkW9ylHEl2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eOdHO7/btsHtp5DRwy/mfhKhTJWBczLkW9ylHEl2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eOdHO7/btsHtp5DRwy/mfhKhTJWBczLkW9ylHEl2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeOdHO7%2FbtsHtp5DRwy%2FmfhKhTJWBczLkW9ylHEl2K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;401&quot; height=&quot;136&quot; data-filename=&quot;식별자관계.png&quot; data-origin-width=&quot;433&quot; data-origin-height=&quot;147&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;부모 자식 관계에서 자식이 부모로부터 받은 주식별자를 자식 엔터티의 외래 식별자로 참조해서 자신의 주식별자로 설정하는 경우&lt;/li&gt;
&lt;li&gt;실선으로 표현한다.&lt;/li&gt;
&lt;li&gt;위 그림에서는 자식 엔터티(학생 주소)가 부모 엔터티(학생)의 &lt;b&gt;학번&lt;/b&gt;을 자신의 주식별자로 설정하였다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;비식별자 관계&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;비식별자관계.png&quot; data-origin-width=&quot;501&quot; data-origin-height=&quot;167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgB1wf/btsHu3NqxDy/EkadtKFdKd8BuWKdX0NEvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgB1wf/btsHu3NqxDy/EkadtKFdKd8BuWKdX0NEvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgB1wf/btsHu3NqxDy/EkadtKFdKd8BuWKdX0NEvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgB1wf%2FbtsHu3NqxDy%2FEkadtKFdKd8BuWKdX0NEvK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;441&quot; height=&quot;147&quot; data-filename=&quot;비식별자관계.png&quot; data-origin-width=&quot;501&quot; data-origin-height=&quot;167&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;부모 자식 관계에서 자식이 부모로부터 받은 주식별자를 자식 엔터티의 외래 식별자로 참조해서 일반 속성으로 사용하는 경우&lt;/li&gt;
&lt;li&gt;점선으로 표현한다.&lt;/li&gt;
&lt;li&gt;위 그림에서는 자식 엔터티(주문 항목)가 부모 엔터티(주문)의 &lt;b&gt;주문코드&lt;/b&gt;를 일반 속성으로 사용했다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Database</category>
      <category>Database</category>
      <category>데이터베이스</category>
      <category>비식별자</category>
      <category>비식별자관계</category>
      <category>식별자</category>
      <category>식별자관계</category>
      <category>주식별자</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/8</guid>
      <comments>https://cloud-grace.tistory.com/entry/Database-%EC%8B%9D%EB%B3%84%EC%9E%90-%EA%B4%80%EA%B3%84-vs-%EB%B9%84%EC%8B%9D%EB%B3%84%EC%9E%90-%EA%B4%80%EA%B3%84#entry8comment</comments>
      <pubDate>Sat, 18 May 2024 19:43:45 +0900</pubDate>
    </item>
    <item>
      <title>[디자인 패턴] 싱글톤 패턴(Singleton Pattern)</title>
      <link>https://cloud-grace.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EC%8B%B1%EA%B8%80%ED%86%A4-%ED%8C%A8%ED%84%B4Singleton-Pattern</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;싱글톤 패턴(Singleton Pattern)이란?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;싱글톤 패턴은 디자인 패턴(Design Pattern) 중 &lt;b&gt;생성 패턴(Creational Pattern)&lt;/b&gt;이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;생성 패턴 : 객체의 생성과 관련된 패턴이며, 객체의 생성 절차를 추상화하는 패턴&lt;/b&gt;&lt;br /&gt;객체를 생성 및 합성하는 방법과 객체의 표현 방법과 시스템을 분리한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GoF 디자인 패턴에 의하면 싱글톤 패턴은 어떤 클래스의 인스턴스는 하나임을 보장하고 어디서든 참조할 수 있도록 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용 목적은 단 하나만 생성하고 그 인스턴스를 사용하기 위해서이다. 주로 공통된 객체를 여러 개 생성해서 사용하는 &lt;b&gt;Database Connection Pool(DBCP), Thread Pool, Device 설정, 로그 기록 객체, 스프링의 Bean&lt;/b&gt; 등의 경우, 인스턴스를 여러 개 만든다면 자원을 낭비하게 되고 버그가 발생할 수 있다. 따라서 프로그램 내에서 하나로 공유를 해야하는 객체가 존재할 때, 프로그램 내에서 여러 부분에서 해당 객체를 공유하여 사용하도록 할 때 활용된다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;싱글톤 패턴 : '하나'의 인스턴스만 생성하여 사용하는 디자인 패턴이다. 생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고, 최초 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴한다. 즉, 애플리케이션이 시작될 때, 어떤 클래스가 최초에 한 번만 메모리를 할당(static)하며 해당 메모리에 인스턴스를 만들어 사용하는 패턴이다.&lt;/b&gt;&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;싱글톤 패턴의 장단점&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;메모리 측면 : 한 개의 인스턴스만을 고정 메모리 영역에 생성하고 추후 해당 객체에 접근할 때 메모리 낭비를 방지할 수 있다.&lt;/li&gt;
&lt;li&gt;속도 측면 : 생성된 인스턴스를 사용할 때는 속도 측면에서 새로 생성할 때보다 빠르다.&lt;/li&gt;
&lt;li&gt;데이터 공유 측면 : 전역으로 사용하는 인스턴스이므로 다른 여러 클래스에서 데이터를 공유하기에 좋다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;객체 역할이 복잡한 경우 : 싱글톤 객체가 혼자 많은 것을 하고 많은 데이터를 공유하게 해주면, 해당 싱글톤 객체를 사용하는 객체 간의 결합도가 높아진다. 따라서 객체지향 설계 원칙인 &lt;b&gt;'개방-폐쇄 원칙'&lt;/b&gt; 에 어긋난다. 따라서 유지보수 및 테스트 진행에 어려움이 발생한다.&lt;/li&gt;
&lt;li&gt;멀티 스레드 환경인 경우 : 만약 멀티 스레드 환경에서 동기화 처리를 하지 않았다면, 인스턴스가 여러 개 생성될 수도 있다. 즉, 반드시 싱글톤을 써야하는 경우가 아니라면 사용하지 않는 것이 좋다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;싱글톤 패턴 구조&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Singleton Pattern.png&quot; data-origin-width=&quot;817&quot; data-origin-height=&quot;485&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6VhBI/btsHtLmXpBK/DIbIp7Tpw34TzRp1YoskOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6VhBI/btsHtLmXpBK/DIbIp7Tpw34TzRp1YoskOK/img.png&quot; data-alt=&quot;출처 : 위키백과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6VhBI/btsHtLmXpBK/DIbIp7Tpw34TzRp1YoskOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6VhBI%2FbtsHtLmXpBK%2FDIbIp7Tpw34TzRp1YoskOK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;337&quot; height=&quot;200&quot; data-filename=&quot;Singleton Pattern.png&quot; data-origin-width=&quot;817&quot; data-origin-height=&quot;485&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 위키백과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;싱글톤 패턴 구현&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;싱글톤 패턴&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716022636671&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Singleton {
    // 정적 변수로 1개만 존재해야 하는 유일한 인스턴스를 저장한다.
    private static Singleton instance;

    // private 생성자: 외부에서 인스턴스를 생성을 막는다.
    private Singleton() {

    }

    // 정적 메서드로 유일한 인스턴스를 반환한다.
    // 외부에서는 getInstance()로 인스턴스를 반환한다.
    public static Singleton getInstance() {
    	// 인스턴스가 null일 때만 생성한다.
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;싱글톤 패턴 생성 예제&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716022847309&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {
        // Singleton 클래스의 유일한 인스턴스를 얻음
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();
        
        // 출력
        System.out.println(singleton1); // 출력 : singleton.Singleton@2d98a335
        System.out.println(singleton2); // 출력 : singleton.Singleton@2d98a335
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Multi-Thread에서의 싱글톤 패턴 문제점&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[1] 여러 개의 인스턴스 생성의 문제&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Multi-Thread 환경에서 인스턴스가 없는 상황에 동시에 getInstance() 메소드를 실행한다면 각각 새로운 인스턴스를 생성할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716023253889&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    // 정적 메서드로 유일한 인스턴스를 반환한다.
    // 외부에서는 getInstance()로 인스턴스를 반환한다.
    public static Singleton getInstance() {
    	// 인스턴스가 null일 때만 생성한다.
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;[2] 변수 값의 일관성 문제&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Multi-Thread 환경에서 increment() 메소드를 동시에 실행한다면 일관되지 않는 값들이 만들어질 수도 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716023529855&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Singleton {
    private static Singleton instance;
    private static int count = 0;
    
    private Singleton() {
    }
    
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
    
    public static void increment() {
        count++;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;싱글톤 패턴 해결 방법&lt;/b&gt;&lt;/h2&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[1] 정적 변수 선언에서 인스턴스 생성하기&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;static 변수로 Singleton 인스턴스를 생성하는 방법으로 해결한다.&lt;/li&gt;
&lt;li&gt;getInstance()로 Multi-Thread 환경에서도 다른 객체들이 하나의 인스턴스를 공유할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716023982366&quot; class=&quot;routeros&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class Singleton {
    private static Singleton instance = new Singleton();

    private Singleton() {

    }

    public static Singleton getInstance() {
        return instance;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[2] synchronized 사용하기&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;synchronized 키워드를 통해 동시성 문제를 해결한다.&lt;/li&gt;
&lt;li&gt;하지만 synchronized는 Thread-Safe 보장을 위해 성능 저하를 크게 발생시키기 때문에 권장되지는 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716024181912&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Singleton {
    private static Singleton instance;

    private Singleton() {

    }

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[3] Holder 방식으로 싱글톤 패턴 구현하기&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;싱글톤 패턴의 초기화 문제를 해결하기 위해 'Holder' 방식을 사용한다.&lt;/li&gt;
&lt;li&gt;초기화 책임을 JVM에게 넘기며 클래스 로딩 시점에서 싱글톤 인스턴스가 안전하게 초기화된다.&lt;/li&gt;
&lt;li&gt;SingletonHolder 내부 정적 클래스는 Singleton 인스턴스를 정적 필드로 가지고 있다.&lt;/li&gt;
&lt;li&gt;이 필드는 클래스가 로딩될 때 초기화되며, Singleton 클래스가 로딩될 때까지 로드되지 않으므로 인스턴스가 필요할 때까지 초기화되지 않는다.&lt;/li&gt;
&lt;li&gt;getInstance() 메서드는 SingletonHolder 클래스의 INSTANCE 필드를 반환한다.&lt;/li&gt;
&lt;li&gt;클래스 로딩 시점에 인스턴스가 생성되므로 스레드 안전성을 보장한다.&lt;/li&gt;
&lt;li&gt;Holder 방식은 코드가 간결하고 이해하기 쉬우며 불필요한 동기화를 피할 수 있고 지연 초기화를 지원하여 효율적이다.&lt;/li&gt;
&lt;li&gt;실제로 싱글톤 패턴을 이 방식으로 가장 많이 사용한다고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716024810146&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Singleton {
    private Singleton() {

    }

    // 내부 정적 클래스가 싱글톤 인스턴스를 홀드한다.
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    // 외부에서 싱글톤 인스턴스를 접근할 수 있는 메서드
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>디자인 패턴 &amp;amp; OOP</category>
      <category>Creational Pattern</category>
      <category>Design Pattern</category>
      <category>Singleton Pattern</category>
      <category>디자인 패턴</category>
      <category>생성 패턴</category>
      <category>싱글톤 패턴</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/7</guid>
      <comments>https://cloud-grace.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EC%8B%B1%EA%B8%80%ED%86%A4-%ED%8C%A8%ED%84%B4Singleton-Pattern#entry7comment</comments>
      <pubDate>Sat, 18 May 2024 18:42:47 +0900</pubDate>
    </item>
    <item>
      <title>[디자인 패턴] 퍼사드 패턴(Facade Pattern)</title>
      <link>https://cloud-grace.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%ED%8D%BC%EC%82%AC%EB%93%9C-%ED%8C%A8%ED%84%B4Facade-Pattern</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;퍼사드 패턴(Facade Pattern)이란?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;퍼사드 패턴은 디자인 패턴(Design Pattern) 중 &lt;b&gt;구조 패턴(Structural Pattern)&lt;/b&gt;이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;구조 패턴 : 클래스나 객체를 조합해서 더 큰 구조를 만드는 패턴&lt;/b&gt;&lt;br /&gt;예를 들어, 서로 다른 인터페이스를 지닌 객체 2개를 묶어서 단일 인터페이스를 제공하거나 객체들을 서로 묶어서 새로운 기능을 제공하는 패턴이다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GoF 디자인 패턴에 의하면 퍼사드 패턴은 하위 시스템을 보다 쉽게 사용할 수 있게 해주는 하나의 통합된 고급 인터페이스(Wrapper)로 제공하기 위함이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용 목적은 복잡한 서브 시스템을 인터페이스로 감싸서 보다 사용하기 쉽게 만드는 것이다. &lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;Facade(외관) 퍼사드는 건물의 정면을 의미하는 단어이며,&lt;span&gt; &lt;/span&gt;&lt;/span&gt;주로, &lt;b&gt;객체지향 프로그래밍 분야와 외부 라이브러리를 추상화&lt;/b&gt;하는 데에 많이 사용된다. 즉, 많은 분량의 코드에 접근할 수 있는 단순한 인터페이스를 제공한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;퍼사드 패턴 : 어떤 소프트웨어의 다른 커다란 코드 부분에 대해 간략화된 인터페이스를 제공해주는 디자인 패턴을 의미한다. 즉, 복잡한 서브 시스템을 단순화된 인터페이스로 감싸서 사용자가 서브 시스템의 내부 구성 요소에 신경 쓰지 않고도 시스템을 쉽게 사용할 수 있도록 하는 패턴이다.&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 퍼사드 패턴은 시스템의 복잡성을 감추고, 클라이언트와 서브 시스템 간의 결합도를 낮춰서 코드를 더 읽기 쉽고 유지보수하기 쉽게 만든다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;퍼사드 패턴 구조&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;UML_DP_Fa&amp;amp;ccedil;ade.png&quot; data-origin-width=&quot;537&quot; data-origin-height=&quot;524&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJQtrp/btsHuyUxYXL/9GCesrFwRKOMiLQKP22oIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJQtrp/btsHuyUxYXL/9GCesrFwRKOMiLQKP22oIk/img.png&quot; data-alt=&quot;출처 : 위키백과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJQtrp/btsHuyUxYXL/9GCesrFwRKOMiLQKP22oIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJQtrp%2FbtsHuyUxYXL%2F9GCesrFwRKOMiLQKP22oIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;380&quot; height=&quot;371&quot; data-filename=&quot;UML_DP_Fa&amp;ccedil;ade.png&quot; data-origin-width=&quot;537&quot; data-origin-height=&quot;524&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 위키백과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;퍼사드 클래스 : Interne1, 2, 3 패키지 및 그림에 나오지 않은 그 밖의 응용 프로그램 코드와도 상호 동작을 하며 복잡한 구성 요소들을 단순한 인터페이스로 감싸서 제공하는 클래스이다.&lt;/li&gt;
&lt;li&gt;Interne 패키지 : 소프트웨어 라이브러리 or API 집합이며, 퍼사드 클래스를 통해 접근되는 서브 시스템이다.&lt;/li&gt;
&lt;li&gt;클라이언트 : 패키지 내의 리소스에 접근하기 위해 퍼사드 클래스를 활용하는 객체이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;퍼사드 패턴 예제 코드&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;예제 : 세탁기 시스템&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;서브 시스템 클래스&lt;/b&gt; : 세탁기의 각 구성 요소&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716018107699&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class WaterSupply {
    public void on() {
        System.out.println(&quot;Water supply on.&quot;);
    }

    public void off() {
        System.out.println(&quot;Water supply off.&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1716018206625&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Drum {
    public void rotate() {
        System.out.println(&quot;Drum rotating.&quot;);
    }

    public void stop() {
        System.out.println(&quot;Drum stopped.&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1716018215836&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Heater {
    public void on() {
        System.out.println(&quot;Heater on.&quot;);
    }

    public void off() {
        System.out.println(&quot;Heater off.&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1716018222616&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class DetergentDispenser {
    public void dispense() {
        System.out.println(&quot;Detergent dispensed.&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1716018232742&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Dryer {
    public void on() {
        System.out.println(&quot;Dryer on.&quot;);
    }

    public void off() {
        System.out.println(&quot;Dryer off.&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;퍼사드 클래스&lt;/b&gt; : 세탁기의 복잡한 구성 요소들을 단순한 인터페이스로 감싸서 제공&lt;/li&gt;
&lt;li&gt;실무에서는 ~~~Facade로 퍼사드 패턴이 사용되었다는 것을 따로 명시하지는 않고, Service 형태로 많이 이용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716018307308&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class WashingMachineFacade {
    private WaterSupply waterSupply;
    private Drum drum;
    private Heater heater;
    private DetergentDispenser detergentDispenser;
    private Dryer dryer;

    public WashingMachineFacade() {
        this.waterSupply = new WaterSupply();
        this.drum = new Drum();
        this.heater = new Heater();
        this.detergentDispenser = new DetergentDispenser();
        this.dryer = new Dryer();
    }

    public void startWashing() {
        System.out.println(&quot;Starting washing cycle...&quot;);
        waterSupply.on();
        detergentDispenser.dispense();
        heater.on();
        drum.rotate();
    }

    public void startDrying() {
        System.out.println(&quot;Starting drying cycle...&quot;);
        drum.stop();
        heater.off();
        waterSupply.off();
        dryer.on();
    }

    public void stop() {
        System.out.println(&quot;Stopping washing machine...&quot;);
        drum.stop();
        dryer.off();
        heater.off();
        waterSupply.off();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Main&lt;/b&gt; : 퍼사드 클래스를 사용하여 세탁기를 제어하는 클라이언트 코드&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716018370179&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {
        WashingMachineFacade washingMachine = new WashingMachineFacade();
        
        // 세탁 사이클 시작
        washingMachine.startWashing();
        
        // (시간 경과 후) 건조 사이클 시작
        washingMachine.startDrying();
        
        // 세탁기 정지
        washingMachine.stop();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위의 세탁기 예제를 보면 사용자는 세탁을 할 때 최종적으로 세탁 사이클 시작, 건조 사이클 시작, 세탁기 정지 버튼만 누르면 세탁기가 세탁의 세부적인 과정을 자동적으로 모두 진행한다. 복잡한 서브 시스템들을 인터페이스로 감싸 사용하기 쉽게 만드는 것이 퍼사드 패턴이다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>디자인 패턴 &amp;amp; OOP</category>
      <category>Design Pattern</category>
      <category>facade pattern</category>
      <category>Structural Pattern</category>
      <category>구조 패턴</category>
      <category>디자인 패턴</category>
      <category>퍼사드 패턴</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/6</guid>
      <comments>https://cloud-grace.tistory.com/entry/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%ED%8D%BC%EC%82%AC%EB%93%9C-%ED%8C%A8%ED%84%B4Facade-Pattern#entry6comment</comments>
      <pubDate>Sat, 18 May 2024 16:52:34 +0900</pubDate>
    </item>
    <item>
      <title>[Database] 데이터베이스 모델링(Database Modeling), ERD(ER Diagram), 엔터티(Entity), 제약조건(Constraint)</title>
      <link>https://cloud-grace.tistory.com/entry/Database-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EB%AA%A8%EB%8D%B8%EB%A7%81Database-Modeling-ERDER-Diagram-%EC%97%94%ED%8B%B0%ED%8B%B0Entity-%EC%A0%9C%EC%95%BD%EC%A1%B0%EA%B1%B4Constraint</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;[1] 데이터베이스 모델링이란?&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개념 : 주어진 개념으로부터 논리적인 데이터 모델을 구성하는 작업, 데이터베이스 골격을 이해하면서 모델 기능과 성능 측면에서 효율적인 모델링이 필요하다. 물리적인 데이터베이스 모델로 만들어 고객 요구사항에 맞춰 반영하는 작업까지 포함한다.&lt;/li&gt;
&lt;li&gt;목적 : 업무 정보를 구성하는 정보를 일정한 표기법에 의해 표현함으로써 업무 내용을 정확하게 분석하며, 분석된 모델로 실제 DB를 생성하고 개발 및 데이터 관리에 편리하게 사용하기 위함이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;[2] 데이터베이스 모델링 과정&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;① 요구사항 수집 및 분석&lt;br /&gt;② 설계&amp;nbsp;▶ 개념적 모델링&lt;br /&gt;③ 설계&amp;nbsp;▶ 논리적 모델링&lt;br /&gt;④ 설계 ▶ 물리적 모델링&lt;br /&gt;⑤ 데이터베이스 구현&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3가지 모델링&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개념적 모델링 : 개체와 개체 간 관계에서 ER Diagram을 만드는 과정
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;중요 개념을 구분하여&lt;span&gt; &lt;/span&gt;&lt;/span&gt;핵심 Entity 독립개체 도출&lt;/li&gt;
&lt;li&gt;ERD 작성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;논리적 모델링 : ER Diagram을 사용하여 관계 Schema 모델을 만드는 과정
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;각 개념을 구체화하여 ERD-RDB 모델 사상&lt;/li&gt;
&lt;li&gt;상세 속성 정의&lt;/li&gt;
&lt;li&gt;정규화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;물리적 모델링 : 관계 스키마 모델의 물리적 구조를 정의하고 구현하는 과정
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;데이터베이스 생성 계획에 따라 개체, 인덱스 등을 생성&lt;/li&gt;
&lt;li&gt;DB 개체 정의&lt;/li&gt;
&lt;li&gt;테이블 및 인덱스 등 설계&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;[3] ERD(Entity Relationship Diagram)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Entity 개체와 Relationship 관계를 중점적으로 데이터베이스 구조를 한 눈에 알아볼 수 있는 다이어그램&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;[4] 엔터티(Entity)&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[4-1] 엔터티란?&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;저장되고 관리되는 데이터 집합&lt;/li&gt;
&lt;li&gt;개념, 사건, 장소 등&lt;/li&gt;
&lt;li&gt;유형 or 무형의 대상&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[4-2] 엔터티의 특징&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;유일한 식별자를 가져야 한다.&lt;/li&gt;
&lt;li&gt;2개 이상의 인스턴스가 있어야 한다.&lt;/li&gt;
&lt;li&gt;반드시 속성을 가져야 한다.&lt;/li&gt;
&lt;li&gt;다른 엔터티와 최소 1개 이상 관계를 가져야 한다.&lt;/li&gt;
&lt;li&gt;업무에서 관리가 되는 집합이어야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[4-3] 엔터티의 특징&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;유형 or 무형에 따른 종류
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;유형 엔터티 : 지속적으로 사용됨 (ex. 학생, 선생님)&lt;/li&gt;
&lt;li&gt;개념 엔터티(무형 엔터티) : 물리적 형태 X, 개념적으로 사용됨 (ex. 조직, 보험상품)&lt;/li&gt;
&lt;li&gt;사건 엔터티 : 비즈니스 프로세스 실행하며 생성됨 (ex. 주문, 취소, 수수료)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;발생시점에 따른 엔터티 종류
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;기본 엔터티 : 다른 엔터티에 영향받지 않으며 독립적으로 생성 (ex. 고객, 상품)&lt;/li&gt;
&lt;li&gt;중심 엔터티 : 기본 엔터티와 행위 엔터티 중간에 있으며, 기본 엔터티로부터 발생되고 행위 엔터티를 생성함 (ex. 주문, 취소, 체결)&lt;/li&gt;
&lt;li&gt;행위 엔터티 : 2개 이상의 엔터티로부터 발생함 (ex. 주문 내용, 취소 내용)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;[5] ERD 키와 제약조건&lt;/b&gt;&lt;/h2&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[5-1] 주 식별자 (PK)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테이블의 Primary Key&lt;/li&gt;
&lt;li&gt;중복 X, NULL 값 X&lt;/li&gt;
&lt;li&gt;유일성, 최소성, 불변성, 존재성, 대표성&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[5-2] 외래 식별자 (FK)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테이블의 Foreign Key&lt;/li&gt;
&lt;li&gt;타 엔터티와의 관계를 통해 생성되는 식별자&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;[5-3] 제약조건(Constraint)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본키 (Primary Key) : UNIQUE + NOT NULL&lt;/li&gt;
&lt;li&gt;외래키 (Foreign key) : UNIQUE or PK&lt;/li&gt;
&lt;li&gt;고유키 (Unique Key) : 중복 X, NULL 허용&lt;/li&gt;
&lt;li&gt;NOT NULL : NULL 값 허용 X&lt;/li&gt;
&lt;li&gt;CHECK : 범위나 조건 설정해서 지정된 값만 허용&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Database</category>
      <category>Database</category>
      <category>database modeling</category>
      <category>db</category>
      <category>ERD</category>
      <category>데이터베이스</category>
      <category>데이터베이스 모델링</category>
      <category>식별자</category>
      <category>엔터티</category>
      <category>제약조건</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/5</guid>
      <comments>https://cloud-grace.tistory.com/entry/Database-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EB%AA%A8%EB%8D%B8%EB%A7%81Database-Modeling-ERDER-Diagram-%EC%97%94%ED%8B%B0%ED%8B%B0Entity-%EC%A0%9C%EC%95%BD%EC%A1%B0%EA%B1%B4Constraint#entry5comment</comments>
      <pubDate>Fri, 17 May 2024 13:27:57 +0900</pubDate>
    </item>
    <item>
      <title>[Java] JDBC란? Database 연결 과정, JDBC Driver, JDBC API 흐름</title>
      <link>https://cloud-grace.tistory.com/entry/JDBC-JDBC%EB%9E%80-Database-%EC%97%B0%EA%B2%B0-%EA%B3%BC%EC%A0%95-JDBC-Driver-JDBC-API-%ED%9D%90%EB%A6%84</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;JDBC&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JDBC는 Java Database Connectivity로 Java에서 데이터베이스와 연결하여 데이터 저장 및 수정, 저장된 데이터를 사용할 수 있게 해주는 Java API이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;JDBC 표준 인터페이스로 정의한 3가지 기능&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;java.sql.Connection : DB 연결&lt;/li&gt;
&lt;li&gt;java.sql.Statement : SQL이 담겨 있는 내용&lt;/li&gt;
&lt;li&gt;java.sql.ResultSet : SQL의 요청에 응답한 내용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Data JPA, Spring Data JDBC 등의 기술이 나타나며 JDBC API를 직접 사용할 일은 줄었지만, 이 기술들이 DB와의 연동을 위해 내부적으로 JDBC를 이용하므로 JDBC 동작 과정을 익혀둘 필요가 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;JDBC 동작 과정&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Java Application ▶ JDBC API ▶ JDBC Driver ▶ 데이터베이스&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;JDBC Driver&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스와 통신하는 인터페이스&lt;/li&gt;
&lt;li&gt;MariaDB, MySQL, MS SQL, Oracle 등의 데이터베이스에 각각 알맞은 JDBC 드라이버를 구현하여 제공한다.&lt;/li&gt;
&lt;li&gt;JDBC Driver의 구현체를 통해 특정 벤더 DB에 접근이 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;JDBC API 동작 과정&lt;/b&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;JDBC Driver 로딩 ▶ Connection 객체 생성 ▶ Statement 객체 생성 ▶ Query 실행 ▶ ResultSet 객체로부터 데이터 조회 ▶ ResultSet 객체 Close ▶ Statement 객체 Close ▶ Connection 객체 Close&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;JDBC Driver 로딩 : 내가 사용할 DB의 JDBC Driver를 로딩하고, Driver는 DriverManager Class를 통해 로딩된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;Connection 객체 생성 : JDBC Driver 정상 로딩 후, DriverManager를 통해 데이터베이스와 연결되는 Session인 Connection 객체를 생성한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;Statement 객체 생성 : Statement 객체는 SQL 쿼리문을 작성하여 이를 실행하기 위한 객체이며, 정적 SQL 쿼리 문자열을 입력으로 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;Query 실행 : 생성된 Statement 객체를 이용해서 입력된 SQL 쿼리가 실행된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;ResultSet 객체로부터 데이터 조회 : SQL 쿼리문 실행 결과 데이터 Set이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;ResultSet, Statement, Connection 객체 Close : JDBC API로 사용한 객체는 역순으로 Close한다.&lt;/span&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;PreparedStatement&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;PreparedStatement는 SQL 쿼리를 실행하기 전에 미리 컴파일하여 효율적으로 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;보안 강화 : SQL 쿼리에 사용되는 매개변수를 자동으로 이스케이핑하여 SQL Injection 공격을 방지한다.&lt;/li&gt;
&lt;li&gt;성능 향상 : DB에 쿼리를 보낼 때 매번 컴파일하지 않고 미리 컴파일되어 있으므로 성능이 향상된다.&lt;/li&gt;
&lt;li&gt;가독성과 유지보수성 향상 : SQL 쿼리와 매개변수가 분리되어 가독성 및 유지보수성이 향상된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1716621865353&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.sql.*;

public class InsertExample {
    public static void main(String[] args) {
        System.out.println(insert(&quot;기획1팀&quot;));
        System.out.println(insert(&quot;기획2팀&quot;));
    }

    public static boolean insert(String deptName) {
        boolean result = false;
        Connection connection = null;
        PreparedStatement pstmt = null;
        try {
            // 1. JDBC Driver 로딩
            Class.forName(&quot;org.mariadb.jdbc.Driver&quot;);

            // 2. 연결하기
            String url = &quot;jdbc:mariadb://localhost:3306/database?charset=utf8&quot;;
            connection = DriverManager.getConnection(url, &quot;아이디&quot;, &quot;비밀번호&quot;);

            // 3. Statement 준비
            String sql = &quot;insert into dept values(null, ?)&quot;;
            pstmt = connection.prepareStatement(sql);

            // 4.binding
            pstmt.setString(1, deptName);

            // 5. SQL 실행
            int count = pstmt.executeUpdate();

            // 6. 결과 처리
            result = count == 1;
        } catch (ClassNotFoundException e) {
            System.out.println(&quot;드라이버 로딩 실패: &quot; + e);
        } catch (SQLException e) {
            System.out.println(&quot;error: &quot; + e);
        } finally {
            try {
                if (pstmt!= null) {
                    pstmt.close();
                }
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        return result;
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Java</category>
      <category>connection</category>
      <category>Database</category>
      <category>JDBC</category>
      <category>JDBC API</category>
      <category>jdbc driver</category>
      <category>resultset</category>
      <category>Statement</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/4</guid>
      <comments>https://cloud-grace.tistory.com/entry/JDBC-JDBC%EB%9E%80-Database-%EC%97%B0%EA%B2%B0-%EA%B3%BC%EC%A0%95-JDBC-Driver-JDBC-API-%ED%9D%90%EB%A6%84#entry4comment</comments>
      <pubDate>Thu, 16 May 2024 23:19:09 +0900</pubDate>
    </item>
    <item>
      <title>[Database] Rocky Linux에 MariaDB 설치 방법</title>
      <link>https://cloud-grace.tistory.com/entry/Database-Rocky-Linux9%EC%97%90-MariaDB-%EC%84%A4%EC%B9%98-%EB%B0%A9%EB%B2%95</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Rocky Linux9에 MariaDB 설치하는 방법에 대해 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;[1] MariaDB 설치&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 작업 디렉토리 확인&lt;/p&gt;
&lt;pre id=&quot;code_1715833672747&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# pwd
/root&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 의존 라이브러리 설치&lt;/p&gt;
&lt;pre id=&quot;code_1715833800379&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# dnf install -y gcc gcc-c++ zlib* libxml* freetype* libpng* flex gmp ncurses-devel gnutls-devel libaio&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. iconv 소스 컴파일 설치&lt;/p&gt;
&lt;pre id=&quot;code_1715833924700&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# wget https://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.17.tar.gz
# tar xvfz libiconv-1.17.tar.gz
# cd libiconv-1.17
# ./configure --prefix=/usr/local
# make &amp;amp;&amp;amp; make install&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 소스 다운로드&lt;/p&gt;
&lt;pre id=&quot;code_1715833945967&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# wget https://downloads.mariadb.org/interstitial/mariadb-10.6.17/source/mariadb-10.6.17.tar.gz&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 압축 풀기&lt;/p&gt;
&lt;pre id=&quot;code_1715833988651&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# tar xvfz mariadb-10.6.17.tar.gz&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. 소스 디렉토리 이동&lt;/p&gt;
&lt;pre id=&quot;code_1715834006643&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# cd mariadb-10.6.17&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. 빌드 환경 설정&lt;/p&gt;
&lt;pre id=&quot;code_1715834034945&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# cmake -DCMAKE_INSTALL_PREFIX=/usr/local/cloud/mariadb -DMYSQL_USER=mysql -DMYSQL_TCP_PORT=3306 -DMYSQL_DATADIR=/usr/local/cloud/mariadb/data -DMYSQL_UNIX_ADDR=/usr/local/cloud/mariadb/tmp/mariadb.sock -DINSTALL_SYSCONFDIR=/usr/local/cloud/mariadb/etc -DINSTALL_SYSCONF2DIR=/usr/local/cloud/mariadb/etc/my.cnf.d -DDEFAULT_CHARSET=utf8 -DDEFAULT_COLLATION=utf8_general_ci -DWITH_EXTRA_CHARSETS=all -DWITH_ARIA_STORAGE_ENGINE=1 -DWITH_XTRADB_STORAGE_ENGINE=1 -DWITH_ARCHIVE_STORAGE_ENGINE=1 -DWITH_INNOBASE_STORAGE_ENGINE=1 -DWITH_PARTITION_STORAGE_ENGINE=1 -DWITH_BLACKHOLE_STORAGE_ENGINE=1 -DWITH_FEDERATEDX_STORAGE_ENGINE=1 -DWITH_PERFSCHEMA_STORAGE_ENGINE=1 -DWITH_READLINE=1 -DWITH_SSL=bundled -DWITH_ZLIB=system&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8. 빌드 &amp;amp; 설치&lt;/p&gt;
&lt;pre id=&quot;code_1715834061849&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# make &amp;amp;&amp;amp; make install&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;[2]&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;MariaDB 설정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 설정 작업을 위해 root 홈 디렉토리로 이동&lt;/p&gt;
&lt;pre id=&quot;code_1715834116273&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# cd 
# pwd
/root&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 실행 계정 생성&lt;/p&gt;
&lt;pre id=&quot;code_1715834193553&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# groupadd mysql
# useradd -M -g mysql mysql&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. MariaDB 설치 디렉토리 소유자 변경&lt;/p&gt;
&lt;pre id=&quot;code_1715834271681&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# chown -R mysql:mysql /usr/local/cloud/mariadb&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 설정 파일 위치 변경&lt;/p&gt;
&lt;pre id=&quot;code_1715834301463&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cp -R /usr/local/cloud/mariadb/etc/my.cnf.d /etc&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 기본(관리) 데이터베이스(mysql) 생성&lt;/p&gt;
&lt;pre id=&quot;code_1715834451613&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# /usr/local/cloud/mariadb/scripts/mysql_install_db --user=mysql --basedir=/usr/local/cloud/mariadb --defaults-file=/usr/local/cloud/mariadb/etc/my.cnf --datadir=/usr/local/cloud/mariadb/data&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. 서버 구동&lt;/p&gt;
&lt;pre id=&quot;code_1715834487394&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# /usr/local/cloud/mariadb/bin/mysqld_safe &amp;amp;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. root 패스워드 설정&lt;/p&gt;
&lt;pre id=&quot;code_1715834548916&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# /usr/local/cloud/mariadb/bin/mysqladmin -u root password '........'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8. 데이터베이스 접속 테스트&lt;/p&gt;
&lt;pre id=&quot;code_1715834585881&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# /usr/local/cloud/mariadb/bin/mysql -u root -p&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;9. path 설정(/etc/profile)&lt;/p&gt;
&lt;pre id=&quot;code_1715834622082&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# mysql
export PATH=$PATH:/usr/local/cloud/mariadb/bin&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;10. 서버 강제 종료&lt;/p&gt;
&lt;pre id=&quot;code_1715834947198&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# ps -ef | grep mysql
root       865     1  0 16:23 ?        00:00:00 /bin/sh /usr/local/cloud/mariadb/bin/mysqld_safe --datadir=/usr/local/cloud/mariadb/data --pid-file=/usr/local/cloud/mariadb/data/lx.cloud.me.pid
mysql      968   865  0 16:23 ?        00:00:00 /usr/local/cloud/mariadb/bin/mysqld --basedir=/usr/local/cloud/mariadb --datadir=/usr/local/cloud/mariadb/data --plugin-dir=/usr/local/cloud/mariadb/lib/plugin --user=mysql --log-error=/usr/local/cloud/mariadb/data/lx.cloud.me.err --pid-file=/usr/local/cloud/mariadb/data/lx.cloud.me.pid
# kill -9 865 968
# ps -ef | grep mysql&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;[3]&lt;span&gt;&amp;nbsp;&lt;/span&gt;서비스 데몬 등록&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. MariaDB systemd service script (/usr/lib/systemd/system/mariadb.service)&lt;/p&gt;
&lt;pre id=&quot;code_1715835905621&quot; class=&quot;routeros&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;#
# mariadb systemd service file
#

[Unit]
Description=MariaDB 10.6.11 Server
After=network.target
After=syslog.target

[Install]
WantedBy=multi-user.target
Alias=mariadb.service

[Service]
User=mysql
Group=mysql

# Execute pre and post scripts as root
PermissionsStartOnly=true

# Needed to create system tables etc.
# ExecStartPre=/usr/bin/mysql-systemd-start pre

# Start main service
ExecStart=/usr/local/poscodx/mariadb/bin/mysqld_safe

# Don't signal startup success before a ping works
# ExecStartPost=/usr/bin/mysql-systemd-start post

# Give up if ping don't get an answer
TimeoutSec=600
Restart=always
PrivateTmp=false&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 서비스(데몬, Daemon) 등록/시작/중지&lt;/p&gt;
&lt;pre id=&quot;code_1715835973695&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# systemctl enable mariadb.service
# systemctl start mariadb
# ps -ef | grep mysql&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 재부팅 후, mysql 클라이언트로 접속 테스트&lt;/p&gt;
&lt;pre id=&quot;code_1715836415171&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# mysql -u root -p
password:
MariaDB [(none)]&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;[4] 데이터베이스 생성 및 사용자 인증/권한 부여&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. DBA(DB 관리자) 권한으로 접속&lt;/p&gt;
&lt;pre id=&quot;code_1715836648265&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# mysql -p;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. webdb database 생성&lt;/p&gt;
&lt;pre id=&quot;code_1715836988839&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;MariaDB [none]&amp;gt; create database webdb;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. local 접속 계정 webdb 생성&lt;/p&gt;
&lt;pre id=&quot;code_1715837305834&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;MariaDB [none]&amp;gt; create user 'webdb'@&amp;amp;'localhost' identified by 'webdb';
MariaDB [none]&amp;gt; grant all privileges on webdb.* to 'webdb'@'localhost';
MariaDB [none]&amp;gt; flush privileges;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 테스트&lt;/p&gt;
&lt;pre id=&quot;code_1715837319680&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# mysql -u webdb -D webdb -p&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 특정 IP(ex. windows 192.168.00.00)의 접속 계정 webdb 생성&lt;/p&gt;
&lt;pre id=&quot;code_1715837511701&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;MariaDB [none]&amp;gt; create user 'webdb'@'192.168.00.00' identified by 'webdb';
MariaDB [none]&amp;gt; grant all privileges on webdb.* to 'webdb'@'192.168.00.00';
MariaDB [none]&amp;gt; flush privileges;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. MySQL Workbench로 연결 테스트&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;256&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/macwg/btsHq3ATXI2/Wzq4DukhuD3i6rLjKiVNm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/macwg/btsHq3ATXI2/Wzq4DukhuD3i6rLjKiVNm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/macwg/btsHq3ATXI2/Wzq4DukhuD3i6rLjKiVNm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmacwg%2FbtsHq3ATXI2%2FWzq4DukhuD3i6rLjKiVNm1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;236&quot; height=&quot;189&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;256&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Database</category>
      <category>Database</category>
      <category>Linux</category>
      <category>MariaDB</category>
      <category>mysql</category>
      <category>Rocky Linux</category>
      <category>Shell</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/3</guid>
      <comments>https://cloud-grace.tistory.com/entry/Database-Rocky-Linux9%EC%97%90-MariaDB-%EC%84%A4%EC%B9%98-%EB%B0%A9%EB%B2%95#entry3comment</comments>
      <pubDate>Thu, 16 May 2024 14:35:19 +0900</pubDate>
    </item>
    <item>
      <title>[Database] RDBMS vs NoSQL</title>
      <link>https://cloud-grace.tistory.com/entry/Database-RDBMS-NoSQL</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;데이터베이스 기본 용어들과 RDBMS와 NoSQL의 차이점에 대해 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;Database, DBMS, SQL&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;Database&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Database는 컴퓨터 시스템에 구조화된 정보 또는 데이터를 전자적으로 저장하며 체계적인 데이터 모음이다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;DBMS&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;DBMS는 DataBase Management System으로 사용자와 DB 사이에서 사용자 요구에 따라 정보 생성 및 DB 관리를 위한 소프트웨어이다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;SQL&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;SQL은 Structured Query Language로 관계형 데이터베이스 관리 시스템의 데이터 추출 및 조작 등 데이터를 관리하기 위해 설계된 프로그래밍 언어이다. 자료 검색 및 관리, DB Schema 생성 및 수정, DB 객체 접근 조정 관리 등을 위해 사용된다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;RDBMS&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;DBMS 앞에 R이 붙은 RDBMS는 Relational이 붙어 관계형 데이터베이스 관리 시스템을 말한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;RDB라는 관계형 데이터 모델을 활용하여 데이터를 2차원 테이블로 표현한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;RDBMS의 테이블은 서로 연관이 되어 있으므로 일반 DBMS보다 효율적인 데이터 관리가 가능하다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;정규화를 거쳐 데이터 중복성 최소화를 통해 트랜잭션을 수행하기에 용이하다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;데이터 원자성, 일관성, 격리, 내구성 유지로 무결성을 높일 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;ex) MySQL, PostgreSQL, MariaDB, Microsoft SQL Server, Oracle Database&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;NoSQL&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Not Only SQL로 RDBMS와 다르게 테이블 간의 간계를 정의하지 않는다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;데이터 테이블은 그냥 전체 1개의 테이블이며 테이블 간 Join도 당연히 불가능하다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;점차 방대한 데이터의 양으로 빅데이터와 같이 기하급수적인 트래픽 증가로 등장했다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;데이터 일관성보다는 데이터 분산을 위해 수평적 확장성인 Scale-Out에 초점이 맞춰져 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;ex) Redis, Hadoop, MongoDB, Firebase, HBase, Apache Cassandra&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;RDBMS와 NoSQL의 장단점&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100.233%; height: 192px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 7.3663%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 45.4265%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;RDBMS&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 56.8401%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;NoSQL&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 86px;&quot;&gt;
&lt;td style=&quot;width: 7.3663%; height: 86px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;장점&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.4265%; height: 86px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;1. 명확한 데이터 구조 보장이 된다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;2. 데이터 중복성 방지를 해준다.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 56.8401%; height: 86px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;1. 스키마가 없어 데이터 구조가 자유로워 항상 데이터 조정 및 추가가 가능하다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;2. 데이터 분산 용이하여 Scale-Up과 Sclae-Out 모두 가능하다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 89px;&quot;&gt;
&lt;td style=&quot;width: 7.3663%; height: 89px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;단점&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.4265%; height: 89px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;1. 시스템이 커지면서 Join이 많아지면 쿼리가 복잡해질 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;2. Scale-Up으로 서버 성능 향상만을 지원하여 비용이 커질 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;3. 스키마 변경 시 번거로워진다.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 56.8401%; height: 89px;&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;1. 데이터 중복 발생이 가능하여 중복된 데이터 변경 시 모든 컬렉션에서 수정을 해야 한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;2. 스키마가 없어 명확한 데이터 구조 보장이 되지 않아 구조 결정이 어렵다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;RDBMS와 NoSQL 중, 어느 것을 사용할까?&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;RDBMS는 명확한 스키마가 중요한 경우, 데이터가 자주 변경되는 경우 적합하다. 데이터 구조가 명확하기 때문에 변경되지 않으며, 데이터 무결성이 보장되어 있기 때문에 중복된 데이터가 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;NoSQL은 데이터 변경 및 확장이 일어날 경우 사용하면 좋다. 수정이 자주 이루어지지 않는 시스템이 적합하며, 막대한 데이터를 활용하여 Scale-Out이 필요하다면 선택한다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Database</category>
      <category>Database</category>
      <category>dbms</category>
      <category>NoSQL</category>
      <category>RDBMS</category>
      <category>SQL</category>
      <category>데이터베이스</category>
      <author>cloud-grace</author>
      <guid isPermaLink="true">https://cloud-grace.tistory.com/2</guid>
      <comments>https://cloud-grace.tistory.com/entry/Database-RDBMS-NoSQL#entry2comment</comments>
      <pubDate>Thu, 16 May 2024 10:34:54 +0900</pubDate>
    </item>
  </channel>
</rss>