如何设置上下文类加载器的类路径以进行运行时编译?

问题描述 投票:0回答:5

我想在 weblogic 10.3 服务器中运行时编译和加载新类。类加载似乎有些简单:

class ClassFileManager 
extends ForwardingJavaFileManager<StandardJavaFileManager> {

  Map<String, JavaClassObject> classes = new HashMap<String, JavaClassObject>();

  public ClassFileManager(StandardJavaFileManager standardManager) {
    super(standardManager);
  }

  @Override
  public ClassLoader getClassLoader(Location location) {
    return new SecureClassLoader(currentThread().getContextClassLoader()) {
      @Override
      protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] b = classes.get(name).getBytes();
        return super.defineClass(name, b, 0, b.length);
      }
    };
  }

  @Override
  public JavaFileObject getJavaFileForOutput(
      Location location, String className, Kind kind, FileObject sibling)
      throws IOException {
    JavaClassObject result = new JavaClassObject(className, kind);
    classes.put(className, result);
    return result;
  }
}

执行类加载的最简单方法似乎是初始化

SecureClassLoader
并让它使用
contextClassLoader
作为父级。

但是当为JDK的运行时编译器设置

-classpath
选项时,我似乎找不到字符串形式的“上下文类路径”。以下是一些可行的黑客技术“足够好”

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
ClassFileManager fileManager = 
    new ClassFileManager(compiler.getStandardFileManager(null, null, null));
List<String> options = new ArrayList<String>();
options.add("-classpath");
options.add(System.getProperty("java.class.path") + ";" +
    getClass().getProtectionDomain()
              .getCodeSource().getLocation()
              .toURI().toString()
              .replace("file:/", "").replace("/", "\\"));

但是它不会生成上下文类加载器的完整类路径。我怎样才能可靠地做到这一点?我可以吗?

java weblogic java-6
5个回答
2
投票

WebLogic 10.3.6 有一个相当复杂的

ClassLoader
实现。幸运的是,用于 Web 应用程序的类加载器公开了一个
getClassPath
方法。

ClassLoader cl = Thread.currentThread().getContextClassLoader();
String classPath = ((weblogic.utils.classloaders.GenericClassLoader)cl).getClassPath();

// Once we have a classpath it's standard procedure
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager sfm = compiler.getStandardFileManager(null, null, null);
List<String> optionList = new ArrayList<String>();
optionList.addAll(Arrays.asList("-classpath", classPath));
compiler.getTask(null, sfm, null, optionList, null, sources).call();

1
投票

也许这可以帮助你。它适用于我在 WebLogic 上的项目。

String getClassPath() {
    final String BASE_PATH = "<your_project_folder_name>";
    String path = "";

    String classPathProperty = System.getProperty("java.class.path");
    if (classPathProperty != null) {
        path = classPathProperty + File.pathSeparator;
    }

    URL classLocation = this.getClass().getProtectionDomain().getCodeSource().getLocation();
    URL classesLocation = this.getClass().getClassLoader().getResource("/");
    if (classesLocation == null) {
        path = path + classLocation.getPath();
    }
    else {
        String classesLocationPath = classesLocation.getPath();
        String libsLocationPath = classesLocationPath + "../lib";
        File libsLocation = new File(libsLocationPath);
        if (libsLocation.exists() == false) {
            libsLocationPath = URLDecoder.decode(classesLocationPath + "../" + BASE_PATH + "/WEB-INF/lib/");
            libsLocation = new File(libsLocationPath);
        }

        File[] filesInLibraryPath = libsLocation.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return name.endsWith(".jar");
            }
        });
        if (filesInLibraryPath != null) {
            for (File libraryFile : filesInLibraryPath) {
                libsLocationPath += File.pathSeparator + URLDecoder.decode(libraryFile.getAbsolutePath());
            }
        }
        path =  path +
                classLocation.getPath() + File.pathSeparator + 
                classesLocationPath + File.pathSeparator + 
                libsLocationPath;
        path = URLDecoder.decode(path);
    }
    return path;
}

1
投票

Tomcat 使用的开源 Jasper JSP 编译器询问上下文 URLClassLoader 以生成传递给编译器的类路径字符串。

如果 WebLogic 不公开

getURLs
方法,另一种方法是使用
JavaFileManager
的自定义实现,该实现使用上下文类加载器
getResource()
方法来获取类文件。

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
JavaFileManager customFileManager = ...
compiler.getTask(null, customFileManager, null, null, null, sources).call();

这里有一个完整的示例


1
投票

我建议您按照 @anttix 的想法,让您的自定义

JavaFileManager
了解上下文类加载器,并将其指定为
JavaCompiler.getTask
的参数。

有关更多信息和示例实现(包括说明)(此处过于冗长,无法在此重复),请参阅博客文章 使用内置 JavaCompiler 和自定义类加载器


0
投票

由于 "WebApplicationClassLoader" 是一种 "URLClassLoader",也许您可以使用此代码片段。

ClassLoader classLoader = getClass().getClassLoader();
System.out.println("ClassLoader: " + classLoader);
URLClassLoader urlClassLoader = (URLClassLoader)classLoader;
URL[] urls = urlClassLoader.getURLs();
for (URL u : urls) {
    System.out.println("url: " + u);
}

此代码列出了类路径中的所有 jar 和目录。

© www.soinside.com 2019 - 2024. All rights reserved.