Spring Boot

Spring Boot tạo Bean Instance bằng cách nào ?

🔹 1. Dựa trên Cơ chế Dependency Injection (DI)

Spring Boot dùng IoC Container để quản lý và tạo Bean.

🔹 2. Cách Spring Boot tạo Bean Instance:

✅ a. Annotation-Based (phổ biến nhất):

  • Spring Boot tự scan các class có annotation như:

    • @Component

    • @Service

    • @Repository

    • @Controller

→ Sau đó tự động khởi tạo Bean từ các class đó và đưa vào context.

@Component
public class MyService {
   // Bean sẽ được Spring quản lý
}

✅ b. Manual via @Bean trong @Configuration class:

  • Khi cần custom cách khởi tạo Bean (vd: khởi tạo bằng constructor phức tạp):

@Configuration
public class AppConfig {
    @Bean
    public MyService myService() {
        return new MyService("custom config");
    }
}

✅ c. Constructor Injection / Field Injection / Setter Injection:

  • Khi khởi tạo, Spring tự resolve dependency và inject vào constructor:

@Service
public class OrderService {
    private final ProductService productService;

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

🔹 3. Lifecycle khi tạo Bean:

  1. Scan class & detect annotation

  2. Instantiate (bằng constructor)

  3. Dependency Injection

  4. Gọi các lifecycle method (vd: @PostConstruct, InitializingBean, ...)

  5. Đưa vào ApplicationContext

🔹 4. Cơ chế mặc định trong Spring Boot

Spring Boot auto-configures thông qua:

  • @SpringBootApplication → kết hợp @ComponentScan, @EnableAutoConfiguration

  • Các starter giúp tự động tạo và cấu hình Bean mà không cần cấu hình tay.

Tóm lại:

Spring Boot tạo Bean instance chủ yếu qua annotation + IoC container, tự động inject dependencies và quản lý lifecycle đầy đủ. Điều này giúp giảm cấu hình, tăng khả năng mở rộng và maintain.


Có những cách nào để Inject Dependency ? Cách nào được khuyến khích nhất ?

Có những cách nào để Inject Dependency trong Spring?

3 cách chính:

🔹 1. Constructor Injection[Khuyến khích nhất]

@Service
public class UserService {
    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}

Ưu điểm:

  • Immutable dependency

  • Dễ viết Unit Test (dễ mock)

  • Dễ phát hiện thiếu dependency (Compile-time error)

  • Chuẩn Clean Code + được Spring khuyến khích

🔹 2. Setter Injection

@Service
public class UserService {
    private UserRepository userRepository;

    @Autowired
    public void setUserRepository(UserRepository repo) {
        this.userRepository = repo;
    }
}

Ưu điểm:

  • Linh hoạt, có thể thay đổi sau khi khởi tạo.

Nhược điểm:

  • Có thể gây ra trạng thái không nhất quán nếu setter không được gọi.

🔹 3. Field Injection[Không khuyến khích trong production]

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;
}

Nhược điểm:

  • Khó test (không inject mock được)

  • Không rõ ràng dependency

  • Không hỗ trợ cho final field

  • Vi phạm nguyên tắc SOLID (DIP)

Tổng kết:

Cách Inject
Ưu tiên sử dụng
Ghi chú

Constructor

✅ Rất khuyến khích

Tốt cho test & maintainability

Setter

⚠️ Dùng khi cần thiết

Khi dependency là optional

Field

❌ Tránh dùng

Khó test, khó maintain

Nếu trong project dùng Lombok, có thể dùng:

@RequiredArgsConstructor
@Service
public class UserService {
    private final UserRepository userRepository;
}

→ Vừa gọn, vừa chuẩn constructor injection.


Em hiểu @RestController và @Controller khác nhau thế nào ?

Dạ, em xin trả lời ngắn gọn, đúng trọng tâm như khi đi phỏng vấn:

Sự khác nhau giữa @RestController@Controller trong Spring Boot:

Thuộc tính

@Controller

@RestController

Dùng cho

Web MVC (Trả về HTML, JSP, Thymeleaf)

REST API (Trả về JSON/XML)

Trả về mặc định

View name (template page)

Object → JSON

Cần @ResponseBody

✅ Cần dùng nếu muốn trả về JSON

