Published on

The Complete Guide to Modern Java Architecture - Part 3: Implementation Deep Dives

Authors

Welcome back to our Modern Java Architecture series! In Part 1, we laid the foundation with core principles and modern Java features. In Part 2, we explored architecture patterns from monoliths to serverless. Now, let's dive deep into the implementation details that make or break production systems.

After architecting systems that handle millions of requests daily, I've learned that the devil truly is in the details. This guide shares battle-tested patterns for APIs, data management, security, and observability that have proven themselves under fire.

Series Navigation

API Design and Versioning Strategies

RESTful API Design with Modern Java

Let's start with a production-ready REST API using Spring Boot 3.2 and Java 21 features:

@RestController
@RequestMapping("/api/v1/products")
@Validated
@Tag(name = "Product API", description = "Product management operations")
public class ProductController {
    
    private final ProductService productService;
    private final ProductMapper mapper;
    
    @GetMapping
    @Operation(summary = "List products with pagination and filtering")
    public ResponseEntity<PagedResponse<ProductDTO>> listProducts(
            @RequestParam(defaultValue = "0") @Min(0) int page,
            @RequestParam(defaultValue = "20") @Min(1) @Max(100) int size,
            @RequestParam(required = false) String category,
            @RequestParam(required = false) BigDecimal minPrice,
            @RequestParam(required = false) BigDecimal maxPrice,
            @RequestParam(defaultValue = "createdAt") String sortBy,
            @RequestParam(defaultValue = "DESC") Sort.Direction sortDirection) {
        
        var pageable = PageRequest.of(page, size, Sort.by(sortDirection, sortBy));
        var spec = ProductSpecifications.withFilters(category, minPrice, maxPrice);
        
        var products = productService.findAll(spec, pageable);
        var response = PagedResponse.of(products.map(mapper::toDTO));
        
        return ResponseEntity.ok()
                .cacheControl(CacheControl.maxAge(5, TimeUnit.MINUTES))
                .body(response);
    }
    
    @GetMapping("/{id}")
    @Operation(summary = "Get product by ID")
    public ResponseEntity<ProductDTO> getProduct(
            @PathVariable @UUID String id,
            @RequestHeader(value = "If-None-Match", required = false) String ifNoneMatch) {
        
        var product = productService.findById(UUID.fromString(id))
                .orElseThrow(() -> new ResourceNotFoundException("Product not found"));
        
        var etag = generateETag(product);
        if (etag.equals(ifNoneMatch)) {
            return ResponseEntity.status(HttpStatus.NOT_MODIFIED).build();
        }
        
        return ResponseEntity.ok()
                .eTag(etag)
                .cacheControl(CacheControl.maxAge(1, TimeUnit.HOURS))
                .body(mapper.toDTO(product));
    }
    
    @PostMapping
    @Operation(summary = "Create new product")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<ProductDTO> createProduct(
            @Valid @RequestBody CreateProductRequest request) {
        
        var product = productService.create(mapper.toEntity(request));
        var location = ServletUriComponentsBuilder
                .fromCurrentRequest()
                .path("/{id}")
                .buildAndExpand(product.getId())
                .toUri();
        
        return ResponseEntity.created(location)
                .body(mapper.toDTO(product));
    }
    
    @PutMapping("/{id}")
    @Operation(summary = "Update product")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<ProductDTO> updateProduct(
            @PathVariable @UUID String id,
            @Valid @RequestBody UpdateProductRequest request,
            @RequestHeader(value = "If-Match", required = false) String ifMatch) {
        
        var existing = productService.findById(UUID.fromString(id))
                .orElseThrow(() -> new ResourceNotFoundException("Product not found"));
        
        // Optimistic locking check
        if (ifMatch != null && !generateETag(existing).equals(ifMatch)) {
            throw new OptimisticLockException("Product was modified by another user");
        }
        
        var updated = productService.update(existing, mapper.toEntity(request));
        return ResponseEntity.ok()
                .eTag(generateETag(updated))
                .body(mapper.toDTO(updated));
    }
    
