Tomcat source code: ClassLoader design, tomcatclassloader
Tomcat is a classic web server. Learning the source code of tomcat is of great help to us. Some time ago, I learned about the general process of tomcat's work, which is of great help to my new work. I just learned ClassLoader (the original intention of learning classloader is due to a bug in the company's products) and wrote a blog on classloaderp. For more understanding of ClassLoader, let's take a look at the ClassLoader Design of Tomcat 6.
In the past, I had a brief understanding of the tomcat Startup Process and tomcat request processing process to understand the various components and functions of tomcat. Both processes have the ClassLoader shadow, so today we are still starting from these two aspects to learn how Tomcat uses ClassLoader.
StandardClassLoader
The Bootstrap. main () method is simply used to execute four methods: init, setAwait, load, and start.
Init
public void init() throws Exception { // Set Catalina path setCatalinaHome(); setCatalinaBase(); initClassLoaders(); Thread.currentThread().setContextClassLoader(catalinaLoader); SecurityClassLoad.securityClassLoad(catalinaLoader); // Load our startup class and call its process() method if (log.isDebugEnabled()) log.debug("Loading startup class"); Class startupClass = catalinaLoader.loadClass ("org.apache.catalina.startup.Catalina"); Object startupInstance = startupClass.newInstance(); // Set the shared extensions class loader if (log.isDebugEnabled()) log.debug("Setting startup class properties"); String methodName = "setParentClassLoader"; Class paramTypes[] = new Class[1]; paramTypes[0] = Class.forName("java.lang.ClassLoader"); Object paramValues[] = new Object[1]; paramValues[0] = sharedLoader; Method method = startupInstance.getClass().getMethod(methodName, paramTypes); method.invoke(startupInstance, paramValues); catalinaDaemon = startupInstance; }
In the init method, call the initClassLoader method to initialize Tomcat's ClassLoader module, and then use the newly-defined class loader to load catalinaLoader to load the org. apache. catalina. startup. Catalina class. Next, call the setParentClassLoader method in Catalina.
Let's take a look at what the ClassLoader module of Tomcat initialization looks like in initClassLoader:
private void initClassLoaders() { try { commonLoader = createClassLoader("common", null); if( commonLoader == null ) { // no config file, default to this loader - we might be in a 'single' env. commonLoader=this.getClass().getClassLoader(); } catalinaLoader = createClassLoader("server", commonLoader); sharedLoader = createClassLoader("shared", commonLoader); } catch (Throwable t) { log.error("Class loader creation threw exception", t); System.exit(1); }}
Three ClassLoader, commonLoader, catalinaLoader, and sharedLoader, are created here. In fact, there is a certain relationship between them:
private ClassLoader createClassLoader(String name, ClassLoader parent) throws Exception {String value = CatalinaProperties.getProperty(name + ".loader"); if ((value == null) || (value.equals(""))) return parent;// some statementClassLoader classLoader = ClassLoaderFactory.createClassLoader (locations, types, parent); // some statement}
That is to say, the ClassLoader model after Initialization is:
The three classLoader objects at the top are provided by JDK. CommonLoader, catalinaLoader, and sharedLoader have a common name: StandardClassLoader.
BootstrapClassLoader is used to load some jar packages under the java_home/jre/lib directory (not all)
ExtClassLoader is used to load the jar package under the java_home/jre/lib/ext directory.
AppClassLoader is used to load the specified jar package in classpath.
In the catalina. properties file, the default loading paths of the three ClassLoader are pointed out.
common.loader=${catalina.home}/lib,${catalina.home}/lib/*.jarserver.loader=shared.loader=
This file is in the jar package and cannot be modified when tomcat is used. What should I do if I want to modify the default loading path?You can configure it in catalina. config.
For more information, see the implementation of the CatalinaProperties class.
As mentioned above, the main method of Bootstrap actually calls four methods: init, setAwait, start, load, except init, the other three methods are actually the setAwait, start, and load methods corresponding to the Catalina object.
From the implementation of the init method, we can know that in the Bootstrap class, except that the Catalina class is loaded by catalinaClassLoader, the other classes are loaded by ClassLoader provided by JDK. That is to say, according to the content learned in the previous section, the Catalina class cannot be directly called in the current Bootstrap class. However, we have to call the method in Catalina here. In the test above, we started another thread to solve this problem. Today, let's take a look at how Tomcat solves such application scenarios:
1) Call the setParentClassLoader method of Catalina in init
Object startupInstance = startupClass.newInstance(); // Set the shared extensions class loader if (log.isDebugEnabled()) log.debug("Setting startup class properties"); String methodName = "setParentClassLoader"; Class paramTypes[] = new Class[1]; paramTypes[0] = Class.forName("java.lang.ClassLoader"); Object paramValues[] = new Object[1]; paramValues[0] = sharedLoader; Method method = startupInstance.getClass().getMethod(methodName, paramTypes); method.invoke(startupInstance, paramValues);
2) Call the setAwait method of catalina in setAwait
public void setAwait(boolean await) throws Exception { Class paramTypes[] = new Class[1]; paramTypes[0] = Boolean.TYPE; Object paramValues[] = new Object[1]; paramValues[0] = new Boolean(await); Method method = catalinaDaemon.getClass().getMethod("setAwait", paramTypes); method.invoke(catalinaDaemon, paramValues); }
3) start calls the start method of catalina.
public void start() throws Exception { if( catalinaDaemon==null ) init(); Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null); method.invoke(catalinaDaemon, (Object [])null); }
4) load calls the load method of catalina
private void load(String[] arguments) throws Exception { // Call the load() method String methodName = "load"; Object param[]; Class paramTypes[]; if (arguments==null || arguments.length==0) { paramTypes = null; param = null; } else { paramTypes = new Class[1]; paramTypes[0] = arguments.getClass(); param = new Object[1]; param[0] = arguments; } Method method = catalinaDaemon.getClass().getMethod(methodName, paramTypes); if (log.isDebugEnabled()) log.debug("Calling startup class " + method); method.invoke(catalinaDaemon, param); }
They are all processed using reflection.
Now,Different classLoaderThe method call before the class loaded by the loader has 2Solution:
Solution 1: Start another thread
Solution 2: Use reflection.
Catalina is loaded by catalinaClassLoader. During the Tomcat startup process, Tomcat components are loaded and initialized, And the entries of these processes are in Catalina. Therefore, some components in Tomcat should be loaded by catalinaClassLoader. This sentence may be full. However, I say this for a reason:
There is such a process in the init method: SecurityClassLoad.SecurityClassLoad(CatalinaLoader );
Let's take a look at the true nature of this process:
public static void securityClassLoad(ClassLoader loader) throws Exception { if( System.getSecurityManager() == null ){ return; } loadCorePackage(loader); loadLoaderPackage(loader); loadServletsPackage(loader); loadSessionPackage(loader); loadUtilPackage(loader); loadJavaxPackage(loader); loadCoyotePackage(loader); loadHttp11Package(loader); loadTomcatPackage(loader);}private final static void loadCorePackage(ClassLoader loader) throws Exception { String basePackage = "org.apache.catalina."; loader.loadClass (basePackage + "core.ApplicationContextFacade$1"); loader.loadClass (basePackage + "core.ApplicationDispatcher$PrivilegedForward"); loader.loadClass (basePackage + "core.ApplicationDispatcher$PrivilegedInclude"); loader.loadClass (basePackage + "core.ContainerBase$PrivilegedAddChild"); loader.loadClass (basePackage + "core.StandardWrapper$1"); loader.loadClass (basePackage + "core.ApplicationHttpRequest$AttributeNamesEnumerator"); }
SecurityClassLoad (ClassLoader loader) uses the facade mode to load various classes. Only the implementation of loadCorePackage is listed here. The implementation of other methods is exactly the same as this. That's why I saidTomcatIn most cases, some components should be played by catalinaClassLoaderLoaded.
According to this method, we can also see that,To load the internal class, you must add$.
========================================================== ========================================================
WebappClassLoader
The above is actually the StandardClassLoader in Tomcat, and there is also a WebappClassLoader in Tomcat. According to the name, we can see that this ClassLoader is designed to load various Web applications. Each component of Tomcat corresponds to the Web Application, that is, StandardContext. Why? The ServletConext (Java EE standard API) we use in Web applications is implemented by ApplicationContext in Tomcat, and ApplicationContext is actually the delegate of StandardContext.
This Classloader is used to load classes in web applications. This class will be used in the future.