Step‑by‑Step Guide to Spring AOP: Proxy Patterns, Static and Dynamic Proxies, and Practical Implementation
This article explains the fundamentals of Spring AOP by introducing proxy patterns, demonstrating static and dynamic proxy implementations with full Java code examples, and showing how Spring integrates JDK and CGLIB proxies through XML configuration for real‑world cross‑cutting concerns such as transactions and logging.
The article continues a previous Spring source‑code analysis and introduces Aspect‑Oriented Programming (AOP) to solve cross‑cutting concerns like logging, transaction management, and security that are difficult to handle with pure OOP.
1. Proxy Pattern
A proxy provides a surrogate object that controls access to the real object, adding behavior before or after the original method execution.
2. Static Proxy Principle and Practice
Static proxies are compiled beforehand; the proxy class implements the same interface as the target class. The following Java code demonstrates a static proxy for IUserDao:
package test.staticProxy;
public interface IUserDao {
void save();
void find();
}
// Target object
class UserDao implements IUserDao {
@Override
public void save() {
System.out.println("模拟:保存用户!");
}
@Override
public void find() {
System.out.println("模拟:查询用户");
}
}
/**
* 静态代理
* 1. 目标对象必须实现接口
* 2. 代理对象也必须实现相同接口
*/
class UserDaoProxy implements IUserDao {
private IUserDao target = new UserDao();
@Override
public void save() {
System.out.println("代理操作: 开启事务...");
target.save();
System.out.println("代理操作:提交事务...");
}
@Override
public void find() {
target.find();
}
}Static proxies reduce duplicated code but require a proxy class for each method and interface.
3. Dynamic Proxy Principle and Practice
Dynamic proxies generate proxy classes at runtime using reflection. The example below shows a JDK dynamic proxy factory:
package test.dynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public interface IUserDao {
void save();
void find();
}
// Target object
class UserDao implements IUserDao {
@Override
public void save() {
System.out.println("模拟: 保存用户!");
}
@Override
public void find() {
System.out.println("查询");
}
}
/**
* 动态代理:
* 代理工厂,给多个目标对象生成代理对象!
*/
class ProxyFactory {
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
public Object getProxyInstance() {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
Object result = null;
if ("find".equals(methodName)) {
result = method.invoke(target, args);
} else {
System.out.println("开启事务...");
result = method.invoke(target, args);
System.out.println("提交事务...");
}
return result;
}
}
);
}
}
// Usage example
IUserDao proxy = (IUserDao) new ProxyFactory(new UserDao()).getProxyInstance();Dynamic proxies eliminate the need for a separate proxy class per method and work for any interface‑based target.
4. Spring AOP Principle and Practice
Spring integrates both JDK and CGLIB proxies. When a bean implements an interface, Spring uses JDK dynamic proxies; otherwise it falls back to CGLIB subclass proxies (which cannot proxy final classes).
The following XML configuration demonstrates how to declare a pointcut and associate various advice types (around, before, after, after‑returning, after‑throwing) with a TransactionAop aspect:
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- DAO beans -->
<bean id="userDao" class="test.spring_aop_anno.UserDao"/>
<bean id="orderDao" class="test.spring_aop_anno.OrderDao"/>
<!-- Aspect bean -->
<bean id="transactionAop" class="test.spring_aop_anno.TransactionAop"/>
<!-- AOP configuration -->
<aop:config>
<!-- Pointcut definition -->
<aop:pointcut expression="execution(* test.spring_aop_anno.*Dao.*(..))" id="transactionPointcut"/>
<!-- Aspect definition -->
<aop:aspect ref="transactionAop">
<aop:around method="arroud" pointcut-ref="transactionPointcut"/>
<aop:before method="beginTransaction" pointcut-ref="transactionPointcut"/>
<aop:after method="commit" pointcut-ref="transactionPointcut"/>
<aop:after-returning method="afterReturing" pointcut-ref="transactionPointcut"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="transactionPointcut"/>
</aop:aspect>
</aop:config>
</beans>The article concludes with typical use cases for Spring AOP such as declarative transaction management, controller parameter validation, read/write splitting for MySQL, permission checks, logging, and alert notifications.
Spring AOP enables developers to modularize cross‑cutting concerns, making code cleaner, more maintainable, and easier to extend.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Captain
Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
