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