1/54
Looks like no tags are added yet.
Name | Mastery | Learn | Test | Matching | Spaced | Call with Kai | Chat |
|---|
No analytics yet
Send a link to your students to track their progress
I.1 Spring Framework giải quyết những vấn đề gì trong ứng dụng Java?
Spring quản lý việc tạo và kết nối đối tượng (IoC/DI), giảm coupling giữa các thành phần, cung cấp hạ tầng cho transaction, AOP, truy cập dữ liệu, web MVC, bảo mật, cấu hình. Nhờ đó developer tập trung vào business logic thay vì code hạ tầng lặp lại (boilerplate).
I.2 IoC là gì?
Inversion of Control (đảo ngược điều khiển): thay vì đối tượng tự tạo và quản lý dependency của mình, quyền điều khiển đó được giao cho container (Spring). Container chịu trách nhiệm khởi tạo, cấu hình và cung cấp dependency cho đối tượng.
I.3 Dependency Injection là gì?
DI là một cách hiện thực IoC: container 'tiêm' (inject) các dependency mà một Bean cần vào Bean đó thông qua constructor, setter hoặc field, thay vì Bean tự đi tạo/tìm chúng.
I.4 IoC và Dependency Injection có hoàn toàn giống nhau không?
Không. IoC là nguyên lý tổng quát (đảo ngược quyền điều khiển), còn DI chỉ là một kỹ thuật cụ thể để hiện thực IoC. Ngoài DI, IoC còn có thể được hiện thực bằng Service Locator, callback, template method…
I.5 Spring Bean là gì?
Bean là đối tượng do Spring IoC container khởi tạo, lắp ghép (assemble) và quản lý vòng đời. Bean được định nghĩa qua metadata (annotation, Java config, XML).
I.6 Bean được Spring tạo và quản lý như thế nào?
Container đọc định nghĩa Bean (BeanDefinition), tạo instance, giải quyết và inject dependency, chạy các callback khởi tạo (@PostConstruct/InitializingBean/BeanPostProcessor), lưu vào context, và cuối cùng gọi callback hủy khi context đóng.
I.7 ApplicationContext là gì?
Là container trung tâm của Spring, đại diện cho IoC container nâng cao: quản lý Bean, hỗ trợ event, i18n, resource loading, tích hợp AOP và các tính năng doanh nghiệp khác.
I.8 ApplicationContext và BeanFactory khác nhau thế nào?
BeanFactory là container cơ bản, lazy-init Bean. ApplicationContext kế thừa BeanFactory nhưng thêm nhiều tính năng (event publishing, i18n, resource, tích hợp AOP…) và mặc định eager-init các singleton Bean khi khởi động.
I.9 Có những cách nào để khai báo một Bean?
Dùng stereotype annotation kèm component scanning (@Component/@Service/@Repository/@Controller), dùng @Bean trong lớp @Configuration, hoặc khai báo bằng XML (cách cũ).
I.10 @Component, @Service, @Repository và @Controller khác nhau thế nào?
Về kỹ thuật đều là @Component nên đều được scan thành Bean. Khác nhau ở ngữ nghĩa: @Service cho tầng business, @Repository cho tầng data (còn được dịch exception JPA/JDBC thành DataAccessException), @Controller cho web MVC.
I.11 @Bean và @Component khác nhau ra sao?
@Component đặt trên class để Spring tự scan và tạo Bean từ class đó. @Bean đặt trên method trong @Configuration, Bean được trả về từ method do developer tự khởi tạo — phù hợp khi tạo Bean từ class không sửa được hoặc cần logic khởi tạo tùy biến.
I.12 Khi nào nên dùng @Bean thay vì @Component?
Khi Bean là class của thư viện bên thứ ba không thể gắn annotation, hoặc khi cần logic khởi tạo phức tạp/điều kiện, hoặc muốn tạo nhiều Bean cùng kiểu với cấu hình khác nhau.
I.13 Component scanning hoạt động như thế nào?
Spring quét các package chỉ định để tìm class có stereotype annotation, tạo BeanDefinition cho mỗi class tìm thấy rồi đăng ký vào container.
I.14 @ComponentScan được sử dụng để làm gì?
Chỉ định (các) base package mà Spring sẽ quét để phát hiện Bean. @SpringBootApplication đã bao gồm @ComponentScan mặc định quét từ package của application class trở xuống.
I.15 Điều gì xảy ra nếu Bean nằm ngoài package được scan?
Bean đó sẽ không được phát hiện và không được tạo, dẫn đến lỗi NoSuchBeanDefinitionException khi cần inject. Phải mở rộng phạm vi scan hoặc khai báo Bean thủ công.
I.16 Constructor injection, setter injection và field injection khác nhau thế nào?
Constructor: inject qua constructor, đảm bảo dependency bắt buộc và bất biến. Setter: inject qua setter, phù hợp dependency tùy chọn/thay đổi được. Field: inject trực tiếp vào field bằng reflection, ngắn gọn nhưng khó test và ẩn dependency.
I.17 Vì sao constructor injection thường được ưu tiên?
Nó bảo đảm dependency bắt buộc không null, cho phép khai báo field là final (bất biến), giúp phát hiện circular dependency sớm, và dễ viết unit test vì không cần Spring để tạo đối tượng.
I.18 @Autowired hoạt động như thế nào?
Đánh dấu điểm cần inject; Spring tìm Bean phù hợp theo kiểu (by type), nếu nhiều Bean thì dùng @Qualifier/@Primary/tên để phân giải, rồi inject vào constructor/setter/field.
I.19 Constructor có một tham số có cần @Autowired không?
Không. Từ Spring 4.3, nếu một class chỉ có một constructor thì Spring tự động dùng nó để inject, không cần @Autowired.
I.20 Điều gì xảy ra khi Spring tìm thấy nhiều Bean cùng một interface?
Nếu không phân biệt được, Spring ném NoUniqueBeanDefinitionException. Cần dùng @Primary để chọn Bean ưu tiên, hoặc @Qualifier để chỉ định chính xác Bean cần inject.
I.21 @Qualifier và @Primary khác nhau như thế nào?
@Primary đánh dấu một Bean là mặc định khi có nhiều ứng viên. @Qualifier chỉ định cụ thể tên/định danh Bean muốn inject tại từng điểm. @Qualifier có độ ưu tiên cao hơn @Primary ở điểm inject đó.
I.22 Circular dependency là gì?
Khi Bean A cần Bean B và Bean B lại cần Bean A (trực tiếp hoặc gián tiếp), tạo thành vòng phụ thuộc mà container không thể khởi tạo theo thứ tự tuyến tính.
I.23 Vì sao constructor injection giúp phát hiện circular dependency sớm?
Vì với constructor injection, Spring phải có sẵn dependency ngay lúc tạo đối tượng; khi vòng phụ thuộc constructor không thể giải được, nó ném lỗi ngay khi khởi động thay vì để lỗi tiềm ẩn.
I.24 Bạn xử lý circular dependency như thế nào?
Tốt nhất là thiết kế lại: tách trách nhiệm, đưa logic chung ra một Bean thứ ba, hoặc dùng event/callback. Giải pháp kỹ thuật gồm chuyển sang setter/field injection hoặc @Lazy, nhưng chỉ nên coi là biện pháp tạm.
I.25 @Lazy có thể giải quyết circular dependency không? Có nên lạm dụng không?
Có thể: @Lazy khiến một Bean được inject qua proxy và chỉ khởi tạo khi dùng, giúp phá vòng. Nhưng không nên lạm dụng vì nó che giấu vấn đề thiết kế và làm lỗi chuyển từ lúc startup sang lúc runtime.
II.1 Các Bean scope phổ biến trong Spring là gì?
singleton (mặc định), prototype, và các web scope: request, session, application, websocket.
II.2 singleton trong Spring có giống Singleton Design Pattern không?
Không hoàn toàn. Singleton pattern là một instance duy nhất trong toàn JVM. Singleton của Spring là một instance duy nhất trong phạm vi một container (ApplicationContext); nhiều container có thể có nhiều instance.
II.3 prototype scope hoạt động thế nào?
Mỗi lần yêu cầu Bean (getBean hoặc inject), Spring tạo một instance mới. Spring không quản lý toàn bộ vòng đời prototype sau khi tạo — không tự gọi callback hủy.
II.4 request, session và application scope được dùng trong trường hợp nào?
request: một instance cho mỗi HTTP request. session: một instance cho mỗi HTTP session (dữ liệu theo phiên người dùng). application: một instance cho mỗi ServletContext. Dùng trong ứng dụng web cần trạng thái theo request/phiên.
II.5 Bean singleton có thread-safe không?
Không tự động thread-safe. Vì được chia sẻ cho mọi thread, nếu Bean có trạng thái mutable thì phải tự đảm bảo đồng bộ. Nên thiết kế singleton Bean stateless.
II.6 Có nên lưu dữ liệu của từng người dùng trong singleton Bean không?
Không. Singleton được chia sẻ giữa mọi request/thread nên lưu dữ liệu theo người dùng sẽ gây rò rỉ và trộn lẫn dữ liệu giữa các người dùng. Dùng scope request/session hoặc truyền dữ liệu qua tham số.
II.7 Vòng đời của Spring Bean gồm những bước chính nào?
Khởi tạo instance → inject dependency → các Aware callback → BeanPostProcessor before-init → @PostConstruct/afterPropertiesSet/init-method → BeanPostProcessor after-init (tạo proxy) → Bean sẵn sàng dùng → khi context đóng: @PreDestroy/destroy-method.
II.8 @PostConstruct được thực thi khi nào?
Sau khi Bean được khởi tạo và inject xong toàn bộ dependency, trước khi Bean được đưa vào sử dụng. Dùng để khởi tạo bổ sung.
II.9 @PreDestroy được thực thi khi nào?
Ngay trước khi Bean bị hủy, thường khi container/context đóng. Dùng để giải phóng tài nguyên (đóng connection, flush cache…).
II.10 InitializingBean và DisposableBean là gì?
Hai interface callback: InitializingBean.afterPropertiesSet() chạy sau khi set xong property (tương tự @PostConstruct); DisposableBean.destroy() chạy khi hủy Bean. Nhược điểm là gắn code vào API Spring nên thường ưu tiên @PostConstruct/@PreDestroy.
II.11 BeanPostProcessor dùng để làm gì?
Cho phép can thiệp vào mỗi Bean sau khi khởi tạo, trước và sau bước init — dùng để bọc proxy (AOP, transaction), sửa đổi hoặc kiểm tra Bean.
II.12 BeanFactoryPostProcessor khác BeanPostProcessor thế nào?
BeanFactoryPostProcessor chạy sớm hơn, tác động lên BeanDefinition (metadata) trước khi Bean được khởi tạo (ví dụ PropertySourcesPlaceholderConfigurer thay placeholder). BeanPostProcessor tác động lên instance Bean đã khởi tạo.
II.13 Spring tạo proxy cho Bean ở thời điểm nào?
Thường ở bước post-initialization của BeanPostProcessor (ví dụ AbstractAutoProxyCreator): sau khi Bean khởi tạo xong, Spring bọc proxy để áp AOP/transaction rồi trả proxy vào context.
II.14 Một Bean prototype có được Spring gọi @PreDestroy tự động không?
Không. Với prototype, Spring giao instance cho client rồi ngừng quản lý, nên không tự gọi callback hủy; client phải tự dọn dẹp.
II.15 Nếu inject Bean prototype vào Bean singleton thì chuyện gì xảy ra?
Bean prototype chỉ được tạo một lần lúc inject vào singleton nên thực tế bị 'đóng băng' như singleton. Muốn mỗi lần dùng lấy instance mới, dùng ObjectProvider, @Lookup method hoặc scoped proxy.
III.1 @Configuration có ý nghĩa gì?
Đánh dấu class là nguồn định nghĩa Bean bằng Java. Các method @Bean bên trong sẽ tạo Bean, và mặc định class được xử lý ở chế độ full (CGLIB proxy) để đảm bảo ngữ nghĩa singleton.
III.2 @Configuration và class thông thường chứa @Bean khác nhau thế nào?
Trong @Configuration (full mode), gọi method @Bean khác trả về cùng instance singleton nhờ proxy CGLIB. Class thường chứa @Bean (lite mode) thì mỗi lần gọi method sẽ tạo instance mới, không đảm bảo singleton giữa các Bean liên quan.
III.3 proxyBeanMethods dùng để làm gì?
Thuộc tính của @Configuration. proxyBeanMethods=true (mặc định) tạo CGLIB proxy để gọi liên method @Bean vẫn trả singleton. Đặt false (lite mode) bỏ proxy, tăng tốc khởi động khi các method @Bean không gọi lẫn nhau.
III.4 Làm thế nào để đọc giá trị từ application.properties hoặc application.yml?
Dùng @Value("${key}") cho từng giá trị, hoặc @ConfigurationProperties bind cả nhóm key vào một POJO, hoặc truy cập qua Environment.
III.5 @Value và @ConfigurationProperties khác nhau ra sao?
@Value inject từng giá trị riêng lẻ, hỗ trợ SpEL nhưng không type-safe và khó validate theo nhóm. @ConfigurationProperties bind cả cây cấu hình vào object type-safe, hỗ trợ validation, relaxed binding và metadata.
III.6 Khi nào nên dùng @ConfigurationProperties?
Khi có nhóm nhiều thuộc tính liên quan (cùng prefix), cần type-safe, validation, cấu trúc lồng nhau/list, hoặc tái sử dụng — thay vì rải nhiều @Value.
III.7 Làm thế nào để validate cấu hình ứng dụng?
Gắn @Validated lên lớp @ConfigurationProperties và dùng các annotation Bean Validation (@NotNull, @Min, @Email…) trên field; ứng dụng sẽ fail-fast khi cấu hình sai lúc khởi động.
III.8 Spring Profile là gì?
Cơ chế nhóm Bean/cấu hình theo môi trường (dev, test, prod). Chỉ Bean thuộc profile đang active mới được nạp, cho phép cấu hình khác nhau giữa các môi trường.
III.9 @Profile hoạt động như thế nào?
Đặt trên @Component/@Configuration/@Bean; Bean chỉ được đăng ký khi profile chỉ định đang active. Hỗ trợ biểu thức như !prod, dev & test.
III.10 Làm thế nào để kích hoạt profile dev, test hoặc production?
Đặt spring.profiles.active (trong properties, biến môi trường SPRING_PROFILES_ACTIVE, hoặc tham số dòng lệnh --spring.profiles.active=prod).
III.11 Có thể kích hoạt nhiều profile cùng lúc không?
Có. Liệt kê nhiều profile cách nhau bằng dấu phẩy, ví dụ spring.profiles.active=prod,metrics.
III.12 Profile group là gì?
Cho phép gộp nhiều profile dưới một tên logic (spring.profiles.group.production=prod,db,mq); kích hoạt 'production' sẽ tự bật tất cả profile con.
III.13 Làm thế nào để quản lý thông tin bí mật như mật khẩu database?
Không hardcode trong repo; dùng biến môi trường, secret manager (Vault, AWS Secrets Manager, K8s Secrets), hoặc file cấu hình ngoài không commit. Có thể mã hóa và giải mã lúc runtime.
III.14 Có nên lưu mật khẩu production trong application.yml không?
Không, đặc biệt nếu file được commit vào version control. Dùng biến môi trường hoặc secret manager và giữ file cấu hình sạch bí mật.
III.15 Thứ tự ưu tiên giữa biến môi trường, command-line argument và file cấu hình như thế nào?
Spring Boot có thứ tự ưu tiên: command-line argument cao hơn biến môi trường (OS env), và cả hai đều cao hơn application.properties/yml đóng gói. Nguồn ưu tiên cao ghi đè nguồn thấp hơn.