❌ Không cần – đã bao gồm sẵn

Kết hợp thực tế

@Controller + @ResponseBody = REST API

@RestController = gộp sẵn


🔹 Ví dụ:

1. @Controller:

@Controller
public class PageController {
    @GetMapping("/home")
    public String home() {
        return "home"; // trả về file home.html
    }
}

2. @RestController:

@RestController
public class ApiController {
    @GetMapping("/users")
    public List<User> getUsers() {
        return userService.findAll(); // tự động trả về JSON
    }
}

Tóm lại:

  • @RestController được dùng cho RESTful API → trả JSON/XML.

  • @Controller dùng cho ứng dụng có giao diện web, cần trả về HTML template.

Nếu dùng API thì nên chọn @RestController để viết ngắn gọn, rõ ràng hơn ạ.


Em đã sử dụng AOP làm gì trong dự án ? Có ví dụ cụ thể không ?

Dạ, em xin trả lời câu này ngắn gọn và cụ thể như sau:


Em đã sử dụng AOP (Aspect-Oriented Programming) để làm gì trong dự án?

Trong dự án thực tế, em sử dụng AOP chủ yếu cho các tác vụ cross-cutting concerns – tức là những logic dùng chung, lặp lại ở nhiều nơi, ví dụ:

🔹 1. Ghi log toàn bộ request/response

  • Log method name, parameters, response, execution time, v.v.

@Aspect
@Component
public class LoggingAspect {

    @Around("execution(* com.myapp.service..*(..))")
    public Object logExecution(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();

        Object result = joinPoint.proceed(); // Gọi phương thức gốc

        long duration = System.currentTimeMillis() - start;
        System.out.println("Method: " + joinPoint.getSignature() +
                           " executed in " + duration + "ms");
        return result;
    }
}

🔹 2. Kiểm tra phân quyền (authorization) trước khi xử lý logic

  • Tạo custom annotation @RequireRole("ADMIN"), rồi dùng AOP để chặn và kiểm tra quyền người dùng.

🔹 3. Validate hoặc xử lý exception toàn cục

🔸 Lợi ích khi dùng AOP:

  • Giúp code sạch, tách biệt rõ business logic và kỹ thuật.

  • Dễ maintain, dễ mở rộng.


Làm sao xử lý exception trong Spring MVC ?

Dạ, em xin trình bày ngắn gọn, đúng trọng tâm phỏng vấn:

Cách xử lý Exception trong Spring MVC

Spring cung cấp nhiều cách để handle exception một cách tập trung, rõ ràng:

🔹 1. Dùng @ControllerAdvice + @ExceptionHandler (Khuyến khích)

Tạo 1 class riêng để xử lý toàn bộ exception cho ứng dụng.

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<String> handleNotFound(ResourceNotFoundException ex) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage());
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<String> handleGeneric(Exception ex) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Lỗi hệ thống");
    }
}

🔹 2. Xử lý tại từng controller (ít dùng)

@GetMapping("/user/{id}")
public ResponseEntity<?> getUser(@PathVariable Long id) {
    try {
        return ResponseEntity.ok(userService.findById(id));
    } catch (ResourceNotFoundException ex) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage());
    }
}

🔹 3. Custom ErrorController (trường hợp nâng cao)

Dùng khi muốn override toàn bộ xử lý lỗi mặc định của Spring Boot.

Tóm lại:

Em ưu tiên dùng @ControllerAdvice để tách riêng logic xử lý lỗi, giúp mã sạch, dễ maintain và nhất quán.


Khi một request đi vào hệ thống Spring Boot, nó sẽ đi qua những bước nào ?

Dạ, đây là câu em rất hay gặp khi phỏng vấn Spring Boot, nên em xin trình bày theo flow rõ ràng, ngắn gọn:

Flow xử lý một HTTP Request trong hệ thống Spring Boot

🧭 1. Client gửi request → đi vào Servlet Container (Tomcat, Jetty...)

🧭 2. Servlet Container gọi DispatcherServlet (trung tâm điều phối)

  • Là bean do Spring Boot tự cấu hình, đứng giữa controller và client.

🧭 3. DispatcherServlet xử lý lần lượt qua các bước sau:

Bước
Thành phần
Mô tả

1️⃣

HandlerMapping

