Keywords: Tomcat 7 | Annotation Scanning | ClassFormatException | Servlet 3.0 | Spring MVC | Bytecode Compatibility
Abstract: This paper provides an in-depth analysis of the "SEVERE: A child container failed during start" error encountered when deploying Spring MVC applications on Tomcat 7. By examining the critical error message "Invalid byte tag in constant pool: 60" from the logs, the study reveals that this issue stems from compatibility problems between Tomcat 7's annotation scanning mechanism and specific bytecode structures. The article thoroughly explores the annotation scanning principles under the Servlet 3.0 specification, compares the handling mechanisms between Tomcat 6 and Tomcat 7, and offers multiple practical solutions including configuring the metadata-complete attribute in web.xml, adjusting dependency scopes, and optimizing build configurations. Through code examples and configuration explanations, it helps developers fundamentally understand and resolve such container startup failures.
Problem Background and Error Analysis
During migration from Tomcat 6 to Tomcat 7, many developers encounter container startup failures manifested as the SEVERE: A child container failed during start error. From the provided error logs, the root cause is identified as org.apache.tomcat.util.bcel.classfile.ClassFormatException: Invalid byte tag in constant pool: 60. This exception indicates that Tomcat encountered an unrecognized byte tag while parsing the constant pool of class files.
Servlet 3.0 Annotation Scanning Mechanism
The Servlet 3.0 specification introduced automatic annotation scanning functionality, requiring the container to scan all class files during application startup to identify various annotation configurations. Tomcat 7 employs a parser based on Apache Commons BCEL to perform this task. When BCEL encounters class files containing specific bytecode structures, it may fail to parse them correctly due to version compatibility issues, resulting in ClassFormatException.
Here is a simple example illustrating the basic principle of annotation scanning:
// Example: Spring MVC controller class
@Controller
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/users")
public String listUsers(Model model) {
model.addAttribute("users", userService.findAll());
return "userList";
}
}
Differences Between Tomcat 6 and Tomcat 7
Tomcat 6, based on the Servlet 2.5 specification, does not perform automatic annotation scanning by default and requires explicit configuration. In contrast, Tomcat 7 adheres to the Servlet 3.0 specification and enables annotation scanning by default. This difference causes applications that run normally on Tomcat 6 to potentially fail startup on Tomcat 7 due to bytecode parsing issues during annotation scanning.
Solutions and Configuration Adjustments
Solution 1: Disable Annotation Scanning
By setting the metadata-complete="true" attribute, you can instruct the container not to perform annotation scanning, with all configurations defined through the web.xml file:
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
version="3.0"
metadata-complete="true">
<!-- Traditional Servlet configuration -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
</web-app>
Solution 2: Downgrade Servlet Version Declaration
Change the version declaration in web.xml to 2.5 to run the application in Servlet 2.5 compatibility mode:
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
version="2.5">
<!-- Application configuration -->
</web-app>
Solution 3: Optimize Dependency Management
Ensure that the Servlet API dependency scope is set to provided to avoid conflicts with classes provided by the container:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
Build Configuration Optimization
In Maven configuration, ensure that compiler settings match the target environment:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<compilerArgument>-Xlint:all</compilerArgument>
</configuration>
</plugin>
In-depth Analysis of Root Cause
Byte tag 60 in the Java class file format corresponds to CONSTANT_MethodHandle, a new constant type introduced in Java 7. When older versions of BCEL (such as those used in Tomcat 7) attempt to parse class files containing this new constant type, parsing errors occur. This situation typically arises when:
- Class files are compiled with newer versions of the Java compiler
- Dependency libraries contain bytecode compiled using new Java features
- There is a mismatch between JDK versions in development and runtime environments
Preventive Measures and Best Practices
To avoid similar issues, the following measures are recommended:
- Maintain consistent JDK versions across development, build, and runtime environments
- Regularly update Tomcat versions for better compatibility
- Explicitly specify Tomcat version in pom.xml (as mentioned in the reference article)
- Use continuous integration tools to ensure consistency testing across different environments
By understanding Tomcat container workings and the evolution of Servlet specifications, developers can better diagnose and resolve such deployment compatibility issues, ensuring smooth application migration and stable operation.