[英]How do I read the manifest file for a webapp running in apache tomcat?
我有一個包含清單文件的 webapp,我在 ant 構建任務期間編寫了我的應用程序的當前版本。 清單文件已正確創建,但是當我嘗試在運行時讀取它時,我得到了一些奇怪的副作用。 我在清單中讀取的代碼是這樣的:
InputStream manifestStream = Thread.currentThread()
.getContextClassLoader()
.getResourceAsStream("META-INFFFF/MANIFEST.MF");
try {
Manifest manifest = new Manifest(manifestStream);
Attributes attributes = manifest.getMainAttributes();
String impVersion = attributes.getValue("Implementation-Version");
mVersionString = impVersion;
}
catch(IOException ex) {
logger.warn("Error while reading version: " + ex.getMessage());
}
當我將 eclipse 附加到 tomcat 時,我看到上面的代碼有效,但它似乎得到了一個與我預期不同的清單文件,我可以看出這是因為 Z63B07E828BF016E976FF95D6EE07A10Z 版本和構建時間戳都不同。 然后,我把“META-INFFFF”放在那里,上面的代碼仍然有效,這意味着我正在閱讀其他一些清單。 不是我的。 我也試過
this.getClass().getClassLoader().getResourceAsStream(...)
但結果是一樣的。 從在 tomcat 中運行的 web 應用程序內部讀取清單文件的正確方法是什么?
編輯:感謝到目前為止的建議。 另外,我應該注意我正在獨立運行 tomcat; 我從命令行啟動它,然后附加到 Eclipse 調試器中正在運行的實例。 這不應該有所作為,不是嗎?
也許您的副作用來自幾乎所有 jars 都包含 MANIFEST.MF 而您沒有得到正確的事實。 要從 webapp 中讀取 MANIFEST.MF,我會說:
ServletContext application = getServletConfig().getServletContext();
InputStream inputStream = application.getResourceAsStream("/META-INF/MANIFEST.MF");
Manifest manifest = new Manifest(inputStream);
Please note that running Tomcat from Eclipse is not the same as running Tomcat alone as Eclipse plays with the classloader.
有點晚了,但這對我有用(Glassfish中的網絡應用程序)
Properties prop = new Properties();
prop.load(getServletContext().getResourceAsStream("/META-INF/MANIFEST.MF"));
System.out.println("All attributes:" + prop.stringPropertyNames());
System.out.println(prop.getProperty("{whatever attribute you want}"));
嘗試使用jcabi-manifests ,它會為您完成所有這些加載工作。 例如:
String version = Manifests.read("My-Version");
從可用的MANIFEST.MF
文件之一加載My-Version
屬性。
重要的是要提到(更多細節在這里)在大多數 web 容器當前線程 class 加載器與 servlet 上下文 class 加載器不同。 這就是為什么您應該在運行時將您的 servlet 上下文 append 到寄存器中的原因(更多信息):
Manifests.append(servletContext);
另外,請查看:http://www.yegor256.com/2014/07/03/how-to-read-manifest-mf.html
正確的清單存在於服務器的應用程序根目錄中。 找出應用程序根,例如找出 class 的類路徑:
String rootPath = getClass().getProtectionDomain().getCodeSource().getLocation().getPath()
然后將上面的路徑替換為已建立的路徑: Glassfish 示例:
/applications/<webProject>/META-INF/MANIFEST.MF
它對我有用。
class 加載程序的默認工作方式是在嘗試查找自己的資源之前先推遲到父級。 因此,如果父 class 加載程序有任何可用的清單,這就是您將得到的。 事實上,應用服務器不一定會這樣做,以允許應用程序覆蓋庫的版本。 此外,class 加載程序可以具有多個 jars 並因此具有多個清單。
它可能能夠獲得您唯一命名的資源之一的資源 URL。 打開一個連接。 投射到JarURLConnection
。 獲取JarFile
。 從中加載清單。 這可能行不通,特別是如果 Tomcat 引發戰爭。
[更新] 當然,war 文件本身不在類路徑中。 類路徑將包含類似 WEB-INF/lib/( .jar| .zip) 和 WEB-INF/classes/ 的內容。 從ServletContext
獲取資源應該可以工作。
最佳解決方案:做一些不同的事情。 :)
不知道閱讀它的“官方”方式,但如果 MANIFEST.MF 無法正確加載為資源,那么嘗試從某些 web 路徑上的“ServletContext.getRealPath()”獲取其路徑怎么樣在您的應用程序中定義?
在構建期間由 ant 將應用程序版本也寫入其他地方(WEB-INF/類中的屬性文件)是我想到的另一個解決方案。
這就是我將各種版本打印到日志文件的方法。 我已經對擴展路徑進行了硬編碼,但應用程序可能會使用servletContext.getRealPath("/")
來讀取 webapp 文件夾的完整路徑。 可以打印剛剛給定的庫或 lib 文件夾中的所有內容。
// print library versions (jersey-common.jar, jackson-core-2.6.1.jar)
try {
List<String> jars = Arrays.asList( "jersey-common", "jackson-core", "openjpa", "mylib" );
StringBuilder verbuf = new StringBuilder();
for(File file : new File("/opt/tomcat/webapps/myapp/WEB-INF/lib/").listFiles() ) {
String name = file.getName();
if (file.isDirectory() || !file.isFile() || !name.endsWith(".jar") ) continue;
name = name.substring(0, name.length()-4);
boolean found = jars.contains(name);
if (!found) {
int idx = name.lastIndexOf('-');
if (idx>0)
found = jars.contains( name.substring(0, idx) );
}
if (!found) continue;
JarFile jarFile = new JarFile(file, false);
try {
String ver;
Manifest mf = jarFile.getManifest();
if (mf!=null) {
ver = mf.getMainAttributes().getValue("Bundle-Version");
if (ver==null || ver.isEmpty())
ver = mf.getMainAttributes().getValue("Implementation-Version");
} else ver=null;
if (verbuf.length()>0) verbuf.append(", ");
verbuf.append(name + "=" + (ver!=null?ver:"") );
} finally {
jarFile.close();
}
}
System.out.println( verbuf.toString() );
} catch(Exception ex) {
ex.printStackTrace();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.