Tìm ra method tương ứng với URL (vd: /api/users)

2️⃣

HandlerAdapter

Chuẩn hóa handler (Controller method) để có thể gọi được

3️⃣

Interceptor (nếu có)

Thực hiện các logic như logging, auth check trước khi controller chạy

4️⃣

Controller method

Xử lý chính → gọi Service, Repository…

5️⃣

@ResponseBody / ViewResolver

Trả JSON hoặc render HTML (tùy theo kiểu controller)

6️⃣

ExceptionResolver

Nếu có lỗi, Spring gọi xử lý tại @ControllerAdvice

🧭 4. Response trả về client

📌 Tóm tắt ngắn:

Request → DispatcherServlet → HandlerMapping → Controller → Service → Response → Client


Em có thể giải thích ngắn gọn sự khác nhau giữa Spring và Spring Boot không ?

Dạ, em xin trình bày ngắn gọn, đúng tinh thần phỏng vấn:

Spring vs Spring Boot – Sự khác nhau chính

Tiêu chí

Spring Framework

Spring Boot

Cấu hình

Phải cấu hình thủ công (XML, Java Config)

Auto Configuration – cấu hình sẵn

Web Server

Không tích hợp sẵn

Tích hợp sẵn (Tomcat, Jetty…) – chỉ cần chạy là chạy

Phụ thuộc (Dependencies)

Tự khai báo và quản lý

Dùng Starter – đơn giản, gọn gàng

Mục tiêu chính

Nền tảng phát triển ứng dụng Java EE

Giúp phát triển microservices nhanh hơn

File cấu hình

Không bắt buộc application.properties

Dùng application.properties hoặc application.yml

🔍 Tóm gọn:

Spring Boot = Spring + Auto Configuration + Embedded Server + Opinionated Defaults ➡️ Giúp phát triển ứng dụng nhanh, ít cấu hình, dễ triển khai.


Spring Boot kết nối với DB khi nào ? Quá trình đó diễn ra như thế nào ?

Dạ, em xin trình bày theo hướng phỏng vấn – ngắn gọn, kỹ thuật rõ ràng:

Spring Boot kết nối với Database khi nào?

Spring Boot kết nối với database trong quá trình khởi động ứng dụng, cụ thể là khi ApplicationContext được khởi tạoBean liên quan đến DataSource được cấu hình.

🔁 Quy trình kết nối DB trong Spring Boot

1️⃣ Đọc cấu hình từ application.properties hoặc application.yml

spring.datasource.url=jdbc:mysql://localhost:3306/db
spring.datasource.username=root
spring.datasource.password=1234

2️⃣ Tự động cấu hình (AutoConfiguration)

  • Spring Boot dùng DataSourceAutoConfiguration để tạo DataSource bean.

  • Dựa vào dependency (VD: HikariCP, H2, MySQL driver…), Spring chọn DataSource phù hợp.

3️⃣ Tạo các Bean:

  • DataSource

  • EntityManagerFactory (nếu dùng JPA)

  • TransactionManager

4️⃣ Kết nối được thiết lập khi các bean trên được khởi tạo

  • Nếu dùng JPA, Spring sẽ kiểm tra schema, mapping entity, thực hiện ddl-auto, v.v.

🧪 Khi nào xảy ra lỗi DB?

  • Nếu thông tin kết nối sai, driver thiếu, DB không khởi động, lỗi xảy ra ngay khi ứng dụng khởi động, trước khi controller nào chạy.

📌 Ghi nhớ:

Spring Boot tự động kết nối DB trong giai đoạn Bean Initialization, thông qua auto-configuration dựa trên properties đã khai báo.


Spring Security dùng cách nào để chặn user truy cập tài nguyên không hợp lệ ?

Dạ, em xin trình bày ngắn gọn, rõ ràng theo kiểu đi phỏng vấn:

Spring Security chặn user truy cập tài nguyên không hợp lệ bằng cách nào?

🔒 1. Filter Chain – lớp đầu tiên kiểm soát request

  • Spring Security tạo một chuỗi filter (Security Filter Chain) xử lý mọi request trước khi đến controller.

  • Quan trọng nhất là UsernamePasswordAuthenticationFilterAuthorizationFilter.

