Configuring AOP Using XML in Spring
Spring supports aspect-oriented programming through both annotations and XML-based configuration. While annotation-driven AOP is more common in modern applications, XML configuration remains a viable and explicit alternative—especially in legacy or highly controlled enviroments.
1. Defining the Aspect Class
The aspect encapsulates cross-cutting concerns such as transaction management, logging, or security checks. Below is an example aspect class that implements five types of advice:
package org.example.aop;
import org.aspectj.lang.ProceedingJoinPoint;
public class TransactionAspect {
public void startTransaction() {
System.out.println("[Before] Starting transaction...");
}
public void completeTransaction() {
System.out.println("[After] Committing transaction...");
}
public void onSuccess() {
System.out.println("[AfterReturning] Operation succeeded.");
}
public void onException() {
System.out.println("[AfterThrowing] An error occurred.");
}
public void wrapExecution(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("[Around] Before target method...");
joinPoint.proceed();
System.out.println("[Around] After target method...");
}
}
2. Declaring the Target Service Interface and Implementation
A simple service interface and its implementation serve as the target for advice injection:
package org.example.service;
public interface UserService {
void register();
void remove();
}
package org.example.service;
public class UserServiceImpl implements UserService {
@Override
public void register() {
System.out.println("[Core] Executing user registration.");
}
@Override
public void remove() {
System.out.println("[Core] Executing user deletion.");
}
}
3. Configuring AOP in applicationContext.xml
The XML configuration registers beans and defines pointcuts and advice bindings. Note how pointcut expressions can be reused via pointcut-ref, or declared inline:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="transactionAspect" class="org.example.aop.TransactionAspect" />
<bean id="userService" class="org.example.service.UserServiceImpl" />
<aop:config>
<!-- Reusable pointcut matching all methods in the service package -->
<aop:pointcut id="serviceMethods"
expression="execution(* org.example.service.*.*(..))" />
<aop:aspect ref="transactionAspect">
<aop:around method="wrapExecution" pointcut-ref="serviceMethods" />
<aop:before method="startTransaction" pointcut-ref="serviceMethods" />
<aop:after method="completeTransaction" pointcut-ref="serviceMethods" />
<aop:after-returning method="onSuccess" pointcut-ref="serviceMethods" />
<aop:after-throwing method="onException" pointcut-ref="serviceMethods" />
</aop:aspect>
</aop:config>
</beans>
4. Running the Configuration
To test the setup, load the context and invoke service methods:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.example.service.UserService;
public class AopXmlDemo {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService service = ctx.getBean(UserService.class);
service.register();
service.remove();
}
}
Expected output includes interleaved core logic and advice messages—demonstrating successful weaving.
5. Pointcut Expression Patterns
Pointcut expressions determine which join points are intercepted. Common patterns include:
execution(* *(..))— All methods in any class.execution(public * *(..))— All public methods.execution(* save*(..))— Methods starting with "save".execution(* org.example.service.UserService.register(..))— Exact method signature.execution(* org.example.service.*.*(..))— All methods inUserServiceand other classes in the package.execution(* org.example.service..*.*(..))— All methods inserviceand its subpackages.execution(* org.example.service.UserService.register(..)) || execution(* org.example.service.UserService.remove(..))— Logical OR.!execution(* org.example.service.UserService.remove(..))— Negation.
These expressions support fine-grained control over where advice applies, enabling modular and maintainable cross-cutting logic.