What is Spring's ProxyFactory and how do you use it to create an AOP proxy programmatically?
answer
- setTarget -> addAdvice -> getProxy
- extends AdvisedSupport, implements Advised
- JDK proxy if interfaces, else CGLIB
- cast to interface not concrete class
- same engine as container auto-proxy
basics
~20 sProxyFactory is a Spring class that builds an AOP proxy in plain code (no Spring container). You give it a target object, add one or more advices, then call getProxy() to get a wrapped object that runs the advice around the target's methods.
solid answer
~40 sProxyFactory is Spring AOP's programmatic entry point for building a proxy without a Spring context. You set a target object with setTarget(), attach behavior with addAdvice() (or addAdvisor() for advice plus a pointcut), optionally declare setInterfaces() or setProxyTargetClass(true), then call getProxy() which returns an Object you cast to your interface. Calls to the returned proxy pass through the advisor chain before hitting the target. Under the hood it decides between a JDK dynamic proxy (if the target exposes interfaces) and a CGLIB subclass proxy. It is the same machinery Spring uses internally when it auto-proxies your beans; ProxyFactory just exposes it for standalone use, tests, or library code that needs to wrap an object by hand.
code
java · 17 linespublic interface Greeter { String hello(String name); }
public class GreeterImpl implements Greeter {
public String hello(String name) { return "Hi " + name; }
}
// Build a proxy programmatically
ProxyFactory pf = new ProxyFactory(new GreeterImpl());
pf.addAdvice((MethodInterceptor) invocation -> {
System.out.println("before " + invocation.getMethod().getName());
Object result = invocation.proceed(); // call the target
System.out.println("after");
return result;
});
Greeter proxy = (Greeter) pf.getProxy(); // cast to the INTERFACE
proxy.hello("Ada"); // prints before/after around "Hi Ada"go deeper
Know the three steps: target, advice, getProxy(); and that the result is cast to the interface.
Explain JDK vs CGLIB selection and the addAdvice-vs-addAdvisor distinction.
Connect ProxyFactory to the same AdvisedSupport machinery the container's auto-proxy creator uses; discuss exposeProxy/self-invocation.
Reason about when hand-rolled proxies belong in library code vs. relying on container auto-proxying, and the maintenance cost of each.
**What it is.** `org.springframework.aop.framework.ProxyFactory` is the programmatic (code-driven) way to create a Spring AOP proxy, as opposed to the declarative auto-proxying the container does for you when you use `@Aspect`/`@EnableAspectJAutoProxy`. A *proxy* here is an object that looks like your target (same interfaces or a subclass of its type) but intercepts method calls so extra behavior (*advice*) can run before/after/around the real call. **Class hierarchy.** `ProxyFactory` extends `ProxyCreatorSupport`, which extends `AdvisedSupport`, which extends `ProxyConfig` and implements the `Advised` interface. That means a `ProxyFactory` *is* an `Advised` config object holding the target, the interfaces, the advisor chain, and flags like `proxyTargetClass`, `exposeProxy`, `frozen`. **Core steps / API.** 1. `new ProxyFactory(targetObject)` or `new ProxyFactory()` then `setTarget(target)`. 2. Add behavior: `addAdvice(Advice)` — e.g. a `MethodInterceptor` — which Spring wraps in a `DefaultPointcutAdvisor` matching all methods; or `addAdvisor(Advisor)` when you want a `Pointcut` to limit which methods are advised. 3. Optional config: `setInterfaces(...)` to force which interfaces the proxy exposes; `setProxyTargetClass(true)` to force a CGLIB class-based proxy; `setExposeProxy(true)` to publish the proxy via `AopContext.currentProxy()`. 4. `getProxy()` (or `getProxy(ClassLoader)`) returns the proxy as `Object`; cast to your interface/class. **Advice types you can add.** `MethodInterceptor` (AOP Alliance, around advice), `MethodBeforeAdvice`, `AfterReturningAdvice`, `ThrowsAdvice`. Around advice must call `invocation.proceed()` to continue the chain and reach the target. **JDK vs CGLIB choice.** If the target implements at least one interface and `proxyTargetClass` is false (default), you get a JDK dynamic proxy implementing those interfaces — so you must cast the result to the *interface*, not the concrete class. If the target has no interfaces, or `proxyTargetClass=true`, Spring uses CGLIB to generate a runtime subclass, so `final` classes/methods can't be proxied and a no-arg-constructor-free class still works because CGLIB uses Objenesis. **When to use it.** Standalone/library code that needs to wrap an object outside a Spring context; tests that verify an interceptor; frameworks building decorators dynamically. In ordinary application code you rarely call it directly — the container's auto-proxy infrastructure (`AnnotationAwareAspectJAutoProxyCreator`) uses the same `AdvisedSupport`/`ProxyFactory` machinery for you. **Gotchas.** (1) Casting a JDK-proxy to the concrete class throws `ClassCastException` — cast to the interface. (2) Self-invocation (target calling its own `this.method()`) bypasses the proxy unless you enable `exposeProxy` and call `AopContext.currentProxy()`. (3) `getProxy()` builds a fresh proxy each call reflecting the current advisor chain. (4) `AspectJProxyFactory` is the sibling that additionally lets you add whole `@Aspect` classes via `addAspect(...)`.
- Why must you cast the result of getProxy() to the interface and not GreeterImpl?Because with an interface-implementing target and default settings Spring creates a JDK dynamic proxy, which is a new class implementing Greeter but is NOT a subclass of GreeterImpl, so casting to the concrete class throws ClassCastException. Set proxyTargetClass(true) for a CGLIB subclass proxy if you need the concrete type.
- What's the difference between addAdvice() and addAdvisor()?addAdvice() takes just the behavior and Spring wraps it in a DefaultPointcutAdvisor with Pointcut.TRUE, so it applies to every method. addAdvisor() takes an Advisor = pointcut + advice, letting you restrict which methods are intercepted.
saying these in an interview costs you the question
- Thinking ProxyFactory requires a running Spring ApplicationContext
- Believing you can always cast the proxy to the concrete target class
- Confusing addAdvice (all methods) with a pointcut-scoped advisor