Backend Development 7 min read

Mastering Spring AOP: From @Aspect to ProxyFactoryBean and ProxyFactory

This guide explains how to define Spring AOP aspects with @Aspect, configure ProxyFactoryBean for fine‑grained proxy control, and create proxies programmatically using ProxyFactory, providing complete code examples and configuration details for Spring 6.1.2.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Mastering Spring AOP: From @Aspect to ProxyFactoryBean and ProxyFactory

In Spring 6.1.2, the @Aspect annotation is used to define aspects and create AOP proxies for modularizing cross‑cutting concerns.

1. Defining an Aspect with @Aspect

<code>@Aspect
public class LogAspect {
    // Pointcut definition
    @Pointcut("execution(* com.pack..*.*(..))")
    public void log() {}

    // Before advice
    @Before("log()")
    public void beforeLog() {
        System.out.println("记录日志Before...");
    }

    // After advice
    @After("log()")
    public void afterLog() {
        System.out.println("记录日志After");
    }

    // After throwing advice
    @AfterThrowing(pointcut = "log()", throwing = "tx")
    public void ex(Throwable tx) {
        System.err.println("发生异常: " + tx.getMessage());
    }

    // Around advice
    @Around("log() && args(name)")
    public Object around(ProceedingJoinPoint pjp, String name) throws Throwable {
        System.out.println("log before...");
        System.out.println("name = " + name);
        Object ret = pjp.proceed();
        System.out.println("log after...");
        return ret;
    }
}
</code>

The aspect above demonstrates pointcut definition and four types of advice: before, after, after‑throwing, and around.

2. Creating Proxy Objects

2.1 ProxyFactoryBean

ProxyFactoryBean provides full control over pointcuts, advisors, and their order. It acts as a FactoryBean that returns the actual proxy from its getObject() method.

<code>ProxyFactoryBean proxy = new ProxyFactoryBean();
// Whether to create a CGLIB proxy instead of an interface‑based proxy
proxy.setProxyTargetClass(false);
// Optimize CGLIB proxy (should be used only when fully understood)
proxy.setOptimize(false);
// Freeze configuration to prevent further changes
proxy.setFrozen(false);
// Expose the proxy in a ThreadLocal for target access
proxy.setExposeProxy(false);
// Interfaces to proxy (empty means use CGLIB on the target class)
proxy.setProxyInterfaces(new Class<?>[] {});
// Names of interceptors/advisors to apply
proxy.setInterceptorNames("interceptor01");
// Whether the bean should be a singleton
proxy.setSingleton(true);
</code>

Example usage with a DAO interface, a service class, and a configuration that registers a logging interceptor and the ProxyFactoryBean.

<code>public interface CommonDAO {}

public class PersonService {
    public void save() {
        System.out.println("save method invoke...");
    }
}

@Configuration
public class AppConfig {
    @Bean
    public MethodInterceptor logInterceptor() {
        return new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("日志记录...");
                return invocation.proceed();
            }
        };
    }

    @Bean
    public ProxyFactoryBean personService() throws Exception {
        ProxyFactoryBean proxy = new ProxyFactoryBean();
        proxy.setProxyTargetClass(true);
        proxy.setTargetSource(new SingletonTargetSource(new PersonService()));
        proxy.setProxyInterfaces(new Class<?>[] {CommonDAO.class});
        proxy.setInterceptorNames("logInterceptor");
        return proxy;
    }
}
</code>

2.2 ProxyFactory

ProxyFactory allows programmatic creation of AOP proxies without relying on the Spring IoC container.

<code>public interface CommonDAO {}

public class PersonService {
    public void save() {
        System.out.println("save method invoke...");
    }
}

public static void main(String[] args) {
    ProxyFactory factory = new ProxyFactory(new PersonService());
    factory.setProxyTargetClass(true);
    // Add a logging advice
    factory.addAdvice(new MethodInterceptor() {
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            System.out.println("日志记录...");
            return invocation.proceed();
        }
    });
    // Add an advisor that matches the "save" method
    factory.addAdvisor(new PointcutAdvisor() {
        @Override
        public Advice getAdvice() {
            return new MethodInterceptor() {
                @Override
                public Object invoke(MethodInvocation invocation) throws Throwable {
                    System.out.println("权限控制...");
                    return invocation.proceed();
                }
            };
        }
        @Override
        public Pointcut getPointcut() {
            return new StaticMethodMatcherPointcut() {
                @Override
                public boolean matches(Method method, Class<?> targetClass) {
                    return method.getName().equals("save");
                }
            };
        }
    });
    PersonService ps = (PersonService) factory.getProxy();
    ps.save();
}
</code>

The article concludes with the complete code examples and encourages readers to apply these techniques in their projects.

JavaAOPSpringProxyFactoryBeanProxyFactory
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

login 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.