    @DeleteMapping("/{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    @Operation(summary = "Delete product")
    @PreAuthorize("hasRole('ADMIN')")
    public void deleteProduct(@PathVariable @UUID String id) {
        productService.delete(UUID.fromString(id));
    }
    
    private String generateETag(Product product) {
        return "\"" + product.getVersion() + "-" + 
               product.getUpdatedAt().toEpochMilli() + "\"";
    }
}

API Versioning Strategies

Here's a comprehensive versioning approach that supports multiple strategies:

@Configuration
@EnableWebMvc
public class ApiVersioningConfig implements WebMvcConfigurer {
    
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer.addPathPrefix("/api/v{version:\\d+}", 
            HandlerTypePredicate.forAnnotation(RestController.class)
                .and(HandlerTypePredicate.forAnnotation(ApiVersion.class)));
    }
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new ApiVersionInterceptor());
    }
}

@Component
public class ApiVersionInterceptor implements HandlerInterceptor {
    
    @Override
    public boolean preHandle(HttpServletRequest request, 
                           HttpServletResponse response, 
                           Object handler) {
        
        if (handler instanceof HandlerMethod handlerMethod) {
            var apiVersion = handlerMethod.getMethodAnnotation(ApiVersion.class);
            if (apiVersion == null) {
                apiVersion = handlerMethod.getBeanType().getAnnotation(ApiVersion.class);
            }
            
            if (apiVersion != null) {
                var requestedVersion = extractVersion(request);
                if (!isVersionSupported(requestedVersion, apiVersion)) {
                    throw new UnsupportedApiVersionException(
                        "API version " + requestedVersion + " is not supported");
                }
            }
        }
        return true;
    }
    
    private int extractVersion(HttpServletRequest request) {
        // Support multiple versioning strategies
        
        // 1. URL path versioning: /api/v1/products
        var pathVersion = extractFromPath(request.getRequestURI());
        if (pathVersion != null) return pathVersion;
        
        // 2. Header versioning: X-API-Version: 1
        var headerVersion = request.getHeader("X-API-Version");
        if (headerVersion != null) return Integer.parseInt(headerVersion);
        
        // 3. Media type versioning: Accept: application/vnd.api.v1+json
        var acceptHeader = request.getHeader("Accept");
        if (acceptHeader != null && acceptHeader.contains("vnd.api.v")) {
            return extractFromMediaType(acceptHeader);
        }
        
        // Default to latest version
        return 1;
    }
}

GraphQL Implementation

For more complex query requirements, here's a GraphQL implementation:

@Component
public class ProductGraphQLResolver implements GraphQLQueryResolver {
    
    private final ProductService productService;
    private final DataLoader<UUID, Product> productLoader;
    
    public CompletableFuture<Product> product(String id) {
        return productLoader.load(UUID.fromString(id));
    }
    
    public Connection<Product> products(
            int first, 
            String after, 
            ProductFilter filter, 
            ProductSort sort) {
        
        return new SimpleConnection<>(
            productService.findAll(filter, sort, first, after)
        );
    }
}

@Component
public class ProductDataLoader implements BatchLoader<UUID, Product> {
    
    private final ProductRepository repository;
    
    @Override
    public CompletableFuture<List<Product>> load(List<UUID> ids) {
        return CompletableFuture.supplyAsync(() -> 
            repository.findAllById(ids)
        );
    }
}

// GraphQL schema
type Product {
    id: ID!
    name: String!
    description: String
    price: BigDecimal!
    category: Category!
    inventory: Inventory
    reviews: [Review!]!
    createdAt: DateTime!
    updatedAt: DateTime!
}

type Query {
    product(id: ID!): Product
    products(
        first: Int = 20
        after: String
        filter: ProductFilter
        sort: ProductSort
    ): ProductConnection!
}

input ProductFilter {
    categories: [String!]
    minPrice: BigDecimal
    maxPrice: BigDecimal
    inStock: Boolean
}

Data Layer Patterns and Consistency

Repository Pattern with Specifications

@Repository
public interface ProductRepository extends 
        JpaRepository<Product, UUID>, 
        JpaSpecificationExecutor<Product> {
    
    @Query("SELECT p FROM Product p WHERE p.deletedAt IS NULL")
    @EntityGraph(attributePaths = {"category", "inventory"})
    Page<Product> findAllActive(Pageable pageable);
    
    @Modifying
    @Query("UPDATE Product p SET p.viewCount = p.viewCount + 1 WHERE p.id = :id")
    void incrementViewCount(@Param("id") UUID id);
    
    @Query(value = """
        WITH RECURSIVE category_tree AS (
            SELECT id, parent_id, name
            FROM categories
            WHERE id = :categoryId
            UNION ALL
            SELECT c.id, c.parent_id, c.name
            FROM categories c
            INNER JOIN category_tree ct ON c.parent_id = ct.id
        )
        SELECT p.* FROM products p
        WHERE p.category_id IN (SELECT id FROM category_tree)
        """, nativeQuery = true)
    List<Product> findByCategoryTree(@Param("categoryId") UUID categoryId);
}