🔐 2. Authentication (Xác thực)

  • Kiểm tra xem user đã đăng nhập chưa.

  • Nếu chưa → Spring Security trả về 401 Unauthorized.

🔐 3. Authorization (Phân quyền)

  • Kiểm tra xem user có đủ quyền truy cập tài nguyên hay không (dựa vào role, authority).

Ví dụ:

@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<?> getAdminData() { ... }
  • Nếu không có quyền → Spring trả về 403 Forbidden.

🧠 Cách cấu hình phân quyền phổ biến:

http
  .authorizeHttpRequests(auth -> auth
      .requestMatchers("/admin/**").hasRole("ADMIN")
      .anyRequest().authenticated()
  );

🎯 Tóm lại:

Spring Security dùng Filter + Authentication + Authorization để ngăn user trái phép truy cập tài nguyên, và phản hồi lại với 401 hoặc 403 tùy trường hợp.


Bean lifecycle trong Spring diễn ra như thế nào ?

Dạ, em xin trình bày rõ ràng – đúng chất phỏng vấn kỹ thuật:

Bean Lifecycle trong Spring diễn ra như thế nào?

Spring quản lý vòng đời của bean theo các bước sau:

🔁 1. Instantiation – Khởi tạo đối tượng

  • Spring tạo instance của bean thông qua constructor hoặc reflection.

🔁 2. Populate Properties – Gán giá trị cho các thuộc tính

  • Gán các dependency vào bean thông qua setter, constructor hoặc field injection.

🔁 3. Set Bean Name, Bean Factory (tùy chọn)

  • Nếu bean implement:

    • BeanNameAware → Spring gọi setBeanName(...)

    • BeanFactoryAware → Spring gọi setBeanFactory(...)

🔁 4. Pre-Initialization (Before Init)

  • Gọi các bean BeanPostProcessor (postProcessBeforeInitialization)

🔁 5. Initialize Bean

  • Nếu bean có:

    • @PostConstruct → gọi method đó

    • Hoặc implement InitializingBean → gọi afterPropertiesSet()

    • Hoặc khai báo init-method trong XML

🔁 6. Post-Initialization

  • Gọi tiếp postProcessAfterInitialization trong BeanPostProcessor

🔁 7. Ready to use – Bean sẵn sàng hoạt động

🔁 8. Destroy – Khi context shutdown

  • Nếu bean:

    • @PreDestroy → được gọi

    • Hoặc implement DisposableBean → gọi destroy()

    • Hoặc có destroy-method trong cấu hình XML

📝 Tóm tắt bằng sơ đồ đơn giản:

create -> inject -> aware -> pre-init -> init -> post-init -> use -> destroy

@Transactional hoạt động thế nào ? Rollback khi nào ?

Dạ, em xin trình bày ngắn gọn – đúng tinh thần phỏng vấn thực chiến:

@Transactional hoạt động như thế nào?

  • Khi một method được đánh dấu bằng @Transactional, Spring sẽ:

    • Tạo proxy (AOP) cho class đó.

    • Bắt đầu transaction trước khi method thực thi.

    • Commit hoặc rollback sau khi method kết thúc.

➡️ Tất cả quá trình này được quản lý bởi Transaction Manager (ví dụ: JpaTransactionManager nếu dùng JPA).

🔄 Quy trình:

  1. Bắt đầu transaction trước khi method chạy

  2. Nếu method chạy thành côngcommit

  3. Nếu method ném ra exceptionrollback theo quy tắc bên dưới

❗ Khi nào rollback?

Loại Exception
Mặc định rollback?
Ghi chú

RuntimeException

✅ Có rollback

Bao gồm NullPointerException, IllegalArgumentException...

CheckedException

❌ Không rollback

VD: IOException, SQLException → phải chỉ rõ bằng rollbackFor

➡️ Nếu muốn rollback checked exception:

@Transactional(rollbackFor = IOException.class)
public void updateFile() throws IOException {
   // ...
}

📌 Ví dụ thực tế trong dự án:

@Transactional
public void registerUser(User user) {
    userRepository.save(user); // step 1
    sendWelcomeEmail(user);    // step 2 (nếu lỗi ở đây, step 1 rollback)
}

✅ Tổng kết:

  • @Transactional giúp đảm bảo toàn vẹn dữ liệu (ACID).

  • Rollback xảy ra khi:

    • RuntimeException

    • Hoặc CheckedException được cấu hình thêm


