2025-12-23
Rippling with the waves for thousands of miles, where is the spring river without moonlight! --- “Spring River, Flower, Moon, Night” · Tang Dynasty · Zhang Ruoxu
Details
Full Text
The spring river tides rise to meet the sea, the sea and the bright moon rise with the tide.Rippling with the waves for thousands of miles, where is the spring river without moonlight!
The river winds around fragrant islets, moonlight on flower forests looks like falling frost.
In the empty air, flowing frost seems unseen, on the shoals, white sand cannot be discerned.
River and sky merge in one pure hue, a solitary bright moon hangs in the vast sky.
Who by the river first beheld the moon, in what year did the moon first shine upon mankind?
Life passes on generation after generation, yet the river moon looks the same year after year.
I wonder whom the river moon awaits, only seeing the long river sending flowing waters away.
A single cloud drifts leisurely, endless sorrow at Green Maple Islet.
Who tonight is the boatman adrift, where is the longing at the moonlit tower?
Pitifully the moon lingers over the tower, shining on the mirror stand of the departed.
Through jade doors and curtains it cannot be rolled away, from washing stones it brushes past again.
At this moment we gaze at each other but cannot hear, I wish to follow the moonlight and shine upon you.
Wild geese fly far, yet their light does not pass, fish and dragons leap, water forming patterns.
Last night I dreamed of falling flowers by a quiet pool, pitiful that spring is half gone and I have not returned home.
The river carries spring away, soon to be gone, the moon sinks westward over the river pool.
The slanting moon sinks deep into sea mist, endless roads toward Jieshi and Xiaoxiang.
Who knows how many return by moonlight, the setting moon stirs emotion across the river trees.
Docker Registry Study Notes
Basic Concepts of Docker Registry
Docker Registry is a server-side component used to store and distribute Docker images. The official implementation provided by Docker is registry:2 (Distribution).
Its core positioning is very clear:
It is only responsible for storing and serving images, not for complex management and governance.
Registry itself is a stateless service; the actual data is stored in the backend storage (local filesystem, object storage, etc.).
The Capability Boundaries of Docker Registry
Before learning and using Registry, you must first clarify what it can / cannot do.
What it can do
-
Private image repository storage
-
Support
push / pull / delete -
Support Basic Auth and TLS
-
Support single-upstream pull-through cache (proxy cache)
-
Support filesystem or object storage as backend
What it cannot do
-
Multiple upstream Registry aggregation
-
Fine-grained RBAC permission model
-
Graphical management interface
-
Image lifecycle management
-
Intelligent routing and policy control
In one sentence:
registry:2 is an “image HTTP storage service,” not an “image management platform.”
Two Typical Usage Modes of Registry
Hosted (Private Repository Mode)
-
Images are
docker push’ed by internal systems -
Registry only stores them
-
Address form:
registry.example.com:5000/project/app:1.0.0
Suitable for:
-
Internal development images
-
CI/CD build artifacts
-
Offline or semi-offline environments
Pull-Through Cache (Proxy Cache Mode)
Registry can be configured with an upstream (such as Docker Hub):
-
The image does not exist locally
-
Forward the request to the upstream and pull it
-
Cache it locally
-
Return it to the client
Main purposes:
-
Docker Hub acceleration
-
Networks with instability or rate limiting
How Pull-Through Cache Works
Request Path
docker pull nginx
↓
Docker daemon
↓
registry (proxy mode)
↓
Docker Hub
-
First pull: hits the upstream and caches
-
Subsequent pulls: hit the local cache directly
Proxy Configuration Example (Single Upstream)
version: 0.1
http:
addr: :5000
storage:
filesystem:
rootdirectory: /var/lib/registry
proxy:
remoteurl: https://registry-1.docker.io
Key points:
-
remoteurlcan only be configured with one -
The correct entry for Docker Hub is
registry-1.docker.io -
registry.docker.iois not the Registry V2 API entry
Why Registry Does Not Support Multiple remoteurl Values
This is a design-level limitation, not a configuration capability issue.
Reasons include:
-
Registry V2 token / scope is strongly bound to a single upstream
-
Image namespaces cannot be routed and determined
-
Authentication flows cannot be combined
Conclusion:
The proxy model of registry:2 is “single-upstream caching,” not “multi-source aggregation.”
The Relationship Between Docker Client and Registry
The Role of Registry Mirror
The Docker client can configure image mirrors:
{
"registry-mirrors": ["http://registry.example.com:5000"]
}
Behavior description:
-
Prefer pulling Docker Hub images through the mirror
-
If the mirror does not have it, fall back to pulling directly from Docker Hub
Notes:
-
mirror ≠ multi-registry routing
-
Only applies to the Docker Hub namespace
The Security Model of HTTP and HTTPS
HTTP Registry (Insecure)
Characteristics:
-
Easy to deploy
-
Only suitable for intranet environments
The client must declare it explicitly:
{
"insecure-registries": ["registry.example.com:5000"]
}
HTTPS Registry (Recommended)
Characteristics:
-
Secure by default
-
No need for insecure configuration
The client needs to trust the CA:
/etc/docker/certs.d/registry.example.com:5000/ca.crt
Registry Authentication Mechanisms
Basic Auth
-
Based on
htpasswd -
Registry does not maintain a user system
-
Suitable for small-scale usage
Token / OAuth
-
Not supported natively by Registry
-
Usually provided by reverse proxies or upper-layer platforms
Registry Data Storage Model
Stored Content
-
Layer blobs (disk usage)
-
Manifest / index (metadata)
Important Understanding
-
The same layer is stored only once (content-addressable)
-
Deleting a tag does not mean the disk space is freed immediately
-
You must run GC to reclaim disk space
Operational Concerns for Registry
Disk Space
-
Images grow fast
-
Disk usage must be monitored
Backup Strategy
-
Back up the storage directory directly
-
Registry itself is stateless
Garbage Collection (GC)
-
Service must be stopped during GC
-
Not suitable for high-concurrency online environments
Suitable and Unsuitable Scenarios for Registry
Suitable Scenarios
-
Intranet image caching
-
Docker Hub acceleration
-
CI/CD private repository
-
Offline image distribution
Unsuitable Scenarios
-
Enterprise-level multi-team governance
-
Multi-registry aggregation
-
Complex permissions and auditing
-
Visual management requirements
The Role of Registry in the Overall Architecture
An engineering conclusion:
Docker Registry is a “lower-level storage component,” not a “platform-level product.”
In a mature architecture, it is often:
-
Taken over by an upper-layer platform
-
Or exists only as a dedicated cache node
Learning Summary
-
Registry supports only single-upstream proxy
-
remoteurlcannot be configured with multiple values by design -
registry-1.docker.iois the real entry for Docker Hub -
Registry Mirror ≠ multi-registry routing
-
A unified entry for multiple upstreams requires a higher-level repository management system
With these understandings established, all Registry behaviors become predictable, explainable, and maintainable.
Systematic Study Notes on Validation, Unique Keys, and String Handling in Spring Boot / Java Projects
This article is a complete engineering-grade summary of our entire discussion. The goal is not merely “to write code,” but to know why it is written this way, what cannot be omitted, and what should not be over-engineered. The content is based on Spring Boot + Java 11/21 + jOOQ, but the principles are broadly applicable.
I. Bean Validation Basics: The Proper Positioning of @Validated
1.1 What @Validated Is
-
@Validatedis a Spring-provided annotation to trigger validation -
It is based on Bean Validation (JSR-303 / JSR-380)
-
The default implementation is Hibernate Validator
Core purpose:
Trigger validation + support validation groups + support method-level validation
1.2 Differences Between @Validated and @Valid
| Dimension | @Valid | @Validated |
|---|---|---|
| Origin | JSR standard | Spring |
| Group validation | ❌ | ✅ |
| Method parameter validation | ❌ | ✅ |
| Controller parameter validation | ✅ | ✅ |
Engineering recommendation:
In Spring Boot projects, use @Validated consistently.
II. Cross-Field Validation: Why You Must Use “Class-Level Validation”
2.1 The Nature of the Problem
Requirement example:
String aandString bcannot both be empty (null / blank), but it is allowed to fill only one
This is a cross-field combination rule, not a single-field rule.
2.2 Why Field-Level Annotations Are Not Suitable
-
@NotNull/@NotBlankexpresses AND -
The actual business semantics is OR
-
Field-level annotations cannot see “the other field”
Conclusion:
If a rule depends on multiple fields, you must use class-level validation
III. Correct Semantics of String Validation: null ≠ blank
3.1 Distinguishing at the Business Semantics Level
| Case | Meaning |
|---|---|
null | not provided |
"" / " " | provided but meaningless |
" 10.1.1.1 " | has value but with noise |
"1.1 .1.1" | invalid input |
Business validation cares about “whether it is meaningful,” not just the memory state.
3.2 Java Native vs Apache Commons
Compare two approaches:
s != null && !s.isBlank()
StringUtils.isNotBlank(s)
Conclusion:
-
Java 11+: prefer native
isBlank() -
Do not introduce
commons-lang3just forisNotBlank -
Dependency governance > saving a few keystrokes
IV. Recommended String Normalization Strategy
4.1 Standard Implementation
private static String normalize(String s) {
if (s == null) return null;
var t = s.trim();
return t.isBlank() ? null : t;
}
4.2 Why trim() Then isBlank()
-
isBlank()can detect all-whitespace -
The real purpose of
trim()is not to check emptiness, but to remove leading/trailing noise -
"10.1.1.1"and" 10.1.1.1 "should be treated as the same value in business terms
4.3 Why Not Handle “Inner Spaces”
For example:
1.1 .1.1
1.1. 1.1
Conclusion:
normalize is responsible for normalization, not correction
Reasons:
-
Inner spaces are invalid input
-
Auto-fixing would “silently swallow errors”
-
It should be rejected clearly at the DTO / validation layer
Engineering principle:
Leading/trailing whitespace is noise and can be cleaned; inner whitespace is an error and must be rejected.
V. Everyday Code Style: Getter Calls vs Local Variables
5.1 Two Styles Compared
if (a.getS() != null && !a.getS().isBlank())
var s = a.getS();
if (s != null && !s.isBlank())
5.2 Recommended Conclusion
Prefer assigning to a local variable before checking
Reasons:
-
Avoid repeated expressions
-
Reduce reading and debugging cost
-
Easier to extend logic
-
No substantive performance difference
VI. Modeling the Core Problem of Unique Key Validation
6.1 The True Semantics of a Unique Key
Unique key validation is not asking:
“Does this set of fields exist?”
It is asking:
“Is there another record that has the same unique-key semantics as mine?”
“Another record” is the key phrase.
6.2 When a Unique Key Contains Branching Logic
Example:
-
systemName + sid + client + scheme + ip -
Or
systemName + sid + client + scheme + domain
Implicit rules:
-
ipanddomainare mutually exclusive -
iphas higher priority
Such rules should be:
-
Validated at the DTO layer (at least one is non-blank)
-
Reflected consistently in DAO-layer condition construction
VII. Differences in Uniqueness Validation Between Create and Update Scenarios
7.1 Fundamental Difference
| Scenario | Does current record exist? | Need to exclude itself? |
|---|---|---|
| Create | No | ❌ |
| Update | Yes | ✅ |
7.2 Why Update Must Exclude Itself
If you do not exclude:
exists (where unique key condition)
-
When updating without changing the unique key
-
The query will always hit itself
-
It will be falsely judged as a conflict
Correct semantics:
exists (
where unique key condition
and id <> currentId
)
7.3 Why Create Cannot Use id != null
-
In SQL,
id <> nullevaluates tounknown -
It can cause the condition to fail or lead to incorrect logic
-
jOOQ should not generate such conditions either
VIII. A Recommended Unified Implementation for Create / Update
8.1 Method Signature
public boolean existsConflictUniqueKey(
@Nullable Long currentId,
String systemName, String sid, Short client,
@Nullable String ip, @Nullable String domain,
Scheme scheme
)
8.2 Core Logic
var cond = baseKeyCond(...);
if (cond == null) return false;
if (currentId != null) {
cond = cond.and(T.ID.ne(currentId)); // Update
}
return fetchExists(cond);
Calling convention:
-
Create:
currentId = null -
Update:
currentId = id
IX. The Outer “Whether the Unique Key Changed” Check: Purpose and Boundaries
9.1 What the Outer Comparison Can Do
if (oldKey.equals(newKey)) {
skip exists query
}
Benefits:
-
Reduce database queries
-
Improve performance and user experience
9.2 What the Outer Comparison Cannot Do
It cannot guarantee uniqueness, for reasons including:
-
Concurrent inserts / concurrent updates
-
Data drift (stale read)
-
TOCTOU (time-of-check to time-of-use gap)
Conclusion:
Outer comparison is an optimization, not a correctness guarantee
X. A Complete Engineering Defense Line (Strongly Recommended)
10.1 Three-Layer Defense Model
First layer: DTO / parameter validation
-
Non-blank
-
At least one field exists
-
Valid format (e.g., IP)
Second layer: application-layer uniqueness check
-
Create:
exists(key) -
Update:
exists(key) AND id != currentId -
Outer comparison used to reduce queries
Third layer: database unique constraint (final safeguard)
-
Prevent concurrency bypass
-
Catch unique constraint exception → convert to business exception
XI. Naming Principles for Validation Annotations and Validators
11.1 Not Recommended: “Field-Name-Based Annotations”
For example:
@AOrBNotBlank
Problems:
-
Breaks when field names change
-
Annotation count explodes
-
Poor reusability
11.2 Recommended: “Semantic + Parameterized”
@AtLeastOneNotBlank(fields = {"a", "b"})
Principle:
Annotation name = rule semantics field names = parameters validator = rule engine
XII. Key Engineering Conclusions Summary
-
@Validatedis the preferred validation annotation in Spring projects -
Cross-field rules must use class-level validation
-
String validation focuses on semantics, not just
null -
normalizeis for normalization, not correction -
Local variables are preferable to repeated getter calls
-
Update uniqueness checks must exclude itself
-
Create scenarios must not generate
id != null -
Outer key comparison is optimization, not correctness guarantee
-
Database unique constraints are the final safeguard
-
Correctness > performance optimization > code brevity
XIII. One Engineering Summary Sentence
Validation is a semantics problem, uniqueness is a concurrency problem, the database is the final judge.
Once you separate these three clearly, your code is already standing on the side of “long-term maintainability.”