我有一个名为BuildNumberService的简单服务,它将由spring实例化。
我正在尝试找到该类最干净的代码,以便从已打包的jar文件中找出MANIFEST.MF文件。
代码必须在servlet容器中运行。
@Service
public class BuildNumberService {
private static final String IMPLEMENTATION_BUILD = "Implementation-Build";
private String version = null;
public BuildNumberService() {
// find correct manifest.mf
// ?????
// then read IMPLEMENTATION_BUILD attributes and caches it.
Attributes mainAttributes = mf.getMainAttributes();
version = mainAttributes.getValue(IMPLEMENTATION_BUILD);
}
public String getVersion() {
return this.version;
}
}
你会怎么做?
编辑:实际上,我正在尝试做的是,按名称找到一个与实际类位于同一个包中的资源。
好吧,如果你知道jar在文件系统上(例如不在战争中)并且你也知道安全管理器授予你访问类保护域的权限,你可以这样做:
public static InputStream findManifest(final Class<?> clazz) throws IOException,
URISyntaxException{
final URL jarUrl =
clazz.getProtectionDomain().getCodeSource().getLocation();
final JarFile jf = new JarFile(new File(jarUrl.toURI()));
final ZipEntry entry = jf.getEntry("META-INF/MANIFEST.MF");
return entry == null ? null : jf.getInputStream(entry);
}
我找到了另一种解决方案来加载MANIFEST.MF而不需要引用servlet上下文,只需使用Spring Framework。
我在Spring 3.1.2.RELEASE中使用了这个配置,但我相信它在以后的版本中应该可以正常工作。
首先,在applicationContext.xml中编写以下bean
<bean class="java.util.jar.Manifest" id="manifest">
<constructor-arg>
<value>/META-INF/MANIFEST.MF</value>
</constructor-arg>
</bean>
您应该注意到Manifest类的构造函数参数接受InputStream作为参数,但是,您不必担心这会导致Spring转换提供的值以匹配构造函数参数。此外,通过使用斜杠/
(/ META-INF / ...)启动路径,Spring在servlet上下文对象上查找此文件,而从classpath:
前缀开始,它会引导Spring查看类路径以查找请求的资源。
其次,在你的班级中声明上述bean:
@Autowired
@Qualifier("manifest")
private Manifest manifest;
我的MANIFEST.MF位于$ WEBAPP_ROOT / META-INF /文件夹下,我已经在Apache Tomcat 7和WildFly 8上成功测试了这个解决方案。
Manifest mf = new Manifest();
Resource resource = new ClassPathResource("META-INF/MANIFEST.MF");
InputStream is= resource.getInputStream();
mf.read(is);
if (mf != null) {
Attributes atts = mf.getMainAttributes();
implementationTitle = atts.getValue("Implementation-Title");
}