2011-10-03 16 views
8

Escenario: Tenemos una aplicación web administrada por Spring que se ejecuta dentro de Websphere. (Spring 3.0.x, WAS 7) La aplicación web aprovecha el administrador de trabajo de Websphere a través del WorkManagerTaskExecutor de Spring (configurado con un tamaño de grupo de subprocesos de 10) para ejecutar operaciones de lectura db intensivas en cómputo. Entonces, básicamente, llega una solicitud para generar, digamos, 10 documentos diferentes. Para generar los documentos solo se necesitan lecturas de DB para recopilar/procesar los datos. Así que, básicamente, engendramos 10 hilos para procesar los 10 documentos y, al final, reunimos los 10 documentos devueltos por los 10 trabajadores, los fusionamos y escribimos una gran respuesta al cliente. Lo que identificamos es que mientras los 10 hilos están recopilando/procesando los datos hay un montón de llamadas a bases de datos similares realizadas. Entonces, lo que se nos ocurre es crear un Aspecto alrededor de los métodos db más ejecutados para almacenar en caché la respuesta. El aspecto se configura como un singleton, y el caché que el aspecto utiliza se conecta automáticamente al aspecto con un alcance establecido para request-scope para que cada solicitud tenga su propio caché.Acceso a los beans de ámbito solicitado en una aplicación web multiproceso

Problema: Ahora el problema con este enfoque es que cuando los hilos están haciendo sus llamadas de db y el aspecto es interjección, obtenemos la excepción java.lang.IllegalStateException: No thread-bound request found. Lo cual entiendo es totalmente válido ya que los hilos se están ejecutando fuera del contexto de solicitud.

¿Hay alguna forma de solucionar este problema? ¿Es posible aplicar el aspecto con un caché con ámbito de solicitud a los métodos invocados por estos hilos?

Respuesta

5

No creo que pueda hacer esto directamente. Incluso si pudieras, sería un poco feo. Sin embargo, puede generar un identificador de solicitud único (o incluso - use la identificación de la sesión, pero tenga cuidado con varias pestañas), y pase eso a cada subproceso de procesamiento. Luego, el aspecto puede usar esa identificación como la clave de la memoria caché. El caché también será singleton, pero habrá Map<String, X>, donde String es el ID y X es su resultado almacenado en caché.

Para facilitar el manejo, puede tener los métodos @Async (en lugar de los subprocesos de desove manuales), y cada método @Async puede tener el Id. De caché pasado como su primer parámetro.

(Por supuesto, sus métodos asincrónicos deben regresar Future<Result> para que pueda recoger sus resultados en la solicitud de rosca)

+0

pensé en el enfoque, pero el único inconveniente que encuentro es que me va a obligar a pasar el identificador de solicitud único en sentido descendente a todas las llamadas a método (durante la ejecución del subproceso) que me gustaría almacenar en caché. Además, ¿no sería el caché bastante grande después de un tiempo? Lo cual me obligaría a administrarlo periódicamente. Tal vez me estoy perdiendo algo aquí. – r4j1v

+0

quizás haya un "contexto de ejecución de subprocesos" que pueda usar para almacenar mi identificador único de solicitud y recuperarlo en el aspecto sin tener que pasarlo yo mismo. – r4j1v

+5

Logré solucionar este problema. Empecé a usar 'SimpleAsyncTaskExecutor' en lugar de' WorkManagerTaskExecutor'. El beneficio es que 'SimpleAsyncTaskExecutor' nunca volverá a usar subprocesos. Esa es solo la mitad de la solución. La otra mitad de la solución es usar un 'RequestContextFilter' en lugar de' RequestContextListener'. 'RequestContextFilter' tiene un método' setThreadContextInheritable() 'que básicamente permitirá que los hilos hijo hereden el contexto principal. – r4j1v

Cuestiones relacionadas