java – WAR共享的容器级版本化库
在一个
Java servlet容器中(最好是Tomcat,但是如果这可以在另一个容器中完成,那么这样说)我希望理论上可行的东西.我的问题是,是否存在支持它的工具,以及是否存在哪些工具(或者我应该进一步研究哪些名称).
这是我的问题:在一个servlet容器中,我想运行大量不同的WAR文件.它们共享一些大型公共库(例如Spring).乍一看,我有两个不可接受的选择: >在每个WAR文件中包含大型库(例如Spring).这是不可接受的,因为它会加载大量的Spring副本,耗尽服务器上的内存. 但理论上,有一种替代方案可行: >将大型库的每个版本放入容器级类路径中.做一些容器级魔术,以便每个WAR文件声明它希望使用哪个版本,并且它将在其类路径中找到它. “魔术”必须在容器级别完成(我认为),因为这只能通过使用不同的类加载器加载库的每个版本来实现,然后调整每个WAR文件可见的类加载器. 所以,你有没有听说过这样做?如果是这样,怎么样?或者告诉我它叫什么,这样我就可以进一步研究. 解决方法
关于Tomcat,对于第7版,你可以像这样使用
VirtualWebappLocader
<Context> <Loader className="org.apache.catalina.loader.VirtualWebappLoader" virtualClasspath="/usr/shared/lib/spring-3/*.jar,/usr/shared/classes" /> </Context> 对于第8版,应该使用Pre- & Post- Resources <Context> <Resources> <PostResources className="org.apache.catalina.webresources.DirResourceSet" base="/usr/shared/lib/spring-3" webAppMount="/WEB-INF/lib" /> <PostResources className="org.apache.catalina.webresources.DirResourceSet" base="/usr/shared/classes" webAppMount="/WEB-INF/classes" /> </Resources> </Context> 不要忘记将相应的context.xml放入webapp的META-INF中. For the jetty以及其他容器可以使用相同的技术. UPDATE SharedWebappLoader package com.foo.bar; import org.apache.catalina.LifecycleException; import org.apache.catalina.loader.WebappLoader; public class SharedWebappLoader extends WebappLoader { private String pathID; private String pathConfig; static final ThreadLocal<ClassLoaderFactory> classLoaderFactory = new ThreadLocal<>(); public SharedWebappLoader() { this(null); } public SharedWebappLoader(ClassLoader parent) { super(parent); setLoaderClass(SharedWebappClassLoader.class.getName()); } public String getPathID() { return pathID; } public void setPathID(String pathID) { this.pathID = pathID; } public String getPathConfig() { return pathConfig; } public void setPathConfig(String pathConfig) { this.pathConfig = pathConfig; } @Override protected void startInternal() throws LifecycleException { classLoaderFactory.set(new ClassLoaderFactory(pathConfig,pathID)); try { super.startInternal(); } finally { classLoaderFactory.remove(); } } } SharedWebappClassLoader package com.foo.bar; import org.apache.catalina.LifecycleException; import org.apache.catalina.loader.ResourceEntry; import org.apache.catalina.loader.WebappClassLoader; import java.net.URL; public class SharedWebappClassLoader extends WebappClassLoader { public SharedWebappClassLoader(ClassLoader parent) { super(SharedWebappLoader.classLoaderFactory.get().create(parent)); } @Override protected ResourceEntry findResourceInternal(String name,String path) { ResourceEntry entry = super.findResourceInternal(name,path); if(entry == null) { URL url = parent.getResource(name); if (url == null) { return null; } entry = new ResourceEntry(); entry.source = url; entry.codeBase = entry.source; } return entry; } @Override public void stop() throws LifecycleException { ClassLoaderFactory.removeLoader(parent); } } ClassLoaderFactory package com.foo.bar; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.HashMap; import java.util.Map; import java.util.Properties; public class ClassLoaderFactory { private static final class ConfigKey { private final String pathConfig; private final String pathID; private ConfigKey(String pathConfig,String pathID) { this.pathConfig = pathConfig; this.pathID = pathID; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ConfigKey configKey = (ConfigKey) o; if (pathConfig != null ? !pathConfig.equals(configKey.pathConfig) : configKey.pathConfig != null) return false; if (pathID != null ? !pathID.equals(configKey.pathID) : configKey.pathID != null) return false; return true; } @Override public int hashCode() { int result = pathConfig != null ? pathConfig.hashCode() : 0; result = 31 * result + (pathID != null ? pathID.hashCode() : 0); return result; } } private static final Map<ConfigKey,ClassLoader> loaders = new HashMap<>(); private static final Map<ClassLoader,ConfigKey> revLoaders = new HashMap<>(); private static final Map<ClassLoader,Integer> usages = new HashMap<>(); private final ConfigKey key; public ClassLoaderFactory(String pathConfig,String pathID) { this.key = new ConfigKey(pathConfig,pathID); } public ClassLoader create(ClassLoader parent) { synchronized (loaders) { ClassLoader loader = loaders.get(key); if(loader != null) { Integer usageCount = usages.get(loader); usages.put(loader,++usageCount); return loader; } Properties props = new Properties(); try (InputStream is = new BufferedInputStream(new FileInputStream(key.pathConfig))) { props.load(is); } catch (IOException e) { throw new RuntimeException(e); } String libsStr = props.getProperty(key.pathID); String[] libs = libsStr.split(File.pathSeparator); URL[] urls = new URL[libs.length]; try { for(int i = 0,len = libs.length; i < len; i++) { urls[i] = new URL(libs[i]); } } catch (MalformedURLException e) { throw new RuntimeException(e); } loader = new URLClassLoader(urls,parent); loaders.put(key,loader); revLoaders.put(loader,key); usages.put(loader,1); return loader; } } public static void removeLoader(ClassLoader parent) { synchronized (loaders) { Integer val = usages.get(parent); if(val > 1) { usages.put(parent,--val); } else { usages.remove(parent); ConfigKey key = revLoaders.remove(parent); loaders.remove(key); } } } } 第一个应用程序的context.xml <Context> <Loader className="com.foo.bar.SharedWebappLoader" pathConfig="${catalina.base}/conf/shared.properties" pathID="commons_2_1"/> </Context> 第二个应用程序的context.xml <Context> <Loader className="com.foo.bar.SharedWebappLoader" pathConfig="${catalina.base}/conf/shared.properties" pathID="commons_2_6"/> </Context> $TOMCAT_HOME / conf目录/ shared.properties commons_2_1=file:/home/xxx/.m2/repository/commons-lang/commons-lang/2.1/commons-lang-2.1.jar commons_2_6=file:/home/xxx/.m2/repository/commons-lang/commons-lang/2.6/commons-lang-2.6.jar (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |