Building a Microservices E-Commerce Platform with Spring Cloud and Alibaba

Project Architecture Overview

The system adopts a microservices architecture, decomposing business capabilities into independently deployable services communicating over lightweight HTTP APIs. Each service handles its own data storage and can be developed with dedicated technology stacks. The architecture diagram splits the monolith into services such as product management, inventory, orders, and user authentication.

Distributed Systems Fundamentals

A microservice is an independent process built around a specific business domain. Multiple instances of a service can form a cluster, and while every cluster comprises multiple machines, not every cluster operates in a distributed manner. Distributed systems present a single coherent system to users while dispersing logic across network-connected computers. For example, an e-commerce platform distributes its modules across hosts, yet each module can scale horizontally through clustering.

Remote invocation occurs when services residing on different hosts need to interact. The chosen mechanism uses HTTP with JSON payloads. Load balancing distributes calls among available service instances using algorithms such as round-robin, least connections, or IP-hash, which routes a client to a consistent backend.

A service registry keeps track of live instances and their health status. When a service starts, it registers its location; when it fails, the registry removes the entry, preventing callers from targeting dead endpoints. Additionally, a configuration center externalizes properties so that all instances can pick up changes without redeployment.

Circuit breaking protects the system from cascading failures. When a downstream service repeatedly times out, the breaker trips and subsequent requests fall back to a default or cached response. Service degradation downgrades non-critical features during peak load, returning stub data or skipping processing entirely. An API gateway sits at the edge, handling routing, authentication, rate limiting, and cross-cutting concerns.

Environment Setup

Docker manages infrastructure components. Typical commands include pulling the MySQL 5.7 image and running a container with volume mounts for logs, data, and configuration:

docker run -p 3306:3306 --name mysql \
  -v /mydata/mysql/log:/var/log/mysql \
  -v /mydata/mysql/data:/var/lib/mysql \
  -v /mydata/mysql/conf:/etc/mysql \
  -e MYSQL_ROOT_PASSWORD=root \
  -d mysql:5.7

Redis installation follows a similar pattern. The development environment aligns on JDK 1.8, Maven with Alibaba Cloud mirrors, and IDE plugins like Lombok and MyBatisX. Front-end tooling uses VS Code, while Git with SSH keys manages version control.

Applying Distributed Components

Nacos functions as both registry and configuration center. Services register with Nacos so that Feign clients can perform declarative REST calls. A Feign interface maps directly to a remote endpoint:

@FeignClient("product-service")
public interface ProductClient {
    @GetMapping("/products/{id}")
    ProductDTO getById(@PathVariable Long id);
}

Configuration is organised by namespaces, groups, and data IDs. Namespaces isolate environments (development, testing, production) or individual microservices. Groups distinguish dataset variations within the same namespace. Multiple configuration files can be loaded and merged.

The Spring Cloud Gateway exposes routes, validates requests, and applies rate limits:

spring:
  cloud:
    gateway:
      routes:
        - id: product_route
          uri: lb://product-service
          predicates:
            - Path=/api/products/**
          filters:
            - RewritePath=/api/(?<segment>.*), /$\{segment}

Product Service Implementation

Tree-structured menus are fetched recursively, and backend paths are rewritten before forwarding. Cross-origin resource sharing is resolved inside the gateway by allowing specific origins, methods, and headers.

File storage leverages Alibaba Cloud OSS with server-side signature. Instead of passing static credentials to the browser, an endpoint generates a temporary policy and signature. The client then uploads directly to OSS, reducing pressure on the application server.

Data validation uses JSR-303 annotations. The @Validated annotation with marker interfaces such as AddGroup and UpdateGroup controls which constraints apply during creation versus updates. A custom constraint annotation is backed by a ConstraintValidator implementation:

@Target({METHOD, FIELD})
@Retention(RUNTIME)
@Constraint(validatedBy = StatusValidator.class)
public @interface ValidStatus {
    String message() default "invalid status";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

Uniform exception handling captures validation errors and business exceptions, converting them into structured error responses with defined error codes and messages.

Full-Text Search with Elasticsearch

Elasticsearch and Kibana are launched via Docker. Basic operations include indexing a document:

PUT customer/_doc/1
{
    "name": "John Doe"
}

Documents can be queried, updated, and deleted. Bulk operations combine multiple actions in one request. Query DSL supports match, match_phrase, multi_match, bool queries, filters, and aggregations. Term queries search for exact values, while aggregations compute statistics like averages or distributions.

Mapping defines field types. Existing field mappings cannot be updated; instead, a new index with the correct mapping must be created and data reindexed:

POST _reindex
{
  "source": { "index": "old_index" },
  "dest": { "index": "new_index" }
}

Chinese text analysis uses the IK Analyzer plugin. A custom dictionary can be added via Nginx to handle domain-specific terms. The Spring Boot integration uses the Elasticsearch REST client, injecting RestHighLevelClient to index and search documents.

Nested data types prevent array flattening. When a product contains multiple SKU attributes, setting the field type to nested keeps each attribute’s internal association intact.

Business Features and Performance Tuning

Listing products on the marketplace builds an index model from product attributes and writes it to Elasticsearch. A reverse proxy with Nginx creates domain-based environments. Stress testing with JMeter evaluates throughput, response times, and concurrency limits. Key indicators include QPS, average latency, and error rate. Memory and GC monitoring via jvisualvm or jconsole helps identify leaks or excessive young-GC pauses. Performance gains come from static resource separation in Nginx, reducing database round-trips, adding indexes, enabling caching, and adjusting JVM heap sizes when necessary.

Caching and Distributed Locks

Data with high read frequency and loose consistency requirements benefits from caching. Redis integration uses StringRedisTemplate with serialized JSON values. Cache invalidation scenarios include penetration (querying non-existent keyss), breakdown (a hot key expiring during heavy traffic), and avalanche (many keys expiring simultaneously). Prevention involves caching null results, setting staggered expiry, and using distributed locks.

Distributed locking evolves from SETNX with automatic expiry to UUID-based ownership checks, culminating in atomic Lua scripts. Redisson provides a production-grade lock with a watchdog that automatically renews the lease while the business logic runs:

RLock lock = redissonClient.getLock("product-lock");
lock.lock();
try {
    // critical section
} finally {
    lock.unlock();
}

Redisson also offers read-write locks, semaphores, and countdown latches. Read-write locks allow concurrent reads but block writes until no readers exist. Semaphores can limit concurrent access, and latches wait for predecessor tasks to complete.

Cache consistency is tackled through two patterns: write-through (update both DB and cache) and cache-aside (invalidate cache on update). Both suffer from race conditions when writes interleave. Solutions include distributed locks or short TTLs that allow eventual consistency. For highly volatile data, bypassing the cache entirely may be preferable.

Spring Cache annotations simplify integration. @Cacheable stores method results, @CacheEvict removes entries, and @CachePut always updates the cache. A custom cache configuration sets JSON serialization and TTLs:

@Configuration
public class CacheConfig {
    @Bean
    public RedisCacheConfiguration cacheConfiguration() {
        return RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(Duration.ofMinutes(30))
            .serializeValuesWith(RedisSerializationContext.SerializationPair
                .fromSerializer(new GenericJackson2JsonRedisSerializer()));
    }
}

Search Service and Asynchronous Processing

Thread pools are created with core size, maximum size, keep-alive time, and work queues. The CompletableFuture API orchestrates asynchronous tasks. A custom thread pool is injected into the Spring context, and properties control pool parameters:

@Bean
public Executor taskExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(corePoolSize);
    executor.setMaxPoolSize(maxPoolSize);
    executor.setQueueCapacity(queueCapacity);
    executor.setThreadNamePrefix("async-task-");
    executor.initialize();
    return executor;
}

Tasks can be chained with thenApply, combined with thenCombine, or raced with applyToEither. After all tasks complete, results are merged.

Authantication and Session Management

Password hashing uses BCrypt, which generates distinct hashes for identical inputs. OAuth2 facilitates social logins such as Weibo. After the user authorises the application, a callback exchanges the code for an access token, which retrieves user details. Spring Session centralises session storage in Redis, decoupling session state from individual service instances. In a multi-domain setup, cookie configuration expands the session scope. JWT tokans offer a stateless alternative, embedding user claims within a signed token.

Additional Notes

All code examples have been restructured to illustrate concepts without repeating original snippets verbatim. Configuration details, endpoint paths, and method signatures are adapted while retaining technical accuracy.

Tags: microservices Spring Cloud elasticsearch Caching Distributed Lock

Posted on Thu, 30 Jul 2026 16:55:42 +0000 by adamlacombe