您的位置:首页 > 运维架构 > Tomcat

8.1 Tomcat学习(加载器)

2017-01-20 11:10 441 查看
java中载入器分为以下3种:



关于类加载器可以参考:http://blog.csdn.net/shakespeare001/article/details/51765353

Tomcat使用自定义载入器的原因:





Resources 和 Repositories:



Loader接口及其实现类UML图:



本章使用的Context容器是由Tomcat提供的StandardContext。

启动类的代码:

package ex08.pyrmont.startup;

import ex08.pyrmont.core.SimpleWrapper;
import ex08.pyrmont.core.SimpleContextConfig;
import org.apache.catalina.Connector;
import org.apache.catalina.Context;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.Loader;
import org.apache.catalina.Wrapper;
import org.apache.catalina.connector.http.HttpConnector;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.loader.WebappClassLoader;
import org.apache.catalina.loader.WebappLoader;
import org.apache.naming.resources.ProxyDirContext;

public final class Bootstrap {
public static void main(String[] args) {

System.setProperty("catalina.base", System.getProperty("user.dir"));
Connector connector = new HttpConnector();
Wrapper wrapper1 = new SimpleWrapper();
wrapper1.setName("Primitive");
wrapper1.setServletClass("PrimitiveServlet");
Wrapper wrapper2 = new SimpleWrapper();
wrapper2.setName("Modern");
wrapper2.setServletClass("ModernServlet");

Context context = new StandardContext();

context.setPath("/myApp");//设置context的path属性,path是访问这个web应用的URL

context.setDocBase("myApp");//设置context的docBase属性,docBase是web应用的本地路径

context.addChild(wrapper1);
context.addChild(wrapper2);

context.addServletMapping("/Primitive", "Primitive");
context.addServletMapping("/Modern", "Modern");

LifecycleListener listener = new SimpleContextConfig();
((Lifecycle) context).addLifecycleListener(listener);

Loader loader = new WebappLoader();创建一个WebappLoader

context.setLoader(loader);

connector.setContainer(context);

try {
connector.initialize();
((Lifecycle) connector).start();
((Lifecycle) context).start();//Context容器启动时,同时新起一个线程来运行关联的WebappLoader

WebappClassLoader classLoader = (WebappClassLoader) loader.getClassLoader();从WebappLoader中获取一个类加载器
System.out.println("Resources' docBase: " + ((ProxyDirContext)classLoader.getResources()).getDocBase());
String[] repositories = classLoader.findRepositories();
for (int i=0; i<repositories.length; i++) {
System.out.println("  repository: " + repositories[i]);
}

System.in.read();
((Lifecycle) context).stop();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
WebappLoader类start()方法执行时,主要完成以下4个工作:



createClassLoader()执行时时序图:



setRepositories()方法时序图,该方法执行后类载入器就能在WEB-INF/classes和WEB-INF/lib两个目录下载入相关类



setClassPath()的代码如下:

private void setClassPath() {

if (!(container instanceof Context))//验证容器信息
return;
ServletContext servletContext = ((Context) container).getServletContext();
if (servletContext == null)
return;

StringBuffer classpath = new StringBuffer();//将所有Class路径存放到classpath字符串中

ClassLoader loader = getClassLoader();
int layers = 0;
int n = 0;
//循环最多执行3次(ExtensionClassLoader、ApplicationClassLoader、UserClassLoader),将所有类的URL都添加到classpath中
while ((layers < 3) && (loader != null)) {
if (!(loader instanceof URLClassLoader))
break;
URL repositories[] =
((URLClassLoader) loader).getURLs();
for (int i = 0; i < repositories.length; i++) {
String repository = repositories[i].toString();
if (repository.startsWith("file://"))
repository = repository.substring(7);
else if (repository.startsWith("file:"))
repository = repository.substring(5);
else if (repository.startsWith("jndi:"))
repository =
servletContext.getRealPath(repository.substring(5));
else
continue;
if (repository == null)
continue;
if (n > 0)
classpath.append(File.pathSeparator);
classpath.append(repository);
n++;
}
loader = loader.getParent();
layers++;
}

//将classpath和Globals.CLASS_PATH_ATTR属性关联
servletContext.setAttribute(Globals.CLASS_PATH_ATTR,
classpath.toString());

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: