Custom Starter — tự viết starter nội bộ và quản lý supply chain
Starter không chỉ là thứ Pivotal viết. Bài này hướng dẫn tự xây custom starter cho team: cấu trúc 2-module (autoconfigure + starter), file AutoConfiguration.imports, naming convention; sau đó bóc supply chain security: CVE scan, SBOM, và chiến lược upgrade để không bị Log4Shell lần 2.
TL;DR: Custom starter gồm 2 module riêng biệt: *-spring-boot-autoconfigure (chứa @AutoConfiguration class + @ConfigurationProperties) và *-spring-boot-starter (jar rỗng, chỉ pull autoconfigure + runtime lib). Boot load autoconfig nhờ file META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports trong mỗi jar classpath. Naming convention: starter chính chủ Pivotal dùng spring-boot-starter-X, third-party và nội bộ dùng X-spring-boot-starter (đảo namespace). Supply chain: mỗi starter kéo 30-100 transitive jar; CVE scan với OWASP Dependency-Check (CVSS vượt 7 → build fail), SBOM qua /actuator/sbom (Boot 3.3+), upgrade theo timeline hỗ trợ để không dẫm vào Log4Shell kiểu khác.
Bài 02 — Starter Dependencies đã bóc spring-boot-starter-web và giới thiệu cấu trúc custom starter ở mức outline. Bài này đào sâu vào cơ chế load autoconfig, lý do tách 2 module, và toàn bộ vòng đời supply chain từ viết đến vận hành production.
1. Vì sao tách autoconfigure và starter thành 2 module
Câu hỏi đầu tiên người mới thường đặt ra: tại sao không viết một module duy nhất chứa cả autoconfig code lẫn dependency declaration? Pivotal tách 2 module vì 2 use case khác nhau:
| Module | Nội dung | Người dùng |
|---|---|---|
*-spring-boot-autoconfigure | @AutoConfiguration, @ConfigurationProperties, condition logic | Library developer, hoặc service cần autoconfigure mà không pull starter |
*-spring-boot-starter | Jar rỗng class; chỉ pom.xml pull autoconfigure + runtime lib | Application developer — 1 dependency duy nhất |
Tách rời cho phép lib author control dependency graph một cách tinh tế. Ví dụ cụ thể: một service muốn dùng autoconfig của acme-tracing nhưng đã có acme-tracing-core qua đường khác — có thể khai báo chỉ acme-tracing-spring-boot-autoconfigure, không pull cả starter và tránh duplicate dependency. Nếu gộp 1 module, không có cách nào tách.
Lý do thứ hai: optional dependency. autoconfigure module khai báo acme-tracing-core dạng optional=true (không transitive), vì autoconfig chỉ activate khi class đó có trên classpath — @ConditionalOnClass. Nếu gộp starter, optional dependency sẽ không pull runtime lib cho user. Starter giải quyết bằng cách kéo cả hai dependency một lần.
flowchart TB S["acme-tracing-spring-boot-starter<br/>(jar rong, pom.xml)"] AC["acme-tracing-spring-boot-autoconfigure<br/>(AutoConfiguration class + Properties)"] Core["acme-tracing-core<br/>(runtime lib)"] App["Application pom.xml<br/>chi khai bao starter"] App -->|"1 dependency duy nhat"| S S -->|"compile"| AC S -->|"compile"| Core AC -->|"optional=true<br/>(khong transitive)"| Core
Quan hệ optional=true trên autoconfigure → core: khi ai đó khai báo chỉ autoconfigure mà không có core → @ConditionalOnClass(Tracer.class) false → autoconfig bỏ qua. Không crash, không bean thừa.
2. Cơ chế load — AutoConfiguration.imports
Trước khi viết code, cần hiểu Spring Boot phát hiện autoconfig từ đâu. Đây là cơ chế nền Boot 2.7+ (thay thế spring.factories):
Khi SpringApplication.run() chạy, AutoConfigurationImportSelector quét toàn bộ jar trên classpath tìm file:
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
File này là danh sách plain text, mỗi dòng 1 fully-qualified class name:
com.acme.tracing.TracingAutoConfiguration
Boot gom tất cả class từ mọi jar, áp @ConditionalOn* filter, rồi register class còn sót. Toàn bộ cơ chế này được đào sâu ở bài @EnableAutoConfiguration. Ở đây cần nhớ: không có file này → autoconfig không bao giờ chạy, dù class có @AutoConfiguration đầy đủ.
Lỗi phổ biến nhất khi viết custom starter: class TracingAutoConfiguration có đủ annotation nhưng service dùng starter không thấy bean nào. Kiểm tra ngay file META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports có tồn tại trong jar built không, và class name có đúng chính tả không. Chạy /actuator/conditions (xem bài 04) để xác nhận autoconfig có được load không.
3. Viết custom starter từng bước
Ví dụ: team enterprise cần mọi service Spring Boot auto-configure distributed tracing endpoint giống nhau, với property acme.tracing.* chuẩn hoá.
3.1 Cấu trúc thư mục
acme-tracing-spring-boot-starter/
├── pom.xml (jar rong, chi pull dependency)
└── src/ (khong co Java code)
acme-tracing-spring-boot-autoconfigure/
├── pom.xml
└── src/main/
├── java/com/acme/tracing/
│ ├── TracingAutoConfiguration.java
│ └── TracingProperties.java
└── resources/
└── META-INF/
└── spring/
└── org.springframework.boot.autoconfigure.AutoConfiguration.imports
3.2 Module autoconfigure — pom.xml
<project>
<artifactId>acme-tracing-spring-boot-autoconfigure</artifactId>
<dependencies>
<!-- Spring Boot autoconfigure: @AutoConfiguration, @ConditionalOn*, @ConfigurationProperties -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<!-- optional=true: khong transitive sang consumer -->
<!-- @ConditionalOnClass(Tracer.class) check runtime co class nay khong -->
<dependency>
<groupId>com.acme</groupId>
<artifactId>acme-tracing-core</artifactId>
<version>1.0.0</version>
<optional>true</optional>
</dependency>
<!-- Annotation processor de generate spring-configuration-metadata.json -->
<!-- -> IDE autocomplete cho acme.tracing.* property -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
3.3 TracingProperties — bind config
@ConfigurationProperties (được bóc ở bài 04 — Externalized Configuration) cho phép bind prefix acme.tracing vào POJO, với validation và relax binding (env var ACME_TRACING_ENDPOINT tự map):
@ConfigurationProperties(prefix = "acme.tracing")
@Validated
public class TracingProperties {
private boolean enabled = true;
/** Endpoint nhan span. Default: internal endpoint. */
@NotBlank
private String endpoint = "https://tracing.acme.internal";
/** Ten service xuat hien tren dashboard tracing. Bat buoc set. */
@NotBlank
private String serviceName;
// getters / setters
}
3.4 TracingAutoConfiguration — logic conditional
@AutoConfiguration
@ConditionalOnClass(Tracer.class) // chi chay khi acme-tracing-core co tren classpath
@EnableConfigurationProperties(TracingProperties.class)
@ConditionalOnProperty(
name = "acme.tracing.enabled",
havingValue = "true",
matchIfMissing = true // default on, opt-out qua property
)
public class TracingAutoConfiguration {
@Bean
@ConditionalOnMissingBean // user co the override bang bean rieng
public Tracer tracer(TracingProperties props) {
return Tracer.builder()
.endpoint(props.getEndpoint())
.serviceName(props.getServiceName())
.build();
}
}
Ba annotation quan trọng giải thích cơ chế:
@ConditionalOnClass: Boot dùng ASM bytecode reader (khôngClass.forName) để check class tồn tại — nếuacme-tracing-corekhông có trên classpath, condition false, toàn bộ autoconfig bỏ qua mà không crash.@ConditionalOnMissingBean: đây là "cơ chế nhường chỗ" — nếu service tự define beanTracer, Boot không tạo bean mặc định. Người dùng luôn thắng.@ConditionalOnPropertyvớimatchIfMissing = true: mặc định bật, opt-out bằngacme.tracing.enabled=false. Pattern an toàn hơnmatchIfMissing = false(mặc định tắt) cho lib infrastructure.
3.5 File AutoConfiguration.imports
# src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.acme.tracing.TracingAutoConfiguration
Một dòng, một class. Nếu có nhiều autoconfig, mỗi class 1 dòng. Comment bằng #.
3.6 Module starter — pom.xml rỗng class
<project>
<artifactId>acme-tracing-spring-boot-starter</artifactId>
<dependencies>
<!-- autoconfigure module chua logic -->
<dependency>
<groupId>com.acme</groupId>
<artifactId>acme-tracing-spring-boot-autoconfigure</artifactId>
<version>1.0.0</version>
</dependency>
<!-- runtime lib: starter pull explicit de consumer khong phai khai bao rieng -->
<dependency>
<groupId>com.acme</groupId>
<artifactId>acme-tracing-core</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</project>
Không có Java source, không có src/main/java. Jar built chỉ chứa META-INF/maven/*/pom.xml và pom.properties.
3.7 Cách service dùng
<!-- Service chỉ cần 1 dependency -->
<dependency>
<groupId>com.acme</groupId>
<artifactId>acme-tracing-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
# application.yml
acme:
tracing:
service-name: order-service # bat buoc
# endpoint: default tu TracingProperties
# enabled: true (default)
Boot startup: scan classpath → tìm AutoConfiguration.imports trong acme-tracing-spring-boot-autoconfigure.jar → load TracingAutoConfiguration → @ConditionalOnClass(Tracer.class) pass (starter đã pull core) → @ConditionalOnMissingBean pass (service chưa define bean) → Tracer bean được tạo với config từ application.yml.
4. Naming convention — tại sao đảo namespace
Spring Boot Reference đặt quy tắc rõ ràng:
| Loại starter | Convention | Ví dụ |
|---|---|---|
| Official (Pivotal/Spring) | spring-boot-starter-X | spring-boot-starter-web, spring-boot-starter-data-jpa |
| Third-party / nội bộ | X-spring-boot-starter | acme-tracing-spring-boot-starter, springdoc-openapi-starter-webmvc-ui |
Lý do đảo namespace: nếu third-party dùng prefix spring-boot-starter-acme-tracing, người dùng dễ nhầm đây là starter Pivotal maintain — nhầm kỳ vọng về support, security patch, compatibility. Bằng cách đặt tên riêng đứng trước (acme-), rõ ràng đây là starter bên ngoài hệ sinh thái chính thức.
Quy tắc tương tự áp với autoconfigure module: acme-tracing-spring-boot-autoconfigure (không phải spring-boot-autoconfigure-acme-tracing).
5. Supply chain security — vì sao quan tâm
Mỗi custom starter kéo acme-tracing-core + spring-boot-autoconfigure — vốn đã pull nhiều transitive jar. Mỗi jar là potential CVE. Tháng 12/2021, Log4Shell (CVE-2021-44228) — RCE critical trong Log4j2 — ảnh hưởng hầu như mọi app Java production. Spring Boot 2.6.2 patch trong 48 giờ, nhưng team nào không track dependency version đã mất nhiều ngày để tìm ra mình có bị ảnh hưởng không.
Supply chain attack không phải lý thuyết. Khi starter pull 50-100 transitive jar, bạn chịu trách nhiệm với mọi jar trong graph đó, không chỉ jar bạn khai báo trực tiếp.
5.1 CVE scan — OWASP Dependency-Check
OWASP Dependency-Check là tool phổ biến nhất cho Java Maven/Gradle. Nó tra cứu NVD (National Vulnerability Database) cho mọi transitive dependency:
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>10.0.4</version>
<configuration>
<!-- Build fail khi co CVE CVSS vuot 7.0 (High/Critical) -->
<failBuildOnCVSS>7</failBuildOnCVSS>
<!-- Suppress false-positive da xem xet + co ghi chu ly do -->
<suppressionFile>dependency-check-suppressions.xml</suppressionFile>
</configuration>
<executions>
<execution>
<goals><goal>check</goal></goals>
</execution>
</executions>
</plugin>
Chạy trong CI pipeline: mvn dependency-check:check. Build fail nếu transitive dependency có CVE CVSS cao hơn 7.0. File suppression lưu false-positive đã review có ghi chú ngày review và lý do — không suppress mù.
GitHub Dependabot cung cấp alert miễn phí cho repo public và private. Snyk có dashboard enterprise với license scan (không chỉ CVE).
5.2 SBOM — Software Bill of Materials
SBOM (Software Bill of Materials) là bản kê khai toàn bộ component của artifact: tên, version, license, dependency tree. Chuẩn phổ biến: CycloneDX và SPDX.
Spring Boot 3.3+ generate SBOM tự động qua Actuator:
# application.yml
management:
endpoints:
web:
exposure:
include: sbom
Endpoint /actuator/sbom trả JSON CycloneDX listing toàn bộ jar trong runtime classpath. Dùng cho:
- Audit compliance (SOC 2, ISO 27001): chứng minh bạn biết mình dùng gì.
- Incident response: khi CVE mới xuất hiện, tra SBOM ngay để biết service nào bị ảnh hưởng.
- License audit: phát hiện lib GPL trong product commercial.
Với Maven, có thể generate SBOM lúc build (không cần runtime):
mvn org.cyclonedx:cyclonedx-maven-plugin:makeAggregateBom
# Output: target/bom.xml (CycloneDX format)
5.3 Chiến lược upgrade — không để dẫm vào Log4Shell lần 2
flowchart LR Renovate["Renovate / Dependabot<br/>tao PR tu dong khi dependency moi"] CI["CI chay full test<br/>+ dependency-check"] Review["Human review<br/>check breaking change"] Deploy["Deploy theo schedule<br/>1 dependency / sprint"] Renovate --> CI --> Review --> Deploy
Nguyên tắc thực tế:
- Minor/patch bump (Boot 3.4.x → 3.4.y): patch CVE, ít risk. Auto-merge sau CI green với human spot-check.
- Major bump (Boot 3.x → 4.x): breaking change. Plan 2-3 sprint, đọc migration guide, test regression.
- 1 dependency / sprint: không batch nhiều dependency upgrade cùng lúc — rollback phức tạp khi có vấn đề.
- CVE emergency (CVSS vượt 9.0 như Log4Shell): upgrade ngay, không chờ sprint cycle. Có pipeline fast-track riêng.
Spring Boot release lifecycle cần nắm để plan upgrade:
| Version | OSS support kết thúc | Commercial support kết thúc |
|---|---|---|
| Boot 3.3 | 2025-05 | 2027-05 |
| Boot 3.4 | 2025-11 | 2027-11 |
| Boot 3.5 | 2026-05 | 2028-05 |
Khi OSS support kết thúc, security patch không được backport. Chạy version unsupported = chấp nhận rủi ro CVE không được vá.
5.4 Minimize attack surface — exclude transitive không dùng
Mỗi jar removed = giảm 1 CVE potential + giảm image size. Exclude có chủ đích:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<!-- Khong dung XML endpoint, giam attack surface -->
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</exclusion>
<exclusion>
<!-- Khong dung JSP/EL, Tomcat EL parser khong can -->
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
</exclusion>
</exclusions>
</dependency>
Khi viết custom starter, cũng áp quy tắc này trong autoconfigure module: khai báo chính xác dependency cần, không kéo thêm transitive thừa.
6. Cơ chế bên dưới — tại sao @ConditionalOnMissingBean là "nhường chỗ"
Đây là mấu chốt khiến custom starter không bao giờ override bean của application. Khi Boot xử lý TracingAutoConfiguration:
flowchart TB
A["Boot process TracingAutoConfiguration"]
B{"@ConditionalOnMissingBean(Tracer.class)<br/>Tracer bean da ton tai trong context?"}
C["User da define: @Bean Tracer customTracer()"]
D["Skip tao bean mac dinh<br/>User bean duoc giu nguyen"]
E["Tao Tracer bean mac dinh<br/>dung TracingProperties"]
A --> B
B -->|"CO (bean ton tai)"| C
C --> D
B -->|"CHUA"| ECơ chế này đảm bảo library không bao giờ cướp bean của application. Người dùng luôn có quyền override bằng cách define bean cùng type. Đây là thiết kế "convention over configuration" — default tốt sẵn, nhưng override dễ dàng không cần subclass hay extend.
Lý do Boot dùng cơ chế này thay vì @Primary: @Primary chỉ giải quyết ambiguity khi có nhiều bean, không ngăn bean thừa. @ConditionalOnMissingBean không tạo bean ngay từ đầu nếu không cần — sạch hơn, ít side effect hơn.
Liên hệ các bài khác
- Bài 02 — Starter Dependencies: nền tảng hiểu BOM, transitive dependency tree, và outline của custom starter. Bài này đào sâu hơn vào cơ chế load autoconfig và supply chain.
- Bài 04 — @EnableAutoConfiguration:
AutoConfiguration.importschỉ là file text — cơ chếAutoConfigurationImportSelectorđọc và filter nó (ASM bytecode,@ConditionalOn*evaluation) được bóc hoàn toàn ở bài đó. Custom starter bạn vừa viết chạy đúng cơ chế này. - Bài 04 — Externalized Configuration:
@ConfigurationPropertiestrongTracingPropertieslà type-safe binding — cách Boot map propertyacme.tracing.*vào POJO, validation, relax binding cho K8s env var. - Container Internals: bean
Tracerdo autoconfig tạo ra sống trongsingletonObjectsmap củaDefaultListableBeanFactory— hiểu container giúp debug "tại sao bean không tạo" sâu hơn chỉ nhìn autoconfig conditions.
Tóm tắt
- Custom starter tách 2 module (
*-autoconfigure+*-starter) để tách concern: autoconfigure chứa logic, starter chứa dependency declaration. Tách cho phép consumer chọn pull chỉ autoconfigure nếu cần. *-autoconfigurekhai báo runtime lib dạngoptional=true— không transitive;*-starterpull explicit cả 2 module để consumer có đủ.- File
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.importslà entry point Boot scan. Thiếu file này → autoconfig không chạy dù annotation đầy đủ. @ConditionalOnMissingBeanlà "cơ chế nhường chỗ": user define bean riêng → Boot không tạo default. User luôn thắng.- Naming convention: official dùng
spring-boot-starter-X; third-party và nội bộ dùngX-spring-boot-starterđể tránh nhầm nguồn gốc. - Supply chain: mỗi starter kéo 50-100 transitive jar. OWASP Dependency-Check scan CVE (build fail khi CVSS vượt 7), SBOM qua
/actuator/sbomcho audit, upgrade theo sprint cycle với fast-track cho CVE emergency.
Tự kiểm tra
Q1Tại sao custom starter tách thành 2 module riêng biệt (*-autoconfigure và *-starter) thay vì gộp 1? Lợi ích cụ thể là gì?▸
*-autoconfigure và *-starter) thay vì gộp 1? Lợi ích cụ thể là gì?Hai lý do cốt lõi:
1. Tách concern dependency graph: Module *-autoconfigure khai báo runtime lib dạng optional=true — không transitive sang consumer. Consumer có thể khai báo chỉ *-autoconfigure nếu đã có runtime lib qua đường khác, tránh duplicate. Module *-starter pull explicit cả hai để consumer "1 dependency duy nhất" có đủ mọi thứ.
2. Optional dependency phối hợp với @ConditionalOnClass: Autoconfig chỉ activate khi runtime lib có trên classpath. Nếu gộp 1 module, không thể vừa khai báo optional vừa kéo lib cho user. Starter giải quyết: autoconfigure dùng optional, starter pull explicit.
Cả Spring Boot official starter đều theo pattern này: spring-boot-autoconfigure là module riêng, mỗi spring-boot-starter-X chỉ là pom rỗng pull nó cùng runtime dependency.
Q2File META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports có vai trò gì? Điều gì xảy ra nếu thiếu file này khi viết custom starter?▸
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports có vai trò gì? Điều gì xảy ra nếu thiếu file này khi viết custom starter?File này là entry point để Boot phát hiện autoconfig class. Khi SpringApplication.run() chạy, AutoConfigurationImportSelector quét toàn bộ jar trên classpath tìm file đường dẫn trên, gom tất cả class name từ mọi jar, rồi áp @ConditionalOn* filter.
Nếu thiếu file: dù TracingAutoConfiguration có @AutoConfiguration đầy đủ, Boot không bao giờ biết class đó tồn tại. Kết quả: không có bean nào từ autoconfig được tạo, không có error, không có warning rõ ràng — âm thầm không hoạt động. Đây là lỗi phổ biến nhất khi viết custom starter.
Cách debug: gọi /actuator/conditions → section "exclusions" hoặc "unconditional" để xem class có được load không. Hoặc chạy với --debug flag để Boot in ra toàn bộ autoconfig evaluation.
Q3@ConditionalOnMissingBean trên bean trong autoconfig có ý nghĩa gì? Nó khác @Primary ra sao?▸
@ConditionalOnMissingBean trên bean trong autoconfig có ý nghĩa gì? Nó khác @Primary ra sao?@ConditionalOnMissingBean: Boot không tạo bean nếu bean cùng type đã tồn tại trong context. Cơ chế "nhường chỗ" — nếu user define @Bean Tracer customTracer(), autoconfig detect thấy Tracer bean đã có → skip tạo default. Bean user không bao giờ bị autoconfig ghi đè.
@Primary: giải quyết ambiguity khi có nhiều bean cùng type — đánh dấu "đây là bean ưu tiên inject". Cả 2 bean vẫn được tạo. Nếu autoconfig dùng @Primary thay @ConditionalOnMissingBean, cả bean mặc định lẫn bean user sẽ tồn tại trong context — bean mặc định thừa, chiếm resource, có thể gây bug nếu ai inject theo tên.
Kết luận: @ConditionalOnMissingBean sạch hơn — không tạo bean ngay từ đầu nếu không cần, không side effect. @Primary không thích hợp cho pattern "user có thể override default".
Q4Naming convention của custom starter là gì? Vì sao third-party không nên đặt tên theo format spring-boot-starter-X?▸
spring-boot-starter-X?Convention:
- Official (Pivotal/Spring):
spring-boot-starter-X— ví dụspring-boot-starter-web,spring-boot-starter-data-jpa. - Third-party và nội bộ:
X-spring-boot-starter— ví dụacme-tracing-spring-boot-starter,springdoc-openapi-starter-webmvc-ui.
Lý do đảo namespace: nếu third-party dùng prefix spring-boot-starter-, người dùng dễ nhầm starter đó do Pivotal maintain — nhầm kỳ vọng về security patch timeline, compatibility guarantee, support policy. Khi Log4Shell xảy ra, Boot official patch trong 48 giờ; starter third-party có thể mất 1-2 tuần hoặc không patch. Nếu nhầm nguồn gốc, user không biết mình cần chủ động theo dõi.
Đảo namespace còn tránh conflict tên nếu Pivotal sau này release starter cùng tên chính thức.
Q5Team bạn discover transitive dependency trong starter có CVE CVSS 8.5 (High). Describe quy trình xử lý từ discovery đến resolution, bao gồm tool và decision points.▸
Quy trình 4 bước:
1. Confirm và scope: Chạy mvn dependency:tree | grep <artifact-id> xác nhận dependency nào pull nó. Tra SBOM (/actuator/sbom hoặc target/bom.xml) để biết service nào bị ảnh hưởng trong toàn bộ fleet. CVSS 8.5 = High → ưu tiên cao, xử lý trong 1-2 ngày làm việc.
2. Evaluate options:
- Upgrade Boot version nếu BOM mới đã có version vá (cách tốt nhất, Pivotal đã test compat).
- Override version dependency qua
<properties>(ví dụ<lib.version>fixed-version</lib.version>) nếu Boot chưa upgrade. - Exclude dependency nếu không thật sự dùng code path bị ảnh hưởng (cần verify kỹ).
3. Implement + test: Tạo branch, apply fix, CI chạy full test suite + dependency-check:check confirm CVE không còn. Không merge nếu test đỏ.
4. Document suppression (nếu false-positive): Nếu CVE không applicable (vd code path không dùng), add vào dependency-check-suppressions.xml với ghi chú ngày review, lý do, người quyết định, ngày re-evaluate. Không suppress mù.
Decision point CVSS vượt 9.0 (Critical như Log4Shell): bỏ sprint cycle, activate fast-track pipeline, patch và deploy trong vài giờ.
Bài tiếp theo: @EnableAutoConfiguration & AutoConfiguration.imports
Bài này có giúp bạn hiểu bản chất không?
Hỏi đáp về bài này
Chưa có câu hỏi
Có gì chưa rõ trong bài? Đặt câu hỏi đầu tiên — câu trả lời từ cộng đồng giúp bạn (và người sau).
Đặt câu hỏi đầu tiên