
本文介绍如何利用 Spring AOP 和 @Bean 条件注册机制,为标注自定义注解的接口实现类动态生成两种代理行为(原始逻辑 or 空占位),并支持运行时条件切换。
本文介绍如何利用 spring aop 和 `@bean` 条件注册机制,为标注自定义注解的接口实现类动态生成两种代理行为(原始逻辑 or 空占位),并支持运行时条件切换。
在 Spring 生态中,单纯依赖 @Before 或 @Around 切面无法直接“替换目标 Bean 实例”——切面作用于方法调用链,而非 Bean 创建过程。因此,真正实现「按条件返回不同实现类的代理对象」,应结合 Spring 的 Bean 生命周期控制 + 动态代理(JDK Proxy)或 @Conditional + 工厂模式,而非仅靠 AOP 通知。
下面提供一种生产就绪、清晰可控、符合 Spring 最佳实践的解决方案:
✅ 推荐方案:基于 @Conditional + FactoryBean + JDK 动态代理
1. 定义自定义注解与接口
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomProxy {}public interface MyService {
void doSomething();
}2. 提供两个具体实现(原始版 & 占位版)
@CustomProxy
public class OriginalService implements MyService {
@Override
public void doSomething() {
System.out.println("✅ Executing original business logic");
}
}
public class PlaceholderService implements MyService {
@Override
public void doSomething() {
System.out.println("⚠️ Placeholder: no-op");
}
}3. 构建条件感知的代理工厂 Bean
@Component
public class MyServiceProxyFactory implements FactoryBean<MyService> {
private final OriginalService original;
private final PlaceholderService placeholder;
private final Environment env;
public MyServiceProxyFactory(OriginalService original,
PlaceholderService placeholder,
Environment env) {
this.original = original;
this.placeholder = placeholder;
this.env = env;
}
@Override
public MyService getObject() throws Exception {
// ✅ 核心条件判断:可来自配置、Feature Flag、Profile、HTTP Header 等
boolean useOriginal = env.getProperty("my.service.use-original", Boolean.class, true);
MyService target = useOriginal ? original : placeholder;
// 使用 JDK 动态代理增强(可选:添加日志、监控等横切逻辑)
return (MyService) Proxy.newProxyInstance(
MyService.class.getClassLoader(),
new Class[]{MyService.class},
(proxy, method, args) -> {
System.out.printf("[Proxy] Calling %s on %s%n",
method.getName(), useOriginal ? "OriginalService" : "PlaceholderService");
return method.invoke(target, args);
}
);
}
@Override
public Class<?> getObjectType() {
return MyService.class;
}
@Override
public boolean isSingleton() {
return true;
}
}4. 启用配置驱动(application.yml)
my:
service:
use-original: "${MY_SERVICE_USE_ORIGINAL:true}" # 支持环境变量覆盖✅ 优势说明:
- 代理对象在容器启动时即完成条件判定与创建,避免运行时重复判断;
FactoryBean天然支持返回任意代理实例,且对注入方完全透明;- 可无缝集成 Spring 表达式(如
@Value("#{systemProperties['env'] == 'prod'}"));- 若需更细粒度控制(如按请求上下文切换),可将条件逻辑移至
getObject()内部,结合RequestContextHolder实现。
⚠️ 注意事项
- ❌ 不要试图在
@Before切面中“返回代理对象”——AOP 通知无权改变目标 Bean 引用; - ❌ 避免手动调用
AopContext.currentProxy()在非代理方法中获取代理,易引发AopConfigException; - ✅ 如需面向多个接口复用该模式,可抽象为泛型
ConditionalProxyFactory<t></t>并配合@Qualifier区分; - ✅ 生产环境建议配合
@ConditionalOnProperty或自定义Condition类提升可测试性与可维护性。
通过该设计,你获得的 MyService Bean 始终是满足当前条件的代理实例,既保持接口契约一致性,又实现逻辑路径的灵活编排——这才是 Spring 条件化代理的正确打开方式。

