public class ProductSpecifications {
    
    public static Specification<Product> withFilters(
            String category, 
            BigDecimal minPrice, 
            BigDecimal maxPrice) {
        
        return Specification.where(hasCategory(category))
                .and(hasPriceGreaterThan(minPrice))
                .and(hasPriceLessThan(maxPrice))
                .and(isActive());
    }
    
    private static Specification<Product> hasCategory(String category) {
        return (root, query, builder) -> 
            category == null ? null : 
            builder.equal(root.get("category").get("name"), category);
    }
    
    private static Specification<Product> hasPriceGreaterThan(BigDecimal price) {
        return (root, query, builder) -> 
            price == null ? null : 
            builder.greaterThanOrEqualTo(root.get("price"), price);
    }
}

Event Sourcing Implementation

@Entity
@Table(name = "event_store")
public class EventEntity {
    @Id
    private UUID id;
    
    private UUID aggregateId;
    private String aggregateType;
    private Long version;
    private String eventType;
    
    @Column(columnDefinition = "jsonb")
    private String eventData;
    
    private Instant occurredAt;
    
    @PrePersist
    protected void onCreate() {
        id = UUID.randomUUID();
        occurredAt = Instant.now();
    }
}

@Component
public class EventStore {
    
    private final EventRepository repository;
    private final ObjectMapper objectMapper;
    private final ApplicationEventPublisher eventPublisher;
    
    @Transactional
    public void append(UUID aggregateId, List<DomainEvent> events) {
        var currentVersion = repository
            .findMaxVersionByAggregateId(aggregateId)
            .orElse(0L);
        
        var eventEntities = new ArrayList<EventEntity>();
        
        for (var event : events) {
            var entity = new EventEntity();
            entity.setAggregateId(aggregateId);
            entity.setAggregateType(event.getAggregateType());
            entity.setVersion(++currentVersion);
            entity.setEventType(event.getClass().getSimpleName());
            entity.setEventData(serialize(event));
            
            eventEntities.add(entity);
        }
        
        repository.saveAll(eventEntities);
        
        // Publish events for projections
        events.forEach(eventPublisher::publishEvent);
    }
    
    public List<DomainEvent> getEvents(UUID aggregateId) {
        return repository.findByAggregateIdOrderByVersion(aggregateId)
            .stream()
            .map(this::deserialize)
            .toList();
    }
    
    public <T extends AggregateRoot> T load(UUID aggregateId, Class<T> type) {
        var events = getEvents(aggregateId);
        if (events.isEmpty()) {
            throw new AggregateNotFoundException(aggregateId);
        }
        
        try {
            var aggregate = type.getDeclaredConstructor().newInstance();
            aggregate.replay(events);
            return aggregate;
        } catch (Exception e) {
            throw new EventSourcingException("Failed to load aggregate", e);
        }
    }
}

public abstract class AggregateRoot {
    
    private UUID id;
    private Long version = 0L;
    private final List<DomainEvent> pendingEvents = new ArrayList<>();
    
    protected void raiseEvent(DomainEvent event) {
        pendingEvents.add(event);
        apply(event);
        version++;
    }
    
    public List<DomainEvent> getPendingEvents() {
        return new ArrayList<>(pendingEvents);
    }
    
    public void markEventsAsCommitted() {
        pendingEvents.clear();
    }
    
    public void replay(List<DomainEvent> events) {
        events.forEach(this::apply);
        version = (long) events.size();
    }
    
    protected abstract void apply(DomainEvent event);
}

CQRS with Projections

@Component
public class ProductProjectionHandler {
    
    private final ProductViewRepository viewRepository;
    
    @EventHandler
    @Transactional
    public void on(ProductCreatedEvent event) {
        var view = new ProductView();
        view.setId(event.getProductId());
        view.setName(event.getName());
        view.setPrice(event.getPrice());
        view.setCategory(event.getCategory());
        view.setCreatedAt(event.getOccurredAt());
        
        viewRepository.save(view);
    }
    
