使用大量AOP请求范围bean时的性能问题 [英] Performance problems when using lots of AOP request scoped beans

查看:170
本文介绍了使用大量AOP请求范围bean时的性能问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Spring 3处理一个半大型应用程序,并且在同时向其投入数百名用户时遇到了性能问题。我使用Spring的AOP代理使用了几个请求范围的bean,我可以看到每次调用其中一个bean上的任何方法时,都会调用CGLIB拦截器,然后调用AbstractBeanFactory.getBean(),调用add()现有Spring bean的同步集。由于这个add()是同步的,所以当有数千个调用它等待添加到同一个列表时,它会有效地锁定服务器。

I'm working on a semi-large application using Spring 3 and am running into performance problems when throwing hundreds of users at it at once. I'm using several request scoped beans using Spring's AOP proxy and I can see that every time I call any method on one of these beans, the CGLIB interceptor is invoked, which then calls AbstractBeanFactory.getBean(), which calls add() on a Synchronized Set of existing Spring beans. Since this add() is synchronized, it effectively locks up the server when there are thousands of calls to it all waiting to add to the same list.

有没有办法使用请求范围的bean来解决这个问题?我在Spring文档中读到,如果bean实现了任何接口(http://static.springsource.org/spring/docs/2.0.0/reference/aop.html#d0e9015),那么CGLIB不会被使用,但是我的请求范围是bean所有实现一个(实际上是同一个),它仍然发生。我肯定需要将bean作为请求作用域,因为它们的某些字段是在应用程序的一个部分中为特定请求计算的,然后我使用SpEL在同一请求期间在应用程序的不同部分获取它们的值。我想如果我把豆子原型作为范围,当我第二次使用SpEL来获取它们时,我会有一个新鲜的对象。

Is there a way to get around this using request scoped beans? I read in the Spring documentation that CGLIB isn't used if the bean implements any interface (http://static.springsource.org/spring/docs/2.0.0/reference/aop.html#d0e9015) but my request scoped beans all implement one (the same one in fact) and it's still happening. And I definitely need the beans to be request scoped because some of their fields are calculated in one part of the app for a particular request and then I use SpEL to get their value in a different part of the app during the same request. I think if I made the beans prototype scoped, I'd have a fresh object when I used SpEL to get them the second time.

这是一个代码示例,说明我的问题。请参阅最后两行,了解描述我遇到问题的地方。

Here is a code sample that illustrates my problem. See the last two lines for comments describing where exactly I'm having issues.

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






我的想法是以下之一:


My ideas are one of the following:


  • 我是否可以在不代理对bean进行的每个方法调用的情况下创建一个Spring Bean请求范围?而且没有将每种方法都标记为最终?

或...


  • 我可以覆盖Spring的bean工厂来实现一个Bean缓存,它会在调用AbstractBeanFactory.getBean()之前检查bean是否被缓存吗?如果是这样,我在哪里配置Spring以使用我的自定义bean工厂?

推荐答案

As事实证明,Spring实际上会在请求属性中缓存请求范围的bean。如果你很好奇,请看看RequestScope扩展的AbstractRequestAttributesScope:

As it turns out, Spring actually does cache the request scoped beans, in the request attributes. If you're curious, take a look at AbstractRequestAttributesScope, which RequestScope extends:

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;
}

因此,当每个bean方法调用都调用AbstractBeanFactory.getBean()时,因为如果在请求属性中找不到bean,它只会导致Spring添加到同步集。

So while AbstractBeanFactory.getBean() does get called on every bean method call because of the aop proxy, it only causes Spring to add to that synchronized set if the bean wasn't already found in the request attributes.

避免代理每个方法调用根据我的要求,scoped bean仍然会降低复杂性,但是通过这种缓存,性能影响将是最小的。我认为如果我想要大量的请求范围的bean并且仍然一次提供大量请求,那么我将不得不忍受这种缓慢的性能。

Avoiding the proxying of every method call on my request scoped beans would still reduce complexity but with this caching in place, the performance impact would be minimal. I think the slow performance is something I'm going to have to live with if I want a ton of request scoped beans and still serve a ton of requests at a time.

这篇关于使用大量AOP请求范围bean时的性能问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