Estoy trabajando en una aplicación de tamaño medio con Spring 3 y tengo problemas de rendimiento al lanzar cientos de usuarios a la vez. Estoy usando varios beans de ámbito de solicitud utilizando el proxy AOP de Spring y puedo ver que cada vez que llamo a cualquier método en uno de estos beans, se invoca el interceptor CGLIB, que luego llama a AbstractBeanFactory.getBean(), que llama a add() en un conjunto sincronizado de beans de primavera existentes. Como este complemento() está sincronizado, efectivamente bloquea el servidor cuando hay miles de llamadas esperando a que se agreguen a la misma lista.Problemas de rendimiento al usar muchos beans de ámbito de solicitud de AOP
¿Hay alguna forma de evitar esto al usar beans de ámbito solicitado? Leí en la documentación de Spring que CGLIB no se usa si el bean implementa alguna interfaz (http://static.springsource.org/spring/docs/2.0.0/reference/aop.html#d0e9015) pero mi solicitud tuvo el alcance de los beans todos implementan uno (el mismo de hecho) y todavía está sucediendo. Y definitivamente necesito que los beans se soliciten con un alcance porque algunos de sus campos se calculan en una parte de la aplicación para una solicitud en particular y luego uso SpEL para obtener su valor en una parte diferente de la aplicación durante la misma solicitud. Creo que si creara el prototipo del frijol, tendría un objeto nuevo cuando use SpEL para obtenerlos por segunda vez.
Aquí hay un ejemplo de código que ilustra mi problema. Vea las últimas dos líneas para comentarios que describan exactamente dónde estoy teniendo problemas.
<!-- 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.
}
}
Mis ideas son uno de los siguientes:
- ¿Puedo hacer una solicitud de beans Spring con ámbito sin proxy cada llamada al método realizado en el grano? ¿Y sin marcar cada método como "final"?
o ...
- ¿Puedo anular fábrica de beans de primavera para implementar una memoria caché Bean que se compruebe si un grano se almacena en caché antes de llamar AbstractBeanFactory.getBean()? Y si es así, ¿dónde configuro Spring para usar mi fábrica de bean personalizada?
1 llamada está bien, pero 2 x llamadas mata a su aplicación? –
Si lo llamó la primera vez que se ha hecho referencia el frijol, que estaría bien. Si llama a la clase proxy cada vez que llamo a cualquier método en el bean, eso mata mi aplicación. – Cameron