    @EventHandler
    @Transactional
    public void on(ProductPriceChangedEvent event) {
        viewRepository.findById(event.getProductId())
            .ifPresent(view -> {
                view.setPrice(event.getNewPrice());
                view.setPreviousPrice(event.getOldPrice());
                view.setPriceChangedAt(event.getOccurredAt());
                viewRepository.save(view);
            });
    }
    
    @EventHandler
    @Transactional
    public void on(ProductInventoryUpdatedEvent event) {
        viewRepository.updateInventory(
            event.getProductId(), 
            event.getQuantity(), 
            event.getOccurredAt()
        );
    }
}

@Component
public class ProductQueryHandler {
    
    private final ProductViewRepository repository;
    private final RedisTemplate<String, ProductView> cache;
    
    public ProductView findById(UUID id) {
        // Try cache first
        var cached = cache.opsForValue().get("product:" + id);
        if (cached != null) {
            return cached;
        }
        
        // Load from read model
        var product = repository.findById(id)
            .orElseThrow(() -> new ProductNotFoundException(id));
        
        // Cache for future reads
        cache.opsForValue().set(
            "product:" + id, 
            product, 
            Duration.ofMinutes(15)
        );
        
        return product;
    }
    
    public Page<ProductView> search(ProductSearchCriteria criteria, Pageable pageable) {
        // Use Elasticsearch for complex searches
        var query = QueryBuilders.boolQuery();
        
        if (criteria.getSearchTerm() != null) {
            query.must(QueryBuilders.multiMatchQuery(criteria.getSearchTerm())
                .field("name", 2.0f)
                .field("description")
                .field("category"));
        }
        
        if (criteria.getMinPrice() != null) {
            query.filter(QueryBuilders.rangeQuery("price")
                .gte(criteria.getMinPrice()));
        }
        
        // Execute search
        return repository.search(query, pageable);
    }
}

Security Implementation Across Architectures

