https://issues.apache.org/bugzilla/show_bug.cgi?id=52549
Bug #: 52549 Summary: scanning HandlesTypes causes aggressive classloading Product: Tomcat 7 Version: 7.0.25 Platform: PC Status: NEW Severity: normal Priority: P2 Component: Catalina AssignedTo: dev@tomcat.apache.org ReportedBy: costin.l...@gmail.com Classification: Unclassified I've ran into, what I would consider a bug, in Tomcat 7 when the web.xml is 3.0 (or higher). I assume based on the Servlet 3.0 spec, the WEB-INF/classes need to be scanned but rather than doing bytecode parsing, Tomcat 7 does actual class loading during the webapp initialization. This change in semantics breaks applications that rely on bytecode enhancements or processing (such as Spring's LoadTimeWeaver). Also any statics that are in place get initialized way too early even if class itself might not get used. Webapps that work on Tomcat 5.x-7.x (with web.xml 2.5) suddenly break on Tomcat 7 web.xml 3.0 due to the eager class loading. I'd assume every app that does instrumentation (such as JPA providers) will face the same issue unless the whole VM is being instrumented which is quite unfortunate and avoidable. I'm using Tomcat 7.0.25. The culprit seems to be ContextConfg#checkHandlesTypes(JavaClass) which could postpone class loading: // No choice but to load the class String className = javaClass.getClassName(); ... clazz = context.getLoader().getClassLoader().loadClass(className); ... // CL: no need to load the class for this if (clazz.isAnnotation()) { // Skip return; } for (Map.Entry<Class<?>, Set<ServletContainerInitializer>> entry ... There are a number of improvements to be applied here all just by looking at the bytecode such as: a. if the class is an annotation, skip it b. if the class doesn't extend/implement any interface skip it c. Look at the class hierarchy - this is actually quite easy (since there's only one parent) and don't load it unless it implements ServletContextListener d. if there are no Servlet initializers, don't load any classes e. if the class needs to be loaded use a throwaway classloader - that is a clone CL of the real one which you can discard after scanning. Thus you can do all the checks against a class but you can get rid of it at the end. If the class is a match you can load it using the "proper" class loader. The problem with e) is that it's not really efficient especially in terms of memory. Loading all the classes (which can be quite a lot (10K+) in several applications) to find one or two initializers seems like a bad trade-off which unfortunately, also breaks compatibility. I realize that the solutions above (especially e) seem complicated but they aren't. I see you guys have used BCEL - if you were using ASM I would have offered help. Basically what I'm suggesting is to be a lot more careful in doing loading and enforcing some basic rules which can go a long way. Also using a cache (reusing data) for the entire scanning should speed things up pretty well. Further more since you are already loading the bytecode, doing additional checks will actually speed things up as it will avoid class loading. Case in point is traversing the class hierarchy: if the parent is in the classpath, it will be scanned anyway and checking the interfaces implemented is trivial. If this result is cached, all direct children will be skipped right away. Thanks, -- Configure bugmail: https://issues.apache.org/bugzilla/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are the assignee for the bug. --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org