我正在使用 Spring 3 开发一个半大型应用程序,并且在同时处理数百个用户时遇到性能问题。我正在使用 Spring 的 AOP 代理来使用多个请求范围的 bean,并且我可以看到,每次我对其中一个 bean 调用任何方法时,都会调用 CGLIB 拦截器,然后调用 AbstractBeanFactory.getBean(),后者再调用 add()现有 Spring bean 的同步集。由于此 add() 是同步的,因此当有数千个调用都等待添加到同一列表时,它会有效地锁定服务器。
有没有办法使用请求范围的 bean 来解决这个问题?我在Spring文档中读到,如果bean实现任何接口(http://static.springsource.org/spring/docs/2.0.0/reference/aop.html#d0e9015),则不使用CGLIB,但我的请求范围bean所有人都实施了一种(实际上是同一种),而且这种情况仍在发生。我确实需要将这些 Bean 限定在请求范围内,因为它们的某些字段是在应用程序的某一部分针对特定请求计算的,然后我使用 SpEL 在同一请求期间在应用程序的不同部分获取它们的值。我想如果我将 beans 原型设置为作用域,那么当我第二次使用 SpEL 获取它们时,我就会得到一个新的对象。
这是说明我的问题的代码示例。请参阅最后两行评论,描述我到底遇到问题的地方。
<!-- Spring config -->
<bean name="someBean" class="some.custom.class.SomeClass" scope="request">
<property name="property1" value="value1"/>
<property name="property2" value="value2"/>
<aop:scoped-proxy/>
</bean>
<bean name="executingClass" class="some.other.custom.class.ExecutingClass" scope="singleton">
<property name="myBean" ref="someBean" />
</bean>
public Interface SomeInterface {
public String getProperty1();
public void setProperty1(String property);
public String getProperty2();
public void setProperty2(String property);
}
public class SomeClass implements SomeInterface {
private String property1;
private String property2;
public String getProperty1() { return propery1; }
public void setProperty1(String property) { property1=property;}
public String getProperty2() { return propery2; }
public void setProperty2(String property) { property2=property;}
}
public class ExecutingClass {
private SomeInterface myBean;
public void execute() {
String property = myBean.getProperty1(); // CGLIB interceptor is invoked here, registering myBean as a bean
String otherProperty = myBean.getProperty2(); // CGLIB interceptor is invoked here too! Seems like this is unnecessary. And it's killing my app.
}
}
我的想法是以下之一:
- 我可以在不代理对 bean 进行的每个方法调用的情况下发出范围限定的 Spring Bean 请求吗?并且不将每个方法标记为“最终”?
or...
- 我可以重写 Spring 的 bean 工厂来实现 Bean 缓存吗?该缓存将在调用 AbstractBeanFactory.getBean() 之前检查 bean 是否已缓存?如果是这样,我在哪里配置 Spring 来使用我的自定义 bean 工厂?
事实证明,Spring 实际上确实在请求属性中缓存了请求范围的 bean。如果您好奇,请看一下 AbstractRequestAttributesScope,它是 RequestScope 的扩展:
public Object get(String name, ObjectFactory objectFactory) {
RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();
Object scopedObject = attributes.getAttribute(name, getScope());
if (scopedObject == null) {
scopedObject = objectFactory.getObject();
attributes.setAttribute(name, scopedObject, getScope());
}
return scopedObject;
}
因此,虽然由于 aop 代理,AbstractBeanFactory.getBean() 在每个 bean 方法调用中都会被调用,但如果在请求属性中尚未找到该 bean,它只会导致 Spring 添加到该同步集。
避免对我的请求作用域 bean 上的每个方法调用进行代理仍然会降低复杂性,但有了此缓存,对性能的影响将很小。我认为如果我想要大量请求范围的 bean 并且仍然一次服务大量请求,那么我将不得不忍受缓慢的性能。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)