Zero Trust Security Model

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
            .csrf(csrf -> csrf
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                .ignoringRequestMatchers("/api/webhooks/**"))
            .sessionManagement(session -> session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/public/**").permitAll()
                .requestMatchers("/api/admin/**").hasRole("ADMIN")
                .requestMatchers("/actuator/health").permitAll()
                .requestMatchers("/actuator/**").hasRole("ADMIN")
                .anyRequest().authenticated())
            .oauth2ResourceServer(oauth2 -> oauth2
                .jwt(jwt -> jwt
                    .jwtAuthenticationConverter(jwtAuthenticationConverter())))
            .addFilterBefore(new RateLimitingFilter(), UsernamePasswordAuthenticationFilter.class)
            .addFilterAfter(new SecurityMetricsFilter(), ExceptionTranslationFilter.class)
            .build();
    }
    
    @Bean
    public JwtAuthenticationConverter jwtAuthenticationConverter() {
        var converter = new JwtAuthenticationConverter();
        converter.setJwtGrantedAuthoritiesConverter(jwt -> {
            var authorities = new ArrayList<GrantedAuthority>();
            
            // Extract roles
            var roles = jwt.getClaimAsStringList("roles");
            if (roles != null) {
                roles.stream()
                    .map(role -> new SimpleGrantedAuthority("ROLE_" + role))
                    .forEach(authorities::add);
            }
            
            // Extract permissions
            var permissions = jwt.getClaimAsStringList("permissions");
            if (permissions != null) {
                permissions.stream()
                    .map(SimpleGrantedAuthority::new)
                    .forEach(authorities::add);
            }
            
            return authorities;
        });
        
        return converter;
    }
}

@Component
public class RateLimitingFilter extends OncePerRequestFilter {
    
    private final RateLimiter rateLimiter;
    
    @Override
    protected void doFilterInternal(
            HttpServletRequest request,
            HttpServletResponse response,
            FilterChain chain) throws ServletException, IOException {
        
        var key = extractKey(request);
        
        if (!rateLimiter.tryAcquire(key)) {
            response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
            response.setHeader("X-RateLimit-Retry-After", 
                String.valueOf(rateLimiter.getRetryAfter(key)));
            return;
        }
        
        response.setHeader("X-RateLimit-Limit", 
            String.valueOf(rateLimiter.getLimit(key)));
        response.setHeader("X-RateLimit-Remaining", 
            String.valueOf(rateLimiter.getRemaining(key)));
        
        chain.doFilter(request, response);
    }
    
    private String extractKey(HttpServletRequest request) {
        // Use authenticated user ID if available
        var auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth != null && auth.isAuthenticated()) {
            return "user:" + auth.getName();
        }
        
        // Fall back to IP address
        return "ip:" + getClientIpAddress(request);
    }
}

Service-to-Service Authentication

@Component
public class ServiceAuthenticationProvider {
    
    private final ServiceRegistry registry;
    private final JwtService jwtService;
    
    @Cacheable("service-tokens")
    public String getServiceToken(String targetService) {
        var credentials = registry.getServiceCredentials(targetService);
        
        var claims = Jwts.claims()
            .setSubject("service:" + credentials.getClientId())
            .setIssuer("auth-service")
            .setAudience(targetService)
            .setIssuedAt(new Date())
            .setExpiration(Date.from(Instant.now().plus(5, ChronoUnit.MINUTES)));
        
        claims.put("service_name", credentials.getServiceName());
        claims.put("permissions", credentials.getPermissions());
        
        return jwtService.generateToken(claims);
    }
}

@Component
public class SecureWebClient {
    
    private final WebClient.Builder webClientBuilder;
    private final ServiceAuthenticationProvider authProvider;
    
    public WebClient createForService(String serviceName) {
        return webClientBuilder
            .baseUrl(getServiceUrl(serviceName))
            .filter(ExchangeFilterFunction.ofRequestProcessor(request -> {
                var token = authProvider.getServiceToken(serviceName);
                return Mono.just(ClientRequest.from(request)
                    .header("Authorization", "Bearer " + token)
                    .header("X-Service-Name", getCurrentServiceName())
                    .header("X-Request-ID", MDC.get("requestId"))
                    .build());
            }))
            .filter(ExchangeFilterFunction.ofResponseProcessor(response -> {
                if (response.statusCode().is4xxClientError() || 
                    response.statusCode().is5xxServerError()) {
                    return response.bodyToMono(String.class)
                        .flatMap(body -> Mono.error(
                            new ServiceCallException(serviceName, 
                                response.statusCode(), body)));
                }
                return Mono.just(response);
            }))
            .build();
    }
}

Data Encryption at Rest

@Component
public class EncryptionService {
    
    private final SecretKey dataKey;
    private final Cipher cipher;
    
    public EncryptionService(@Value("${encryption.key}") String masterKey) {
        this.dataKey = deriveDataKey(masterKey);
        try {
            this.cipher = Cipher.getInstance("AES/GCM/NoPadding");
        } catch (Exception e) {
            throw new EncryptionException("Failed to initialize cipher", e);
        }
    }
    
    public EncryptedData encrypt(String plaintext) {
        try {
            var iv = generateIV();
            var gcmParams = new GCMParameterSpec(128, iv);
            
            cipher.init(Cipher.ENCRYPT_MODE, dataKey, gcmParams);
            var ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
            
            return new EncryptedData(
                Base64.getEncoder().encodeToString(ciphertext),
                Base64.getEncoder().encodeToString(iv)
            );
        } catch (Exception e) {
            throw new EncryptionException("Encryption failed", e);
        }
    }
    
    public String decrypt(EncryptedData data) {
        try {
            var ciphertext = Base64.getDecoder().decode(data.ciphertext());
            var iv = Base64.getDecoder().decode(data.iv());
            
            var gcmParams = new GCMParameterSpec(128, iv);
            cipher.init(Cipher.DECRYPT_MODE, dataKey, gcmParams);
            
            var plaintext = cipher.doFinal(ciphertext);
            return new String(plaintext, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new EncryptionException("Decryption failed", e);
        }
    }
    
    private byte[] generateIV() {
        var iv = new byte[12]; // 96 bits for GCM
        new SecureRandom().nextBytes(iv);
        return iv;
    }
}

@Entity
@EntityListeners(EncryptionListener.class)
public class SensitiveData {
    
    @Id
    private UUID id;
    
    @Encrypted
    @Column(columnDefinition = "text")
    private String ssn;
    
    @Encrypted
    @Column(columnDefinition = "text")
    private String creditCardNumber;
    
    @Column
    private String encryptionIV;
}

@Component
public class EncryptionListener {
    
    private static EncryptionService encryptionService;
    
    @Autowired
    public void init(EncryptionService service) {
        EncryptionListener.encryptionService = service;
    }
    
    @PrePersist
    @PreUpdate
    public void encrypt(Object entity) {
        ReflectionUtils.doWithFields(entity.getClass(), field -> {
            if (field.isAnnotationPresent(Encrypted.class)) {
                field.setAccessible(true);
                var value = (String) field.get(entity);
                if (value != null) {
                    var encrypted = encryptionService.encrypt(value);
                    field.set(entity, encrypted.ciphertext());
                    // Store IV in separate field
                    setIV(entity, encrypted.iv());
                }
            }
        });
    }
    
    @PostLoad
    public void decrypt(Object entity) {
        ReflectionUtils.doWithFields(entity.getClass(), field -> {
            if (field.isAnnotationPresent(Encrypted.class)) {
                field.setAccessible(true);
                var encrypted = (String) field.get(entity);
                if (encrypted != null) {
                    var iv = getIV(entity);
                    var data = new EncryptedData(encrypted, iv);
                    field.set(entity, encryptionService.decrypt(data));
                }
            }
        });
    }
}

Observability and Monitoring

Distributed Tracing with OpenTelemetry

@Configuration
public class ObservabilityConfig {
    
    @Bean
    public OpenTelemetry openTelemetry() {
        var resource = Resource.getDefault()
            .merge(Resource.create(Attributes.of(
                ResourceAttributes.SERVICE_NAME, "product-service",
                ResourceAttributes.SERVICE_VERSION, getVersion(),
                ResourceAttributes.DEPLOYMENT_ENVIRONMENT, getEnvironment()
            )));
        
        var sdkTracerProvider = SdkTracerProvider.builder()
            .addSpanProcessor(BatchSpanProcessor.builder(
                OtlpGrpcSpanExporter.builder()
                    .setEndpoint("http://otel-collector:4317")
                    .build())
                .build())
            .setResource(resource)
            .build();
        
        var sdkMeterProvider = SdkMeterProvider.builder()
            .registerMetricReader(
                PeriodicMetricReader.builder(
                    OtlpGrpcMetricExporter.builder()
                        .setEndpoint("http://otel-collector:4317")
                        .build())
                    .setInterval(Duration.ofSeconds(60))
                    .build())
            .setResource(resource)
            .build();
        
        return OpenTelemetrySdk.builder()
            .setTracerProvider(sdkTracerProvider)
            .setMeterProvider(sdkMeterProvider)
            .setPropagators(ContextPropagators.create(
                W3CTraceContextPropagator.getInstance()
            ))
            .buildAndRegisterGlobal();
    }
    
    @Bean
    public Tracer tracer(OpenTelemetry openTelemetry) {
        return openTelemetry.getTracer("product-service");
    }
}

@Component
@Aspect
public class TracingAspect {
    
    private final Tracer tracer;
    
    @Around("@annotation(Traced)")
    public Object trace(ProceedingJoinPoint joinPoint) throws Throwable {
        var method = joinPoint.getSignature().getName();
        var span = tracer.spanBuilder(method)
            .setSpanKind(SpanKind.INTERNAL)
            .startSpan();
        
        try (var scope = span.makeCurrent()) {
            // Add method parameters as span attributes
            var args = joinPoint.getArgs();
            var params = ((MethodSignature) joinPoint.getSignature()).getParameterNames();
            
            for (int i = 0; i < params.length && i < args.length; i++) {
                if (args[i] != null && !isSensitive(params[i])) {
                    span.setAttribute("param." + params[i], args[i].toString());
                }
            }
            
            var result = joinPoint.proceed();
            span.setStatus(StatusCode.OK);
            return result;
            
        } catch (Exception e) {
            span.setStatus(StatusCode.ERROR, e.getMessage());
            span.recordException(e);
            throw e;
        } finally {
            span.end();
        }
    }
}

Metrics Collection and Custom Dashboards

@Component
public class MetricsCollector {
    
    private final MeterRegistry registry;
    private final Counter apiRequestCounter;
    private final Timer apiRequestTimer;
    private final Gauge activeConnectionsGauge;
    
    public MetricsCollector(MeterRegistry registry) {
        this.registry = registry;
        
        this.apiRequestCounter = Counter.builder("api.requests.total")
            .description("Total API requests")
            .register(registry);
        
        this.apiRequestTimer = Timer.builder("api.requests.duration")
            .description("API request duration")
            .publishPercentiles(0.5, 0.95, 0.99)
            .register(registry);
        
        this.activeConnectionsGauge = Gauge.builder("db.connections.active", 
                this, MetricsCollector::getActiveConnections)
            .description("Active database connections")
            .register(registry);
    }
    
    public void recordApiCall(String endpoint, String method, int status, long duration) {
        apiRequestCounter.increment();
        
        registry.counter("api.requests",
            "endpoint", endpoint,
            "method", method,
            "status", String.valueOf(status),
            "status_class", status < 400 ? "success" : "error"
        ).increment();
        
        apiRequestTimer.record(duration, TimeUnit.MILLISECONDS);
    }
    
    public void recordBusinessMetric(String metric, double value, String... tags) {
        registry.gauge("business." + metric, Tags.of(tags), value);
    }
    
    @EventListener
    public void handleOrderCreated(OrderCreatedEvent event) {
        registry.counter("orders.created",
            "product_category", event.getCategory(),
            "payment_method", event.getPaymentMethod()
        ).increment();
        
        registry.summary("orders.value",
            "currency", event.getCurrency()
        ).record(event.getTotalAmount());
    }
}

@RestController
@RequestMapping("/metrics/custom")
public class CustomMetricsController {
    
    private final MeterRegistry registry;
    private final ProductService productService;
    
    @GetMapping("/business")
    public Map<String, Object> getBusinessMetrics() {
        return Map.of(
            "activeUsers", getCurrentActiveUsers(),
            "conversionRate", calculateConversionRate(),
            "averageOrderValue", getAverageOrderValue(),
            "inventoryHealth", calculateInventoryHealth(),
            "customerSatisfaction", getCustomerSatisfactionScore()
        );
    }
    
    @GetMapping("/slo")
    public Map<String, Object> getSLOMetrics() {
        var errorBudget = calculateErrorBudget();
        var availability = calculateAvailability();
        
        return Map.of(
            "availability", Map.of(
                "current", availability,
                "target", 99.9,
                "withinSLO", availability >= 99.9
            ),
            "latency", Map.of(
                "p95", getP95Latency(),
                "p99", getP99Latency(),
                "target", 200,
                "withinSLO", getP95Latency() <= 200
            ),
            "errorBudget", Map.of(
                "remaining", errorBudget,
                "consumed", 100 - errorBudget,
                "burnRate", calculateBurnRate()
            )
        );
    }
}

Structured Logging

@Component
public class StructuredLogger {
    
    private static final Logger log = LoggerFactory.getLogger(StructuredLogger.class);
    
    public void logApiRequest(HttpServletRequest request, HttpServletResponse response, 
                             long duration, Exception error) {
        try (var ignored = MDC.putCloseable("request_id", getRequestId(request));
             var ignored2 = MDC.putCloseable("user_id", getUserId(request));
             var ignored3 = MDC.putCloseable("trace_id", getTraceId())) {
            
            var event = LogEvent.builder()
                .timestamp(Instant.now())
                .level(error != null ? "ERROR" : "INFO")
                .message("API Request")
                .service("product-service")
                .environment(getEnvironment())
                .request(RequestInfo.builder()
                    .method(request.getMethod())
                    .path(request.getRequestURI())
                    .queryString(request.getQueryString())
                    .userAgent(request.getHeader("User-Agent"))
                    .ip(getClientIp(request))
                    .build())
                .response(ResponseInfo.builder()
                    .status(response.getStatus())
                    .duration(duration)
                    .build())
                .error(error != null ? ErrorInfo.builder()
                    .type(error.getClass().getName())
                    .message(error.getMessage())
                    .stackTrace(getStackTrace(error))
                    .build() : null)
                .metadata(Map.of(
                    "server_region", getServerRegion(),
                    "deployment_id", getDeploymentId(),
                    "feature_flags", getActiveFeatureFlags()
                ))
                .build();
            
            if (error != null) {
                log.error(toJson(event), error);
            } else {
                log.info(toJson(event));
            }
        }
    }
    
    public void logBusinessEvent(String eventType, Map<String, Object> data) {
        var event = BusinessEvent.builder()
            .timestamp(Instant.now())
            .eventType(eventType)
            .userId(getCurrentUserId())
            .sessionId(getCurrentSessionId())
            .data(data)
            .context(Map.of(
                "experiment_variants", getExperimentVariants(),
                "user_segment", getUserSegment(),
                "client_version", getClientVersion()
            ))
            .build();
        
        log.info(toJson(event));
        
        // Also send to analytics pipeline
        analyticsPublisher.publish(event);
    }
}

@Configuration
public class LoggingConfig {
    
    @Bean
    public LoggingEventListener loggingEventListener() {
        return new LoggingEventListener();
    }
    
    @Bean
    public CommonsRequestLoggingFilter requestLoggingFilter() {
        var filter = new CommonsRequestLoggingFilter();
        filter.setIncludeClientInfo(true);
        filter.setIncludeQueryString(true);
        filter.setIncludePayload(true);
        filter.setMaxPayloadLength(10000);
        filter.setIncludeHeaders(true);
        filter.setHeaderPredicate(header -> 
            !header.equalsIgnoreCase("Authorization") &&
            !header.equalsIgnoreCase("Cookie"));
        return filter;
    }
}

Production-Ready Patterns

Circuit Breaker Implementation

@Component
public class ResilientServiceClient {
    
    private final WebClient webClient;
    private final CircuitBreaker circuitBreaker;
    private final Retry retry;
    private final Bulkhead bulkhead;
    
    public ResilientServiceClient(WebClient.Builder webClientBuilder) {
        this.webClient = webClientBuilder.build();
        
        this.circuitBreaker = CircuitBreaker.ofDefaults("inventory-service");
        this.retry = Retry.ofDefaults("inventory-service");
        this.bulkhead = Bulkhead.ofDefaults("inventory-service");
        
        circuitBreaker.getEventPublisher()
            .onStateTransition(event -> 
                log.warn("Circuit breaker state transition: {}", event));
    }
    
    public Mono<InventoryStatus> checkInventory(UUID productId) {
        return Mono.fromCallable(() -> 
                circuitBreaker.executeSupplier(() ->
                    bulkhead.executeSupplier(() -> {
                        var response = webClient.get()
                            .uri("/inventory/{productId}", productId)
                            .retrieve()
                            .bodyToMono(InventoryStatus.class)
                            .block(Duration.ofSeconds(5));
                        
                        if (response == null) {
                            throw new ServiceException("Null response from inventory service");
                        }
                        return response;
                    })
                ))
            .retryWhen(Retry.backoff(3, Duration.ofMillis(100))
                .filter(throwable -> throwable instanceof ServiceException))
            .onErrorReturn(new InventoryStatus(productId, 0, false))
            .doOnError(error -> log.error("Failed to check inventory", error));
    }
}

Feature Flags and A/B Testing

@Component
public class FeatureFlagService {
    
    private final FeatureFlagRepository repository;
    private final Cache<String, FeatureFlag> cache;
    
    public boolean isEnabled(String feature, User user) {
        var flag = cache.get(feature, () -> 
            repository.findByName(feature)
                .orElse(FeatureFlag.disabled(feature)));
        
        if (!flag.isEnabled()) {
            return false;
        }
        
        // Check targeting rules
        for (var rule : flag.getTargetingRules()) {
            if (rule.matches(user)) {
                return rule.isEnabled();
            }
        }
        
        // Check percentage rollout
        if (flag.getPercentageRollout() < 100) {
            var hash = Hashing.murmur3_32()
                .hashString(user.getId() + feature, StandardCharsets.UTF_8)
                .asInt();
            return Math.abs(hash) % 100 < flag.getPercentageRollout();
        }
        
        return true;
    }
    
    public <T> T getVariant(String experiment, User user, Class<T> type) {
        var config = repository.findExperiment(experiment)
            .orElseThrow(() -> new ExperimentNotFoundException(experiment));
        
        // Determine variant based on user bucketing
        var variant = determineVariant(config, user);
        
        // Log exposure for analytics
        logExposure(experiment, variant, user);
        
        return parseVariantValue(variant, type);
    }
}

Next Steps

We've covered the critical implementation details that transform architectural designs into production-ready systems. In Part 4, we'll dive into performance optimization and scalability patterns, including reactive programming, caching strategies, and handling millions of concurrent users.

Remember, great architecture isn't just about the big picture—it's about getting these implementation details right. Every production outage I've experienced came down to overlooking one of these "details."

The complete code examples from this guide are available in our GitHub repository.

Stay tuned for Part 4 where we'll push these implementations to their performance limits!


Have questions or experiences to share about production Java implementations? Find me on LinkedIn or check out more articles at atruedev.com.