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.

Java Captain
Java Captain
Java Captain
Step‑by‑Step Guide to Spring AOP: Proxy Patterns, Static and Dynamic Proxies, and Practical Implementation

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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackendJavaProxyaopspringDynamic Proxycglib
Java Captain
Written by

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.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.