高并发Spring应用中,如何强制使用CglibAopProxy$DynamicUnadvisedInterceptor优化性能?
最佳优化方案(无需覆盖Spring核心类)
针对你遇到的高并发Spring Web应用中代理带来的性能瓶颈,核心问题在于请求作用域Bean的默认代理会强制绑定一个Advisor,导致Spring使用DynamicAdvisedInterceptor而非更轻量的DynamicUnadvisedInterceptor,进而引发ConcurrentHashMap竞争和高CPU开销。以下是无需修改Spring核心类的可行方案:
方案一:自定义无通知的作用域代理FactoryBean
既然默认ScopedProxyFactoryBean会给代理添加ScopedObjectAdvisor,我们可以直接实现一个跳过Advisor绑定的自定义FactoryBean,让代理自动使用DynamicUnadvisedInterceptor:
实现步骤
- 编写自定义FactoryBean,继承
ScopedProxyFactoryBean并重写代理创建逻辑:
import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.scope.ScopedProxyFactoryBean; public class NoAdviceScopedProxyFactoryBean extends ScopedProxyFactoryBean { @Override protected Object createProxy(ClassLoader classLoader, Object[] interfaces) { ProxyFactory proxyFactory = new ProxyFactory(); // 保留作用域代理的核心目标源逻辑 proxyFactory.setTargetSource(getTargetSource()); // 保留接口配置(适配有接口的Bean) proxyFactory.setInterfaces(interfaces); // 强制使用CGLIB代理(适配无接口的Bean) proxyFactory.setProxyTargetClass(true); // 关键:不添加任何Advisor,让Spring自动使用无通知拦截器 return proxyFactory.getProxy(classLoader); } }
- 替换默认的作用域代理配置:
- XML配置场景:替换
<aop:scoped-proxy/>为自定义FactoryBean:<bean id="requestScopedBean" class="com.yourpackage.YourRequestScopedBean" scope="request"> <property name="someProperty" value="someValue"/> </bean> <bean class="com.yourpackage.NoAdviceScopedProxyFactoryBean"> <property name="targetBeanName" value="requestScopedBean"/> </bean> - 注解配置场景:通过自定义FactoryBean创建代理,关闭默认代理模式:
@Bean public NoAdviceScopedProxyFactoryBean requestScopedBeanProxy() { NoAdviceScopedProxyFactoryBean factoryBean = new NoAdviceScopedProxyFactoryBean(); factoryBean.setTargetBeanName("innerRequestScopedBean"); return factoryBean; } @Bean @Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.NO) public YourRequestScopedBean innerRequestScopedBean() { return new YourRequestScopedBean(); }
- XML配置场景:替换
方案二:全局替换AopProxyFactory(适用于所有无通知代理场景)
如果你的应用中所有代理Bean都没有业务通知,可通过自定义AopProxyFactory全局控制代理使用的拦截器:
实现步骤
- 实现自定义
AopProxyFactory,继承DefaultAopProxyFactory,针对无Advisor的场景返回轻量代理:
import org.springframework.aop.framework.AdvisedSupport; import org.springframework.aop.framework.DefaultAopProxyFactory; import org.springframework.aop.framework.aopalliance.AopProxy; public class NoAdviceAopProxyFactory extends DefaultAopProxyFactory { @Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { // 无Advisor且使用CGLIB代理时,返回自定义轻量代理 if (config.getAdvisors().length == 0 && config.isProxyTargetClass()) { return new NoAdviceCglibAopProxy(config); } return super.createAopProxy(config); } }
- 实现简化版无通知CGLIB代理(参考Spring原生
CglibAopProxy逻辑,仅保留无通知拦截器):
import org.springframework.aop.framework.AdvisedSupport; import org.springframework.aop.framework.CglibAopProxy; import org.springframework.aop.framework.DynamicUnadvisedInterceptor; import org.springframework.cglib.proxy.Callback; public class NoAdviceCglibAopProxy extends CglibAopProxy { public NoAdviceCglibAopProxy(AdvisedSupport config) { super(config); } @Override protected Callback[] getCallbacks() { // 仅返回无通知拦截器,跳过所有通知逻辑 return new Callback[]{ new DynamicUnadvisedInterceptor(this.advised), new SerializableNoOp() }; } }
- 在Spring上下文初始化时替换默认工厂:
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory; public class CustomApplicationContext extends AnnotationConfigApplicationContext { @Override protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { super.postProcessBeanFactory(beanFactory); // 全局设置自定义AopProxyFactory ((DefaultListableBeanFactory) beanFactory).setAopProxyFactory(new NoAdviceAopProxyFactory()); } }
方案选择建议
- 若性能瓶颈仅来自请求作用域Bean的代理,优先选方案一:针对性强,轻量且不会影响其他代理场景。
- 若应用中所有代理都不需要通知,可选择方案二:实现全局统一优化。
验证注意事项
- 测试需确认作用域Bean的代理逻辑正常(比如请求作用域Bean是否每次请求都能获取新实例)。
- 压测对比优化前后的CPU使用率和延迟,确保达到预期性能提升。
内容的提问来源于stack exchange,提问作者John Engebretson
相关产品推荐
相关产品推荐

