ArchitectMind
  1. Home
  2. Tutorials
  3. Book 4 · Spring & Spring Boot
  4. Volume II
  5. Cross-Cutting Concerns
Book 4 · Volume II — Spring AOP, Proxies, Events & Transactions · Topic 1.1

Cross-Cutting Concerns

Logging, security, transactions, auditing, metrics and caching — behaviour that belongs to every module and none

8 min readStage 2 · Frameworks & design7 interview questions
Chapter
Chapter 1 — Cross-Cutting Concerns
Prerequisites
Book 4 Volume I (container, beans, post-processors)
You will be able to
Identify cross-cutting concerns, explain how Spring implements each one, and decide where a new concern should be applied
Covers
Logging · Security · Transactions · Auditing · Metrics · Caching
On this page
  1. 1. Concept / Definition
  2. 2. Why It Exists
  3. 3. Core Concepts
  4. 4. How It Works Internally
  5. 4A. Deep Dive — Choosing the Interception Layer
  6. 5. APIs / Features / Syntax
  7. 6. Practical Examples
  8. 7. Common Problems & Mistakes
  9. 8. Performance & Production Considerations
  10. 9. Architecture & Design Considerations
  11. 10. Interview Questions & Answers

1Concept / Definition

A concern is a particular area of interest or responsibility in a system. A core concern is the reason a module exists — placing an order, charging a payment. A cross-cutting concern is a responsibility that must be applied uniformly across many modules but is not the purpose of any of them.

PropertyCore concernCross-cutting concern
Belongs toOne module (Orders)Many modules (every service)
Changes whenBusiness rules changeOperational or regulatory policy changes
Expressed asDomain classes and methodsPolicies: "every write is audited", "every public API is timed"
OwnerProduct/feature teamPlatform, security, operations
Table 1 — Core versus cross-cutting concerns
Six classic cross-cutting concerns wrap the same business method
Figure 1 — Six classic cross-cutting concerns wrap the same business method

2Why It Exists

Enterprise applications must be observable, secure, consistent and fast — requirements that apply to every feature. In the EJB era the container provided some of them (transactions, security) through deployment descriptors, but only for EJB components and only for a fixed set of concerns. Spring generalised the idea: any bean can receive any concern through interception, and new concerns can be added by applications and libraries. Understanding which concerns are cross-cutting is the first step to applying them consistently.

3Core Concepts

Concerns cut horizontally across vertical business modules
Figure 2 — Concerns cut horizontally across vertical business modules

3.1 Logging

Entry/exit logs, parameter and error logging, correlation and trace IDs. The policy ("log failures of every service call with the trace ID") is uniform; hand-written log statements in every method are not.

Spring mechanismUse
Micrometer Observation / @ObservedTiming + tracing + logging correlation per operation
MDC via tracing integrationTrace/span IDs in every log line automatically
Custom @Around aspectSpecial entry/exit logging where genuinely needed
Table 2 — Logging mechanisms

3.2 Security

Authentication (who are you?) and authorisation (may you do this?). Web requests pass through the Spring Security filter chain; method-level rules are applied by a method-security interceptor.

JAVA
@Service
class PayoutService {
    @PreAuthorize("hasAuthority('payouts:approve') and #p.amount < 100000")
    public void approve(Payout p) { ... }       // no security code inside the method
}

3.3 Transactions

Begin before, commit after, roll back on failure — around every business operation that touches transactional resources. @Transactional is applied by TransactionInterceptor (Chapter 5).

3.4 Auditing

Recording who changed what and when, often for regulatory reasons. Spring Data provides entity-level auditing (@CreatedBy, @LastModifiedDate with @EnableJpaAuditing); business-level audit trails ("payout approved by X") are commonly a custom aspect or domain events.

3.5 Metrics

Counters, timers and gauges for throughput, latency and errors. Micrometer's @Timed/@Counted and the Observation API record them through an aspect; Spring MVC, WebFlux, data sources and clients are instrumented automatically by Boot.

3.6 Caching

"If the result for these arguments is cached, return it; otherwise compute and store it." @Cacheable, @CachePut and @CacheEvict are applied by CacheInterceptor against a CacheManager (Caffeine, Redis, …).

