Spring AOP and Conditional Bean Creation Guide
Environment Configuration Without Profiles
Section titled “Environment Configuration Without Profiles”Alternatives to @Profile for enabling/disabling beans:
Conditional Beans
Section titled “Conditional Beans”@Bean@ConditionalOnProperty(name="feature.payment.enabled", havingValue="true")public PaymentService paymentService() { return new PaymentService();}Other Alternatives
Section titled “Other Alternatives”- Feature flags
- Environment variables
- Spring Cloud Config
@Profile vs @ConditionalOnXXX
Section titled “@Profile vs @ConditionalOnXXX”| Feature | @Profile |
@ConditionalOnXXX |
|---|---|---|
| Purpose | Environment-based bean creation | Conditional bean creation |
| Based on | Active profile | Property, class, bean, resource, expression |
| Flexibility | Limited | Highly flexible |
| Typical Use | dev/test/prod | Feature toggles and auto-configuration |
Examples:
@Profile("dev")@ConditionalOnPropertyAspect-Oriented Programming (AOP)
Section titled “Aspect-Oriented Programming (AOP)”AOP separates cross-cutting concerns from business logic.
Common use cases:
- Logging
- Security
- Transactions
- Auditing
- Performance monitoring
Core Concepts
Section titled “Core Concepts”Join Point
Section titled “Join Point”A point during execution, such as a method execution.
Pointcut
Section titled “Pointcut”An expression selecting join points.
@Pointcut("execution(* com.service.*.*(..))")Advice Types
Section titled “Advice Types”| Advice | Execution Time |
|---|---|
@Before |
Before method execution |
@After |
After method execution |
@AfterReturning |
After successful completion |
@AfterThrowing |
When an exception occurs |
@Around |
Before and after execution |
AOP Execution Flow
Section titled “AOP Execution Flow”flowchart LR A[Caller] --> B[AOP Proxy] B --> C["@Before"] C --> D["@Around Before"] D --> E[Target Method] E --> F["@AfterReturning / @AfterThrowing"] F --> G["@After"] G --> H[Caller]
Performance Monitoring with AOP
Section titled “Performance Monitoring with AOP”Advice methods live inside a class marked @Aspect (and @Component, so Spring registers it as a bean):
@Aspect@Componentpublic class LoggingAspect {
@Around("execution(* com.service.*.*(..))") public Object measureTime(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed();
long end = System.currentTimeMillis();
log.info("Execution time: {}", end - start);
return result; }}Multiple aspects can target the same service independently:
flowchart LR Client --> Service LoggingAspect --> Service SecurityAspect --> Service TransactionAspect --> Service
Logging Request and Response with AOP
Section titled “Logging Request and Response with AOP”@Around("@annotation(Loggable)")public Object logMethod(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("Request: {}", Arrays.toString(joinPoint.getArgs()));
Object response = joinPoint.proceed();
log.info("Response: {}", response);
return response;}This pattern is commonly used for request/response logging, audit logging, API tracing, and performance monitoring — without duplicating that logic inside every service method.
Key Takeaways
Section titled “Key Takeaways”- Prefer
@ConditionalOnXXXover@Profilewhen the decision is a feature toggle rather than a dev/test/prod environment split — it’s driven by properties, classpath, or other beans instead of a fixed profile name. - AOP terminology: a Join Point is a point in execution (e.g. a method call), a Pointcut is an expression selecting which join points to intercept, and Advice is the code that runs at those join points.
@Aroundis the most powerful advice type — it can run code both before and after the target method, and controls whether the method executes at all viajoinPoint.proceed().- Use AOP for cross-cutting concerns (logging, performance timing, auditing) instead of duplicating that code inside every method it applies to — this is also how Spring implements
@Transactionaland@Cacheableinternally.