java - El uso de Spring AOP en App Engine causa StackOverflowError
google-app-engine spring-aop (3)
Tenemos una aplicación ejecutándose en App Engine y usando Spring framework. Recientemente, hemos agregado algunas características nuevas que se basan en AOP. Decidimos usar el estilo @AspectJ, por lo tanto, agregamos <aop:aspectj-autoproxy>
en nuestra configuración basada en XML e implementamos los aspectos respectivos. Todo funciona bien en el servidor de desarrollo, sin embargo, cuando se implementa en el entorno de la nube obtenemos java.lang.StackOverflowError
cada vez que se inicializa la aplicación.
El bean que no se puede crear y causa el error es una clase de configuración anotada con la anotación @Configuration
. Parece que básicamente cualquier configuración Bean puede causar el error.
A continuación puede ver el seguimiento de la pila correspondiente.
org.springframework.web.context.ContextLoader initWebApplicationContext: Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name ''objectifyConfig'' defined in URL [jar:file:/base/data/home/apps/{app-id}/8.372375422460842231/WEB-INF/lib/{app-name}-1.0-SNAPSHOT.jar!/{path-to-class}/ObjectifyConfig.class]: Initialization of bean failed; nested exception is java.lang.StackOverflowError
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:529)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:296)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:293)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:628)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:389)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
at org.mortbay.jetty.handler.ContextHandler.startContext(ContextHandler.java:548)
at org.mortbay.jetty.servlet.Context.startContext(Context.java:136)
at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1250)
at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:517)
at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:467)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.createHandler(AppVersionHandlerMap.java:219)
at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.getHandler(AppVersionHandlerMap.java:194)
at com.google.apphosting.runtime.jetty.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:134)
at com.google.apphosting.runtime.JavaRuntime$RequestRunnable.run(JavaRuntime.java:446)
at com.google.tracing.TraceContext$TraceContextRunnable.runInContext(TraceContext.java:435)
at com.google.tracing.TraceContext$TraceContextRunnable$1.run(TraceContext.java:442)
at com.google.tracing.CurrentContext.runInContext(CurrentContext.java:186)
at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContextNoUnref(TraceContext.java:306)
at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContext(TraceContext.java:298)
at com.google.tracing.TraceContext$TraceContextRunnable.run(TraceContext.java:439)
at com.google.apphosting.runtime.ThreadGroupPool$PoolEntry.run(ThreadGroupPool.java:251)
at java.lang.Thread.run(Thread.java:724)
Caused by: java.lang.StackOverflowError
at java.util.concurrent.ConcurrentSkipListSet.contains(ConcurrentSkipListSet.java:214)
at sun.misc.URLClassPath$LoaderSearchCursor.nextLoader(URLClassPath.java:598)
at sun.misc.URLClassPath.getLoader(URLClassPath.java:365)
at sun.misc.URLClassPath.findResource(URLClassPath.java:213)
at java.net.URLClassLoader$2.run(URLClassLoader.java:551)
at java.net.URLClassLoader$2.run(URLClassLoader.java:549)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findResource(URLClassLoader.java:548)
at com.google.apphosting.runtime.security.UserClassLoader.findResource(UserClassLoader.java:723)
at java.lang.ClassLoader.getResource(ClassLoader.java:1142)
at com.google.apphosting.runtime.security.UserClassLoader$3.run(UserClassLoader.java:757)
at com.google.apphosting.runtime.security.UserClassLoader$3.run(UserClassLoader.java:751)
at java.security.AccessController.doPrivileged(Native Method)
at com.google.apphosting.runtime.security.UserClassLoader.findResource(UserClassLoader.java:751)
at java.lang.ClassLoader.getResource(ClassLoader.java:1142)
at com.google.apphosting.runtime.security.UserClassLoader$3.run(UserClassLoader.java:757)
at com.google.apphosting.runtime.security.UserClassLoader$3.run(UserClassLoader.java:751)
at java.security.AccessController.doPrivileged(Native Method)
at com.google.apphosting.runtime.security.UserClassLoader.findResource(UserClassLoader.java:751)
at java.lang.ClassLoader.getResource(ClassLoader.java:1142)
at com.google.apphosting.runtime.security.UserClassLoader$3.run(UserClassLoader.java:757)
at com.google.apphosting.runtime.security.UserClassLoader$3.run(UserClassLoader.java:751)
at java.security.AccessController.doPrivileged(Native Method)
at com.google.apphosting.runtime.security.UserClassLoader.findResource(UserClassLoader.java:751)
at java.lang.ClassLoader.getResource(ClassLoader.java:1142)
...
Actualización: pongo el problema en el rastreador de problemas de App Engine junto con la aplicación de muestra que demuestra el problema. Por favor, siga el enlace para ver detalles.
Un desbordamiento de pila generalmente indica un bucle infinito. Con aspectj podrías tener esto en el siguiente caso:
Class Logger {
@Autowired
ConfigService conf;
//... used for logging intercepted methods
}
Class ConfigServiceImpl implements ConfigService {
//... this is used to retrieve config
}
Si ahora usa expresiones aspectj que dicen: Quiero registrar mi configServiceImpl, entonces también tendrá un bucle infinito cuando use configService:
- interceptado por el registrador
- configservice inyectado en el registrador intenta recuperar la configuración de registro ...
- ==> ese servicio de configuración es interceptado por el registrador y la historia se repite
No puedo explicar por qué está funcionando en su configuración local y no en el motor de la aplicación. O por qué es solo cuando está usando @Configuration, pero creo que debería mirar en la dirección de una "dependencia circular" como esta.
Parece que el problema se ha resuelto en App Engine versión 1.9.7. Ver más detalles aquí .
Esto es debido a la recursión infinita, o porque tu stack es demasiado grande. Intenta aumentar el tamaño de tu pila para ver si eso resuelve el problema (usando, por ejemplo, -Xss1m
). Si esto no ayuda, entonces puede tener recursión infinita. Ver también:
Error de desbordamiento de la pila Java: ¿cómo aumentar el tamaño de la pila en Eclipse?