JAVA
@Cacheable(cacheNames = "fx-rates", key = "#from + '-' + #to")
public BigDecimal rate(String from, String to) { return fxClient.fetch(from, to); }
Where each concern is implemented in a Spring application
Figure 3 — Where each concern is implemented in a Spring application

4How It Works Internally

Almost every concern above follows the same pattern: an annotation or configuration marks join points, an advisor (pointcut + interceptor) matches them, and a proxy created by a BeanPostProcessor runs the interceptor around the call.

ConcernMarkerInterceptorEnabled by (Boot auto-configures)
Transactions@TransactionalTransactionInterceptor@EnableTransactionManagement
Caching@Cacheable etc.CacheInterceptor@EnableCaching
Method security@PreAuthorize etc.AuthorizationManagerBeforeMethodInterceptor@EnableMethodSecurity
Async@AsyncAnnotationAsyncExecutionInterceptor@EnableAsync
Metrics/tracing@Timed, @ObservedTimedAspect, ObservedAspectAspect beans + AOP
Retry (Framework 7)@RetryableRetry interceptor@EnableResilientMethods
Table 3 — Concerns implemented as interceptors

Web-layer concerns (authentication, CORS, request logging) are usually applied earlier by servlet filters or WebFlux WebFilters — also interception, but at the HTTP boundary rather than on beans.

4ADeep Dive — Choosing the Interception Layer

A concern can be applied at several layers. Choosing the right one avoids duplicate processing and gaps.

LayerMechanismSeesGood for
HTTP boundaryServlet Filter, WebFilter, HandlerInterceptorRequest/response, headers, userAuthentication, CORS, request logging, rate limiting
Service methodsAOP proxies (@Transactional, @PreAuthorize, aspects)Method, arguments, return valueTransactions, authorisation rules on domain operations, caching, metrics per use case
Data accessRepository proxies, Hibernate interceptors, entity listenersEntities, SQLEntity auditing, soft-delete filters, exception translation
MessagingListener container interceptors, ChannelInterceptorMessagesTracing propagation, deduplication
InfrastructureMicrometer instrumentation, JDBC proxiesConnections, callsLow-level metrics, slow-query logs
Table 4 — Where a concern can be applied
JAVA
// Service layer: one aspect applies an audit policy to all annotated operations
@Target(METHOD) @Retention(RUNTIME)
public @interface Audited { String action(); }
 
@Aspect @Component
class AuditAspect {
    private final AuditTrail trail;
    AuditAspect(AuditTrail trail) { this.trail = trail; }
 
    @AfterReturning("@annotation(audited)")
    void record(JoinPoint jp, Audited audited) {
        trail.record(audited.action(), currentUser(), jp.getArgs());
    }
}

5APIs / Features / Syntax

ConcernKey annotations / APIs
Logging/tracing@Observed, ObservationRegistry, MDC, Logback/Log4j2 patterns
Security@PreAuthorize, @PostAuthorize, @Secured, SecurityFilterChain
Transactions@Transactional, TransactionTemplate, PlatformTransactionManager
Auditing@CreatedBy, @LastModifiedBy, @CreatedDate, AuditorAware, custom aspects
Metrics@Timed, @Counted, MeterRegistry, Actuator /metrics
Caching@Cacheable, @CachePut, @CacheEvict, @Caching, CacheManager
Table 5 — APIs per concern

6Practical Examples

6.1 One method, five concerns, zero infrastructure code

JAVA
@Service
class TransferService {
    @Transactional
    @PreAuthorize("hasAuthority('transfers:write')")
    @Observed(name = "transfer.execute")
    @Audited(action = "TRANSFER")
    @CacheEvict(cacheNames = "balances", key = "#cmd.from")
    public TransferId execute(TransferCommand cmd) {
        return ledger.move(cmd.from(), cmd.to(), cmd.amount());   // pure business logic
    }
}

6.2 Checking which concerns were applied

JAVA
Advised advised = (Advised) ctx.getBean(TransferService.class);   // it is a proxy
for (Advisor a : advised.getAdvisors()) {
    log.info("advisor: {}", a.getAdvice().getClass().getSimpleName());
}
// TransactionInterceptor, AuthorizationManagerBeforeMethodInterceptor, ...

