1.问题
今天在本地和测试环境用jetty跑应用发现本地环境跑起来有问题,而测试环境却没有问题,出现的是war包的WEB-INF的lib目录下有两个jar包a.jar和b.jar,但是这两个jar包邮两个包名和类目一样,但是功能却不一样的类,那么jetty启动加载这个类的时候用的是a.jar里面的类还是b.jar里面的类呢,出了问题只能查了。
2.本地环境jetty加载目录里面是b.jar排在a.jar前面,而测试环境是a.jar排在b.jar前面,而记载a.jar里面的类是正确的。我们看看jetty怎么处理:
首先jetty加载一个APP war的过程中WebInfConfiguration.java类里面加载类的顺序,优先加载的是WEB-INF/classes,然后再加载WEB-INF/lib里面的jar包,而jar的加载顺序又是怎么样的呢?
[java]
@Override
public void configure(WebAppContext context) throws Exception
{
//cannot configure if the context is already started
if (context.isStarted())
{
if (Log.isDebugEnabled()){Log.debug("Cannot configure webapp "+context+" after it is started");}
return;
}
Resource web_inf = context.getWebInf();
// Add WEB-INF classes and lib classpaths
if (web_inf != null && web_inf.isDirectory() && context.getClassLoader() instanceof WebAppClassLoader)
{
// Look for classes directory
Resource classes= web_inf.addPath("classes/");
if (classes.exists())
((WebAppClassLoader)context.getClassLoader()).addClassPath(classes);
// Look for jars
Resource lib= web_inf.addPath("lib/");
if (lib.exists() || lib.isDirectory())
((WebAppClassLoader)context.getClassLoader()).addJars(lib);
}
// Look for extra resource
List<Resource> resources = (List<Resource>)context.getAttribute(RESOURCE_URLS);
if (resources!=null)
{
Resource[] collection=new Resource[resources.size()+1];
int i=0;
collection[i++]=context.getBaseResource();
for (Resource resource : resources)
collection[i++]=resource;
context.setBaseResource(new ResourceCollection(collection));
}
}
((WebAppClassLoader)context.getClassLoader()).addClassPath(classes); 这是加载每个class类的过程
addURL(url);调用jdk包的URLClassPath把每个class文件放到list的后续,每次加载类的时候从这个list第一个开始查找,找到则加载
这里看完我们就可以再看加载lib下面的jar包的过程了
addJars是对lib下面所有jar包用jdk的list方法获取所有jar包,然后对每个jar进行处理。
[java]
/* ------------------------------------------------------------ */
/** Add elements to the class path for the context from the jar and zip files found
* in the specified resource.
* @param lib the resource that contains the jar and/or zip files.
*/
public void addJars(Resource lib)
{
if (lib.exists() && lib.isDirectory())
{
String[] files=lib.list();
for (int f=0;files!=null && f<files.length;f++)
{
try
{
Resource fn=lib.addPath(files[f]);
String fnlc=fn.getName().toLowerCase();
if (!fn.isDirectory() && isFileSupported(fnlc))
{
String jar=fn.toString();
jar=StringUtil.replace(jar, ",", "%2C");
jar=StringUtil.replace(jar, ";", "%3B");
addClassPath(jar);
}
}
catch (Exception ex)
{
Log.warn(Log.EXCEPTION,ex);
}
}
}
}
String[] files=lib.list(); 这一行就是关系jar包的加载顺序关键点,这里列出来的顺序就是jar包的加载顺序,
[java]
/* --------------------------------------------------------- */
/**
* Returns a list of resources contained in the given resource
*/
@Override
public String[] list()
{
String[] list =_file.list();
if (list==null)
return null;
for (int i=list.length;i-->0;)
{
if (new File(_file,list[i]).isDirectory() &&
!list[i].endsWith("/"))
list[i]+="/";
}
return list;
}
最终 String[] list =_file.list();就是java.io.File的list方法,而这个方法的顺序是怎么样,只能看jdk的代码了。我们写个程序简单
补充:软件开发 , Java ,