Cấu hình application.properties khác gì với application.yml ?

Dạ, em xin trả lời ngắn gọn – rõ ràng như khi đi phỏng vấn thực chiến:

Khác nhau giữa application.propertiesapplication.yml:

Tiêu chí

application.properties

application.yml (YAML)

Cấu trúc

Dạng key-value phẳng

Cấu trúc phân cấp, rõ ràng hơn

Đọc dễ

Đơn giản, quen thuộc

Dễ đọc với cấu hình lồng nhau

Hỗ trợ cấu trúc phức tạp

Khó biểu diễn danh sách, nested config

Biểu diễn list, object rất tốt

Cú pháp lỗi dễ phát hiện

Dễ debug hơn

Nhạy cảm với thụt dòng (indentation)

💡 Kết luận:

  • Nếu config đơn giản → properties tiện hơn.

  • Nếu config phức tạp, nhiều cấp → nên dùng YAML để dễ đọc, dễ bảo trì hơn.

Trong thực tế, em thường dùng application.yml vì nó trực quan hơn khi quản lý nhiều cấu hình.


Khi nào cần dùng @Component ?

Dạ, em xin trả lời ngắn gọn – rõ ràng theo phong cách phỏng vấn:

Khi nào cần dùng @Component trong Spring?

@Component được dùng khi mình muốn đánh dấu một class là một Spring Bean để Spring quản lý vòng đời và dependency injection của nó.

📌 Dùng @Component khi:

  1. Class không thuộc các vai trò đặc biệt như Controller, Service, Repository

    • Ví dụ: các helper, util, mapper, validator, task runner…

    @Component
    public class EmailValidator {
        public boolean isValid(String email) {
            return email.contains("@");
        }
    }
  2. Muốn để Spring tự động phát hiện (Component Scan)

    • Khi ứng dụng chạy, Spring sẽ scan các class có @Component và tạo bean.

  3. Cần inject vào nơi khác

    • VD: @Autowired EmailValidator ở service/controller.

💡 Ghi nhớ:

  • Nếu class có vai trò rõ ràng hơn → dùng annotation chuyên biệt hơn:

    • @Service, @Repository, @Controller → đều là dạng mở rộng của @Component.

Kết luận:

Dùng @Component khi muốn Spring quản lý 1 class không thuộc 3 tầng chính (Controller, Service, Repository), nhưng vẫn cần tạo bean để inject hoặc cấu hình.


Làm sao xử lí lỗi toàn cục trong Spring Boot ?

Dạ, em xin trình bày ngắn gọn và đúng trọng tâm phỏng vấn:

Cách xử lý lỗi toàn cục trong Spring Boot

Spring Boot hỗ trợ Global Exception Handling thông qua:

🔧 1. Dùng @ControllerAdvice + @ExceptionHandler

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<?> handleNotFound(ResourceNotFoundException ex) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND)
                             .body(new ErrorResponse("Not Found", ex.getMessage()));
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<?> handleGeneric(Exception ex) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                             .body(new ErrorResponse("Server Error", ex.getMessage()));
    }
}

✅ Ưu điểm:

  • Tách riêng logic xử lý lỗi.

  • Áp dụng toàn bộ ứng dụng (ControllerAdvice áp dụng cho tất cả controller).

⚙️ 2. Tuỳ chỉnh ErrorController (nâng cao)

Khi muốn can thiệp sâu hơn hoặc customize response cho 404, 500,...

📌 Thực tế em thường dùng @ControllerAdvice để:

  • Trả response JSON chuẩn cho FE.

  • Log lỗi.

  • Phân biệt lỗi domain/business và lỗi hệ thống.


Spring Boot auto-configuration hoạt động như thế nào ?

Dạ, em xin trình bày ngắn gọn, mạch lạc đúng tinh thần phỏng vấn Java Backend:

Spring Boot Auto-Configuration hoạt động như thế nào?

Auto-configuration là cơ chế giúp Spring Boot tự động cấu hình các bean dựa trên:

  • Các dependency có trong classpath

  • Các cấu hình trong application.properties / application.yml

  • Và một số điều kiện cụ thể khác

⚙️ Cơ chế hoạt động chi tiết:

  1. Annotation @SpringBootApplication

    • Nó bao gồm @EnableAutoConfiguration, kích hoạt auto-config.

  2. Spring Boot scan file spring.factories

    • File này nằm trong:

      META-INF/spring.factories
    • Liệt kê danh sách các class cấu hình sẵn (được đánh dấu @Configuration)

      Ví dụ:

      org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
      org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
      org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
  3. Điều kiện cấu hình (@ConditionalOnXxx)

    • Mỗi auto-configuration class chỉ được kích hoạt nếu thỏa mãn điều kiện.

    • Ví dụ:

      @ConditionalOnClass(DataSource.class)
      @ConditionalOnProperty(name = "spring.datasource.url")
      public class DataSourceAutoConfiguration {
          // cấu hình datasource nếu có JDBC và cấu hình URL
      }

📌 Ví dụ thực tế:

  • Khi ta thêm spring-boot-starter-data-jpa, Spring Boot sẽ:

    • Phát hiện JPA trong classpath

    • Tự cấu hình EntityManagerFactory, TransactionManager, DataSource v.v.

Tóm lại:

Auto-configuration là một cơ chế "hợp lý theo mặc định" (convention over configuration) giúp giảm bớt cấu hình thủ công – chỉ cần khai báo dependency, Spring Boot sẽ lo phần còn lại.


Cách bạn validate dữ liệu đầu vào trong Controller ?

Dạ, em xin trình bày ngắn gọn như khi đi phỏng vấn thực tế:


Cách em validate dữ liệu đầu vào trong Controller (Spring Boot):

Em thường dùng Bean Validation (JSR 380) với các annotation như @NotNull, @Size, @Email, v.v… kết hợp với @Valid trong controller.

📌 1. Sử dụng annotation trong DTO:

public class UserRequest {
    @NotBlank
    private String username;

    @Email
    @NotBlank
    private String email;

    @Min(18)
    private int age;

    // getters/setters
}

📌 2. Dùng @Valid hoặc @Validated trong controller:

@RestController
@RequestMapping("/users")
public class UserController {

    @PostMapping
    public ResponseEntity<?> createUser(@RequestBody @Valid UserRequest request) {
        // nếu dữ liệu hợp lệ → xử lý
        return ResponseEntity.ok("User created");
    }
}

📌 3. Xử lý lỗi validate (toàn cục):

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<?> handleValidationError(MethodArgumentNotValidException ex) {
        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getFieldErrors().forEach(err -> {
            errors.put(err.getField(), err.getDefaultMessage());
        });
        return ResponseEntity.badRequest().body(errors);
    }
}

Tóm lại:

  • Dùng @Valid để kích hoạt validation

  • Đặt constraint ngay trong DTO

  • Dùng @ControllerAdvice để xử lý lỗi gọn gàng, tái sử dụng


Cách quản lý cấu hình đa môi trường (dev, staging, prod) ?

Dạ, câu này rất hay và thực tế trong dự án. Em xin trình bày gọn gàng – đúng tinh thần phỏng vấn Senior Java Developer:

Cách quản lý cấu hình đa môi trường trong Spring Boot

Spring Boot hỗ trợ cấu hình đa môi trường rất linh hoạt qua profile.

🛠️ 1. Sử dụng profile-specific config files

Tạo các file riêng biệt:

  • application-dev.yml

  • application-staging.yml

  • application-prod.yml

Ví dụ:

# application-dev.yml
server:
  port: 8081
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/devdb

🧠 2. Kích hoạt profile thông qua:

a. application.yml (default)

spring:
  profiles:
    active: dev

b. Command line (thường dùng trong CI/CD)

java -jar app.jar --spring.profiles.active=prod

c. Biến môi trường (khi deploy)

SPRING_PROFILES_ACTIVE=staging

🧪 3. Em sử dụng để:

  • Tách biệt cấu hình DB, logging, API key giữa môi trường dev, test, prod

  • Tránh hardcode cấu hình nhạy cảm

  • CI/CD triển khai từng môi trường bằng đúng cấu hình tương ứng

✅ Kết luận:

Em dùng Spring Profile để tách biệt cấu hình, tránh lỗi cấu hình giữa các môi trường, và dễ dàng quản lý khi deploy thực tế.


Last updated