7Common Problems & Mistakes

  • Treating a cross-cutting concern as business logic. Scattered audit code drifts; declare policy once.
  • Treating business logic as cross-cutting. Discount rules implemented as an "aspect" hide essential behaviour.
  • Applying authorisation only at the web layer. Non-HTTP entry points bypass it.
  • Double application. The same metric recorded by auto-instrumentation and a custom aspect.
  • Forgetting that interception needs proxies. Self-invocation and private methods skip concerns (Chapter 3).

8Performance & Production Considerations

ConcernCost profileGuidance
LoggingI/O-boundStructured, sampled, async appenders; avoid logging large arguments
SecurityExpression evaluation per callKeep SpEL simple; cache authorisation data
TransactionsConnection hold timeKeep transactions short (Chapter 5)
MetricsLow; tag cardinality mattersAvoid user IDs or URLs with IDs as tags
CachingMemory, stalenessBounded caches, TTLs, eviction on writes
AuditingExtra writesWrite in the same transaction or via outbox
Table 6 — Production cost of concerns

9Architecture & Design Considerations

  • Concerns are platform capabilities. Deliver them as starters and conventions so every service applies them identically.
  • Declarative over programmatic. Annotations or configuration express policy; code expresses business.
  • Visible policies. Keep a catalogue of the organisation's cross-cutting policies and where each is enforced.
  • Concerns across services — tracing propagation, authentication tokens, idempotency — need the same uniformity at the network level (service mesh, gateways, shared libraries).

10Interview Questions & Answers

Q1Basic

What is a cross-cutting concern?

A cross-cutting concern is behaviour that many parts of a system need, but that is not the main purpose of any of them. Logging, security checks, transaction management, auditing, metrics, tracing and caching are typical examples. If each class implements them by hand, the same code is duplicated across the system and mixed into business methods, which makes both harder to change. For example, changing the audit format would mean editing hundreds of methods. Frameworks such as Spring let you declare these concerns once and apply them consistently, so business code stays focused on business rules and policies can change in one place.

Q2 · [Basic] · Give examples of cross-cutting concerns handled by Spring annotations.
Answer: Spring offers annotations for most common cross-cutting concerns. @Transactional manages database transactions around a method. @PreAuthorize and @PostAuthorize enforce method-level security rules. @Cacheable, @CachePut and @CacheEvict add caching. @Timed and @Observed, from Micrometer, record metrics and traces. @Async runs a method on another thread, and @Retryable retries failed calls. @Validated triggers bean validation of method arguments. Each annotation declares the policy where it applies, while the implementation lives in infrastructure code shared by the whole application. For example, a payment method can be transactional, secured and timed with three annotations and no extra code.
Q3Intermediate

How does Spring apply these annotations at runtime?

At start-up, Spring's bean post-processors inspect each bean. If a bean has methods annotated with, for example, @Transactional or @Cacheable, Spring wraps it in a proxy, either a JDK dynamic proxy for interfaces or a CGLIB subclass, and injects that proxy wherever the bean is used. The proxy holds a chain of interceptors, also called advice. When a caller invokes a method through the proxy, the interceptors run in order, starting a transaction or checking a cache, then call the real method, and finally commit, roll back or store the result. Calls from inside the same object bypass the proxy.

Q4Intermediate

Is authentication a cross-cutting concern at the service layer?

Authentication, establishing who the caller is, is normally handled once at the boundary, for example by Spring Security's filters for HTTP requests or by the messaging infrastructure for messages, so it is not a service-layer concern. Authorisation, deciding whether that caller may perform a specific operation, is a cross-cutting concern that should also be enforced at the service layer. Services can be invoked from several entry points, such as REST controllers, message listeners, scheduled jobs and batch processes, and only some pass through web security. Annotations such as @PreAuthorize on service methods protect business operations whatever the entry point.

Q5Senior Engineer

How do you decide whether something should be an aspect?

Ask two questions. First, is it a uniform policy that should apply the same way to many methods, such as starting a transaction, recording a metric or writing an audit entry? Second, is it independent of the business purpose of those methods? If both answers are yes, an aspect or annotation-driven interceptor fits well. If the behaviour contains business rules, varies by use case, or needs detailed knowledge of the method's data, it belongs in domain or application code, where it is visible and testable. A useful warning sign is an aspect that inspects arguments to decide what to do; that is usually business logic hiding in infrastructure.

Q6Senior Engineer

What layers can a concern be applied at in a Spring application?

A concern can be applied at several layers, and the right one depends on what information it needs. At the HTTP boundary, servlet filters and handler interceptors see requests and responses, which suits authentication, correlation IDs and request logging. At the service layer, AOP proxies see business method calls and arguments, which suits transactions, method security and auditing of business actions. At the data-access layer, repository interceptors and JPA entity listeners suit auditing of changes. Messaging interceptors handle the same needs for message flows, and infrastructure instrumentation such as Micrometer and OpenTelemetry covers metrics and tracing across all of them.

Q7Technical Architect

How would you ensure consistent auditing across fifty services?

Make auditing a platform capability rather than something each team builds. Publish an internal Spring Boot starter that provides a standard @Audited annotation or domain-event mechanism, a shared audit event schema with fields such as actor, action, target, outcome and correlation ID, and a reliable delivery path, typically a transactional outbox feeding a central audit store. Teams add the starter and annotate business actions; the starter handles formatting, delivery and retries. Enforce adoption with architecture tests and pipeline checks, review audit coverage during design reviews, and version the schema carefully, because auditors and compliance tools will depend on it for years.

Q8Solution Architect

How do cross-cutting concerns influence the platform strategy?

Cross-cutting concerns are where consistency matters most, so they should be delivered as platform capabilities rather than reimplemented by every team. Internal Spring Boot starters can provide security, logging, metrics, tracing and auditing defaults; API gateways can handle authentication, rate limiting and TLS at the edge; a service mesh can provide mutual TLS and retries between services; and a shared observability stack collects the results. This reduces each team's effort, makes behaviour consistent across services and lets policies, such as a new logging format or security rule, change centrally. Teams still own business concerns, while the platform owns the cross-cutting ones.

Newsletter

Get new tutorials every week

New ArchitectMind tutorials and interview questions, once a week. No spam, unsubscribe anytime.

Almost done! Check your inbox and click the confirmation link to complete your subscription.
Keep going in Book 4

Spring & Spring Boot

Volume I · Topic 1.1

Why Spring Exists

Spring Core, IoC & Dependency Injection

Volume I · Topic 1.2

Spring Framework Architecture

Spring Core, IoC & Dependency Injection

Volume I · Topic 1.3

Spring Modules

Spring Core, IoC & Dependency Injection

Volume II · Topic 1.2

Why Cross-Cutting Concerns Are Difficult

Spring AOP, Proxies, Events & Transactions

Volume II · Topic 1.3

Aspect-Oriented Programming

Spring AOP, Proxies, Events & Transactions

Volume III · Topic 1.1

Why Spring Boot Exists

Spring Boot, Configuration & Application Lifecycle

Volume III · Topic 1.2

Spring Boot Architecture

Spring Boot, Configuration & Application Lifecycle

Volume III · Topic 1.3

Spring Boot vs Spring Framework

Spring Boot, Configuration & Application Lifecycle

Volume IV · Topic 1.1

MVC

Spring MVC, REST & Web Applications

Volume IV · Topic 1.2

DispatcherServlet

Spring MVC, REST & Web Applications

Volume IV · Topic 1.3

MVC Request Lifecycle

Spring MVC, REST & Web Applications

Volume V · Topic 1.1

Repository Abstraction

Spring Data, JPA & Persistence

Volume V · Topic 1.2

Spring Data Architecture

Spring Data, JPA & Persistence

Volume V · Topic 1.3

Repository Types

Spring Data, JPA & Persistence

Volume VI · Topic 1.1

Security Architecture

Spring Security, OAuth2 & Identity

Volume VI · Topic 1.2

Security Filter Chain

Spring Security, OAuth2 & Identity

Volume VI · Topic 1.3

Security Context

Spring Security, OAuth2 & Identity

Volume VII · Topic 1.1

Enterprise Integration

Spring Integration, Testing & Cloud-Native Development

Volume VII · Topic 1.2

Integration Patterns

Spring Integration, Testing & Cloud-Native Development

Volume VII · Topic 1.3

Messaging Systems

Spring Integration, Testing & Cloud-Native Development