Java扩展应用程序类加载器?

Java扩展应用程序类加载器?,java,classloader,Java,Classloader,问题: 我的公司有很多不同的JAR/现有项目,它们针对客户运行。出于调试目的,我们希望生成一个日志,用于对每个组件进行加载,更具体地说:从何处加载。例如:jar StackOverFlowJar.jar中的stack.overflow.ClassA 我的想法: 我已经尝试过向每个jar/现有项目传递一个自定义类加载器。这个自定义类装入器可能会将上述信息写入一个文件,并将类装入的正常流程委托给其父类 我的CustomClassLoader扩展了ClassLoader,我可以看到它加载了如下类: j

问题: 我的公司有很多不同的JAR/现有项目,它们针对客户运行。出于调试目的,我们希望生成一个日志,用于对每个组件进行加载,更具体地说:从何处加载。例如:jar StackOverFlowJar.jar中的stack.overflow.ClassA

我的想法: 我已经尝试过向每个jar/现有项目传递一个自定义类加载器。这个自定义类装入器可能会将上述信息写入一个文件,并将类装入的正常流程委托给其父类

我的CustomClassLoader扩展了ClassLoader,我可以看到它加载了如下类:

java.lang.Class
java.lang.Thread
java.lang.ThreadGroup
等等,核心库中的所有标准java类。这些类确实到达了我的CustomClassLoader。但是,如下图所示:

资料来源:

有多个类加载器。引导类加载器(我用CustomClassLoader扩展的)只负责核心库。如果找不到自定义创建的类,它会将其委托回扩展类加载器。如果扩展类加载器找不到它,它会将它委托回应用程序类加载器,我可以在调试modus中看到,这确实是加载我的自定义类的一个。但它不是通过我的CustomClassLoader实现的

我的问题: 是否可以扩展应用程序类加载器和扩展类加载器?或者我的问题还有其他解决方法吗


提前非常感谢

您可以创建一个简单的Jar文件,运行该文件,只需在类路径中使用该Jar即可。然后,您可以拥有一个扩展
URLClassLoader
的类,将此对象传递给实际的类路径,通过类加载器加载实际的主类,并使用反射调用main方法

示例主方法

  public static void main (String... args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    URL[] classpath = new URL[0];

    LoggingClassLoader loggingClassLoader = new LoggingClassLoader(classpath, Main.class.getClassLoader());
    Class<?> aClass = loggingClassLoader.loadClass("com.company.project.RealMain");
    Method main = aClass.getMethod("main", args.getClass());
    main.invoke(null);

  }
publicstaticvoidmain(String…args)抛出ClassNotFoundException、NoSuchMethodException、InvocationTargetException、IllegalAccessException{
URL[]类路径=新URL[0];
LoggingClassLoader LoggingClassLoader=新的LoggingClassLoader(类路径,Main.class.getClassLoader());
类aClass=loggingClassLoader.loadClass(“com.company.project.RealMain”);
方法main=aClass.getMethod(“main”,args.getClass());
main.invoke(null);
}
示例类装入器对象

编辑

我稍微扩展了这个示例,现在每个jar/URL有一个加载程序,以防您需要跟踪哪个类是从哪个jar加载的:

  public static class LoggingClassLoader extends URLClassLoader {
    final List<ChildLogger> childLochildLoggersders = new ArrayList<>();

    public LoggingClassLoader(URL[] urls, ClassLoader parent) {
      super(urls, parent);
      for(URL url : urls) {
        childLochildLoggersders.add(new ChildLogger(url, this));
      }
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
      for(ChildLogger childLoader : childLochildLoggersders) {
        try {
          return childLoader.loadClass(name);
        } catch(ClassNotFoundException ignore) {
        }
      }
      throw new ClassNotFoundException(name);
    }

    private static class ChildLogger extends URLClassLoader {
      private final URL url;

      private ChildLogger(URL url, ClassLoader parent) {
        super(new URL[]{url}, parent);
        this.url = url;
      }

      @Override
      protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class<?> aClass = super.findClass(name);
        System.out.println("Loaded from :" + url + " class: " + name);
        return aClass;
      }
    }

  }
公共静态类LoggingClassLoader扩展URLClassLoader{
最终列表childLochildLoggersders=new ArrayList();
公共日志类加载器(URL[]URL,类加载器父级){
超级(URL,父级);
用于(URL:URL){
添加(新的ChildLogger(url,this));
}
}
@凌驾
受保护类findClass(字符串名称)引发ClassNotFoundException{
用于(ChildLogger childLoader:childLochildLoggersders){
试一试{
返回childLoader.loadClass(名称);
}捕获(ClassNotFoundException忽略){
}
}
抛出新的ClassNotFoundException(名称);
}
私有静态类ChildLogger扩展URLClassLoader{
私有最终URL;
私有子记录器(URL、类加载器父级){
超级(新URL[]{URL},父级);
this.url=url;
}
@凌驾
受保护类findClass(字符串名称)引发ClassNotFoundException{
类aClass=super.findClass(名称);
System.out.println(“加载自:“+url+”类:“+name”);
返回aClass;
}
}
}
您也可以使用

-详细:类


JVM选项打印类从何处加载

这可能是一个非常好的主意!今天我将尝试使用这个,如果有帮助,请将这个答案标记为“唯一”:)谢谢!如果您遇到任何问题或有任何问题,只需添加一条评论:)谢谢您的帮助。最后,我选择使用verbose选项调用每个项目,并让它从命令写入文件。不过,非常感谢你的好例子,实际上我从中学到了很多:)解决方法: