<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:series="https://publishpress.com/"
	>

<channel>
	<title>Solution Archives - Tomoshare</title>
	<atom:link href="https://blog.tomosia.com.vn/danh-muc/solution/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.tomosia.com.vn/danh-muc/solution/</link>
	<description>Kênh chia sẻ kiến thức Tomosia Việt Nam</description>
	<lastBuildDate>Tue, 09 Dec 2025 03:26:47 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://blog.tomosia.com.vn/wp-content/uploads/2023/09/cropped-icon-32x32.png</url>
	<title>Solution Archives - Tomoshare</title>
	<link>https://blog.tomosia.com.vn/danh-muc/solution/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Keycloak: Giải pháp IAM toàn diện cho ứng dụng hiện đại</title>
		<link>https://blog.tomosia.com.vn/keycloak-giai-phap-iam-toan-dien-cho-ung-dung-hien-dai/</link>
					<comments>https://blog.tomosia.com.vn/keycloak-giai-phap-iam-toan-dien-cho-ung-dung-hien-dai/#comments</comments>
		
		<dc:creator><![CDATA[Nguyen Luan]]></dc:creator>
		<pubDate>Tue, 09 Dec 2025 03:26:45 +0000</pubDate>
				<category><![CDATA[Solution]]></category>
		<category><![CDATA[Java]]></category>
		<guid isPermaLink="false">https://blog.tomosia.com.vn/?p=3519</guid>

					<description><![CDATA[<p>Keycloak là một giải pháp quản lý danh tính và truy cập (IAM – Identity and Access Management)&#8230;</p>
<p>The post <a href="https://blog.tomosia.com.vn/keycloak-giai-phap-iam-toan-dien-cho-ung-dung-hien-dai/">Keycloak: Giải pháp IAM toàn diện cho ứng dụng hiện đại</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p><em>Keycloak là <strong>một giải pháp quản lý danh tính và truy cập (IAM – Identity and Access Management)</strong> mã nguồn mở, giúp bạn triển khai đăng nhập, phân quyền và bảo mật cho ứng dụng mà không cần tự xây từ đầu.</em><br></p>



<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="538" src="https://blog.tomosia.com.vn/wp-content/uploads/2025/11/image-1-1024x538.png" alt="" class="wp-image-3520" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2025/11/image-1-1024x538.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2025/11/image-1-300x158.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2025/11/image-1-768x403.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2025/11/image-1-380x200.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2025/11/image-1-800x420.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2025/11/image-1.png 1034w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Bảo mật luôn là yếu tố cốt lõi trong quá trình phát triển ứng dụng, đặc biệt khi bạn phải xử lý việc xác thực và phân quyền cho nhiều người dùng khác nhau.</p>



<p>Dù các developer hoàn toàn có thể tự xây dựng hệ thống quản lý danh tính từ con số 0, nhưng việc này tốn rất nhiều thời gian, công sức và dễ phát sinh lỗi &#8211; nhất là khi phải hỗ trợ các giao thức tiêu chuẩn như OAuth2 hay OpenID Connect.</p>



<p>Keycloak xuất hiện như một giải pháp giúp đơn giản hóa toàn bộ quá trình này. Nó không chỉ giảm tải việc triển khai xác thực mà còn mang đến sự đồng nhất, bảo mật cao và khả năng tùy biến mạnh mẽ. Bạn có thể tích hợp đăng nhập bằng Google, Facebook hoặc thiết lập SSO chỉ trong vài bước cấu hình mà không cần viết lại cả hệ thống.</p>



<h2 id="1-what-keycloak-la-gi" class="wp-block-heading"><strong>1.</strong> <strong>What? Keycloak là gì?</strong></h2>



<p><strong>Keycloak</strong> là một nền tảng mã nguồn mở mạnh mẽ, cung cấp giải pháp đăng nhập một lần (SSO) cùng hệ thống quản lý danh tính và quyền truy cập cho các ứng dụng và dịch vụ.<br><br>Nền tảng này được thiết kế nhằm đơn giản hóa toàn bộ bài toán bảo mật, giúp developer dễ dàng tích hợp cơ chế đăng nhập, phân quyền và xác thực vào ứng dụng mà không phải xây dựng mọi thứ từ đầu. Tất cả đều được Keycloak cung cấp sẵn dưới dạng các tính năng linh hoạt, dễ tùy chỉnh để phù hợp với nhu cầu của từng doanh nghiệp hay tổ chức.<br></p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://mintlify.s3.us-west-1.amazonaws.com/infisical/images/sso/keycloak-oidc/create-client-login-settings.png" alt=""/></figure>



<p><br>Keycloak cho phép bạn tùy chỉnh giao diện người dùng cho các trang đăng nhập, đăng ký, quản lý tài khoản hay trang quản trị. Bên cạnh đó, nó còn hỗ trợ tích hợp với các hệ thống quản lý danh tính sẵn có như LDAP hoặc Active Directory, và cho phép xác thực thông qua các nhà cung cấp bên thứ ba như Google hay Facebook.<br><br><strong>Tóm lại</strong>: đối với developer, Keycloak giống như một “bộ công cụ all-in-one” để giải quyết toàn bộ vấn đề liên quan đến đăng nhập và phân quyền. Thay vì tự xây các tính năng như login, role-based access hay kết nối với các nền tảng bên ngoài, bạn chỉ cần cấu hình và sử dụng những gì Keycloak đã cung cấp.</p>



<p><strong>Luồng hoạt động:</strong><br>+ Spring Boot kiểm tra Token và cho phép truy cập nếu hợp lệ.<br>+ User đăng nhập vào Keycloak.<br>+ Keycloak trả về Token.<br>+ User gửi request kèm Token đến Spring Boot.<br></p>



<h2 id="2-why-tai-sao-lai-la-keycloak" class="wp-block-heading"><strong>2.</strong> <strong>Why? Tại sao lại là Keycloak?</strong></h2>



<figure class="wp-block-image size-large is-resized"><img decoding="async" src="https://www.voiceatthetable.com/wp-content/uploads/why-1780726_640.png" alt="" style="width:680px;height:auto"/></figure>



<p>Thay vì tự xây dựng module đăng nhập (Login) trong Spring Boot, việc sử dụng Keycloak mang lại các lợi ích:</p>



<p><strong>a</strong>. <strong>Quản lý tập trung:</strong> Admin có thể khóa user, đổi password, cấp quyền ngay trên giao diện Keycloak mà không cần sửa code hay database của ứng dụng.</p>



<p><strong>b</strong>. <strong>Bảo mật chuyên sâu (Delegated Authentication):</strong> Việc xử lý mật khẩu, mã hóa, 2FA (xác thực 2 bước) được Keycloak đảm nhận. Spring Boot không cần lo về lộ mật khẩu.</p>



<p><strong>c. Single Sign-On (SSO):</strong> Nếu bạn có 10 ứng dụng (Microservices), user chỉ cần đăng nhập 1 lần tại Keycloak là vào được cả 10 ứng dụng.</p>



<p><strong>d. Chuẩn hóa (Standardization):</strong> Sử dụng giao thức OAuth2 và OpenID Connect chuẩn quốc tế. Dễ dàng tích hợp với Frontend (React, Angular, Mobile App).</p>



<h2 id="3-cac-thanh-phan-chinh-trong-keycloak" class="wp-block-heading"><strong>3.</strong> <strong>Các thành phần chính trong Keycloak</strong></h2>



<h3 id="3-1-realm-khong-gian-quan-ly" class="wp-block-heading"><em><strong>3.1. Realm (Không gian quản lý)</strong></em></h3>



<p><strong>Định nghĩa:</strong> Realm là một không gian quản lý định danh hoàn toàn độc lập. Dữ liệu (user, role, client) của Realm A hoàn toàn tách biệt với Realm B.<br><br><strong>Master Realm:</strong> Khi cài đặt xong, Keycloak có sẵn realm tên là <strong><em>Master</em></strong>. Đây là realm dùng để quản trị hệ thống Keycloak. Không nên dùng realm này để quản lý user cho ứng dụng của bạn.<br><br><strong>Ví dụ:</strong> Bạn có thể tạo Realm <strong><em>Users </em></strong>cho người dùng cuối và Realm <strong><em>Admins </em></strong>cho site quản trị.</p>



<h3 id="3-2-client-ung-dung-khach" class="wp-block-heading"><em><strong>3.2. Client (Ứng dụng khách)</strong></em></h3>



<p><strong>Định nghĩa:</strong> Client là các ứng dụng hoặc dịch vụ muốn sử dụng Keycloak để xác thực. Client đại diện cho các ứng dụng hoặc dịch vụ được bảo mật bởi Keycloak. Mỗi client có cấu hình riêng, bao gồm giao thức (OAuth2, OpenID Connect), URL callback, và thông tin bảo mật như client secret.</p>



<h3 id="3-3-user-nguoi-dung" class="wp-block-heading"><strong><em>3.3. User (Người dùng)</em></strong></h3>



<p><strong>Định nghĩa:</strong> Thực thể có thể đăng nhập vào hệ thống.</p>



<p><strong>Thuộc tính:</strong> User có Username, Password, Email, và các thuộc tính tùy chỉnh (Attributes) như số điện thoại, mã nhân viên, phòng ban&#8230;</p>



<p>Keycloak hỗ trợ các phương thức xác thực đa dạng:<br>&#8211; Đăng nhập bằng email/mật khẩu.<br>&#8211; Đăng nhập qua các nhà cung cấp bên thứ ba (Google, Facebook).<br>&#8211; Xác thực hai yếu tố (2FA).</p>



<h3 id="3-4-role-vai-tro" class="wp-block-heading"><strong><em>3.4. Role (Vai trò)</em></strong></h3>



<p>Role dùng để phân quyền (Authorization). Có 2 loại Role trong Keycloak:<br>&#8211; <strong>Realm Role:</strong> Role toàn cục. Ví dụ: <code>Global_Admin</code>, <code>User</code>. Có hiệu lực trên toàn bộ Realm.<br>&#8211; <strong>Client Role:</strong> Role gắn liền với một Client cụ thể. Ví dụ: Client <code>Inventory-App</code> có role <code>stock-keeper</code>. Role này chỉ có ý nghĩa với app kho, không có ý nghĩa với app nhân sự.</p>



<h3 id="3-5-group-nhom" class="wp-block-heading"><strong><em>3.5. Group (Nhóm)</em></strong></h3>



<p><strong>Định nghĩa:</strong> Dùng để gom nhóm các User lại.<br><br><strong>Đặc điểm:</strong> Group có thể lồng nhau (Parent &#8211; Child). Ví dụ: <code>IT Department</code> -> <code>Dev Team</code>.<br><br><strong>Tác dụng:</strong> Bạn có thể gán Role cho Group, tất cả User trong Group đó sẽ tự động kế thừa Role. Giúp quản lý quyền hạn dễ dàng hơn gán lẻ tẻ.</p>



<h2 id="4-how-lam-the-nao-de-tich-hop-keycloak-vao-1-ung-dung-spring-boot-chi-trong-vai-buoc-don-gian" class="wp-block-heading"><strong>4. How? Làm thế nào để tích hợp Keycloak vào 1 ứng dụng Spring Boot chỉ trong vài bước đơn giản.</strong></h2>



<figure class="wp-block-image size-large"><img decoding="async" width="842" height="1024" src="https://blog.tomosia.com.vn/wp-content/uploads/2025/11/image-16-842x1024.png" alt="" class="wp-image-3591" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2025/11/image-16-842x1024.png 842w, https://blog.tomosia.com.vn/wp-content/uploads/2025/11/image-16-247x300.png 247w, https://blog.tomosia.com.vn/wp-content/uploads/2025/11/image-16-scaled.png 2104w" sizes="(max-width: 842px) 100vw, 842px" /></figure>



<p><strong>Phần A: Cấu hình Keycloak (Docker)</strong><br><strong>Bước 1: Khởi chạy Keycloak</strong> Mở terminal và chạy lệnh Docker (bản developer):</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:7.703125px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">ShellScript</span><span role="button" tabindex="0" data-code="docker run -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:24.0.1 start-dev" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #62E884">docker</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">run</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">-p</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">8080</span><span style="color: #E7EE98">:8080</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">-e</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">KEYCLOAK_ADMIN=admin</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">-e</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">KEYCLOAK_ADMIN_PASSWORD=admin</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">quay.io/keycloak/keycloak:24.0.1</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">start-dev</span></span></code></pre></div>



<p><strong>Bước 2: Thiết lập Realm và Client</strong></p>



<ol class="wp-block-list">
<li>Truy cập <code>http://localhost:8080</code> -&gt; Vào <strong>Administration Console</strong> (Login: admin/admin).</li>



<li><strong>Tạo Realm:</strong> Bấm vào dropdown menu góc trái -&gt; <strong>Create Realm</strong> -&gt; Tên: <code>springboot-demo</code>.</li>



<li><strong>Tạo Client:</strong><br>&#8211; Vào menu <strong>Clients</strong> -&gt; <strong>Create client</strong>.<br>&#8211; Client ID: <code>my-backend-api</code>.<br>&#8211; Capability config: Bật <strong>Client authentication</strong> (để có Client Secret) và <strong>Authorization</strong>.<br>&#8211; Lưu lại.</li>



<li><strong>Tạo Roles:</strong><br>&#8211; Vào menu <strong>Realm roles</strong> -&gt; <strong>Create role</strong>.<br>&#8211; Tạo 2 role: <code>USER</code> và <code>ADMIN</code>.</li>
</ol>



<p><strong>Phần B: Lập trình Spring Boot (Resource Server)</strong><br><strong>Bước 1: Dependencies (<code>pom.xml</code>)</strong> Cần Java 17+ và Spring Boot 3.x.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:15.40625px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">XML</span><span role="button" tabindex="0" data-code="&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
        &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
    &lt;/dependency&gt;
    &lt;!-- Thư viện quan trọng nhất để biến App thành Resource Server --&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
        &lt;artifactId&gt;spring-boot-starter-oauth2-resource-server&lt;/artifactId&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
        &lt;artifactId&gt;spring-boot-starter-security&lt;/artifactId&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.projectlombok&lt;/groupId&gt;
        &lt;artifactId&gt;lombok&lt;/artifactId&gt;
        &lt;optional&gt;true&lt;/optional&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F6F6F4">&lt;</span><span style="color: #F286C4">dependencies</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">    &lt;</span><span style="color: #F286C4">dependency</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">        &lt;</span><span style="color: #F286C4">groupId</span><span style="color: #F6F6F4">&gt;org.springframework.boot&lt;/</span><span style="color: #F286C4">groupId</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">        &lt;</span><span style="color: #F286C4">artifactId</span><span style="color: #F6F6F4">&gt;spring-boot-starter-web&lt;/</span><span style="color: #F286C4">artifactId</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">    &lt;/</span><span style="color: #F286C4">dependency</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #7B7F8B">&lt;!-- Thư viện quan trọng nhất để biến App thành Resource Server --&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">    &lt;</span><span style="color: #F286C4">dependency</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">        &lt;</span><span style="color: #F286C4">groupId</span><span style="color: #F6F6F4">&gt;org.springframework.boot&lt;/</span><span style="color: #F286C4">groupId</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">        &lt;</span><span style="color: #F286C4">artifactId</span><span style="color: #F6F6F4">&gt;spring-boot-starter-oauth2-resource-server&lt;/</span><span style="color: #F286C4">artifactId</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">    &lt;/</span><span style="color: #F286C4">dependency</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">    &lt;</span><span style="color: #F286C4">dependency</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">        &lt;</span><span style="color: #F286C4">groupId</span><span style="color: #F6F6F4">&gt;org.springframework.boot&lt;/</span><span style="color: #F286C4">groupId</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">        &lt;</span><span style="color: #F286C4">artifactId</span><span style="color: #F6F6F4">&gt;spring-boot-starter-security&lt;/</span><span style="color: #F286C4">artifactId</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">    &lt;/</span><span style="color: #F286C4">dependency</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">    &lt;</span><span style="color: #F286C4">dependency</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">        &lt;</span><span style="color: #F286C4">groupId</span><span style="color: #F6F6F4">&gt;org.projectlombok&lt;/</span><span style="color: #F286C4">groupId</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">        &lt;</span><span style="color: #F286C4">artifactId</span><span style="color: #F6F6F4">&gt;lombok&lt;/</span><span style="color: #F286C4">artifactId</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">        &lt;</span><span style="color: #F286C4">optional</span><span style="color: #F6F6F4">&gt;true&lt;/</span><span style="color: #F286C4">optional</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">    &lt;/</span><span style="color: #F286C4">dependency</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">&lt;/</span><span style="color: #F286C4">dependencies</span><span style="color: #F6F6F4">&gt;</span></span></code></pre></div>



<p><strong>Bước 2: Cấu hình (<code>application.yml</code>)</strong> Khai báo địa chỉ của Keycloak để Spring Boot biết nơi xác thực token.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:15.40625px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">YAML</span><span role="button" tabindex="0" data-code="server:
  port: 5000 # Chạy port khác Keycloak

spring:
  application:
    name: keycloak-integration-demo
  security:
    oauth2:
      resourceserver:
        jwt:
          # Đường dẫn Issuer của Realm (Quan trọng)
          # Cấu trúc: http://&lt;host&gt;:&lt;port&gt;/realms/&lt;realm-name&gt;
          issuer-uri: http://localhost:8080/realms/springboot-demo
          # jwk-set-uri sẽ được tự động cấu hình từ issuer-uri" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #97E1F1">server</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">port</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">5000</span><span style="color: #F6F6F4"> </span><span style="color: #7B7F8B"># Chạy port khác Keycloak</span></span>
<span class="line"></span>
<span class="line"><span style="color: #97E1F1">spring</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">application</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #97E1F1">name</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">keycloak-integration-demo</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">security</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #97E1F1">oauth2</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #97E1F1">resourceserver</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #97E1F1">jwt</span><span style="color: #F286C4">:</span></span>
<span class="line"><span style="color: #F6F6F4">          </span><span style="color: #7B7F8B"># Đường dẫn Issuer của Realm (Quan trọng)</span></span>
<span class="line"><span style="color: #F6F6F4">          </span><span style="color: #7B7F8B"># Cấu trúc: http://&lt;host&gt;:&lt;port&gt;/realms/&lt;realm-name&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">          </span><span style="color: #97E1F1">issuer-uri</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">http://localhost:8080/realms/springboot-demo</span></span>
<span class="line"><span style="color: #F6F6F4">          </span><span style="color: #7B7F8B"># jwk-set-uri sẽ được tự động cấu hình từ issuer-uri</span></span></code></pre></div>



<p><strong>Bước 3: Class <code>SecurityConfig.java</code> (Quan trọng nhất)</strong> Mặc định Keycloak trả về role trong JSON phức tạp, ta cần convert nó về dạng <code>ROLE_ABC</code> để Spring Security hiểu.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:15.40625px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Java</span><span role="button" tabindex="0" data-code="package com.example.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import 
org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
import org.springframework.security.web.SecurityFilterChain;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Configuration
@EnableWebSecurity
@EnableMethodSecurity // Cho phép dùng @PreAuthorize ở Controller
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -&gt; csrf.disable()) // Tắt CSRF cho API
            .authorizeHttpRequests(auth -&gt; auth
                .requestMatchers(&quot;/public/**&quot;).permitAll() // API public không cần token
                .anyRequest().authenticated() // Các API còn lại yêu cầu phải login
            )
            .oauth2ResourceServer(oauth2 -&gt; oauth2
                .jwt(jwt -&gt; jwt.jwtAuthenticationConverter(jwtAuthenticationConverter()))
            );
        
        return http.build();
    }

    // Converter: Biến đổi thông tin từ JWT Keycloak sang Spring Security Authority
    @Bean
    public JwtAuthenticationConverter jwtAuthenticationConverter() {
        JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
        converter.setJwtGrantedAuthoritiesConverter(source -&gt; {
            // Lấy map roles từ claim &quot;realm_access&quot; của Keycloak
            Map&lt;String, Object&gt; realmAccess = source.getClaimAsMap(&quot;realm_access&quot;);
            
            if (realmAccess == null || !realmAccess.containsKey(&quot;roles&quot;)) {
                return List.of();
            }

            List&lt;String&gt; roles = (List&lt;String&gt;) realmAccess.get(&quot;roles&quot;);
            
            // Convert: [USER, ADMIN] -&gt; [ROLE_USER, ROLE_ADMIN]
            return roles.stream()
                    .map(role -&gt; new org.springframework.security.core.authority.SimpleGrantedAuthority(&quot;ROLE_&quot; + role))
                    .collect(Collectors.toList());
        });
        return converter;
    }
}
" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">package</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">com.example.demo.config</span><span style="color: #F6F6F4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> org.springframework.context.annotation.Bean;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> org.springframework.context.annotation.Configuration;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> org.springframework.security.config.annotation.web.builders.HttpSecurity;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> org.springframework.security.web.SecurityFilterChain;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> java.util.Collection;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> java.util.List;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> java.util.Map;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> java.util.stream.Collectors;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">@</span><span style="color: #97E1F1; font-style: italic">Configuration</span></span>
<span class="line"><span style="color: #F6F6F4">@</span><span style="color: #97E1F1; font-style: italic">EnableWebSecurity</span></span>
<span class="line"><span style="color: #F6F6F4">@</span><span style="color: #97E1F1; font-style: italic">EnableMethodSecurity</span><span style="color: #F6F6F4"> </span><span style="color: #7B7F8B">// Cho phép dùng @PreAuthorize ở Controller</span></span>
<span class="line"><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">class</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">SecurityConfig</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">    @</span><span style="color: #97E1F1; font-style: italic">Bean</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">SecurityFilterChain</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">filterChain</span><span style="color: #F6F6F4">(</span><span style="color: #97E1F1; font-style: italic">HttpSecurity</span><span style="color: #F6F6F4"> </span><span style="color: #FFB86C; font-style: italic">http</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">throws</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">Exception</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">        http</span></span>
<span class="line"><span style="color: #F6F6F4">            .</span><span style="color: #62E884">csrf</span><span style="color: #F6F6F4">(csrf </span><span style="color: #97E1F1; font-style: italic">-&gt;</span><span style="color: #F6F6F4"> csrf.</span><span style="color: #62E884">disable</span><span style="color: #F6F6F4">()) </span><span style="color: #7B7F8B">// Tắt CSRF cho API</span></span>
<span class="line"><span style="color: #F6F6F4">            .</span><span style="color: #62E884">authorizeHttpRequests</span><span style="color: #F6F6F4">(auth </span><span style="color: #97E1F1; font-style: italic">-&gt;</span><span style="color: #F6F6F4"> auth</span></span>
<span class="line"><span style="color: #F6F6F4">                .</span><span style="color: #62E884">requestMatchers</span><span style="color: #F6F6F4">(</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">/public/**</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">).</span><span style="color: #62E884">permitAll</span><span style="color: #F6F6F4">() </span><span style="color: #7B7F8B">// API public không cần token</span></span>
<span class="line"><span style="color: #F6F6F4">                .</span><span style="color: #62E884">anyRequest</span><span style="color: #F6F6F4">().</span><span style="color: #62E884">authenticated</span><span style="color: #F6F6F4">() </span><span style="color: #7B7F8B">// Các API còn lại yêu cầu phải login</span></span>
<span class="line"><span style="color: #F6F6F4">            )</span></span>
<span class="line"><span style="color: #F6F6F4">            .</span><span style="color: #62E884">oauth2ResourceServer</span><span style="color: #F6F6F4">(oauth2 </span><span style="color: #97E1F1; font-style: italic">-&gt;</span><span style="color: #F6F6F4"> oauth2</span></span>
<span class="line"><span style="color: #F6F6F4">                .</span><span style="color: #62E884">jwt</span><span style="color: #F6F6F4">(jwt </span><span style="color: #97E1F1; font-style: italic">-&gt;</span><span style="color: #F6F6F4"> jwt.</span><span style="color: #62E884">jwtAuthenticationConverter</span><span style="color: #F6F6F4">(</span><span style="color: #62E884">jwtAuthenticationConverter</span><span style="color: #F6F6F4">()))</span></span>
<span class="line"><span style="color: #F6F6F4">            );</span></span>
<span class="line"><span style="color: #F6F6F4">        </span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #F286C4">return</span><span style="color: #F6F6F4"> http.</span><span style="color: #62E884">build</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #7B7F8B">// Converter: Biến đổi thông tin từ JWT Keycloak sang Spring Security Authority</span></span>
<span class="line"><span style="color: #F6F6F4">    @</span><span style="color: #97E1F1; font-style: italic">Bean</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">JwtAuthenticationConverter</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">jwtAuthenticationConverter</span><span style="color: #F6F6F4">() {</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #97E1F1; font-style: italic">JwtAuthenticationConverter</span><span style="color: #F6F6F4"> converter </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4; font-weight: bold">new</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">JwtAuthenticationConverter</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4">        converter.</span><span style="color: #62E884">setJwtGrantedAuthoritiesConverter</span><span style="color: #F6F6F4">(source </span><span style="color: #97E1F1; font-style: italic">-&gt;</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">            </span><span style="color: #7B7F8B">// Lấy map roles từ claim &quot;realm_access&quot; của Keycloak</span></span>
<span class="line"><span style="color: #F6F6F4">            </span><span style="color: #97E1F1; font-style: italic">Map</span><span style="color: #F6F6F4">&lt;String, Object&gt; realmAccess </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> source.</span><span style="color: #62E884">getClaimAsMap</span><span style="color: #F6F6F4">(</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">realm_access</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">);</span></span>
<span class="line"><span style="color: #F6F6F4">            </span></span>
<span class="line"><span style="color: #F6F6F4">            </span><span style="color: #F286C4">if</span><span style="color: #F6F6F4"> (realmAccess </span><span style="color: #F286C4">==</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">null</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">||</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">!</span><span style="color: #F6F6F4">realmAccess.</span><span style="color: #62E884">containsKey</span><span style="color: #F6F6F4">(</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">roles</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">)) {</span></span>
<span class="line"><span style="color: #F6F6F4">                </span><span style="color: #F286C4">return</span><span style="color: #F6F6F4"> List.</span><span style="color: #62E884">of</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4">            }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">            </span><span style="color: #97E1F1; font-style: italic">List</span><span style="color: #F6F6F4">&lt;String&gt; roles </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> (</span><span style="color: #97E1F1; font-style: italic">List</span><span style="color: #F286C4">&lt;</span><span style="color: #F6F6F4">String</span><span style="color: #F286C4">&gt;</span><span style="color: #F6F6F4">) realmAccess.</span><span style="color: #62E884">get</span><span style="color: #F6F6F4">(</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">roles</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">);</span></span>
<span class="line"><span style="color: #F6F6F4">            </span></span>
<span class="line"><span style="color: #F6F6F4">            </span><span style="color: #7B7F8B">// Convert: [USER, ADMIN] -&gt; [ROLE_USER, ROLE_ADMIN]</span></span>
<span class="line"><span style="color: #F6F6F4">            </span><span style="color: #F286C4">return</span><span style="color: #F6F6F4"> roles.</span><span style="color: #62E884">stream</span><span style="color: #F6F6F4">()</span></span>
<span class="line"><span style="color: #F6F6F4">                    .</span><span style="color: #62E884">map</span><span style="color: #F6F6F4">(role </span><span style="color: #97E1F1; font-style: italic">-&gt;</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4; font-weight: bold">new</span><span style="color: #F6F6F4"> org.springframework.security.core.authority.</span><span style="color: #62E884">SimpleGrantedAuthority</span><span style="color: #F6F6F4">(</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">ROLE_</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">+</span><span style="color: #F6F6F4"> role))</span></span>
<span class="line"><span style="color: #F6F6F4">                    .</span><span style="color: #62E884">collect</span><span style="color: #F6F6F4">(Collectors.</span><span style="color: #62E884">toList</span><span style="color: #F6F6F4">());</span></span>
<span class="line"><span style="color: #F6F6F4">        });</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #F286C4">return</span><span style="color: #F6F6F4"> converter;</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span>
<span class="line"></span></code></pre></div>



<p><strong>Bước 4: Class <code>DemoController.java</code></strong></p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:15.40625px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Java</span><span role="button" tabindex="0" data-code="package com.example.demo.controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

    @GetMapping(&quot;/public/hello&quot;)
    public String hello() {
        return &quot;Public: Xin chào, ai cũng xem được!&quot;;
    }

    @GetMapping(&quot;/user/profile&quot;)
    @PreAuthorize(&quot;hasRole('USER')&quot;)
    public String userProfile() {
        return &quot;Secured: Đây là trang dành cho User có role USER.&quot;;
    }

    @GetMapping(&quot;/admin/dashboard&quot;)
    @PreAuthorize(&quot;hasRole('ADMIN')&quot;)
    public String adminDashboard() {
        return &quot;Secured: Đây là trang quản trị (ADMIN ONLY).&quot;;
    }
}" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">package</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">com.example.demo.controller</span><span style="color: #F6F6F4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> org.springframework.security.access.prepost.PreAuthorize;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> org.springframework.web.bind.annotation.GetMapping;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> org.springframework.web.bind.annotation.RestController;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">@</span><span style="color: #97E1F1; font-style: italic">RestController</span></span>
<span class="line"><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">class</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">DemoController</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">    @</span><span style="color: #97E1F1; font-style: italic">GetMapping</span><span style="color: #F6F6F4">(</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">/public/hello</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">)</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">String</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">hello</span><span style="color: #F6F6F4">() {</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #F286C4">return</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">Public: Xin chào, ai cũng xem được!</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">    @</span><span style="color: #97E1F1; font-style: italic">GetMapping</span><span style="color: #F6F6F4">(</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">/user/profile</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">)</span></span>
<span class="line"><span style="color: #F6F6F4">    @</span><span style="color: #97E1F1; font-style: italic">PreAuthorize</span><span style="color: #F6F6F4">(</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">hasRole(&#39;USER&#39;)</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">)</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">String</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">userProfile</span><span style="color: #F6F6F4">() {</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #F286C4">return</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">Secured: Đây là trang dành cho User có role USER.</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">    @</span><span style="color: #97E1F1; font-style: italic">GetMapping</span><span style="color: #F6F6F4">(</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">/admin/dashboard</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">)</span></span>
<span class="line"><span style="color: #F6F6F4">    @</span><span style="color: #97E1F1; font-style: italic">PreAuthorize</span><span style="color: #F6F6F4">(</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">hasRole(&#39;ADMIN&#39;)</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">)</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">String</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">adminDashboard</span><span style="color: #F6F6F4">() {</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #F286C4">return</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">Secured: Đây là trang quản trị (ADMIN ONLY).</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span></code></pre></div>



<p><strong>4. RESULT: Kiểm thử hoạt động</strong></p>



<p>Sử dụng <strong>Postman</strong> để demo luồng OAuth2.</p>



<p>Bước 1: Lấy Token từ Keycloak (Login)<br>&#8211; <strong>URL:</strong> <code>http://localhost:8080/realms/springboot-demo/protocol/openid-connect/token</code><br>&#8211; <strong>Body (x-www-form-urlencoded):</strong> <br>   + <code>client_id</code>: <code>my-backend-api</code><br>   + <code>client_secret</code>: <em>(Lấy trong Keycloak: Clients -&gt; my-backend-api -&gt; Credentials)</em><br>   + <code>grant_type</code>: <code>password</code><br>   + <code>username</code>: <code>testuser</code><br>   + <code>password</code>: <code>123</code><br>&#8211; <strong>Kết quả:</strong> Bạn nhận được JSON chứa <code>access_token</code>. Copy chuỗi này.</p>



<p>Bước 2: Gọi API bảo mật<br>&#8211; <strong>URL:</strong> <code>http://localhost:8081/user/profile</code><br>&#8211; <strong>Authorization Tab:</strong> Chọn type <strong>Bearer Token</strong> và dán access token vào.<br>&#8211; <strong>Kết quả:</strong><br>   + Nếu token hợp lệ: Trả về <code>Secured: Đây là trang dành cho User...</code> (Status 200).<br>   + Nếu không gửi token: <code>401 Unauthorized</code>.</p>



<p><strong>Kết luận:</strong> Bạn đã xây dựng thành công một hệ thống bảo mật hiện đại, tách biệt hoàn toàn Resource Server và Authorization Server, tuân thủ chuẩn OAuth2.</p>
<p>The post <a href="https://blog.tomosia.com.vn/keycloak-giai-phap-iam-toan-dien-cho-ung-dung-hien-dai/">Keycloak: Giải pháp IAM toàn diện cho ứng dụng hiện đại</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.tomosia.com.vn/keycloak-giai-phap-iam-toan-dien-cho-ung-dung-hien-dai/feed/</wfw:commentRss>
			<slash:comments>18</slash:comments>
		
		
			</item>
		<item>
		<title>Đưa Localhost lên Internet miễn phí với Cloudflare Tunnel: Giải pháp thay thế Ngrok để Test Webhook &#038; Demo App</title>
		<link>https://blog.tomosia.com.vn/dua-localhost-len-internet-mien-phi-voi-cloudflare-tunnel-giai-phap-thay-the-ngrok-de-test-webhook-demo-app/</link>
					<comments>https://blog.tomosia.com.vn/dua-localhost-len-internet-mien-phi-voi-cloudflare-tunnel-giai-phap-thay-the-ngrok-de-test-webhook-demo-app/#comments</comments>
		
		<dc:creator><![CDATA[Hoang Nam]]></dc:creator>
		<pubDate>Tue, 09 Dec 2025 01:41:48 +0000</pubDate>
				<category><![CDATA[Solution]]></category>
		<category><![CDATA[Kinh nghiệm]]></category>
		<category><![CDATA[Web Server]]></category>
		<category><![CDATA[Hosting]]></category>
		<guid isPermaLink="false">https://blog.tomosia.com.vn/?p=3752</guid>

					<description><![CDATA[<p>Bạn cần test webhook ZaloPay, Stripe hay demo app cho khách hàng ngay trên localhost? Hướng dẫn sử&#8230;</p>
<p>The post <a href="https://blog.tomosia.com.vn/dua-localhost-len-internet-mien-phi-voi-cloudflare-tunnel-giai-phap-thay-the-ngrok-de-test-webhook-demo-app/">Đưa Localhost lên Internet miễn phí với Cloudflare Tunnel: Giải pháp thay thế Ngrok để Test Webhook &amp; Demo App</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p><em>Bạn cần test webhook ZaloPay, Stripe hay demo app cho khách hàng ngay trên localhost? Hướng dẫn sử dụng Cloudflare Tunnel để expose local server ra internet với HTTPS miễn phí, bảo mật, không cần mở port.</em></p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 id="mo-dau-noi-dau-cua-developer" class="wp-block-heading">Mở đầu: Nỗi đau của Developer</h2>



<p>Bạn đang phát triển một ứng dụng local, mọi thứ chạy mượt mà ở&nbsp;localhost:3000. Nhưng vấn đề nảy sinh khi:</p>



<ul class="wp-block-list">
<li>Bạn cần <strong>test Webhook</strong> từ các dịch vụ bên ngoài như ZaloPay, Stripe, Telegram (các bên này bắt buộc phải có HTTPS).</li>



<li>Khách hàng muốn <strong>xem demo ngay lập tức</strong>, nhưng bạn chưa kịp deploy lên server.</li>



<li>Bạn chán ngấy cảnh dùng <strong>Ngrok bản free</strong> vì tên miền bị đổi liên tục sau mỗi lần restart.</li>
</ul>



<p>Giải pháp tối ưu nhất hiện nay chính là&nbsp;<strong>Cloudflare Tunnel</strong>.</p>



<h2 id="1-cloudflare-tunnel-la-gi" class="wp-block-heading">1. Cloudflare Tunnel là gì?</h2>



<p><strong>Cloudflare Tunnel</strong>&nbsp;(trước đây là Argo Tunnel) là công cụ giúp bạn kết nối máy chủ local (hoặc máy ảo) ra internet mà&nbsp;<strong>không cần mở port (port forwarding)</strong>&nbsp;trên router.</p>



<p>Thay vì cho phép người lạ truy cập trực tiếp vào IP của bạn (rất rủi ro), Tunnel tạo một đường hầm bảo mật (outbound connection) từ máy bạn đến mạng lưới Cloudflare Edge. Từ đó, Cloudflare sẽ &#8220;public&#8221; ứng dụng của bạn ra ngoài bằng một tên miền HTTPS xịn xò.</p>



<h3 id="tai-sao-nen-dung-cloudflare-tunnel-thay-vi-ngrok" class="wp-block-heading">Tại sao nên dùng Cloudflare Tunnel thay vì Ngrok?</h3>



<figure class="wp-block-table"><table class="has-fixed-layout"><tbody><tr><td>Tiêu chí</td><td>Ngrok (Free)</td><td>Cloudflare Tunnel</td></tr><tr><td><strong>Domain</strong></td><td>Random, đổi liên tục</td><td><strong>Cố định</strong>&nbsp;(theo domain của bạn)</td></tr><tr><td><strong>Chi phí</strong></td><td>Giới hạn tính năng</td><td><strong>Miễn phí</strong>&nbsp;hoàn toàn</td></tr><tr><td><strong>Bảo mật</strong></td><td>Thấp</td><td>Rất cao (Cloudflare Shield)</td></tr><tr><td><strong>Cài đặt</strong></td><td>Nhanh</td><td>Cần domain riêng (nhưng đáng giá)</td></tr></tbody></table></figure>



<h2 id="2-mo-hinh-hoat-dong" class="wp-block-heading">2. Mô hình hoạt động</h2>



<p>Hãy tưởng tượng luồng dữ liệu sẽ đi như sau:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>User Browser</strong> -> <strong>Cloudflare Edge (HTTPS)</strong> -> <strong>Cloudflared (trên máy bạn)</strong> -> <strong>Localhost (3000, 8080&#8230;)</strong></p>
</blockquote>



<p>Bạn có thể chạy nhiều dịch vụ cùng lúc qua một đường hầm duy nhất:</p>



<ul class="wp-block-list">
<li>api.domain.com -> trỏ về localhost:3000</li>



<li>admin.domain.com -> trỏ về localhost:8080</li>
</ul>



<h2 id="3-chuan-bi-do-nghe" class="wp-block-heading">3. Chuẩn bị &#8220;đồ nghề&#8221;</h2>



<p>Trước khi bắt đầu, bạn cần:</p>



<ol class="wp-block-list">
<li><strong>Tài khoản Cloudflare</strong> (đăng ký miễn phí).</li>



<li><strong>Một tên miền (Domain)</strong> đã thêm vào Cloudflare.
<ul class="wp-block-list">
<li><em>Lưu ý:</em> Freenom hiện tại không ổn định. Bạn nên mua các domain giá rẻ như .xyz, .dev, .click (chỉ khoảng 1-2$/năm) tại Namecheap hoặc Hostinger để dùng lâu dài.</li>
</ul>
</li>



<li><strong>Máy tính</strong> (Linux/Mac/Windows) để chạy tool.</li>
</ol>



<h2 id="4-huong-dan-trien-khai-chi-tiet-step-by-step" class="wp-block-heading">4. Hướng dẫn triển khai chi tiết (Step-by-step)</h2>



<h3 id="buoc-1-cai-dat-cloudflared" class="wp-block-heading">Bước 1: Cài đặt&nbsp;cloudflared</h3>



<p>Công cụ&nbsp;cloudflared&nbsp;là cầu nối giữa máy bạn và Cloudflare.</p>



<p><strong>Trên Linux (Ubuntu/Debian):</strong>codeBash</p>



<pre class="wp-block-code"><code>curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb -o cloudflared.deb
sudo dpkg -i cloudflared.deb</code></pre>



<p><strong>Trên Windows:</strong><br>Tải file&nbsp;.msi&nbsp;mới nhất từ GitHub chính chủ:&nbsp;<a target="_blank" href="https://www.google.com/url?sa=E&amp;q=https%3A%2F%2Fgithub.com%2Fcloudflare%2Fcloudflared%2Freleases" rel="noreferrer noopener">Cloudflare Downloads</a><br><em>(Mở PowerShell dưới quyền Administrator để chạy các lệnh sau này).</em></p>



<h3 id="buoc-2-dang-nhap-cloudflare" class="wp-block-heading">Bước 2: Đăng nhập Cloudflare</h3>



<p>Chạy lệnh sau để xác thực:codeBash</p>



<pre class="wp-block-code"><code>cloudflared tunnel login</code></pre>



<p>Trình duyệt sẽ bật lên, bạn hãy chọn tên miền muốn sử dụng và bấm&nbsp;<strong>Authorize</strong>.</p>



<h3 id="buoc-3-tao-tunnel" class="wp-block-heading">Bước 3: Tạo Tunnel</h3>



<p>Đặt tên cho tunnel của bạn (ví dụ:&nbsp;my-local-server):codeBash</p>



<pre class="wp-block-code"><code>cloudflared tunnel create my-local-server</code></pre>



<p>Sau khi tạo xong, Cloudflare sẽ sinh ra một&nbsp;<strong>Tunnel ID</strong>&nbsp;và file credentials (thường nằm ở&nbsp;~/.cloudflared/).</p>



<h3 id="buoc-4-cau-hinh-dinh-tuyen-routing" class="wp-block-heading">Bước 4: Cấu hình định tuyến (Routing)</h3>



<p>Đây là bước quan trọng nhất để map domain về localhost.<br>Tạo file&nbsp;config.yml&nbsp;trong thư mục&nbsp;~/.cloudflared/&nbsp;(hoặc cùng thư mục chạy tool) với nội dung:codeYaml</p>



<pre class="wp-block-code"><code>tunnel: &lt;TUNNEL-NAME-HOẶC-ID&gt;
credentials-file: /duong/dan/den/file/json/credentials.json

ingress:
  # Service 1: API Backend
  - hostname: api.namdevlabs.com
    service: http://localhost:3000

  # Service 2: Webhook test (ZaloPay, Stripe)
  - hostname: hook.namdevlabs.com
    service: http://localhost:5678

  # Service 3: Dashboard Admin
  - hostname: admin.namdevlabs.com
    service: http://localhost:8080

  # Rule cuối cùng bắt buộc: Trả về 404 nếu không khớp domain nào
  - service: http_status:404</code></pre>



<h3 id="buoc-5-gan-dns-cho-subdomain" class="wp-block-heading">Bước 5: Gắn DNS cho Subdomain</h3>



<p>Bạn cần báo cho Cloudflare biết subdomain nào sẽ đi vào tunnel này.codeBash</p>



<pre class="wp-block-code"><code># Cú pháp: cloudflared tunnel route dns &lt;TUNNEL_NAME&gt; &lt;SUBDOMAIN&gt;
cloudflared tunnel route dns my-local-server api.namdevlabs.com
cloudflared tunnel route dns my-local-server hook.namdevlabs.com</code></pre>



<p>Lệnh này sẽ tự động tạo bản ghi CNAME trên Cloudflare Dashboard.</p>



<h3 id="buoc-6-kich-hoat-tunnel" class="wp-block-heading">Bước 6: Kích hoạt Tunnel</h3>



<p>Chạy tunnel với file config vừa tạo:codeBash</p>



<pre class="wp-block-code"><code>cloudflared tunnel run my-local-server</code></pre>



<p><em>Mẹo:</em>&nbsp;Nếu file config không nằm ở vị trí mặc định, dùng flag&nbsp;&#8211;config:<br>cloudflared tunnel &#8211;config /path/to/config.yml run</p>



<p> <strong>Xong!</strong> Bây giờ bạn có thể truy cập https://api.namdevlabs.com và thấy nó trỏ thẳng về localhost:3000 của bạn với HTTPS xanh mượt.</p>



<h2 id="5-meo-nang-cao-cho-pro-developer" class="wp-block-heading">5. Mẹo nâng cao cho Pro Developer</h2>



<ul class="wp-block-list">
<li><strong>Chạy ngầm (Service Mode):</strong> Để tunnel tự chạy khi khởi động máy (dành cho server home lab):codeBash<code>sudo cloudflared service install sudo systemctl start cloudflared</code></li>



<li><strong>Bảo mật Zero Trust:</strong> Bạn sợ người lạ vào link demo? Vào Cloudflare Dashboard -> Zero Trust, bật tính năng yêu cầu đăng nhập bằng Email/Google trước khi truy cập vào domain.</li>



<li><strong>Debug lỗi:</strong> Nếu không truy cập được, hãy thêm flag &#8211;loglevel debug khi chạy để xem log chi tiết.</li>
</ul>



<h2 id="6-tong-ket" class="wp-block-heading">6. Tổng kết</h2>



<p>Cloudflare Tunnel thực sự là một vũ khí lợi hại trong bộ công cụ của developer. Nó giúp bạn:</p>



<ol class="wp-block-list">
<li><strong>Tiết kiệm tiền:</strong> Không tốn phí server staging.</li>



<li><strong>Tiết kiệm thời gian:</strong> Không cần deploy để demo.</li>



<li><strong>An toàn:</strong> Không mở port, hạn chế tấn công DDoS.</li>
</ol>



<p>Hy vọng bài viết giúp bạn giải quyết được bài toán đau đầu về Webhook và Demo. Chúc bạn code vui!</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>
<p>The post <a href="https://blog.tomosia.com.vn/dua-localhost-len-internet-mien-phi-voi-cloudflare-tunnel-giai-phap-thay-the-ngrok-de-test-webhook-demo-app/">Đưa Localhost lên Internet miễn phí với Cloudflare Tunnel: Giải pháp thay thế Ngrok để Test Webhook &amp; Demo App</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.tomosia.com.vn/dua-localhost-len-internet-mien-phi-voi-cloudflare-tunnel-giai-phap-thay-the-ngrok-de-test-webhook-demo-app/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Thông não Dependency Injection bằng Eimi Fukada</title>
		<link>https://blog.tomosia.com.vn/thong-nao-dependency-injection-bang-eimi-fukada/</link>
					<comments>https://blog.tomosia.com.vn/thong-nao-dependency-injection-bang-eimi-fukada/#comments</comments>
		
		<dc:creator><![CDATA[admin_tomosia]]></dc:creator>
		<pubDate>Fri, 01 Mar 2024 02:39:09 +0000</pubDate>
				<category><![CDATA[Solution]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Dependency Injection]]></category>
		<category><![CDATA[Design Patterns]]></category>
		<category><![CDATA[java]]></category>
		<guid isPermaLink="false">https://blog.tomosia.com.vn/?p=3173</guid>

					<description><![CDATA[<p>Hello what&#8217;s up, dạo này anh em còn bị chửi code như shit nữa không nhờ. Tôi thì&#8230;</p>
<p>The post <a href="https://blog.tomosia.com.vn/thong-nao-dependency-injection-bang-eimi-fukada/">Thông não Dependency Injection bằng Eimi Fukada</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p style="font-size:16px">Hello what&#8217;s up, dạo này anh em còn bị chửi code như shit nữa không nhờ. Tôi thì vẫn thế =)))), vẫn như shit nhưng hôm nay tôi muốn giới thiệu đến anh em một kỹ thuật mới là <strong>Dependency Injection</strong> để code của anh em đỡ bốc mùi hơn một chút nhé, vào việc.</p>



<h2 id="1-dependency-injection-la-gi" class="wp-block-heading" style="font-size:30px"><strong>1. Dependency Injection là gì?</strong></h2>



<p>Theo tài liệu thì:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p style="font-size:16px">Dependency Injection is a design pattern, &#8230;</p>
</blockquote>



<p style="font-size:16px">Nôm na Dependency Injection (DI) là một kỹ thuật cho phép xóa bỏ sự phụ thuộc giữa các module, làm cho ứng dụng dễ dàng hơn trong việc thay đổi module, bảo trì code và&nbsp;testing.</p>



<p style="font-size:16px"><strong>DI</strong>&nbsp;cung cấp cho một đối tượng các thể hiện phụ thuộc (dependencies) của nó&nbsp;từ bên ngoài truyền vào mà không phải khởi tạo trực tiếp từ trong class sử dụng.</p>



<h2 id="2-nhiem-vu-cua-dependency-injection" class="wp-block-heading" style="font-size:30px"><strong>2. Nhiệm vụ của dependency injection</strong></h2>



<ul class="wp-block-list">
<li style="font-size:16px">Tạo các đối tượng.</li>



<li style="font-size:16px">Quản lý sự phụ thuộc (dependencies) giữa các đối tượng.</li>



<li style="font-size:16px">Cung cấp (inject) các phụ thuộc được yêu cầu cho đối tượng (được truyền từ bên ngoài đối tượng).</li>
</ul>



<h2 id="3-nguyen-tac-hoat-dong-cua-di" class="wp-block-heading" style="font-size:30px"><strong>3. Nguyên tắc hoạt động của&nbsp;DI</strong></h2>



<ul class="wp-block-list">
<li style="font-size:16px">Các module không giao tiếp trực tiếp với nhau, mà thông qua interface. Module cấp thấp sẽ implement interface, module cấp cao sẽ gọi module cấp thấp thông qua interface.</li>



<li style="font-size:16px">Việc khởi tạo các module cấp thấp sẽ do DI Container/ IoC Container thực hiện.</li>



<li style="font-size:16px">Việc Module nào gắn với interface nào sẽ được config trong file properties, trong file XML hoặc thông qua Annotation. Annotation là một cách thường được sử dụng trong các Framework, chẳng hạn như @Inject với&nbsp;<a href="http://www.cdi-spec.org/">CDI</a>, @Autowired với&nbsp;<a href="https://spring.io/">Spring</a>&nbsp;hay @ManagedProperty với&nbsp;<a href="https://www.oracle.com/technetwork/java/javaee/javaserverfaces-139869.html">JSF</a>.</li>
</ul>



<h2 id="4-cac-dang-dependency-injection" class="wp-block-heading" style="font-size:30px"><strong>4. Các dạng Dependency Injection</strong></h2>



<ul class="wp-block-list">
<li style="font-size:16px"><strong>Constructor Injection</strong>: Các dependency sẽ được container&nbsp;truyền vào (inject vào)&nbsp;1 class thông qua constructor của class đó. Đây là cách thông dụng nhất.</li>



<li style="font-size:16px"><strong>Setter Injection</strong>: Các dependency sẽ được truyền vào 1 class thông qua các hàm Setter.</li>



<li style="font-size:16px"><strong>Fields/ properties</strong>: Các dependency sẽ được truyền vào 1 class một cách trực tiếp vào các field.</li>



<li style="font-size:16px"><strong>Interface Injection</strong>: Class cần inject sẽ implement 1 interface. Interface này chứa 1 hàm tên&nbsp;Inject. Container sẽ injection dependency vào 1 class thông qua việc gọi hàm&nbsp;Inject&nbsp;của interface đó. Đây là cách rườm rà và cũng ít được sử dụng.</li>



<li style="font-size:16px"><strong>Service Locator</strong>: nó hoạt động như một mapper, cho phép thay đổi code tại thời điểm run-time mà không cần biên dịch lại ứng dụng hoặc phải khởi động lại.</li>
</ul>



<p style="font-size:16px">Anh em đọc đến đây đã hiểu <strong>Dependency Injection</strong> là gì chưa? Anh em nào đã thông não thì có thể bỏ qua, anh em nào vẫn lơ tơ mơ thì tiếp tục, full hd không che phía dưới =)))).</p>



<h2 id="5-vi-du-su-dung-dependency-injection" class="wp-block-heading" style="font-size:30px"><strong>5. Ví dụ sử dụng Dependency Injection.</strong></h2>



<p style="font-size:16px">Bikini.java</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Java</span><span role="button" tabindex="0" data-code="package org.tmsblog.patterns.di;

public class Bikini {
    public void wear() {
        System.out.println(&quot;Đã mặc bikini&quot;);
    }
}
" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">package</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">org.tmsblog.patterns.di</span><span style="color: #F6F6F4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">class</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">Bikini</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">void</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">wear</span><span style="color: #F6F6F4">() {</span></span>
<span class="line"><span style="color: #F6F6F4">        System.out.</span><span style="color: #62E884">println</span><span style="color: #F6F6F4">(</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">Đã mặc bikini</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">);</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span>
<span class="line"></span></code></pre></div>



<p style="font-size:16px">Girl.java</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Java</span><span role="button" tabindex="0" data-code="package org.tmsblog.patterns.di;

public class Girl {

    private Bikini outfit = new Bikini();
    
    public void result() {
        outfit.wear();
    }
}
" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">package</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">org.tmsblog.patterns.di</span><span style="color: #F6F6F4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">class</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">Girl</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">private</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">Bikini</span><span style="color: #F6F6F4"> outfit </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4; font-weight: bold">new</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">Bikini</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4">    </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">void</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">result</span><span style="color: #F6F6F4">() {</span></span>
<span class="line"><span style="color: #F6F6F4">        outfit.</span><span style="color: #62E884">wear</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span>
<span class="line"></span></code></pre></div>



<p style="font-size:16px">Ví dụ anh em tạo 1 <strong>Girl</strong>, anh em sẽ tạo ra thêm 1 bộ&nbsp;<strong>Bikini</strong>&nbsp;đi kèm với cô gái đó. Lúc này,&nbsp;<code>Bikini</code>&nbsp;tồn tại mang ý nghĩa là&nbsp;<strong>dependency</strong>&nbsp;(phụ thuộc) của&nbsp;<strong>Girl</strong>.</p>



<p style="font-size:16px">Khi khởi tạo thuộc tính như này, vô tình tạo ra một điểm thắt nút trong chương trình, giả sử,&nbsp;<strong>Girl</strong>&nbsp;muốn mặc một bộ&nbsp;<em>Quần Jeans + áo hai dây</em> thì anh em sẽ phải thay class&nbsp;<strong>Bikini</strong>&nbsp;thành&nbsp;<strong>JeansWithTshirt</strong>(quần jeans với áo T-shirt) ư?</p>



<p style="font-size:16px">Hay nguy hiểm hơn, bộ đồ&nbsp;<strong>Bikini</strong>&nbsp;bị hỏng? (code lớp&nbsp;<strong>Bikini</strong>&nbsp;không hoạt động?) nó sẽ ảnh hưởng trực tiếp tới&nbsp;<strong>Girl</strong>.</p>



<p style="font-size:16px">Vấn đề là ở đó, chúng ta cùng đọc lại nguyên tắc D của <strong><a href="http://blog.tomosia.com.vn/solid-principles/">SOLID</a></strong>:</p>



<ul class="wp-block-list">
<li style="font-size:16px">Các mô-đun cấp cao không được nhập bất cứ thứ gì từ các mô-đun cấp thấp. Cả hai nên phụ thuộc vào sự trừu tượng</li>
</ul>



<p style="font-size:16px">Bây giờ chúng ta sẽ áp dụng <strong>Dependency Injection</strong> để giải quyết vấn đề trên.</p>



<p style="font-size:16px">Girl.java</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Java</span><span role="button" tabindex="0" data-code="package org.tmsblog.patterns.di;

public class Girl {

    private final Outfit anything;

    public Girl(Outfit anything) {
        this.anything = anything;
    }
}
" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">package</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">org.tmsblog.patterns.di</span><span style="color: #F6F6F4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">class</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">Girl</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">private</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">final</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">Outfit</span><span style="color: #F6F6F4"> anything;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">Girl</span><span style="color: #F6F6F4">(</span><span style="color: #97E1F1; font-style: italic">Outfit</span><span style="color: #F6F6F4"> </span><span style="color: #FFB86C; font-style: italic">anything</span><span style="color: #F6F6F4">) {</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #BF9EEE; font-style: italic">this</span><span style="color: #F6F6F4">.anything </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> anything;</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span>
<span class="line"></span></code></pre></div>



<p style="font-size:16px">Bikini.java</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Java</span><span role="button" tabindex="0" data-code="package org.tmsblog.patterns.di;

public class Bikini implements Outfit{
   @Override
    public void wear() {
        System.out.println(&quot;Đã mặc bikini&quot;);
    }
}
" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">package</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">org.tmsblog.patterns.di</span><span style="color: #F6F6F4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">class</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">Bikini</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">implements</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">Outfit</span><span style="color: #F6F6F4">{</span></span>
<span class="line"><span style="color: #F6F6F4">   @</span><span style="color: #97E1F1; font-style: italic">Override</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">void</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">wear</span><span style="color: #F6F6F4">() {</span></span>
<span class="line"><span style="color: #F6F6F4">        System.out.</span><span style="color: #62E884">println</span><span style="color: #F6F6F4">(</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">Đã mặc bikini</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">);</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span>
<span class="line"></span></code></pre></div>



<p style="font-size:16px">Outfit.java</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Java</span><span role="button" tabindex="0" data-code="package org.tmsblog.patterns.di;

public interface Outfit {
    public void wear();
}
" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">package</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">org.tmsblog.patterns.di</span><span style="color: #F6F6F4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">interface</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">Outfit</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">void</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">wear</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span>
<span class="line"></span></code></pre></div>



<p style="font-size:16px">Main.java</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Java</span><span role="button" tabindex="0" data-code="package org.tmsblog.patterns.di;

public class Main {
    public static void main(String[] args) {
        Outfit bikini = new Bikini();

        Girl fukada = new Girl(bikini);
        //Vậy là đã lấy được đối tượng Girl nha
    }
}
" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">package</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">org.tmsblog.patterns.di</span><span style="color: #F6F6F4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">class</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">Main</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">static</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">void</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">main</span><span style="color: #F6F6F4">(</span><span style="color: #97E1F1; font-style: italic">String</span><span style="color: #F6F6F4">[] </span><span style="color: #FFB86C; font-style: italic">args</span><span style="color: #F6F6F4">) {</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #97E1F1; font-style: italic">Outfit</span><span style="color: #F6F6F4"> bikini </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4; font-weight: bold">new</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">Bikini</span><span style="color: #F6F6F4">();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #97E1F1; font-style: italic">Girl</span><span style="color: #F6F6F4"> fukada </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4; font-weight: bold">new</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">Girl</span><span style="color: #F6F6F4">(bikini);</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #7B7F8B">//Vậy là đã lấy được đối tượng Girl nha</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span>
<span class="line"></span></code></pre></div>



<p style="font-size:16px">Với đoạn code ở trên, chúng ta đã&nbsp;<em>gần như</em>&nbsp;tách được&nbsp;<strong>Bikini</strong>&nbsp;ra hoàn toàn khỏi&nbsp;<strong>Girl</strong>. điều này làm giảm sự phụ thuộc giữa&nbsp;<strong>Girl</strong>&nbsp;và&nbsp;<strong>Bikini</strong>. Mà tăng tính tùy biến, linh hoạt cho&nbsp;<code>code</code>.</p>



<p style="font-size:16px">Bây giờ&nbsp;<strong>Girl</strong>&nbsp;sẽ hoạt động với&nbsp;<strong>Outfit</strong>&nbsp;mà thôi. Và&nbsp;<strong>Outfit</strong>&nbsp;ở đâu ra? Chúng ta&nbsp;<strong>tạo ra</strong>&nbsp;và&nbsp;<strong>đưa nó vào</strong>&nbsp;<code>(Inject)</code>&nbsp;cô gái&nbsp;<strong>Girl</strong>.</p>



<p style="font-size:16px">Khái niệm&nbsp;<code>Dependency Injection</code>&nbsp;từ đây mà ra: <br><em><mark style="background-color:#e9ecef" class="has-inline-color has-black-color"><strong>Dependency Injection là việc các&nbsp;Object&nbsp;nên phụ thuộc vào các&nbsp;Abstract Class&nbsp;và thể hiện chi tiết của nó sẽ được&nbsp;Inject&nbsp;vào đối tượng lúc runtime.</strong></mark></em></p>



<p style="font-size:16px">Bây giờ muốn&nbsp;<strong>Girl</strong>&nbsp;mặc gì khác, anh em chỉ cần tạo một Class kế thừa&nbsp;<strong>Outfit</strong>&nbsp;và&nbsp;<em>Inject</em>&nbsp;nó vào&nbsp;<strong>Girl</strong>&nbsp;là xong!</p>



<p style="font-size:16px"><strong>Dependency Injection</strong>&nbsp;giúp chúng ta dễ dàng mở rộng&nbsp;<code>code</code>&nbsp;và giảm sự phụ thuộc giữa các dependency với nhau. Tuy nhiên, lúc này, khi code bạn sẽ phải kiêm thêm nhiệm vụ&nbsp;<strong>Inject dependency (tiêm sự phụ thuộc)</strong>. Thử tưởng tượng một&nbsp;<code>Class</code>&nbsp;có hàng chục dependency thì bạn sẽ phải tự tay inject từng ý cái. Việc này lại dẫn tới khó khăn trong việc code, quản lý code và dependency</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Java</span><span role="button" tabindex="0" data-code="package org.tmsblog.patterns.di;

public class Main {
    public static void main(String[] args) {
       Outfit bikini = new Bikini();
       Accessories gucci = new GucciAccessories();
       HairStyle hair = new KoreanHairStyle();
       Girl fukada = new Girl(bikini, gucci, hair);
    }
}" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">package</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">org.tmsblog.patterns.di</span><span style="color: #F6F6F4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">class</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">Main</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">static</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">void</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">main</span><span style="color: #F6F6F4">(</span><span style="color: #97E1F1; font-style: italic">String</span><span style="color: #F6F6F4">[] </span><span style="color: #FFB86C; font-style: italic">args</span><span style="color: #F6F6F4">) {</span></span>
<span class="line"><span style="color: #F6F6F4">       </span><span style="color: #97E1F1; font-style: italic">Outfit</span><span style="color: #F6F6F4"> bikini </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4; font-weight: bold">new</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">Bikini</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4">       </span><span style="color: #97E1F1; font-style: italic">Accessories</span><span style="color: #F6F6F4"> gucci </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4; font-weight: bold">new</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">GucciAccessories</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4">       </span><span style="color: #97E1F1; font-style: italic">HairStyle</span><span style="color: #F6F6F4"> hair </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4; font-weight: bold">new</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">KoreanHairStyle</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4">       </span><span style="color: #97E1F1; font-style: italic">Girl</span><span style="color: #F6F6F4"> fukada </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4; font-weight: bold">new</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">Girl</span><span style="color: #F6F6F4">(bikini, gucci, hair);</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span></code></pre></div>



<p style="font-size:16px">Vãi chưởng nhỉ, lúc này có thằng nào làm hộ được chúng ta việc này thì tốt biết mấy =))).</p>



<p style="font-size:16px">Bây giờ giả sử, chúng ta định nghĩa trước toàn bộ các&nbsp;<em>dependency</em>&nbsp;có trong Project, mô tả nó và tống nó vào 1 cái&nbsp;<code>kho</code>&nbsp;và giao cho một thằng tên là&nbsp;<code>framework</code>&nbsp;quản lý. Bất kỳ các&nbsp;<code>Class</code>&nbsp;nào khi khởi tạo, nó cần dependency gì, thì cái&nbsp;<code>framework</code>&nbsp;này sẽ tự tìm trong&nbsp;<code>kho</code>&nbsp;rồi&nbsp;<em>inject</em>&nbsp;vào đối tượng thay chúng ta. sẽ tiện hơn phải không?</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1020" height="1024" src="http://blog.tomosia.com.vn/wp-content/uploads/2024/02/Screenshot-2024-02-27-at-11.27.02-1020x1024.png" alt="" class="wp-image-3185" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2024/02/Screenshot-2024-02-27-at-11.27.02-1020x1024.png 1020w, https://blog.tomosia.com.vn/wp-content/uploads/2024/02/Screenshot-2024-02-27-at-11.27.02-300x300.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2024/02/Screenshot-2024-02-27-at-11.27.02-150x150.png 150w, https://blog.tomosia.com.vn/wp-content/uploads/2024/02/Screenshot-2024-02-27-at-11.27.02-768x771.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2024/02/Screenshot-2024-02-27-at-11.27.02-1530x1536.png 1530w, https://blog.tomosia.com.vn/wp-content/uploads/2024/02/Screenshot-2024-02-27-at-11.27.02-80x80.png 80w, https://blog.tomosia.com.vn/wp-content/uploads/2024/02/Screenshot-2024-02-27-at-11.27.02-380x381.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2024/02/Screenshot-2024-02-27-at-11.27.02-800x803.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2024/02/Screenshot-2024-02-27-at-11.27.02-1160x1164.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2024/02/Screenshot-2024-02-27-at-11.27.02.png 1590w" sizes="(max-width: 1020px) 100vw, 1020px" /></figure>



<p style="font-size:16px">Úi dời ơi, tuyệt chứ nhỉ, đó cũng chính là nguyên lý chính của&nbsp;<strong>Inversion of Control (IOC)&nbsp;&#8211;&nbsp;Đảo chiều sự điều khiển</strong></p>



<p style="font-size:16px">Nguyên văn Wiki:</p>



<ul class="wp-block-list">
<li style="font-size:16px"><span style="color: rgb(55, 53, 47); font-family: Inter, Inter-fallback, Helvetica, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, NotoColorEmoji, &quot;Noto Color Emoji&quot;, &quot;Segoe UI Symbol&quot;, &quot;Android Emoji&quot;, EmojiSymbols, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, Roboto, &quot;Helvetica Neue&quot;, &quot;Noto Sans&quot;, sans-serif; font-size: 19.2px; letter-spacing: -0.1px; background-color: rgb(251, 251, 253);">Inversion of Control is a programming principle. flow of control within the application is not controlled by the application itself, but rather by the underlying framework.</span></li>
</ul>



<p style="font-size:16px">Khi đó, code chúng ta sẽ chỉ cần như này, để lấy ra đối tượng <strong>Girl</strong>, còn trong <strong>Girl.java</strong> anh em tiêm chích <strong>Accessories</strong> và <strong>HairStyle</strong> như <strong>Outfit</strong> nha:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Java</span><span role="button" tabindex="0" data-code="package org.tmsblog.patterns.di;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class Main {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(Main.class, args);

        Girl girl = context.getBean(Girl.class);
        // Anh em muốn lấy gì từ Girl thì cứ chấm mút ra nha =))
    }
}" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">package</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">org.tmsblog.patterns.di</span><span style="color: #F6F6F4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> org.springframework.boot.SpringApplication;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> org.springframework.boot.autoconfigure.SpringBootApplication;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> org.springframework.context.ApplicationContext;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">@</span><span style="color: #97E1F1; font-style: italic">SpringBootApplication</span></span>
<span class="line"><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">class</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">Main</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">static</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">void</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">main</span><span style="color: #F6F6F4">(</span><span style="color: #97E1F1; font-style: italic">String</span><span style="color: #F6F6F4">[] </span><span style="color: #FFB86C; font-style: italic">args</span><span style="color: #F6F6F4">) {</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #97E1F1; font-style: italic">ApplicationContext</span><span style="color: #F6F6F4"> context </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> SpringApplication.</span><span style="color: #62E884">run</span><span style="color: #F6F6F4">(Main.class, args);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #97E1F1; font-style: italic">Girl</span><span style="color: #F6F6F4"> girl </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> context.</span><span style="color: #62E884">getBean</span><span style="color: #F6F6F4">(Girl.class);</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #7B7F8B">// Anh em muốn lấy gì từ Girl thì cứ chấm mút ra nha =))</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span></code></pre></div>



<p style="font-size:16px"><strong>Lời kết:</strong></p>



<p style="font-size:16px"><strong>Dependency Injection</strong> và <strong>IoC container </strong>là những khái niệm rất quan trọng, hầu hết các ứng dụng, framework hiện tại đều sử dụng nó. Chúng ta cần tìm hiểu để biết rõ DI và IoC được ứng dụng trong trường hợp nào. Nếu áp dụng hợp lý code của chúng ta sẽ ít kết dính hơn (loose coupling), dễ bảo trì, dễ test hơn, tổ chức ứng dụng hợp lý và gọn gàng hơn.</p>



<p>Source Code tham khảo tại <a href="https://github.com/chienhnc/di">đây</a>: </p>
<p>The post <a href="https://blog.tomosia.com.vn/thong-nao-dependency-injection-bang-eimi-fukada/">Thông não Dependency Injection bằng Eimi Fukada</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.tomosia.com.vn/thong-nao-dependency-injection-bang-eimi-fukada/feed/</wfw:commentRss>
			<slash:comments>8</slash:comments>
		
		
			</item>
		<item>
		<title>Hướng dẫn Java Design Pattern – Singleton</title>
		<link>https://blog.tomosia.com.vn/huong-dan-java-design-pattern-singleton/</link>
					<comments>https://blog.tomosia.com.vn/huong-dan-java-design-pattern-singleton/#comments</comments>
		
		<dc:creator><![CDATA[admin_tomosia]]></dc:creator>
		<pubDate>Tue, 20 Feb 2024 08:21:39 +0000</pubDate>
				<category><![CDATA[Solution]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Singleton]]></category>
		<category><![CDATA[Design Patterns]]></category>
		<category><![CDATA[java]]></category>
		<guid isPermaLink="false">https://blog.tomosia.com.vn/?p=3157</guid>

					<description><![CDATA[<p>Hi các đồng dâm, tôi lại quay trở lại rồi đây, trong bài trước tôi đã giới thiệu&#8230;</p>
<p>The post <a href="https://blog.tomosia.com.vn/huong-dan-java-design-pattern-singleton/">Hướng dẫn Java Design Pattern – Singleton</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p style="font-size:16px">Hi các đồng dâm, tôi lại quay trở lại rồi đây, trong bài trước tôi đã giới thiệu với anh em kiến thức cơ bản của <a href="http://blog.tomosia.com.vn/gioi-thieu-design-patterns/">Design Pattern</a>. Tiếp tục với series Design Patterns, đây sẽ là &#8220;<em>màn dạo đầu</em>&#8221; nhé =))))</p>



<p style="font-size:16px">Đôi khi, trong quá trình phân tích thiết kế một hệ thống, chúng ta mong muốn có những đối tượng cần tồn tại duy nhất và có thể truy xuất mọi lúc mọi nơi. Làm thế nào để hiện thực được một đối tượng như thế khi xây dựng mã nguồn? Chúng ta có thể nghĩ tới việc sử dụng một biến toàn cục (global variable : public static final). Tuy nhiên, việc sử dụng biến toàn cục nó phá vỡ quy tắc của&nbsp;<strong>OOP (encapsulation)</strong>. Để giải bài toán trên, người ta hướng đến một giải pháp là sử dụng&nbsp;<strong>Singleton pattern</strong>.</p>



<h2 id="1-singleton-pattern-la-gi" class="wp-block-heading" style="font-size:30px"><strong>1. Singleton Pattern là gì?</strong></h2>



<p style="font-size:16px"><strong>Singleton</strong>&nbsp;là 1 trong 5 design pattern của nhóm&nbsp;<strong>Creational Design Pattern</strong>.</p>



<p style="font-size:16px"><strong>Singleton</strong>&nbsp;đảm bảo chỉ duy nhất&nbsp;<strong>một thể hiện (instance)</strong>&nbsp;được tạo ra và nó sẽ cung cấp cho anh em một method để có thể truy xuất được thể hiện duy nhất đó mọi lúc mọi nơi trong chương trình.</p>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="640" data-id="3162" src="http://blog.tomosia.com.vn/wp-content/uploads/2024/02/image-9-1024x640.png" alt="" class="wp-image-3162" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2024/02/image-9-1024x640.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2024/02/image-9-300x188.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2024/02/image-9-768x480.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2024/02/image-9-1536x960.png 1536w, https://blog.tomosia.com.vn/wp-content/uploads/2024/02/image-9-380x238.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2024/02/image-9-800x500.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2024/02/image-9-1160x725.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2024/02/image-9.png 1920w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</figure>



<p style="font-size:16px">Sử dụng Singleton khi chúng ta muốn:</p>



<ul class="wp-block-list" style="font-size:16px">
<li>Đảm bảo rằng chỉ có một instance của lớp.</li>



<li>Việc quản lý việc truy cập tốt hơn vì chỉ có một thể hiện duy nhất.</li>



<li>Có thể quản lý số lượng thể hiện của một lớp trong giớn hạn chỉ định.</li>
</ul>



<h2 id="2-implement-singleton-pattern-nhu-the-nao" class="wp-block-heading" style="font-size:30px"><strong>2. Implement Singleton Pattern như thế nào?</strong></h2>



<p style="font-size:16px">Có rất nhiều cách để implement Singleton Pattern. Nhưng dù cho việc implement bằng cách nào đi nữa cũng dựa vào nguyên tắc dưới đây cơ bản dưới đây:</p>



<ul class="wp-block-list">
<li style="font-size:16px"><strong>private constructor</strong>&nbsp;để hạn chế truy cập từ class bên ngoài.</li>



<li style="font-size:16px">Đặt&nbsp;<strong>private static final variable</strong>&nbsp;đảm bảo biến chỉ được khởi tạo trong class.</li>



<li style="font-size:16px">Có một method&nbsp;<strong>public static</strong>&nbsp;để&nbsp;<strong>return instance</strong>&nbsp;được khởi tạo ở trên.</li>
</ul>



<h2 id="3-nhung-cach-nao-de-implement-singleton-pattern" class="wp-block-heading" style="font-size:30px"><strong>3. Những cách nào để implement Singleton Pattern</strong></h2>



<p style="font-size:16px">Dựa trên những nguyên tắc thiết kế Singleton ở trên, chúng ta có các cách implement singleton như sau:</p>



<p style="font-size:23px"><strong>3.1. Eager initialization</strong></p>



<p style="font-size:16px"><strong>Singleton</strong>&nbsp;Class được khởi tạo ngay khi được gọi đến.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Java</span><span role="button" tabindex="0" data-code="package com.tmsblog.patterns.creational.singleton;
 
public class EagerInitializedSingleton {
 
    private static final EagerInitializedSingleton INSTANCE = new EagerInitializedSingleton();
 
    private EagerInitializedSingleton() {}
 
    public static EagerInitializedSingleton getInstance() {
        return INSTANCE;
    }
}" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">package</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">com.tmsblog.patterns.creational.singleton</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">class</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">EagerInitializedSingleton</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">private</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">static</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">final</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">EagerInitializedSingleton</span><span style="color: #F6F6F4"> INSTANCE </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4; font-weight: bold">new</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">EagerInitializedSingleton</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">private</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">EagerInitializedSingleton</span><span style="color: #F6F6F4">() {}</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">static</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">EagerInitializedSingleton</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">getInstance</span><span style="color: #F6F6F4">() {</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #F286C4">return</span><span style="color: #F6F6F4"> INSTANCE;</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span></code></pre></div>



<p style="font-size:16px">Eager initialization là cách tiếp cận tốt, dễ cài đặt, tuy nhiên nó có một nhược điểm mặc dù instance đã được khởi tạo nhưng có thể sẽ không dùng tới và nó dễ dàng bị phá vỡ bởi Reflection.</p>



<p style="font-size:23px"><strong>3.2. Static block initialization</strong></p>



<p style="font-size:16px">Cách làm tương tự như&nbsp;<strong>Eager initialization</strong>&nbsp;chỉ khác phần&nbsp;<strong>static block</strong>&nbsp;cung cấp thêm lựa chọn cho việc handle exception hay các xử lý khác.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Java</span><span role="button" tabindex="0" data-code="package com.tmsblog.patterns.creational.singleton;
 
public class StaticBlockSingleton {
 
    private static final StaticBlockSingleton INSTANCE;
 
    private StaticBlockSingleton() {}
 
    // Static block initialization for exception handling
    static {
        try {
            INSTANCE = new StaticBlockSingleton();
        } catch (Exception e) {
            throw new RuntimeException(&quot;Exception occured in creating singleton instance&quot;);
        }
    }
 
    public static StaticBlockSingleton getInstance() {
        return INSTANCE;
    }
}" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">package</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">com.tmsblog.patterns.creational.singleton</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">class</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">StaticBlockSingleton</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">private</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">static</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">final</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">StaticBlockSingleton</span><span style="color: #F6F6F4"> INSTANCE;</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">private</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">StaticBlockSingleton</span><span style="color: #F6F6F4">() {}</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #7B7F8B">// Static block initialization for exception handling</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">static</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #F286C4">try</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">            INSTANCE </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4; font-weight: bold">new</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">StaticBlockSingleton</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4">        } </span><span style="color: #F286C4">catch</span><span style="color: #F6F6F4"> (</span><span style="color: #97E1F1; font-style: italic">Exception</span><span style="color: #F6F6F4"> </span><span style="color: #FFB86C; font-style: italic">e</span><span style="color: #F6F6F4">) {</span></span>
<span class="line"><span style="color: #F6F6F4">            </span><span style="color: #F286C4">throw</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4; font-weight: bold">new</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">RuntimeException</span><span style="color: #F6F6F4">(</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">Exception occured in creating singleton instance</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">);</span></span>
<span class="line"><span style="color: #F6F6F4">        }</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">static</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">StaticBlockSingleton</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">getInstance</span><span style="color: #F6F6F4">() {</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #F286C4">return</span><span style="color: #F6F6F4"> INSTANCE;</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span></code></pre></div>



<p style="font-size:23px"><strong>3.3. Lazy Initialization</strong></p>



<p style="font-size:16px">Là một cách làm mang tính mở rộng hơn so với 2 cách làm trên và hoạt động tốt trong môi trường đơn luồng (single-thread).</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Java</span><span role="button" tabindex="0" data-code="package com.tmsblog.patterns.creational.singleton;
 
public class LazyInitializedSingleton {
 
    private static LazyInitializedSingleton instance;
 
    private LazyInitializedSingleton() {}
 
    public static LazyInitializedSingleton getInstance() {
        if (instance == null) {
            instance = new LazyInitializedSingleton();
        }
        return instance;
    }
}" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">package</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">com.tmsblog.patterns.creational.singleton</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">class</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">LazyInitializedSingleton</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">private</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">static</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">LazyInitializedSingleton</span><span style="color: #F6F6F4"> instance;</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">private</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">LazyInitializedSingleton</span><span style="color: #F6F6F4">() {}</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">static</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">LazyInitializedSingleton</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">getInstance</span><span style="color: #F6F6F4">() {</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #F286C4">if</span><span style="color: #F6F6F4"> (instance </span><span style="color: #F286C4">==</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">null</span><span style="color: #F6F6F4">) {</span></span>
<span class="line"><span style="color: #F6F6F4">            instance </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4; font-weight: bold">new</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">LazyInitializedSingleton</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4">        }</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #F286C4">return</span><span style="color: #F6F6F4"> instance;</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span></code></pre></div>



<p style="font-size:16px">Cách này đã khắc phục được nhược điểm của cách&nbsp;<strong>Eager initialization</strong>, chỉ khi nào&nbsp;<strong>getInstance()</strong>&nbsp;được gọi thì instance mới được khởi tạo. Tuy nhiên, cách này chỉ sử dụng tốt trong trường hợp đơn luồng (single-thread), trường hợp nếu có nhiều luồng (multi-thread) cùng chạy và cùng gọi hàm getInstance() tại cùng một thời điểm thì có thể có nhiều hơn 1 thể hiện của instance. Để khắc phục nhược điểm này chúng ta sử dụng&nbsp;<strong>Thread Safe Singleton</strong>.</p>



<p style="font-size:16px">Một nhược điểm nữa của&nbsp;<strong>Lazy Initialization</strong>&nbsp;cần quan tâm là: đối với thao tác create instance quá chậm thì người dùng có phải chờ lâu cho lần sử dụng đầu tiên.</p>



<p style="font-size:23px"><strong>3.4. Thread Safe Singleton</strong></p>



<p style="font-size:16px">Cách đơn giản nhất là chúng ta gọi phương thức&nbsp;<strong>synchronized</strong>&nbsp;của hàm&nbsp;<strong>getInstance()</strong>&nbsp;và như vậy hệ thống đảm bảo rằng tại cùng một thời điểm chỉ có thể có 1 luồng có thể truy cập vào hàm getInstance() và đảm bảo rằng chỉ có duy nhất 1 thể hiện của class.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Java</span><span role="button" tabindex="0" data-code="package com.tmsblog.patterns.creational.singleton;
 
public class ThreadSafeLazyInitializedSingleton {
 
    private static volatile ThreadSafeLazyInitializedSingleton instance;
 
    private ThreadSafeLazyInitializedSingleton() {}
 
    public static synchronized ThreadSafeLazyInitializedSingleton getInstance() {
        if (instance == null) {
            instance = new ThreadSafeLazyInitializedSingleton();
        }
        return instance;
    }
}" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">package</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">com.tmsblog.patterns.creational.singleton</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">class</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">ThreadSafeLazyInitializedSingleton</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">private</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">static</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">volatile</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">ThreadSafeLazyInitializedSingleton</span><span style="color: #F6F6F4"> instance;</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">private</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">ThreadSafeLazyInitializedSingleton</span><span style="color: #F6F6F4">() {}</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">static</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">synchronized</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">ThreadSafeLazyInitializedSingleton</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">getInstance</span><span style="color: #F6F6F4">() {</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #F286C4">if</span><span style="color: #F6F6F4"> (instance </span><span style="color: #F286C4">==</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">null</span><span style="color: #F6F6F4">) {</span></span>
<span class="line"><span style="color: #F6F6F4">            instance </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4; font-weight: bold">new</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">ThreadSafeLazyInitializedSingleton</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4">        }</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #F286C4">return</span><span style="color: #F6F6F4"> instance;</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span></code></pre></div>



<blockquote class="wp-block-quote is-style-default is-layout-flow wp-block-quote-is-layout-flow">
<p></p>
<cite>Biến&nbsp;<strong>volatile</strong>&nbsp;trong Java có tác dụng thông báo sự thay đổi giá trị của biến tới các thread khác&nbsp;nhau nếu biến này đang được sử dụng trong nhiều thread.</cite></blockquote>



<p style="font-size:16px">Cách này có nhược điểm là một phương thức&nbsp;<strong>synchronized</strong>&nbsp;sẽ chạy rất chậm và tốn hiệu năng, bất kỳ Thread nào gọi đến đều phải chờ nếu có một Thread khác đang sử dụng. Có những tác vụ xử lý trước và sau khi tạo thể hiện không cần thiết phải block. Vì vậy chúng ta cần cải tiến nó đi 1 chút với&nbsp;<strong>Double Check Locking Singleton</strong>.</p>



<p style="font-size:23px"><strong>3.5. Double Check Locking Singleton</strong></p>



<p style="font-size:16px">Để implement theo cách này, chúng ta sẽ kiểm tra sự tồn tại thể hiện của lớp, với sự hỗ trợ của đồng bộ hóa, hai lần trước khi khởi tạo. Phải khai báo&nbsp;<strong>volatile</strong>&nbsp;cho instance để tránh lớp làm việc không chính xác do quá trình tối ưu hóa của trình biên dịch.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Java</span><span role="button" tabindex="0" data-code="package com.tmsblog.patterns.creational.singleton;
 
public class DoubleCheckLockingSingleton {
 
    private static volatile DoubleCheckLockingSingleton instance;
 
    private DoubleCheckLockingSingleton() {}
 
    public static DoubleCheckLockingSingleton getInstance() {
        // Do something before get instance ...
        if (instance == null) {
            // Do the task too long before create instance ...
            // Block so other threads cannot come into while initialize
            synchronized (DoubleCheckLockingSingleton.class) {
                // Re-check again. Maybe another thread has initialized before
                if (instance == null) {
                    instance = new DoubleCheckLockingSingleton();
                }
            }
        }
        // Do something after get instance ...
        return instance;
    }
}" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">package</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">com.tmsblog.patterns.creational.singleton</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">class</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">DoubleCheckLockingSingleton</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">private</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">static</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">volatile</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">DoubleCheckLockingSingleton</span><span style="color: #F6F6F4"> instance;</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">private</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">DoubleCheckLockingSingleton</span><span style="color: #F6F6F4">() {}</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">static</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">DoubleCheckLockingSingleton</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">getInstance</span><span style="color: #F6F6F4">() {</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #7B7F8B">// Do something before get instance ...</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #F286C4">if</span><span style="color: #F6F6F4"> (instance </span><span style="color: #F286C4">==</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">null</span><span style="color: #F6F6F4">) {</span></span>
<span class="line"><span style="color: #F6F6F4">            </span><span style="color: #7B7F8B">// Do the task too long before create instance ...</span></span>
<span class="line"><span style="color: #F6F6F4">            </span><span style="color: #7B7F8B">// Block so other threads cannot come into while initialize</span></span>
<span class="line"><span style="color: #F6F6F4">            </span><span style="color: #F286C4">synchronized</span><span style="color: #F6F6F4"> (DoubleCheckLockingSingleton.class) {</span></span>
<span class="line"><span style="color: #F6F6F4">                </span><span style="color: #7B7F8B">// Re-check again. Maybe another thread has initialized before</span></span>
<span class="line"><span style="color: #F6F6F4">                </span><span style="color: #F286C4">if</span><span style="color: #F6F6F4"> (instance </span><span style="color: #F286C4">==</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">null</span><span style="color: #F6F6F4">) {</span></span>
<span class="line"><span style="color: #F6F6F4">                    instance </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4; font-weight: bold">new</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">DoubleCheckLockingSingleton</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4">                }</span></span>
<span class="line"><span style="color: #F6F6F4">            }</span></span>
<span class="line"><span style="color: #F6F6F4">        }</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #7B7F8B">// Do something after get instance ...</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #F286C4">return</span><span style="color: #F6F6F4"> instance;</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span></code></pre></div>



<p style="font-size:23px"><strong>3.6. Bill Pugh Singleton Implementation</strong></p>



<p style="font-size:16px">Với cách làm này bạn sẽ tạo ra&nbsp;<strong>static nested class</strong>&nbsp;với vai trò 1 Helper khi muốn tách biệt chức năng cho 1 class function rõ ràng hơn. Đây là cách thường hay được sử dụng và có hiệu suất tốt (theo các chuyên gia đánh giá :v).</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Java</span><span role="button" tabindex="0" data-code="package com.tmsblog.patterns.creational.singleton;
 
public class BillPughSingleton {
 
    private BillPughSingleton() {}
 
    public static BillPughSingleton getInstance() {
        return SingletonHelper.INSTANCE;
    }
 
    private static class SingletonHelper {
        private static final BillPughSingleton INSTANCE = new BillPughSingleton();
    }
}" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">package</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">com.tmsblog.patterns.creational.singleton</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">class</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">BillPughSingleton</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">private</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">BillPughSingleton</span><span style="color: #F6F6F4">() {}</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">static</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">BillPughSingleton</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">getInstance</span><span style="color: #F6F6F4">() {</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #F286C4">return</span><span style="color: #F6F6F4"> SingletonHelper.INSTANCE;</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">private</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">static</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">class</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">SingletonHelper</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #F286C4">private</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">static</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">final</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">BillPughSingleton</span><span style="color: #F6F6F4"> INSTANCE </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4; font-weight: bold">new</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">BillPughSingleton</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span></code></pre></div>



<p style="font-size:16px">Khi Singleton được tải vào bộ nhớ thì SingletonHelper chưa được tải vào. Nó chỉ được tải khi và chỉ khi phương thức getInstance() được gọi. Với cách này tránh được lỗi cơ chế khởi tạo instance của Singleton trong Multi-Thread, performance cao do tách biệt được quá trình xử lý. Do đó, cách làm này được đánh giá là cách triển khai Singleton nhanh và hiệu quả nhất.</p>



<p style="font-size:23px"><strong>3.7. Phá vỡ cấu trúc Singleton Pattern bằng Reflection</strong></p>



<p style="font-size:16px"><strong>Reflection</strong>&nbsp;có thể được dùng để phá vỡ Pattern của&nbsp;<strong>Eager Initialization</strong>&nbsp;ở trên.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Java</span><span role="button" tabindex="0" data-code="package com.tmsblog.patterns.creational.singleton;
 
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
 
public class ReflectionBreakSingleton {
 
    public static void main(String[] args)
            throws InstantiationException, IllegalAccessException, InvocationTargetException {
         
        EagerInitializedSingleton instanceOne = EagerInitializedSingleton.getInstance();
        EagerInitializedSingleton instanceTwo = null;
 
        Constructor&lt;?&gt;[] constructors = EagerInitializedSingleton.class.getDeclaredConstructors();
        for (Constructor&lt;?&gt; constructor : constructors) {
            constructor.setAccessible(true);
            instanceTwo = (EagerInitializedSingleton) constructor.newInstance();
        }
 
        System.out.println(instanceOne.hashCode());
        System.out.println(instanceTwo.hashCode());
    }
}
" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">package</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">com.tmsblog.patterns.creational.singleton</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> java.lang.reflect.Constructor;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> java.lang.reflect.InvocationTargetException;</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">class</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">ReflectionBreakSingleton</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">static</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">void</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">main</span><span style="color: #F6F6F4">(</span><span style="color: #97E1F1; font-style: italic">String</span><span style="color: #F6F6F4">[] </span><span style="color: #FFB86C; font-style: italic">args</span><span style="color: #F6F6F4">)</span></span>
<span class="line"><span style="color: #F6F6F4">            </span><span style="color: #F286C4">throws</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">InstantiationException</span><span style="color: #F6F6F4">, </span><span style="color: #97E1F1; font-style: italic">IllegalAccessException</span><span style="color: #F6F6F4">, </span><span style="color: #97E1F1; font-style: italic">InvocationTargetException</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">         </span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #97E1F1; font-style: italic">EagerInitializedSingleton</span><span style="color: #F6F6F4"> instanceOne </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> EagerInitializedSingleton.</span><span style="color: #62E884">getInstance</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #97E1F1; font-style: italic">EagerInitializedSingleton</span><span style="color: #F6F6F4"> instanceTwo </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">null</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #97E1F1; font-style: italic">Constructor</span><span style="color: #F6F6F4">&lt;</span><span style="color: #97E1F1; font-style: italic">?</span><span style="color: #F6F6F4">&gt;[] constructors </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> EagerInitializedSingleton.class.</span><span style="color: #62E884">getDeclaredConstructors</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #F286C4">for</span><span style="color: #F6F6F4"> (</span><span style="color: #97E1F1; font-style: italic">Constructor</span><span style="color: #F6F6F4">&lt;</span><span style="color: #97E1F1; font-style: italic">?</span><span style="color: #F6F6F4">&gt; constructor </span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> constructors) {</span></span>
<span class="line"><span style="color: #F6F6F4">            constructor.</span><span style="color: #62E884">setAccessible</span><span style="color: #F6F6F4">(</span><span style="color: #BF9EEE">true</span><span style="color: #F6F6F4">);</span></span>
<span class="line"><span style="color: #F6F6F4">            instanceTwo </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> (EagerInitializedSingleton) constructor.</span><span style="color: #62E884">newInstance</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4">        }</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">        System.out.</span><span style="color: #62E884">println</span><span style="color: #F6F6F4">(instanceOne.</span><span style="color: #62E884">hashCode</span><span style="color: #F6F6F4">());</span></span>
<span class="line"><span style="color: #F6F6F4">        System.out.</span><span style="color: #62E884">println</span><span style="color: #F6F6F4">(instanceTwo.</span><span style="color: #62E884">hashCode</span><span style="color: #F6F6F4">());</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span>
<span class="line"></span></code></pre></div>



<p>Output của chương trình:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Java</span><span role="button" tabindex="0" data-code="2018699554
1311053135" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #BF9EEE">2018699554</span></span>
<span class="line"><span style="color: #BF9EEE">1311053135</span></span></code></pre></div>



<p style="font-size:16px">Tương tự&nbsp;<strong>Eager Initialization</strong>, implement theo&nbsp;<strong>Bill Pugh Singleton</strong>&nbsp;cũng bị break bởi Reflection.</p>



<p style="font-size:23px"><strong>3.8. Enum Singleton</strong></p>



<p style="font-size:16px">Khi dùng&nbsp;<strong>enum</strong>&nbsp;thì các params chỉ được khởi tạo 1 lần duy nhất, đây cũng là cách giúp anh em tạo ra Singleton instance.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Java</span><span role="button" tabindex="0" data-code="package com.tmsblog.patterns.creational.singleton;
 
/**
 * Singleton implementation using enum initialization
 */
public enum EnumSingleton {
 
    INSTANCE;
}" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">package</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">com.tmsblog.patterns.creational.singleton</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #7B7F8B">/**</span></span>
<span class="line"><span style="color: #7B7F8B"> * Singleton implementation using enum initialization</span></span>
<span class="line"><span style="color: #7B7F8B"> */</span></span>
<span class="line"><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">enum</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">EnumSingleton</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #BF9EEE">INSTANCE</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span></code></pre></div>



<p style="font-size:16px">Lưu ý:</p>



<ul class="wp-block-list">
<li style="font-size:16px">Enum có thể sử dụng như một Singleton, nhưng nó có nhược điểm là không thể extends từ một lớp được, nên khi sử dụng cần xem xét vấn đề này.</li>



<li style="font-size:16px">Hàm&nbsp;<strong>constructor</strong>&nbsp;của&nbsp;<strong>enum</strong>&nbsp;là&nbsp;<strong>lazy</strong>, nghĩa là khi được sử dụng mới chạy hàm khởi tạo và nó chỉ chạy duy nhất một lần. Nếu muốn sử dụng như một eager singleton thì cần gọi thực thi trong một&nbsp;<strong>static block</strong>&nbsp;khi start chương trình.</li>
</ul>



<p style="font-size:16px">So sánh giữa 2 cách sử dụng&nbsp;<strong>enum initialization</strong>&nbsp;và&nbsp;<strong>static block initialization</strong>&nbsp;<strong>method</strong>, enum có một điểm rất mạnh khi giải quyết về vấn đề&nbsp;<strong>Serialization/ Deserialization</strong>.</p>



<p style="font-size:23px"><strong>3.9. Serialization and Singleton</strong></p>



<p style="font-size:16px">Đôi khi trong các hệ thống phân tán (distributed system), chúng ta cần implement interface&nbsp;<strong>Serializable</strong>&nbsp;trong lớp Singleton để chúng ta có thể lưu trữ trạng thái của nó trong file hệ thống và truy xuất lại nó sau.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Java</span><span role="button" tabindex="0" data-code="package com.tmsblog.patterns.creational.singleton;
 
import java.io.ObjectStreamException;
import java.io.Serializable;
 
public class SerializedSingleton implements Serializable {
 
    private static final long serialVersionUID = 1741825395699241705L;
 
    private SerializedSingleton() {}
 
    private static class SingletonHelper {
        private static final SerializedSingleton instance = new SerializedSingleton();
    }
 
    public static SerializedSingleton getInstance() {
        return SingletonHelper.instance;
    }
     
    /**
     * Special hook provided by serialization where developer can control what object needs to sent.
     * However this method is invoked on the new object instance created by de serialization process.
     *
     * @return
     * @throws ObjectStreamException
     */
//    private Object readResolve() throws ObjectStreamException {
//        return SingletonHelper.instance;
//    }
 
}" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">package</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">com.tmsblog.patterns.creational.singleton</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> java.io.ObjectStreamException;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> java.io.Serializable;</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">class</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">SerializedSingleton</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">implements</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">Serializable</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">private</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">static</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">final</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">long</span><span style="color: #F6F6F4"> serialVersionUID </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">1741825395699241705L</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">private</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">SerializedSingleton</span><span style="color: #F6F6F4">() {}</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">private</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">static</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">class</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">SingletonHelper</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #F286C4">private</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">static</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">final</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">SerializedSingleton</span><span style="color: #F6F6F4"> instance </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4; font-weight: bold">new</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">SerializedSingleton</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">static</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">SerializedSingleton</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">getInstance</span><span style="color: #F6F6F4">() {</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #F286C4">return</span><span style="color: #F6F6F4"> SingletonHelper.instance;</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"><span style="color: #F6F6F4">     </span></span>
<span class="line"><span style="color: #7B7F8B">    /**</span></span>
<span class="line"><span style="color: #7B7F8B">     * Special hook provided by serialization where developer can control what object needs to sent.</span></span>
<span class="line"><span style="color: #7B7F8B">     * However this method is invoked on the new object instance created by de serialization process.</span></span>
<span class="line"><span style="color: #7B7F8B">     *</span></span>
<span class="line"><span style="color: #7B7F8B">     * </span><span style="color: #F286C4">@return</span></span>
<span class="line"><span style="color: #7B7F8B">     * </span><span style="color: #F286C4">@throws</span><span style="color: #7B7F8B"> </span><span style="color: #97E1F1">ObjectStreamException</span></span>
<span class="line"><span style="color: #7B7F8B">     */</span></span>
<span class="line"><span style="color: #7B7F8B">//    private Object readResolve() throws ObjectStreamException {</span></span>
<span class="line"><span style="color: #7B7F8B">//        return SingletonHelper.instance;</span></span>
<span class="line"><span style="color: #7B7F8B">//    }</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span></code></pre></div>



<p style="font-size:16px">Đoạn code test quá trình Serialize/ Deserialize:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Java</span><span role="button" tabindex="0" data-code="package com.tmsblog.patterns.creational.singleton;
 
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
 
public class SingletonSerializedTest {
 
    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
 
        SerializedSingleton serializedSingleton1 = SerializedSingleton.getInstance();
        EnumSingleton enumSingleton1 = EnumSingleton.INSTANCE;
 
        ObjectOutput out = new ObjectOutputStream(new FileOutputStream(&quot;SingletonSerializedTest.txt&quot;));
        out.writeObject(serializedSingleton1);
        out.writeObject(enumSingleton1);
        out.close();
 
        // De-serialize from file to object
        ObjectInput in = new ObjectInputStream(new FileInputStream(&quot;SingletonSerializedTest.txt&quot;));
        SerializedSingleton serializedSingleton2 = (SerializedSingleton) in.readObject();
        EnumSingleton enumSingleton2 = (EnumSingleton) in.readObject();
        in.close();
 
        System.out.println(&quot;serializedSingleton1 hashCode=&quot; + serializedSingleton1.hashCode());
        System.out.println(&quot;serializedSingleton2 hashCode=&quot; + serializedSingleton2.hashCode());
        System.out.println(&quot;enumSingleton1 hashCode=&quot; + enumSingleton1.hashCode());
        System.out.println(&quot;enumSingleton2 hashCode=&quot; + enumSingleton2.hashCode());
    }
}" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">package</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">com.tmsblog.patterns.creational.singleton</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> java.io.FileInputStream;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> java.io.FileNotFoundException;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> java.io.FileOutputStream;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> java.io.IOException;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> java.io.ObjectInput;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> java.io.ObjectInputStream;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> java.io.ObjectOutput;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> java.io.ObjectOutputStream;</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">class</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">SingletonSerializedTest</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">public</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">static</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">void</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">main</span><span style="color: #F6F6F4">(</span><span style="color: #97E1F1; font-style: italic">String</span><span style="color: #F6F6F4">[] </span><span style="color: #FFB86C; font-style: italic">args</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">throws</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">FileNotFoundException</span><span style="color: #F6F6F4">, </span><span style="color: #97E1F1; font-style: italic">IOException</span><span style="color: #F6F6F4">, </span><span style="color: #97E1F1; font-style: italic">ClassNotFoundException</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #97E1F1; font-style: italic">SerializedSingleton</span><span style="color: #F6F6F4"> serializedSingleton1 </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> SerializedSingleton.</span><span style="color: #62E884">getInstance</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #97E1F1; font-style: italic">EnumSingleton</span><span style="color: #F6F6F4"> enumSingleton1 </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> EnumSingleton.INSTANCE;</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #97E1F1; font-style: italic">ObjectOutput</span><span style="color: #F6F6F4"> out </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4; font-weight: bold">new</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">ObjectOutputStream</span><span style="color: #F6F6F4">(</span><span style="color: #F286C4; font-weight: bold">new</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">FileOutputStream</span><span style="color: #F6F6F4">(</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">SingletonSerializedTest.txt</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">));</span></span>
<span class="line"><span style="color: #F6F6F4">        out.</span><span style="color: #62E884">writeObject</span><span style="color: #F6F6F4">(serializedSingleton1);</span></span>
<span class="line"><span style="color: #F6F6F4">        out.</span><span style="color: #62E884">writeObject</span><span style="color: #F6F6F4">(enumSingleton1);</span></span>
<span class="line"><span style="color: #F6F6F4">        out.</span><span style="color: #62E884">close</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #7B7F8B">// De-serialize from file to object</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #97E1F1; font-style: italic">ObjectInput</span><span style="color: #F6F6F4"> in </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4; font-weight: bold">new</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">ObjectInputStream</span><span style="color: #F6F6F4">(</span><span style="color: #F286C4; font-weight: bold">new</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">FileInputStream</span><span style="color: #F6F6F4">(</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">SingletonSerializedTest.txt</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">));</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #97E1F1; font-style: italic">SerializedSingleton</span><span style="color: #F6F6F4"> serializedSingleton2 </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> (SerializedSingleton) in.</span><span style="color: #62E884">readObject</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #97E1F1; font-style: italic">EnumSingleton</span><span style="color: #F6F6F4"> enumSingleton2 </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> (EnumSingleton) in.</span><span style="color: #62E884">readObject</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4">        in.</span><span style="color: #62E884">close</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">        System.out.</span><span style="color: #62E884">println</span><span style="color: #F6F6F4">(</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">serializedSingleton1 hashCode=</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">+</span><span style="color: #F6F6F4"> serializedSingleton1.</span><span style="color: #62E884">hashCode</span><span style="color: #F6F6F4">());</span></span>
<span class="line"><span style="color: #F6F6F4">        System.out.</span><span style="color: #62E884">println</span><span style="color: #F6F6F4">(</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">serializedSingleton2 hashCode=</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">+</span><span style="color: #F6F6F4"> serializedSingleton2.</span><span style="color: #62E884">hashCode</span><span style="color: #F6F6F4">());</span></span>
<span class="line"><span style="color: #F6F6F4">        System.out.</span><span style="color: #62E884">println</span><span style="color: #F6F6F4">(</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">enumSingleton1 hashCode=</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">+</span><span style="color: #F6F6F4"> enumSingleton1.</span><span style="color: #62E884">hashCode</span><span style="color: #F6F6F4">());</span></span>
<span class="line"><span style="color: #F6F6F4">        System.out.</span><span style="color: #62E884">println</span><span style="color: #F6F6F4">(</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">enumSingleton2 hashCode=</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">+</span><span style="color: #F6F6F4"> enumSingleton2.</span><span style="color: #62E884">hashCode</span><span style="color: #F6F6F4">());</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span></code></pre></div>



<p style="font-size:16px">Output của chương trình:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Java</span><span role="button" tabindex="0" data-code="serializedSingleton1 hashCode=1028566121
serializedSingleton2 hashCode=1747585824
enumSingleton1 hashCode=1118140819
enumSingleton2 hashCode=1118140819" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F6F6F4">serializedSingleton1 hashCode</span><span style="color: #F286C4">=</span><span style="color: #BF9EEE">1028566121</span></span>
<span class="line"><span style="color: #F6F6F4">serializedSingleton2 hashCode</span><span style="color: #F286C4">=</span><span style="color: #BF9EEE">1747585824</span></span>
<span class="line"><span style="color: #F6F6F4">enumSingleton1 hashCode</span><span style="color: #F286C4">=</span><span style="color: #BF9EEE">1118140819</span></span>
<span class="line"><span style="color: #F6F6F4">enumSingleton2 hashCode</span><span style="color: #F286C4">=</span><span style="color: #BF9EEE">1118140819</span></span></code></pre></div>



<p style="font-size:16px">Như trong ví dụ trên,&nbsp;<strong>Deserialize</strong>&nbsp;đối tượng của&nbsp;<strong>SerializedSingleton</strong>&nbsp;khác với đối tượng gốc. Tuy nhiên vấn đề này không xảy ra khi sử dụng&nbsp;<strong>enum</strong>.</p>



<p style="font-size:16px">Thực tế thì vẫn có cách khắc phục khi sử dụng class SerializedSingleton là implement một phương thức&nbsp;<strong>readResolve()</strong>. Nhưng khi chúng ta thật sự gặp vấn đề và cần sử dụng Serialize/ Deserialize, thì nên sử dụng&nbsp;<strong>enum</strong>&nbsp;sẽ đơn giản hơn.</p>



<h2 id="4-su-dung-singleton-pattern-khi-nao" class="wp-block-heading" style="font-size:30px"><strong>4. Sử dụng Singleton Pattern khi nào?</strong></h2>



<p style="font-size:16px">Dưới đây là một số trường hợp sử dụng của Singleton Pattern thường gặp:</p>



<ul class="wp-block-list">
<li style="font-size:16px">Vì class dùng Singleton chỉ tồn tại 1 Instance (thể hiện) nên nó thường được dùng cho các trường hợp giải quyết các bài toán cần truy cập vào các ứng dụng như: Shared resource, Logger, Configuration, Caching, Thread pool, …</li>



<li style="font-size:16px">Một số design pattern khác cũng sử dụng Singleton để triển khai: Abstract Factory, Builder, Prototype, Facade,…</li>



<li style="font-size:16px">Đã được sử dụng trong một số class của core java như:&nbsp;java.lang.Runtime, java.awt.Desktop.</li>
</ul>



<h2 id="5-tong-ket" class="wp-block-heading" style="font-size:30px"><strong>5. Tổng kết</strong></h2>



<p style="font-size:16px">Có rất nhiều cách implement cho Singleton, anh em có thể sử dụng&nbsp;<strong>BillPughSingleton</strong>&nbsp;vì có hiệu suất cao, sử dụng&nbsp;<strong>LazyInitializedSingleton</strong>&nbsp;cho những ứng dụng chỉ làm việc với ứng dụng&nbsp;<strong>single-thread</strong>&nbsp;và sử dụng&nbsp;<strong>DoubleCheckLockingSingleton</strong>&nbsp;khi làm việc với ứng dụng&nbsp;<strong>multi-thread</strong>. Tùy theo trường hợp cụ thể, anh em hãy chọn cho mình cách implement phù hợp nhé.</p>



<p style="font-size:16px"><strong>Tài liệu tham khảo:</strong></p>



<ul class="wp-block-list">
<li style="font-size:16px"><a href="https://community.oracle.com/docs/DOC-918906">https://community.oracle.com/docs/DOC-918906</a></li>



<li style="font-size:16px"><a href="https://www.journaldev.com/1377/java-singleton-design-pattern-best-practices-examples">https://www.journaldev.com/1377/java-singleton-design-pattern-best-practices-examples</a></li>



<li style="font-size:16px"><a href="http://www.javacreed.com/the-broken-singleton/">http://www.javacreed.com/the-broken-singleton/</a></li>



<li style="font-size:16px"><a href="https://www.geeksforgeeks.org/prevent-singleton-pattern-reflection-serialization-cloning/">https://www.geeksforgeeks.org/prevent-singleton-pattern-reflection-serialization-cloning/</a></li>



<li style="font-size:16px"><a href="http://www.java67.com/2015/09/thread-safe-singleton-in-java-using-double-checked-locking-pattern.html">http://www.java67.com/2015/09/thread-safe-singleton-in-java-using-double-checked-locking-pattern.html</a></li>
</ul>
<p>The post <a href="https://blog.tomosia.com.vn/huong-dan-java-design-pattern-singleton/">Hướng dẫn Java Design Pattern – Singleton</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.tomosia.com.vn/huong-dan-java-design-pattern-singleton/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
			</item>
		<item>
		<title>Logrotate: Compress và push file log lên S3</title>
		<link>https://blog.tomosia.com.vn/logrotate-compress-va-push-file-log-len-s3/</link>
					<comments>https://blog.tomosia.com.vn/logrotate-compress-va-push-file-log-len-s3/#comments</comments>
		
		<dc:creator><![CDATA[Thuc Phan]]></dc:creator>
		<pubDate>Wed, 22 Nov 2023 01:54:57 +0000</pubDate>
				<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[Solution]]></category>
		<category><![CDATA[Web Server]]></category>
		<category><![CDATA[logrotate]]></category>
		<category><![CDATA[nginx]]></category>
		<guid isPermaLink="false">https://blog.tomosia.com.vn/?p=1939</guid>

					<description><![CDATA[<p>Log files giúp bạn hiểu rõ về lịch sử hoạt động của máy chủ nhưng chúng có thể&#8230;</p>
<p>The post <a href="https://blog.tomosia.com.vn/logrotate-compress-va-push-file-log-len-s3/">Logrotate: Compress và push file log lên S3</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Log files giúp bạn hiểu rõ về lịch sử hoạt động của máy chủ nhưng chúng có thể trở nên nặng nề và khó quản lý</p>



<p>Logrotate không chỉ giúp giảm kích thước file log một cách tự động mà còn có thể nén file để tiết kiệm không gian lưu trữ</p>



<p>Trong bài viết này, chúng ta sẽ tìm hiểu cách Logrotate được cấu hình để tự động nén và đẩy file lên S3, giúp bạn duy trì hệ thống được sạch sẽ và dễ quản lý hơn</p>



<h2 id="config" class="wp-block-heading">Config</h2>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4296875px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">ShellScript</span><span role="button" tabindex="0" data-code="cd /etc/logrotate.d
touch rails_log_rotation" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #97E1F1">cd</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">/etc/logrotate.d</span></span>
<span class="line"><span style="color: #62E884">touch</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">rails_log_rotation</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">ShellScript</span><span role="button" tabindex="0" data-code="/home/ubuntu/path-to-deploy/current/log/production.log {
  daily
  dateext
  missingok
  rotate 90
  compress
  copytruncate
  lastaction
    aws s3 sync /home/ubuntu/path-to-deploy/current/log/ s3://path-to-bucket-name --exclude &quot;*&quot; --include &quot;production.log*.gz&quot; 2&gt;&amp;1
  endscript
  create 0644 root root
  su root root
}" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #62E884">/home/ubuntu/path-to-deploy/current/log/production.log</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">{</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #62E884">daily</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #62E884">dateext</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #62E884">missingok</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #62E884">rotate</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">90</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #62E884">compress</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #62E884">copytruncate</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #62E884">lastaction</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #62E884">aws</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">s3</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">sync</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">/home/ubuntu/path-to-deploy/current/log/</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">s3://path-to-bucket-name</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">--exclude</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">*</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">--include</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">production.log*.gz</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">2&gt;&amp;1</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #62E884">endscript</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #62E884">create</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">0644</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">root</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">root</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #62E884">su</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">root</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">root</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span></code></pre></div>



<p><code><strong>home/ubuntu/path-to-deploy/current/log/production.log</strong></code></p>



<ul class="wp-block-list">
<li>Link đến file log cần được quản lý bởi logrotate</li>
</ul>



<p><code><strong>daily</strong></code></p>



<ul class="wp-block-list">
<li>Thực hiện xoay vòng log hàng ngày (được thực hiện bằng cron-job)</li>
</ul>



<ul class="wp-block-list">
<li>Có nghĩa là file <code>/home/ubuntu/path-to-deploy/current/log/production.log</code> sẽ được làm mới mỗi ngày</li>
</ul>



<ul class="wp-block-list">
<li>Check cron configuration</li>
</ul>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4296875px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">ShellScript</span><span role="button" tabindex="0" data-code="cd /etc/
ls | grep cron
cron.d
cron.daily
cron.hourly
cron.monthly
cron.weekly
crontab" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #97E1F1">cd</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">/etc/</span></span>
<span class="line"><span style="color: #62E884">ls</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">|</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">grep</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">cron</span></span>
<span class="line"><span style="color: #62E884">cron.d</span></span>
<span class="line"><span style="color: #62E884">cron.daily</span></span>
<span class="line"><span style="color: #62E884">cron.hourly</span></span>
<span class="line"><span style="color: #62E884">cron.monthly</span></span>
<span class="line"><span style="color: #62E884">cron.weekly</span></span>
<span class="line"><span style="color: #62E884">crontab</span></span></code></pre></div>



<p><code><strong>dateext</strong></code></p>



<ul class="wp-block-list">
<li>Thêm ngày vào filename của file log được xoay vòng để đảm bảo không bị trùng tên</li>
</ul>



<p><code><strong>missingok</strong></code></p>



<ul class="wp-block-list">
<li>Cho phép logrotate bỏ qua nếu không tìm thấy file</li>
</ul>



<p><code><strong>rotate 90</strong></code></p>



<ul class="wp-block-list">
<li>Giữ lại tối đa 90 file logs đã quay vòng</li>



<li>Trong trường hợp này, có thể hiểu là cho phép lưu trữ file logs của 90 ngày gần nhất</li>
</ul>



<p><code><strong>compress</strong></code></p>



<ul class="wp-block-list">
<li>Nén file log đã xoay vòng để tiết kiệm không gian lưu trữ</li>
</ul>



<p><code><strong>copytruncate</strong></code></p>



<ul class="wp-block-list">
<li>Sao chép nội dung từ file cũ vào file mới, sau đó quay lại đầu file cũ và cắt bớt nó. Điều này giúp logrotate có thể xoay vòng mà không làm ảnh hưởng đến ứng dụng đang chạy</li>
</ul>



<p><code><strong>lastaction</strong></code> và <code><strong>endscript</strong></code> </p>



<ul class="wp-block-list">
<li>Bọc một đoạn code hoặc command được thực thi sau khi xoay vòng</li>



<li>Trong trường hợp này, sử dụng AWS CLI để đồng bộ hóa các file logs đã xoay vòng với Amazon S3</li>



<li>Loại trừ tất cả các files, chỉ bao gồm các file logs đã nén <code>(production.log*.gz)</code></li>



<li>Lưu ý
<ul class="wp-block-list">
<li>Bạn cần thay thế <code>path-to-bucket-name</code> bằng đường dẫn thích hợp đến S3 Bucket của bạn</li>



<li>EC2 phải tương tác được với S3 Bucket của bạn (có thể dùng <code>aws configure</code> hoặc <code>attached IAM role</code> đều được)</li>
</ul>
</li>
</ul>



<p><code><strong>create 0644 root root</strong></code></p>



<ul class="wp-block-list">
<li>Tạo một file log mới với quyền truy cập <code>0644</code> và chủ sở hữu là <code>root</code></li>
</ul>



<p><code><strong>su root root</strong></code></p>



<ul class="wp-block-list">
<li>Chuyển quyền sở hữu của file sang <code>root</code> sau khi tạo mới để đảm bảo an toàn và bảo mật</li>
</ul>



<p><strong>Tóm lại</strong></p>



<ul class="wp-block-list">
<li>Config này giúp bạn quản lý và tự động xoay vòng file <code>production.log</code> mỗi ngày</li>



<li>Nén file để tiết kiệm không gian và đồng thời sao chép lên Amazon S3 để lưu trữ</li>
</ul>



<p><strong>Manual test config</strong></p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4296875px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">ShellScript</span><span role="button" tabindex="0" data-code="sudo logrotate -f /etc/logrotate.conf" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #62E884">sudo</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">logrotate</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">-f</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">/etc/logrotate.conf</span></span></code></pre></div>
<p>The post <a href="https://blog.tomosia.com.vn/logrotate-compress-va-push-file-log-len-s3/">Logrotate: Compress và push file log lên S3</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.tomosia.com.vn/logrotate-compress-va-push-file-log-len-s3/feed/</wfw:commentRss>
			<slash:comments>10</slash:comments>
		
		
			</item>
		<item>
		<title>Short polling vs Long polling Websocket</title>
		<link>https://blog.tomosia.com.vn/short-polling-vs-long-polling-websocket/</link>
					<comments>https://blog.tomosia.com.vn/short-polling-vs-long-polling-websocket/#comments</comments>
		
		<dc:creator><![CDATA[admin_tomosia]]></dc:creator>
		<pubDate>Wed, 18 Oct 2023 08:54:59 +0000</pubDate>
				<category><![CDATA[Solution]]></category>
		<category><![CDATA[solution]]></category>
		<category><![CDATA[nodejs]]></category>
		<guid isPermaLink="false">https://blog.tomosia.com.vn/?p=1323</guid>

					<description><![CDATA[<p>Introducing Topic Short polling Short Polling is a technique in which the client sends a request to the&#8230;</p>
<p>The post <a href="https://blog.tomosia.com.vn/short-polling-vs-long-polling-websocket/">Short polling vs Long polling Websocket</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 id="introducing-topic" class="wp-block-heading"><strong>Introducing Topic</strong></h2>



<ol class="wp-block-list">
<li>Short polling</li>



<li>Long Polling</li>



<li>Websocket (Socket I/O)</li>
</ol>



<h2 id="short-polling" class="wp-block-heading"><strong>Short polling</strong></h2>



<p><code><strong>Short Polling</strong></code> is a technique in which the client sends a request to the server asking for data at fixed delays after getting a response from the previously sent request.</p>



<ul class="wp-block-list">
<li><strong>Client</strong>&nbsp;send a request to the&nbsp;<strong>Server</strong>.</li>



<li>Server responds with an empty response or data, if available.</li>



<li>Client will wait for the specified delay after receiving the response and continues the same request-response process again.</li>
</ul>



<p>Example:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="576" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/10/example1-1024x576.gif" alt="" class="wp-image-1324" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/10/example1-1024x576.gif 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/example1-300x169.gif 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/example1-768x432.gif 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/example1-380x214.gif 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/example1-800x450.gif 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/example1-1160x653.gif 1160w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h2 id="long-polling" class="wp-block-heading"><strong>Long polling</strong></h2>



<p><strong>Long Polling</strong> is a technique in which the client sends a request to the server asking for data, but the server doesn&#8217;t respond instantly if no data is available, rather it waits for a specific amount of time. If in that interval of time, any event happens or data become available, the server will respond with that data and in case of no events or data, the server will respond with an empty response after the specified timeout.</p>



<p>This technique is more complex and does consume server resources, but it can notify the client without any delay so it can give a better real-time experience.</p>



<p><strong>Long Polling works differently from short polling in the following way:</strong></p>



<ul class="wp-block-list">
<li>Client makes a request to the server</li>



<li>Server can respond in two ways:
<ul class="wp-block-list">
<li>If it has some new data available, it can respond right away.</li>



<li>If it doesn&#8217;t have anything new data, it will keep that connection open for a period of time and when it receives new data it will respond back with updated data.</li>
</ul>
</li>
</ul>



<p><strong>Some challenges in long-polling:</strong></p>



<ul class="wp-block-list">
<li>Message ordering and delivery guarantees: Message ordering cannot be guaranteed if the same client opens multiple connections to the server.</li>



<li>If the client was not able to receive the message then there will be possible message loss.</li>



<li>Performance and scaling</li>



<li>Device support and fallbacks</li>
</ul>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="576" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/10/example2-1024x576.gif" alt="" class="wp-image-1325" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/10/example2-1024x576.gif 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/example2-300x169.gif 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/example2-768x432.gif 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/example2-380x214.gif 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/example2-800x450.gif 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/example2-1160x653.gif 1160w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h2 id="web-sockets" class="wp-block-heading">Web Sockets</h2>



<p><em>WebSocket is a computer communication protocol that provides full-duplex communication channels over a single TCP connection.</em></p>



<p>The WebSocket protocol enables interaction between a client and a web server with lesser overheads, providing real-time data transfer from and to the server. WebSockets keeps the connection open, allowing messages to be passed back and forth between the client and the server. In this way, a two-way ongoing conversation can take place between the client and the server.</p>



<p><strong>Some advantages of Web Sockets over long-polling</strong></p>



<ul class="wp-block-list">
<li>WebSockets keeps a unique connection open while eliminating latency problems that arise with Long Polling.</li>



<li>Long polling is much more resource-intensive on servers whereas WebSockets have an extremely lightweight footprint on servers.</li>



<li>WebSockets pass through most firewalls without any reconfiguration.</li>



<li>Good security model (origin-based security model).</li>
</ul>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="576" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/10/websocket-1024x576.gif" alt="" class="wp-image-1326" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/10/websocket-1024x576.gif 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/websocket-300x169.gif 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/websocket-768x432.gif 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/websocket-380x214.gif 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/websocket-800x450.gif 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/websocket-1160x653.gif 1160w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p><strong>Advantages of WebSocket</strong></p>



<ul class="wp-block-list">
<li>It allows for two-way communication.</li>



<li>Websockets allow you to send and receive data much faster than HTTP. They&#8217;re also faster than AJAX.</li>



<li>Communication between origins (however, this poses security risks).</li>



<li>Compatibility between platforms (web, desktop, mobile)</li>



<li>HTTP has a 2000-byte overhead, but WebSocket only has a 2-byte cost.</li>



<li>Long polling is replaced.</li>



<li>AJAX calls can only send string data types because WebSockets are data typed.</li>
</ul>



<p><strong>Disadvantages of WebSocket</strong></p>



<ul class="wp-block-list">
<li>There are still several proxies and transparent proxies not supporting WebSockets.</li>



<li>A WebSocket server requires different optimizations than traditional Web servers, so that a dedicated platform might be required.</li>
</ul>
<p>The post <a href="https://blog.tomosia.com.vn/short-polling-vs-long-polling-websocket/">Short polling vs Long polling Websocket</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.tomosia.com.vn/short-polling-vs-long-polling-websocket/feed/</wfw:commentRss>
			<slash:comments>7</slash:comments>
		
		
			</item>
	</channel>
</rss>
